一、方案一:
我先分析一下这里的问题:
鉴于此源 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:template match="Table">
<a href="#">
Table here
</a>
</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="/">
<xsl:for-each select="//Object/Table">
<a href="#">
some text
</a>
</xsl:for-each>
</xsl:template>
-->
<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
二、解决方案 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
在捕获转换的输出时执行。这确保了现有代码中的任何模板(即使是我们覆盖的模板——例如模板匹配/
)都将被选择执行,就像现有转换由自身执行的情况一样)。
我们使用扩展函数将 RTF 转换为常规树msxsl:node-set()
(XslCompiledTransform 也支持EXSLTnode-set()
扩展函数)。
我们对如此制作的常规树进行外观调整。
请注意:
这代表了一种在不触及现有代码的情况下对现有转换进行后处理的通用算法。