我具有以下XML结构:
<node0>
<beforeContainer @id="test">
<beforeContainer2/>
</beforeContainer>
<container id='1'>
<node1>
<node2>
<text>Test1</text>
</node2>
</node1>
</container>
<node3>
<node4>
<text>Test2</text>
<node5>
<container id='2'>
<node6>
<button>Click</button>
</node6>
</container>
</node5>
</node4>
</node3>
<text>Test3</text>
<node7>
<node8>
<node9>
<container id='3'>
<node10>
<button>Click2</button>
</node10>
</container>
</node9>
</node8>
</node7>
</node0>
我必须提取后续<container>
个节点之间的所有节点名称。 <container>
节点在树中的深度级别不同。
输出应如下所示:
<container id='1'>
<node1/>
<node2/>
<text/>
<node3/>
<node4/>
<text/>
<node5/>
</container>
<container id='2'>
<node6/>
<button/>
<text/>
<node7/>
<node8/>
<node9/>
</container>
<container id='3'>
<node10/><button/>
</container>
我尝试了不同的x-Path表达式,但未成功,因为它们始终具有特定的范围(后代或自身:: node(),后继兄弟等)。
答案 0 :(得分:2)
XSLT 2或3中的简单分组问题
<xsl:template match="/*">
<xsl:for-each-group select="descendant::*" group-starting-with="container">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="current-group() except ." mode="copy"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="*" mode="copy">
<xsl:copy/>
</xsl:template>
完整示例https://xsltfiddle.liberty-development.net/bdxtqQ是:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/*">
<xsl:for-each-group select="descendant::*" group-starting-with="container">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="current-group() except ." mode="copy"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="*" mode="copy">
<xsl:copy/>
</xsl:template>
</xsl:stylesheet>
关于您不想在第一个container
之前包含元素的编辑,请将模板进行分组更改为
<xsl:template match="/*">
<xsl:for-each-group select="descendant::*" group-starting-with="container">
<xsl:if test="self::container">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="current-group() except ." mode="copy"/>
</xsl:copy>
</xsl:if>
</xsl:for-each-group>
</xsl:template>
https://xsltfiddle.liberty-development.net/bdxtqQ/1
for-each-group group-starting-with
的工作方式(请参阅https://www.w3.org/TR/xslt-30/#element-for-each-group)是,如果组填充中的第一项与group-starting-with
模式不匹配,则仍会形成一个组:
如果存在group-starting-with属性,则其值必须 成为模式。
按人口顺序检查人口中的项目。如果 项与模式匹配,或者是总体中的第一项,然后 创建一个新组,该项目成为其第一个成员。 否则,该项目将与其之前的项目附加到同一组 人口中的项目。
在许多情况下这很有用,但随后通常需要在xsl:if
内使用嵌套的xsl:choose
或xsl:for-each-group
来测试我们是否有与{{1 }}模式,或在第一个此类组之前收集了任何物品。