I. 解决方案 1:
首先让我分析一下这里的问题:
假设有以下源XML文档(由于您没有提供任何文档,因此是虚构的):
<Object>
<Table>
</Table>
<Table>
</Table>
<Table>
</Table>
<Table>
</Table>
</Object>
这个转换:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
完全复现问题 -- 结果如下:
<a href="#">
some text
</a><a href="#">
some text
</a><a href="#">
some text
</a><a href="#">
some text
</a>
现在,只需取消注释第二个模板,并注释掉第一个模板即可:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="Table">
<a href="#">
Table here
</a>
</xsl:template>
</xsl:stylesheet>
结果具有想要的缩进:
<a href="#">
Table here
</a>
<a href="#">
Table here
</a>
<a href="#">
Table here
</a>
<a href="#">
Table here
</a>
这是解决方案1
II. 解决方案2:
这个解决方案可以将对现有XSLT代码所需的修改降至最低:
这是一个两阶段转换:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="ext">
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:variable>
<xsl:apply-templates select=
"ext:node-set($vrtfPass1)" mode="pass2"/>
</xsl:template>
<xsl:template match="node()|@*" mode="pass2">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="pass2"/>
</xsl:copy>
</xsl:template>
<xsl:template mode="pass2" match="*[preceding-sibling::node()[1][self::*]]">
<xsl:text>
</xsl:text>
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
我们的想法是不需要修改现有代码,只需捕获其输出,并使用几行额外的代码格式化输出以达到期望的最终外观。
当同一个XML文档应用此转换时,将产生相同的期望结果:
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
最后,这里演示了如何引入这个小改变,而不需要修改任何现有的XSLT代码::
让我们看一下现有的代码 c:\ temp \ delete \ existing.xsl
:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
如果我们运行这个程序,会得到问题输出.
现在,不要运行existing.xsl
,而是运行这个转换:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="ext">
<xsl:import href="file:///c:/temp/delete/existing.xsl"/>
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-imports/>
</xsl:variable>
<xsl:apply-templates select=
"ext:node-set($vrtfPass1)" mode="pass2"/>
</xsl:template>
<xsl:template match="node()|@*" mode="pass2">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="pass2"/>
</xsl:copy>
</xsl:template>
<xsl:template mode="pass2" match="*[preceding-sibling::node()[1][self::*]]">
<xsl:text>
</xsl:text>
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
结果是所需的,并且现有代码完全未被触及:
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
<a href="#">
some text
</a>
解释:
我们使用 xsl:import
导入任何现有代码,该代码位于导入优先级层次结构的顶层(未被其他样式表导入)。
我们在变量中捕获现有转换的输出。它具有臭名昭著的 RTF (结果树片段),需要转换为常规树以进一步处理。
关键时刻是在捕获转换输出时执行xsl:apply-imports
。这确保了任何来自现有代码的模板(即使是我们覆盖的模板--例如匹配/
的模板)都将被选择执行,就像执行现有转换本身一样。
我们使用 msxsl:node-set()
扩展函数(XslCompiledTransform 也支持 EXSLT node-set()
扩展函数)将 RTF 转换为常规树。
我们对所产生的常规树进行美化调整。
请注意:
这代表了一种不触及现有代码的后处理现有转换的通用算法。
XslTransform
不会改变XSL。如果你知道的话,你知道一个学习XSL的好来源吗?我可以谷歌,但如果有人校对过就更好了 :)。谢谢! - nicosantangelo