嵌套平面XML兄弟

时间:2014-12-10 17:08:37

标签: xml xslt xslt-2.0 saxon

尝试使用XSLT 2.0转换XML。

Flat Source XML:

<body>
  <R1/>
  <R1/>
  <R2/>
  <R2/>
  <R2/>
  <R3/>
  <R3/>
  <R3/>
  <R1/>
  <R1/>
  <R2/>
  <R2/>
  <R1/>
</body>

期望的输出:

<body>
  <R1/>
  <R1>
    <R2/>
    <R2/>
    <R2>
       <R3/>
       <R3/>
       <R3/>
    </R2>
  </R1>
  <R1/>
  <R1>
    <R2/>
    <R2/>
  </R1>
  <R1/>
</body>

基本上这些R1-R3元素表示sect-1,sect-2,sect-3类型元素。 R2嵌套在它们之前的兄弟R1中,R3嵌套在它们之前的兄弟R2中。相同的元素在同一级别上。

1 个答案:

答案 0 :(得分:2)

使用for-each-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>