问题
Attemping to transform XML with XSLT 2.0.
Flat Source XML:
<body>
<R1/>
<R1/>
<R2/>
<R2/>
<R2/>
<R3/>
<R3/>
<R3/>
<R1/>
<R1/>
<R2/>
<R2/>
<R1/>
</body>
Desired Output:
<body>
<R1/>
<R1>
<R2/>
<R2/>
<R2>
<R3/>
<R3/>
<R3/>
</R2>
</R1>
<R1/>
<R1>
<R2/>
<R2/>
</R1>
<R1/>
</body>
Basically these R1 - R3 elements signify sect-1, sect-2, sect-3 type elements. R2's are nested within their previous sibling R1 and R3's are nested within their previous sibling R2. Elements that are the same are on the same level.
回答1:
Use for-each-group group-starting-with:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf"
version="2.0">
<xsl:param name="prefix" as="xs:string" select="'R'"/>
<xsl:output indent="yes"/>
<xsl:function name="mf:group" as="element()*">
<xsl:param name="elements" as="element()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$elements" group-starting-with="*[local-name() = concat($prefix, $level)]">
<xsl:element name="{name()}">
<xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
</xsl:element>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="body">
<xsl:copy>
<xsl:sequence select="mf:group(*, 1)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
来源:https://stackoverflow.com/questions/27406846/nesting-flat-xml-siblings