编辑: [从字符替换开始 我最终发现了字符串 在Dimitre Novatchev和Roland Bouman
的帮助下进行替换
我认为样本代码足以解释要求。
这是示例XML:
<root>
<node1>text node</node1>
<node2>space between the text</node2>
<node3> has to be replaced with $</node3>
</root>
这是我期待的输出:
<root>
<node1>text$node</node1>
<node2>space$between$the$text</node2>
<node3>$has$to$be$replaced$with$$</node3>
</root>
我尝试编写一个没有显示所需输出的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>
翻译(。,'','$')函数有效..但不是令人满意的程度..我的问题是..如果它是一个字符串怎么办 而不是性格?我的意思是,假设 我打算用'替换'' “20%”?还有一个案例,如果是的话 输入XML不是“Pretty Print XML”, 那么所有的空间都出现在XML中 被替换为'$'..
漂亮的打印XML 是具有适当缩进的文件,(通常我的输入XML从来没有这个),例如:
再多一个节点 这是@较低级别
你可以观察到,<new> <test>
个节点之前有没有“空格字符”,但它们实际上是正确缩进的(使用altova XMLSPY,我们可以在编辑菜单中给出一个简单的命令..使任何XML文件为“漂亮的打印XML”)..
如下例所示..
<new>
<test>one more node</test>
<test2>
<child>this is @ lower level</child>
</test2>
</new>
在所有开始标记之前都有空格字符.. <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>
当然不是预期的。
Dimitre Novatchev和Roland Bouman发布的解决方案也可以用其他字符串替换字符串, 修改传递给的参数 正在调用模板。
这很棒的学习@Dimitre, @Roland,我真的很感激 感谢你们..
问候,新生儿。
答案 0 :(得分:8)
根据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>
请注意,递归调用是模板中的最后一条指令 - 这就是它的尾递归。尾递归的属性允许智能XSLT处理器(例如Saxon或.NET XslCompiledTransform)优化代码,用简单的迭代替换递归。
即使调用的“嵌套”是数百万,这样的代码也不会以堆栈溢出异常结束,而非尾递归(和递归)代码通常会在大约1000嵌套的深度引发此堆栈溢出调用(这实际上取决于可用内存的数量)。
如果XSLT处理器不够“足够智能”怎么办?还有另一种技术可以避免深层递归调用堆栈溢出,它可以与每个 XSLT处理器一起使用吗?
在另一个问题中问我,我可能会告诉你:)
答案 1 :(得分:4)
查看XPath翻译功能: http://www.w3.org/TR/xpath/#function-translate
<xsl:template match="text()">
<xsl:value-of select="translate(., ' ', '$')"/>
</xsl:template>
如果它不是单个字符,而是您必须替换的字符串,则需要相当多的工作量,并且您需要一个模板来递归替换字符串:
<xsl:template match="text()[not(../*)]">
<xsl:call-template name="replace">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="search" select="' '"/>
<xsl:with-param name="replace" select="'%20'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="text"/>
<xsl:param name="search"/>
<xsl:param name="replace"/>
<xsl:choose>
<xsl:when test="contains($text, $search)">
<xsl:variable name="replace-next">
<xsl:call-template name="replace">
<xsl:with-param name="text" select="substring-after($text, $search)"/>
<xsl:with-param name="search" select="$search"/>
<xsl:with-param name="replace" select="$replace"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of
select="
concat(
substring-before($text, $search)
, $replace
, $replace-next
)
"
/>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$text"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
编辑:将match =“text()”更改为 match =“text()[not(../*)]”,以便 输入xml不一定是一种 “漂亮的打印XML”..(以便删除 用不需要的空间替换 这样的xml文件中的“%20”字符串)
答案 2 :(得分:1)
“prety-printed xml”的解决方案并不是真正的解决方案。
想象一下这样的文档:
<a>
<b>
<c>O M G</c>
<d>D I Y</d>
</b>
</a>
当前接受的解决方案的输出(在将其包装在<xsl:stylesheet>
中并添加标识规则后):
<a>
%20<b>
%20%20<c>O$M$G</c>
%20%20<d>D$I$Y</d>
%20</b>
</a>
现在,为什么建议的解决方法不能保存这种情况?正如我们从上面的例子中看到的,一个元素可以有多个具有文本节点的子元素......
什么是真正的解决方案?
XSLT的创建者已经考虑过这个问题。使用正确的术语,我们希望XSLT处理器忽略所有无关紧要的仅空白文本节点,就好像它们根本不是文档树的一部分一样。这是通过<xsl:strip-space>
指令实现的。
只需在全局级别添加此(作为<xsl:stylesheet>
的子级,并且出于可读性,在任何模板之前):
<xsl:strip-space elements="*"/>
现在你真的有了一个有效的解决方案。