使用 for-each-group 将平面 XML 转换为嵌套

convert flat XML to nested using for-each-group

我不得不承认在理解如何使用 for-each-group 时惨败。我已经尝试过分组、相邻分组,但我得到了任意结果,这些结果违背了我对我做错了什么的理解。

我有以下输入 XML,它是 'flat':里面的所有元素都是兄弟,我需要转换它以创建一个嵌套结构。

<document>
<separator style="XXX"/>
<paragraph style="aaa">
    <p>text1</p>
</paragraph>
<paragraph style="bbb">
    <p>text2</p>
</paragraph>
<paragraph style="list1">
    <p>text3</p>
</paragraph>
<paragraph style="list1">
    <p>text4</p>
</paragraph>
<paragraph style="list1">
    <p>text5</p>
</paragraph>
<paragraph style="ccc">
    <p>text6</p>
</paragraph>
<separator style="YYY"/>
<paragraph style="ddd">
    <p>text7</p>
</paragraph>
<paragraph style="ddd">
    <p>text8</p>
</paragraph>
<paragraph style="ddd">
    <p>text9</p>
</paragraph>
<paragraph style="list1">
    <p>text10</p>
</paragraph>
<paragraph style="list1">
    <p>text11</p>
</paragraph>
<paragraph style="ddd">
    <p>text12</p>
</paragraph>

我需要以下输出:

<document>
<separator style="XXX">
    <paragraph style="aaa">
        <p>text1</p>
    </paragraph>
    <paragraph style="bbb">
        <p>text2</p>
    </paragraph>
    <list>
        <paragraph style="list1">
            <p>text3</p>
        </paragraph>
        <paragraph style="list1">
            <p>text4</p>
        </paragraph>
        <paragraph style="list1">
            <p>text5</p>
        </paragraph>
    </list>
    <paragraph style="ccc">
        <p>text6</p>
    </paragraph>
</separator>
<separator style="YYY">
    <paragraph style="ddd">
        <p>text7</p>
    </paragraph>
    <paragraph style="ddd">
        <p>text8</p>
    </paragraph>
    <paragraph style="ddd">
        <p>text9</p>
    </paragraph>
    <list>
        <paragraph style="list1">
            <p>text10</p>
        </paragraph>
        <paragraph style="list1">
            <p>text11</p>
        </paragraph>
    </list>
</separator>

我没有包含我已经尝试过的任何 XSL,因为它显然不正确!

规则不是一个样例说出来的而是看XSLT sample是否有帮助(tail是XPath/XSLT 3,实在卡住就用subsequence(current-group(), 2)使用 XSLT 2):

  <xsl:template match="document">
    <xsl:copy>
      <xsl:for-each-group select="*" group-starting-with="separator">
        <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:for-each-group select="tail(current-group())" group-adjacent="@style">
            <xsl:choose>
              <xsl:when test="starts-with(current-grouping-key(), 'list')">
                <list>
                  <xsl:apply-templates select="current-group()"/>
                </list>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates select="current-group()"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each-group>
        </xsl:copy>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>