Xml 使用exslt str的问题:替换为节点集

Xml 使用exslt str的问题:替换为节点集,xml,xslt-1.0,exslt,node-set,Xml,Xslt 1.0,Exslt,Node Set,在使用exslt字符串替换函数时,我认为存在一个名称空间问题。我想根据文档使用exslt string replace函数的节点集形式替换目标字符串中的几个字符串。但是,它似乎只替换节点集的第一个字符串,而不替换其他字符串 这是我的档案: <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#160;"> <!ENTITY yen "&#165;"> <!ENTITY cir

在使用exslt字符串替换函数时,我认为存在一个名称空间问题。我想根据文档使用exslt string replace函数的节点集形式替换目标字符串中的几个字符串。但是,它似乎只替换节点集的第一个字符串,而不替换其他字符串

这是我的档案:

<!DOCTYPE xsl:stylesheet  [
    <!ENTITY nbsp   "&#160;">
    <!ENTITY yen    "&#165;">
    <!ENTITY circle  "&#9679;">
    <!ENTITY raquo "&#187;">
]>
<xsl:stylesheet 
    version="1.0" 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    xmlns:str="http://exslt.org/strings"
    xmlns:exsl="http://exslt.org/common"
    xmlns:regexp="http://exslt.org/regular-expressions"
    extension-element-prefixes="msxsl str exsl regexp">
<xsl:output 
    method="html" 
    indent="yes" 
    encoding="utf-8" 
    doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" 
/>

<!-- Start of the main template -->
<xsl:template match="/Top">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">
    <body>
        <xsl:variable name="text">
            -[this]- This is a test string -[that]-
            -[this]- This is another test string -[that]-
        </xsl:variable>
        text: <xsl:value-of select="$text" disable-output-escaping="yes" />

        <xsl:variable name="searches" xmlns="">
            <replacements xmlns="">
                <searches>
                    <search>-[this]-</search>
                    <search>-[that]-</search>
                </searches>
                <replaces>
                    <replace>**[this]**</replace>
                    <replace>**[that]**</replace>
                </replaces>
            </replacements>
        </xsl:variable>

        <xsl:variable name="search_set" select="exsl:node-set($searches)/replacements/searches/search" />
        <xsl:variable name="replace_set" select="exsl:node-set($searches)/replacements/replaces/replace" />
        search_set: <xsl:copy-of select="$search_set" />
        replace_set: <xsl:copy-of select="$replace_set" />
        <xsl:if test="$search_set">
            replaced via function:
            <xsl:value-of select="str:replace($text, $search_set, $replace_set)" disable-output-escaping="yes" />
            replaced via template:
            <xsl:variable name="replaced_tpl">
                <xsl:call-template name="str:replace">
                    <xsl:with-param name="string" select="$text"/>
                    <xsl:with-param name="search" select="$search_set"/>
                    <xsl:with-param name="replace" select="$replace_set"/>
                </xsl:call-template>
            </xsl:variable>
            <xsl:value-of select="$replaced_tpl" disable-output-escaping="yes" />
        </xsl:if>

    </body>
</html>

</xsl:template><!-- / end main template -->

<xsl:template name="str:replace" xmlns="">
   <xsl:param name="string" select="''" />
   <xsl:param name="search" select="/.." />
   <xsl:param name="replace" select="/.." />

   <xsl:choose>
      <xsl:when test="not($string)" />
      <xsl:when test="not($search)">
         <xsl:value-of select="$string" />
      </xsl:when>
      <xsl:when test="function-available('exsl:node-set')">
