XSLT - 使用 for-each-group 对以下兄弟姐妹进行分组

XSLT - grouping following siblings with for-each-group

我正在使用 XSLT 进行 xml 到 html 的转换,

我的输入 xml 文件如下所示,

<doc>
    <h1>main header 1-1</h1>
    <p>para 1</p>
    <p>para 2</p>

    <h1>main header 1-2</h1>
    <p>para 3</p>
    <p>para 4</p>
    <h2>sub header 2-1</h2>
    <p>para 5</p>
    <p>para 6</p>
    <p>para 7</p>
    <h2>sub header 2-3</h2>
    <p>para 8</p>
    <p>para 9</p>

    <h1>main header 1-3</h1>
    <p>para 10</p>
    <h2>sub header 2-3</h2>
    <p>para 11</p>
    <p>para 12</p>
</doc>

我从上面 xml 文件中得到的预期输出是这样的,

   <doc>
        <div id="h1-1">
            <h1>main header 1-1</h1>
            <p>para 1</p>
            <p>para 2</p>
        </div>
        <div id="h1-2">
            <h1>main header 1-2</h1>
            <p>para 3</p>
            <p>para 4</p>
        </div>
        <div id="h2-1">
            <h2>sub header 2-1</h2>
            <p>para 5</p>
            <p>para 6</p>
            <p>para 7</p>
        </div>
        <div id="h2-2">
            <h2>sub header 2-3</h2>
            <p>para 8</p>
            <p>para 9</p>
        </div>
        <div id="h1-3">
            <h1>main header 1-3</h1>
            <p>para 10</p>
        </div>
        <div id="h2-3">
            <h2>sub header 2-3</h2>
            <p>para 11</p>
            <p>para 12</p>
        </div> 
   </doc>

我有以下 xsl 来完成该任务,

<xsl:function name="san:group-div" 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() eq concat('h', $level)]">
            <xsl:choose>
                <xsl:when test="self::*[local-name() eq concat('h', $level)]">
                    <div id="{local-name()}-{count(preceding-sibling::*[local-name() eq local-name(current())]) + 1}"> 
                        <xsl:apply-templates select="current-group()"/>
                    </div>
                    <xsl:sequence select="san:group-div(current-group() except ., $level + 1)"/>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:function>

    <xsl:template match="doc">
        <xsl:copy>
           <xsl:sequence select="san:group-div(*, 1)"/>
        </xsl:copy>
    </xsl:template>

但是它给了我以下结果。

<doc>
        <div id="h1-1">
            <h1>main header 1-1</h1>
            <p>para 1</p>
            <p>para 2</p>
        </div>
        <div id="h1-2">
            <h1>main header 1-2</h1>
            <p>para 3</p>
            <p>para 4</p>
            <h2>sub header 2-1</h2>
            <p>para 5</p>
            <p>para 6</p>
            <p>para 7</p>
            <h2>sub header 2-3</h2>
            <p>para 8</p>
            <p>para 9</p>
        </div>
        <div id="h2-1">
            <h2>sub header 2-1</h2>
            <p>para 5</p>
            <p>para 6</p>
            <p>para 7</p>
        </div>
        <div id="h2-2">
            <h2>sub header 2-3</h2>
            <p>para 8</p>
            <p>para 9</p>
        </div>
        <div id="h1-3">
            <h1>main header 1-3</h1>
            <p>para 10</p>
            <h2>sub header 2-3</h2>
            <p>para 11</p>
            <p>para 12</p>
        </div>
        <div id="h2-3">
            <h2>sub header 2-3</h2>
            <p>para 11</p>
            <p>para 12</p>
        </div>
  </doc>

如结果所示,<h2> 节点也被复制到 <h1> div 中。 (参见 <div id="h1-2"><div id="h1-3">)。

任何人都可以建议我如何安排我的代码以获得预期的输出?

怎么样...

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">

<xsl:output method="html" version="5.0" indent="yes" encoding="utf-8" />
<xsl:strip-space elements="*" />

<xsl:template match="/">
  <html>
    <head>
      <title>Doc</title>
    </head>
    <body>
      <xsl:apply-templates />
    </body>
  </html>
</xsl:template>

<xsl:template match="doc">
  <doc>
    <xsl:for-each-group select="h1|h2|h3|p" group-adjacent="
      if (self::p)
        then
          (preceding-sibling::h1 | preceding-sibling::h2 | preceding-sibling::h3)[last()]/local-name()
        else
          local-name()">
      <xsl:for-each-group select="current-group()" group-starting-with="h1|h2|h3">
        <div id="{local-name()}-{position()}">   
          <xsl:copy-of select="current-group()" />      
        </div>    
      </xsl:for-each-group>   
    </xsl:for-each-group>
  </doc>
</xsl:template>

</xsl:stylesheet>

假设

这假设您的标题级别限制为 h1h2h3。如果不是,根据需要进行调整是一项微不足道的工作。