分组元素未按要求的结构出现

Grouping elements not appearing as per required structure

我尝试根据 @style 对元素进行分组,所有情况看起来都很好,只是这里的问题是第一个 p[@style="TRH7" 在 TRH4 之前没有关闭。

我参考了 here 但运气不好。

输入XML:

<?xml version="1.0" encoding="UTF-8"?>
<text width="12240" height="15840" orient="">
    <p type="itemlist" id-rel="1" level="1" style="TRH2">
        <r>Test scenario 1 (TRH2) /chapter/title</r>
    </p>
    <p type="itemlist" id-rel="1" level="6" style="TRH7">
        <r>Test Scenario 2 (TRH7) /chapter/section/title</r>
    </p>
    <p style="TRNormal">
        <r>Test Scenario 3 (TRNormal) /chapter/section/paragraph </r>
    </p>
    <table>a</table>
    <p type="itemlist" id-rel="1" level="3" style="TRH4">
        <r>Test Scenario 4 (TRH4) /chapter/division/title</r>
    </p>
    <p type="itemlist" id-rel="1" level="6" style="TRH7">
        <r>Test Scenario 5 (TRH7) /chapter/division/section/title</r>
    </p>
    <p style="TRNormal">
        <r>Test Scenario 6 (TRNormal) /chapter/division/section/paragraph </r>
    </p>
    
    <p type="itemlist" id-rel="1" level="4" style="TRH5">
        <r>Test Scenario 7 (TRH5) /chapter/division/subdivision/title</r>
    </p>
    <p type="itemlist" id-rel="1" level="5" style="TRH6">
        <r>Test Scenario 8 (TRH6) /chapter/division/subdivision/arabicSubdivision/title</r>
    </p>
    <p type="itemlist" id-rel="1" level="6" style="TRH7">
        <r>Test Scenario 9 (TRH7) /chapter/division/subdivision/arabicSubdivision/section/title</r>
    </p>
    <p style="TRNormal">
        <r>Test Scenario 10 (TRNormal)
            /chapter/division/subdivision/arabicSubdivision/section/paragraph </r>
    </p>
    <p style="TRNormal">
        <r>Test 1 </r>
    </p>
    <p style="TRNormal">
        <r>Test 2 </r>
    </p>
</text>

当前 XSL:

<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:strip-space elements="*"/>
        
        <xsl:output indent="yes" method="xml"/>
        
        <xsl:function name="mf:group" as="node()*">
            <xsl:param name="elements" as="element()*"/>
            <xsl:param name="level" as="xs:integer"/>
            <xsl:for-each-group select="$elements" group-starting-with="p[@style eq concat('TRH', $level)]">
                <xsl:choose>
                    <xsl:when test="self::p[@style eq 'TRH2']">
                        <chapter>  <!--level="{$level}"-->
                            <title><xsl:apply-templates select="node()"/></title>
                            <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
                        </chapter>
                    </xsl:when>
                    
                    <xsl:when test="self::p[@style eq 'TRH4']">
                        <division>  <!--level="{$level}"-->
                            <title><xsl:apply-templates select="node()"/></title>
                            <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
                        </division>
                    </xsl:when>
                    
                    <xsl:when test="self::p[@style eq 'TRH5']">
                        <subdivision>  <!--level="{$level}"-->
                            <title><xsl:apply-templates select="node()"/></title>
                            <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
                        </subdivision>
                    </xsl:when>
                    
                    <xsl:when test="self::p[@style eq 'TRH6']">
                        <arabicSubdivision>  <!--level="{$level}"-->
                            <title><xsl:apply-templates select="node()"/></title>
                            <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
                        </arabicSubdivision>
                    </xsl:when>
                    
                    <xsl:when test="self::p[@style eq 'TRH7']">
                        <section>  <!--level="{$level}"-->
                            <title><xsl:apply-templates select="node()"/></title>
                            <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
                        </section>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:function>
        
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@*, node()"/>
            </xsl:copy>
        </xsl:template>
        
        <xsl:template match="p">
            <paragraph><xsl:apply-templates/></paragraph>
        </xsl:template>
        
        
        <xsl:template match="text">
            <xsl:sequence select="mf:group(*, 2)"/>
        </xsl:template>
        
        <xsl:template match="r">
            <xsl:apply-templates/>
        </xsl:template>
        
    </xsl:stylesheet>

当前输出:

<?xml version="1.0" encoding="UTF-8"?>
    <chapter>
       <title>Test scenario 1 (TRH2) /chapter/title</title>
       <section>
          <title>Test Scenario 2 (TRH7) /chapter/section/title</title>
          <paragraph>Test Scenario 3 (TRNormal) /chapter/section/paragraph </paragraph>
          <table>a</table>
          <division>
             <title>Test Scenario 4 (TRH4) /chapter/division/title</title>
             <section>
                <title>Test Scenario 5 (TRH7) /chapter/division/section/title</title>
                <paragraph>Test Scenario 6 (TRNormal) /chapter/division/section/paragraph </paragraph>
             </section>
             <subdivision>
                <title>Test Scenario 7 (TRH5) /chapter/division/subdivision/title</title>
                <arabicSubdivision>
                   <title>Test Scenario 8 (TRH6) /chapter/division/subdivision/arabicSubdivision/title</title>
                   <section>
                      <title>Test Scenario 9 (TRH7) /chapter/division/subdivision/arabicSubdivision/section/title</title>
                      <paragraph>Test Scenario 10 (TRNormal)
                /chapter/division/subdivision/arabicSubdivision/section/paragraph </paragraph>
                      <paragraph>Test 1 </paragraph>
                      <paragraph>Test 2 </paragraph>
                   </section>
                </arabicSubdivision>
             </subdivision>
          </division>
       </section>
    </chapter>

期望输出:

<?xml version="1.0" encoding="UTF-8"?>
<chapter>
   <title>Test scenario 1 (TRH2) /chapter/title</title>
   <section>
      <title>Test Scenario 2 (TRH7) /chapter/section/title</title>
      <paragraph>Test Scenario 3 (TRNormal) /chapter/section/paragraph </paragraph>
      <table>a</table>
   </section>
   <division>
      <title>Test Scenario 4 (TRH4) /chapter/division/title</title>
      <section>
         <title>Test Scenario 5 (TRH7) /chapter/division/section/title</title>
         <paragraph>Test Scenario 6 (TRNormal) /chapter/division/section/paragraph </paragraph>
      </section>
      <subdivision>
         <title>Test Scenario 7 (TRH5) /chapter/division/subdivision/title</title>
         <arabicSubdivision>
            <title>Test Scenario 8 (TRH6) /chapter/division/subdivision/arabicSubdivision/title</title>
            <section>
               <title>Test Scenario 9 (TRH7) /chapter/division/subdivision/arabicSubdivision/section/title</title>
               <paragraph>Test Scenario 10 (TRNormal)
                  /chapter/division/subdivision/arabicSubdivision/section/paragraph </paragraph>
               <paragraph>Test 1 </paragraph>
               <paragraph>Test 2 </paragraph>
            </section>
         </arabicSubdivision>
      </subdivision>
   </division>
</chapter>

最近出现了一个类似的问题 Not able to do XSLT transformation with grouping, to which I posted the answer ,要使其与您的输入兼容,其中 p 元素与 table 元素混合,您需要将函数参数键入为element()* 而不是 element(p)*:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:map="http://www.w3.org/2005/xpath-functions/map"
  exclude-result-prefixes="#all"
  xmlns:mf="http://example.com/mf">
  
  <xsl:param name="xml-levels-param">
  <levels>
      <level key="TRH2">
         <container>chapter</container>
         <content>title</content>
      </level>
      <level key="TRH4">
         <container>division</container>
         <content>title</content>
      </level>
      <level key="TRH5">
         <container>subdivision</container>
         <content>title</content>
      </level>
      <level key="TRH6">
         <container>arabicSubdivision</container>
         <content>title</content>
      </level>
      <level key="TRH7">
         <container>section</container>
         <content>title</content>
      </level>
   </levels>
  </xsl:param>
  
  <xsl:variable name="xml-levels" select="$xml-levels-param/levels/level"/>
  
  <xsl:function name="mf:group-xml" as="node()*">
    <xsl:param name="elements" as="element()*"/>
    <xsl:param name="level" as="xs:integer"/>
    <xsl:for-each-group select="$elements" group-starting-with="p[@style = $xml-levels[$level]/@key]">
      <xsl:choose>
        <xsl:when test="self::p[@style = $xml-levels[$level]/@key]">
          <xsl:element name="{$xml-levels[$level]/container}">
            <xsl:element name="{$xml-levels[$level]/content}">
              <xsl:value-of select="r"/>
            </xsl:element>
            <xsl:choose>
              <xsl:when test="exists($xml-levels[$level + 1])">
                <xsl:sequence select="mf:group-xml(current-group()[position() gt 1], $level + 1)"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates select="current-group()[position() gt 1]"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>
          <xsl:choose>
            <xsl:when test="exists($xml-levels[$level + 1])">
                <xsl:sequence select="mf:group-xml(current-group(), $level + 1)"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates select="current-group()"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:function>
  
  <xsl:template match="text">
    <xsl:sequence select="mf:group-xml(*, 1)"/>
  </xsl:template>
  
  <xsl:template match="p[@style = 'TRNormal']">
    <paragraphp>
      <xsl:apply-templates select="r/node()"/>
    </paragraphp>
  </xsl:template>
  
  <xsl:template match="p[not(node())]"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>