编辑: [它开始于角色替换,我最终在Dimitre Novatchev和Roland Bouman的帮助下发现了弦乐替换
我认为样本代码足以解释要求.
这是示例XML:
<root>
<node1>text node</node1>
<node2>space between the text</node2>
<node3> has to be replaced with $</node3>
</root>
Run Code Online (Sandbox Code Playgroud)
这是我期待的输出:
<root>
<node1>text$node</node1>
<node2>space$between$the$text</node2>
<node3>$has$to$be$replaced$with$$</node3>
</root>
Run Code Online (Sandbox Code Playgroud)
我试过写一个没有显示所需输出的XSLT代码..
这是代码:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()[.!='']">
<xsl:call-template name="rep_space">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="rep_space">
<xsl:param name="text"/>
<xsl:variable name="temp" select="'6'"/>
<xsl:choose>
<xsl:when test="contains(text,'2')">
<xsl:call-template name="rep_space">
<xsl:with-param name="text" select="concat((concat(substring-before(text,' '),temp)),substring-after(text,' '))"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)
翻译(.,'','$')函数有效..但不是令人满意的程度..我的问题是..如果它是字符串而不是字符怎么办?我的意思是,假设我打算将''替换为'%20"?还有一个案例,如果输入XML不是"Pretty Print XML",那么XML中出现的所有空格都会被'$'替换.
漂亮的打印XML是具有适当缩进的文件(通常我的输入XML从来没有这个),例如:
还有一个节点,这是@ lower level
你可以观察到,在节点之前没有"空格字符",<new> <test>但它们实际上是正确缩进的(使用altova XMLSPY,我们可以在编辑菜单中给出一个简单的命令..使任何XML文件为"漂亮的打印XML").
如下例所示..
<new>
<test>one more node</test>
<test2>
<child>this is @ lower level</child>
</test2>
</new>
Run Code Online (Sandbox Code Playgroud)
在所有开始标记之前都有空格字符.. <child>标记之前的空格比<test2>节点多.
使用第二个样本xml ..所有空格字符都替换为" %20"..因此输出将是..
<new>
%20%20<test>one%20more%20node</test>
%20%20<test2>
%20%20%20%20<child>this%20is%20@%20lower%20level</child>
%20%20</test2>
</new>
Run Code Online (Sandbox Code Playgroud)
当然不是预期的..
Dimitre Novatchev和Roland Bouman 发布的解决方案也可以通过修改传递给被调用模板的参数,用另一个字符串替换字符串.
那是很好的学习@Dimitre,@ Roland,我真的很感谢和感激你们..
问候,
婴儿亲.
根据Roland的愿望,这是一个尾递归解决方案:
<xsl:template name="replace">
<xsl:param name="ptext"/>
<xsl:param name="ppattern"/>
<xsl:param name="preplacement"/>
<xsl:choose>
<xsl:when test="not(contains($ptext, $ppattern))">
<xsl:value-of select="$ptext"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-before($ptext, $ppattern)"/>
<xsl:value-of select="$preplacement"/>
<xsl:call-template name="replace">
<xsl:with-param name="ptext"
select="substring-after($ptext, $ppattern)"/>
<xsl:with-param name="ppattern" select="$ppattern"/>
<xsl:with-param name="preplacement" select="$preplacement"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)
请注意,递归调用是模板中的最后一条指令 - 这就是它使尾递归的原因.尾递归的属性允许智能XSLT处理器(例如Saxon或.NET XslCompiledTransform)优化代码,用简单的迭代替换递归.
即使调用的"嵌套"是数百万,这样的代码也不会以堆栈溢出异常结束,而非尾递归(和递归)代码通常会在大约1000个嵌套调用的深度引发此堆栈溢出(这真的取决于可用内存的数量).
如果XSLT处理器不够"足够聪明"怎么办?是否有另一种技术可以避免深层递归调用堆栈溢出,这适用于每个 XSLT处理器?
在一个单独的问题中问我,我可能会告诉你:)