<!--  this converts the search and replace arguments to node sets
              if they are one of the other XPath types  -->
         <xsl:variable name="search-nodes-rtf">
            <xsl:copy-of select="$search" />
         </xsl:variable>
         <xsl:variable name="replace-nodes-rtf">
            <xsl:copy-of select="$replace" />
         </xsl:variable>
         <xsl:variable name="replacements-rtf">
            <xsl:for-each select="exsl:node-set($search-nodes-rtf)/node()">
               <xsl:variable name="pos"
                             select="position()" />
               <replace search="{.}">
                  <xsl:copy-of select="exsl:node-set($replace-nodes-rtf)/node()[$pos]" />
               </replace>
            </xsl:for-each>
         </xsl:variable>
         <xsl:variable name="sorted-replacements-rtf">
            <xsl:for-each select="exsl:node-set($replacements-rtf)/replace">
               <xsl:sort select="string-length(@search)"
                         data-type="number"
                         order="descending" />
               <xsl:copy-of select="." />
            </xsl:for-each>
         </xsl:variable>
         <xsl:call-template name="str:_replace">
            <xsl:with-param name="string"
                            select="$string" />
            <xsl:with-param name="replacements"
                            select="exsl:node-set($sorted-replacements-rtf)/replace" />
         </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
         <xsl:message terminate="yes">
            ERROR: template implementation of str:replace relies on exsl:node-set().
         </xsl:message>
      </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="str:_replace">
   <xsl:param name="string"
              select="''" />
   <xsl:param name="replacements"
              select="/.." />
   <xsl:choose>
      <xsl:when test="not($string)" />
      <xsl:when test="not($replacements)">
         <xsl:value-of select="$string" />
      </xsl:when>
      <xsl:otherwise>
         <xsl:variable name="replacement"
                       select="$replacements[1]" />
         <xsl:variable name="search"
                       select="$replacement/@search" />
         <xsl:choose>
            <xsl:when test="not(string($search))">
               <xsl:value-of select="substring($string, 1, 1)" />
               <xsl:copy-of select="$replacement/node()" />
               <xsl:call-template name="str:_replace">
                  <xsl:with-param name="string"
                                  select="substring($string, 2)" />
                  <xsl:with-param name="replacements"
                                  select="$replacements" />
               </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains($string, $search)">
               <xsl:call-template name="str:_replace">
                  <xsl:with-param name="string"
                                  select="substring-before($string, $search)" />
                  <xsl:with-param name="replacements"
                                  select="$replacements[position() > 1]" />
               </xsl:call-template>
               <xsl:copy-of select="$replacement/node()" />
               <xsl:call-template name="str:_replace">
                  <xsl:with-param name="string"
                                  select="substring-after($string, $search)" />
                  <xsl:with-param name="replacements"
                                  select="$replacements" />
               </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
               <xsl:call-template name="str:_replace">
                  <xsl:with-param name="string"
                                  select="$string" />
                  <xsl:with-param name="replacements"
                                  select="$replacements[position() > 1]" />
               </xsl:call-template>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:otherwise>
   </xsl:choose>
</xsl:template>


</xsl:stylesheet>
在这一点上,模板表单工作,这使我相信这是一个名称空间的问题。我相信在函数中,当它对节点进行排序并创建自己的
replace
节点时,如下所示:

<replace search="{.}">
    <xsl:copy-of select="exsl:node-set($replace-nodes-rtf)/node()[$pos]" />
</replace>

该节点最终可能位于不同的名称空间中,因此后续循环无法对其进行寻址。将
xmlns
属性添加到
str:replace
会将其中创建的任何节点与我传入的节点放在同一个空名称空间中,然后它就会工作。然而,无论我尝试什么,我都无法让函数版本正常工作。我甚至从文件和我创建的xml节点集中删除了所有名称空间,但它仍然不起作用。坦率地说,所有这些名称空间的东西对我来说都有点混乱。也许这根本不是问题所在

任何帮助都将不胜感激,谢谢

我可以正常使用函数来替换字符串,只需传入 第二个和第三个参数的字符串

这可能是在处理器中如何实现函数的问题。我建议您消除所有其他可能的失败原因,并尝试应用以下样式表:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/input">
    <output>
        <xsl:choose>
            <xsl:when test="function-available('str:replace')">
                <xsl:value-of select="str:replace(string, search, replace)" />  
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>function str:replace() is not supported</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </output>
</xsl:template>

</xsl:stylesheet>
<input>
    <string>Mary had a little lamb, its fleece was white as snow. 
And everywhere that Mary went, the lamb was sure to go.</string>
    <search>Mary</search>
    <search>lamb</search>
    <search>fleece</search>
    <replace>John</replace>
    <replace>dog</replace>
    <replace>fur</replace>
</input>
<input>
    <string>Mary had a little lamb, its fleece was white as snow. And everywhere that Mary went, the lamb was sure to go.</string>
</input>

不支持函数str:replace()
对于此输入

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/input">
    <output>
        <xsl:choose>
            <xsl:when test="function-available('str:replace')">
                <xsl:value-of select="str:replace(string, search, replace)" />  
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>function str:replace() is not supported</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </output>
</xsl:template>

</xsl:stylesheet>
<input>
    <string>Mary had a little lamb, its fleece was white as snow. 
And everywhere that Mary went, the lamb was sure to go.</string>
    <search>Mary</search>
    <search>lamb</search>
    <search>fleece</search>
    <replace>John</replace>
    <replace>dog</replace>
    <replace>fur</replace>
</input>
<input>
    <string>Mary had a little lamb, its fleece was white as snow. And everywhere that Mary went, the lamb was sure to go.</string>
</input>

玛丽有一只小羊羔,羊毛像雪一样白。
无论玛丽去哪里,羔羊都会去。
玛丽
羔羊
羊毛
约翰
狗
毛皮
并报告结果


