Bru*_*aim 8 xslt xpath xslt-2.0
尝试了8个多小时后,我希望有人可以帮助我:
给出一本书的以下(简化)XML:
<book>
<section name="A">
<chapter name="I">
<paragraph name="1"/>
<paragraph name="2"/>
</chapter>
<chapter name="II">
<paragraph name="1"/>
</chapter>
</section>
<section name="B">
<chapter name="III"/>
<chapter name="IV"/>
</section>
</book>
Run Code Online (Sandbox Code Playgroud)
我能够使用以下XSL基于给定参数提取书籍XML的任何部分(部分,章节或段落):
<xsl:param name="subSelectionXPath" required="yes" as="node()"/>
<xsl:template match="/">
<xsl:apply-templates select="$subSelectionXPath"/>
</xsl:template>
<xsl:template match="*">
<!-- output node with all children -->
<xsl:copy-of select="."/>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)
和参数$ subSelectionXPath的值类似
doc(filename)//chapter[@name='II']
产生输出:
<chapter name="II">
<paragraph name="1"/>
</chapter>
Run Code Online (Sandbox Code Playgroud)
我想要实现的另一个目标是让祖先XML分支包含所选的XML片段,即:
<book>
<section name="A">
<chapter name="II">
<paragraph name="1"/>
</chapter>
</section>
</book>
Run Code Online (Sandbox Code Playgroud)
我想(并尝试)遍历XML树并测试当前节点是否是祖先,类似于(伪代码):
<xsl:if test="node() in $subSelectionXPath/ancestor::node()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:if>
Run Code Online (Sandbox Code Playgroud)
我也尝试过xsl:key但是我担心我的XSLT知识在这里结束了.有什么想法吗?
从您的代码中可以明显看出您使用的是XSLT 2.0.
这个XSLT 2.0转换:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="subSelectionXPath"
as="node()" select="//chapter[@name='II']"
/>
<xsl:template match="*[descendant::node() intersect $subSelectionXPath]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[. intersect $subSelectionXPath]">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当应用于提供的XML文档时:
<book>
<section name="A">
<chapter name="I">
<paragraph name="1"/>
<paragraph name="2"/>
</chapter>
<chapter name="II">
<paragraph name="1"/>
</chapter>
</section>
<section name="B">
<chapter name="III"/>
<chapter name="IV"/>
</section>
</book>
Run Code Online (Sandbox Code Playgroud)
产生完全想要的,正确的结果:
<book>
<section name="A">
<chapter name="II">
<paragraph name="1"/>
</chapter>
</section>
</book>
Run Code Online (Sandbox Code Playgroud)
说明:我们只有两个模板:
与后代与$subSelectionXPath节点集具有非空交集的任何元素匹配的模板.在这里,我们"浅层复制"元素并将模板应用于其子元素.
匹配属于$subSelectionXPath节点集的元素的模板.在这里,我们复制以该元素为根的整个子树.
请注意XPath 2.0 intersect运算符的使用.
没有明确的递归.
II.XSLT 1.0解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="subSelectionXPath"
select="//chapter[@name='II']"
/>
<xsl:template match="*">
<xsl:choose>
<xsl:when test=
"descendant::node()
[count(.|$subSelectionXPath)
=
count($subSelectionXPath)
]
">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:when>
<xsl:when test=
"count(.|$subSelectionXPath)
=
count($subSelectionXPath)
">
<xsl:copy-of select="."/>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当此转换应用于同一XML文档(如上所示)时,将生成相同的想要和正确的结果:
<book>
<section name="A">
<chapter name="II">
<paragraph name="1"/>
</chapter>
</section>
</book>
Run Code Online (Sandbox Code Playgroud)
解释:这基本上是XSLT 2.0解决方案,其中的XPath 2.0 intersect操作者是使用公知的Kayessian(对于@迈克尔凯)式两个节点集的交集翻译成XPath 1.0中$ns1和$ns2:
$ns1[count(.|$ns2) = count($ns2)]
Run Code Online (Sandbox Code Playgroud)