Recursion 将模板重新应用于XSLT中其他模板的输出
下面应该是简单或不可能做到的,但现在我不知道如何做到,所以我问。在我的XSLT中,我有生成元素的模板,这些元素应该再次被转换。更精确的是,每当模板输出一个在原始输入中将要进行转换的元素时,它应该再次进行转换。所以无限循环是可能的,但要通过仔细设计模板来避免。举个例子: input.xmlRecursion 将模板重新应用于XSLT中其他模板的输出,recursion,xslt-1.0,Recursion,Xslt 1.0,下面应该是简单或不可能做到的,但现在我不知道如何做到,所以我问。在我的XSLT中,我有生成元素的模板,这些元素应该再次被转换。更精确的是,每当模板输出一个在原始输入中将要进行转换的元素时,它应该再次进行转换。所以无限循环是可能的,但要通过仔细设计模板来避免。举个例子: input.xml <?xml version="1.0" encoding="utf-8" ?> <example> <a /> <b /> </exampl
<?xml version="1.0" encoding="utf-8" ?>
<example>
<a />
<b />
</example>
transform.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()"><xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy></xsl:template>
<xsl:template match="a">a</xsl:template>
<xsl:template match="b">
<B>b <a /></B>
</xsl:template>
</xsl:transform>
A.
B
current-output.xml
<?xml version="1.0"?>
<example>
a
<B>b <a/></B>
</example>
<?xml version="1.0"?>
<example>
a
<B>b a</B>
</example>
A.
B
所需的-output.xml
<?xml version="1.0"?>
<example>
a
<B>b <a/></B>
</example>
<?xml version="1.0"?>
<example>
a
<B>b a</B>
</example>
A.
b a
只有一次转换(如果有的话)才能实现这一目标的最佳解决方案是什么?这是一个两次转换,可以产生想要的结果:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
;世界你好
;
应用于提供的XML文档时:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
乱数假文
生成所需的正确结果:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
你好,世界
乱数假文
你好,世界
你好,世界
注意事项:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
在XSLT1.0中,应用模板的结果是臭名昭著的RTF类型(结果树片段),根据定义,除了使用xsl:copy of
和标准字符串函数外,无法进一步访问和处理模板
这就是为什么几乎每个XSLT 1.0处理器都提供一个特定于供应商的扩展函数xxx:node-set()
,该函数接受RTF并将其转换为“常规”树,可以使用任何XPath表达式访问其子代。此处,xxx
前缀必须绑定到供应商指定的命名空间uri
EXSLText:node-set()
由大多数XSLT处理器实现,因此它的使用保证了不同XSLT处理器之间的可移植性
有关附加的多过程转换示例,请参见以下内容:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
而这:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
这是一个两次转换,生成所需的结果:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
;世界你好
;
应用于提供的XML文档时:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
乱数假文
生成所需的正确结果:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
你好,世界
乱数假文
你好,世界
你好,世界
注意事项:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
在XSLT1.0中,应用模板的结果是臭名昭著的RTF类型(结果树片段),根据定义,除了使用xsl:copy of
和标准字符串函数外,无法进一步访问和处理模板
这就是为什么几乎每个XSLT 1.0处理器都提供一个特定于供应商的扩展函数xxx:node-set()
,该函数接受RTF并将其转换为“常规”树,可以使用任何XPath表达式访问其子代。此处,xxx
前缀必须绑定到供应商指定的命名空间uri
EXSLText:node-set()
由大多数XSLT处理器实现,因此它的使用保证了不同XSLT处理器之间的可移植性
有关附加的多过程转换示例,请参见以下内容:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
而这:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>
<xsl:apply-templates select="$vPass1" mode="pass2"/>
</xsl:template>
<xsl:template match="content">
<wrapper>
<replace />
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace">
<xsl:text>
Hello world
</xsl:text>
</xsl:template>
<xsl:template match="@*|node()" mode="pass2">
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
<example>
<content>Lorem ipsum</content>
<content><replace /></content>
</example>
<example>
<wrapper>
Hello world
Lorem ipsum</wrapper>
<wrapper>
Hello world
Hello world
</wrapper>
</example>
这并不是在所有情况下都有效,但有一种非常简单的方法可以实现你的要求。您所需要做的就是为
replace
模板指定一个名称,并使用xsl:calltemplate
调用它。这只需要对现有样式表进行几个小的更改:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()"><xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy></xsl:template>
<xsl:template match="content">
<wrapper>
<xsl:call-template name="replace"/>
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace" name="replace">
Hello world
</xsl:template>
</xsl:transform>
你好,世界
并非在所有情况下都有效,但有一种非常简单的方法可以实现您的要求。您所需要做的就是为replace
模板指定一个名称,并使用xsl:calltemplate
调用它。这只需要对现有样式表进行几个小的更改:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()"><xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy></xsl:template>
<xsl:template match="content">
<wrapper>
<xsl:call-template name="replace"/>
<xsl:apply-templates select="@*|node()" />
</wrapper>
</xsl:template>
<xsl:template match="replace" name="replace">
Hello world
</xsl:template>
</xsl:transform>
你好,世界
根据其他答案的输入,这里是我解决问题的方法。考虑作为一个更合适的例子输入:
<?xml version="1.0" encoding="utf-8" ?>
<example>
<a />
<b />
<c />
</example>
元素
、
和
在我的原始示例中的使用方式与
类似,但如转换中所示,它们的模板都包含对它们的进一步引用:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="ext">
<xsl:template match="@*|node()">
<xsl:variable name="this">
<xsl:apply-templates select="." mode="normal" />
</xsl:variable>
<xsl:apply-templates select="ext:node-set($this)" mode="normal" />
</xsl:template>
<xsl:template match="@*|node()" mode="normal">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<xsl:template match="a" mode="normal">a</xsl:template>
<xsl:template match="b" mode="normal">
<B>b <a /></B>
</xsl:template>
<xsl:template match="c" mode="normal">
<C>c <b /></C>
</xsl:template>
</xsl:transform>
A.
B
C
当应用于示例输入时,此转换生成我想要的结果:
<?xml version="1.0"?>
<example>
a
<B>b a</B>
<C>c <B>b a</B></C>
</example>
A.
b a
c b a
显然,所有递归引用都已解决。虽然它通过一些更复杂的例子进行了测试,但我不确定它是否能在所有情况下都起作用
这背后的想法如下:前两个模板用于复制。带有mode=“normal”
的是一个普通的身份转换,而没有的是递归。模式用于防止递归模板中出现无限循环
请让我知道,你对此有何看法,是否有明显的缺陷 根据其他答案的输入,这里是我解决问题的方法。考虑作为一个更合适的例子输入:
<?xml version="1.0" encoding="utf-8" ?>
<example>
<a />
<b />
<c />
</example>
元素
、
和
在我的原始示例中的使用方式与
类似,但如转换中所示,它们的模板都包含对它们的进一步引用:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="ext">
<xsl:template match="@*|node()">
<xsl:variable name="this">
<xsl:apply-templates select="." mode="normal" />
</xsl:variable>
<xsl:apply-templates select="ext:node-set($this)" mode="normal" />
</xsl:template>
<xsl:template match="@*|node()" mode="normal">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<xsl:template match="a" mode="normal">a</xsl:template>
<xsl:template match="b" mode="normal">
<B>b <a /></B>
</xsl:template>
<xsl:template match="c" mode="normal">
<C>c <b /></C>
</xsl:template>
</xsl:transform>