继续的: 约翰有一只小羊羔,它的羊毛是白色的 洁白如雪。无论约翰走到哪里,羔羊都会来 开始。

那么很明显,这个功能并没有按照规范来实现。这并不是一件坏事,因为大多数处理器根本不实现str:replace()函数。在调用函数之前,只需通过调用命名模板来填充缺少的部分,例如:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl="http://exslt.org/common"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="exsl str">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:variable name="dictionary"> 
    <search>Mary</search>
    <search>lamb</search>
    <search>fleece</search>
    <replace>John</replace>
    <replace>dog</replace>
    <replace>fur</replace>
</xsl:variable>

<xsl:template match="/input">
    <output>
        <xsl:call-template name="multi-replace">
            <xsl:with-param name="string" select="string"/>
            <xsl:with-param name="search-strings" select="exsl:node-set($dictionary)/search"/>
            <xsl:with-param name="replace-strings" select="exsl:node-set($dictionary)/replace"/>
        </xsl:call-template>
    </output>
</xsl:template>

<xsl:template name="multi-replace">
    <xsl:param name="string"/>
    <xsl:param name="search-strings"/>
    <xsl:param name="replace-strings"/>
    <xsl:choose>
        <xsl:when test="$search-strings">
            <xsl:call-template name="multi-replace">
                <xsl:with-param name="string" select="str:replace($string, $search-strings[1], $replace-strings[1])"/> 
                <xsl:with-param name="search-strings" select="$search-strings[position() > 1]"/>
                <xsl:with-param name="replace-strings" select="$replace-strings[position() > 1]"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$string"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

玛丽
羔羊
羊毛
约翰
狗
毛皮
应用于以下测试输入:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/input">
    <output>
        <xsl:choose>
            <xsl:when test="function-available('str:replace')">
                <xsl:value-of select="str:replace(string, search, replace)" />  
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>function str:replace() is not supported</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </output>
</xsl:template>

</xsl:stylesheet>
<input>
    <string>Mary had a little lamb, its fleece was white as snow. 
And everywhere that Mary went, the lamb was sure to go.</string>
    <search>Mary</search>
    <search>lamb</search>
    <search>fleece</search>
    <replace>John</replace>
    <replace>dog</replace>
    <replace>fur</replace>
</input>
<input>
    <string>Mary had a little lamb, its fleece was white as snow. And everywhere that Mary went, the lamb was sure to go.</string>
</input>

玛丽有一只小羊羔,羊毛像雪一样白。无论玛丽去哪里,羔羊都会去。
您应该看到以下结果:

<?xml version="1.0" encoding="utf-8"?>
<output>John had a little dog, its fur was white as snow. And everywhere that John went, the dog was sure to go.</output>

约翰有一只小狗,它的毛像雪一样白。无论约翰走到哪里,狗都肯定会去。
(我自己无法测试,因为我的处理器都不支持该功能)


这将使您非常接近指定的行为,除了一件事:规范声明“首先替换最长的搜索字符串”。如果您也想实现它,那么必须首先对字典字符串进行排序——如果您希望实现简单,那么应该成对输入字典字符串

您确定您的处理器支持此功能吗?--附言:将示例最小化到只展示问题所需的内容是最有帮助的。如果您的问题是函数,那么模板是完全不相关的,反之亦然。我相信它是这样的,因为我可以正常使用函数来替换字符串,只为第2个和第3个参数传递字符串。此外,使用节点集的方式,它可以工作,但只替换节点集中的第一个字符串。我只是后来把模板放在那里,试图调试正在发生的事情,它帮助我认识到问题是函数的代码,当它创建自己的
replace
节点时,似乎将它们放在了一个名称空间中,以后无法读取。对,我对
搜索
替换
的字符串也有同样的处理方法,但是当我根据文档为这些参数传入节点集时,它不起作用。@ragamufin对不起,我不明白你在说什么。在上面的示例中,str:replace()函数的最后两个参数是节点集。您的结果是什么?啊,不知什么原因,我没有在底部看到您的输入xml。约翰有一只小羊羔,它的羊毛像雪一样白。无论约翰走到哪里,羔羊都会去。。因此,即使在这种情况下,似乎也只替换了第一个节点。@ragamufin很好,现在我们知道了我们要处理的是什么-问题是您希望如何从这里开始。我已经在我的答案中添加了我认为最简单的方法。谢谢。在这个问题上,我尽了最大努力解释了一些事情,但我相信这有点混乱。然而,您在这里的方法很有意义,使用exslt.org中的模板代码,我也可以通过简单地按照上面的代码向模板添加
xmlns=“”
,来实现这一点。事实上,我已经有了类似于您在这里发布的代码来替换几个字符串。当我意识到
str:replace
可以获取节点集时,我希望通过使用函数语法使我的代码更加紧凑。。。