根据属性将元素分组到新元素

Grouping of elements to new element based on attribute

我需要将没有属性的元素分组到一个新元素中。取决于属性@single h2 是否应该放置在新容器中,或者在没有@single 的情况下与h2s 按顺序放置在一起。我正在为文本 2、3、4 与小组作斗争。我是否需要先为 h1 创建一个模板,然后再创建一个 xsl:for-each?有更聪明的方法吗?

来源:

<h1>
    <h2 single="true" />
    <h2 single="true" />
    <h2>1</h2>
    <h2 single="true" />
    <h2>2</h2>
    <h2>3</h2>
    <h2>4</h2>
    <h2 single="true" />
    <h2>5</h2>
</h1>

结果

<h1>
    <containertypeA>
        <h2 single="true" />
    </containertypeA>
    <containertypeA>
        <h2 single="true" />
    </containertypeA>
    <containertypeB>
        <h2>1</h2>
    </containertypeB>
    <containertypeA>
        <h2 single="true" />
    </containertypeA>
    <containertypeB>
        <h2>2</h2>
        <h2>3</h2>
        <h2>4</h2>
    </containertypeB>
    <containertypeA>
        <h2 single="true" />
    </containertypeA>
    <containertypeB>
        <h2>5</h2>
    </containertypeB>
</h1>

一种可能的 XSLT 1.0 解决方案遵循 XSLT:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" 
 indent="yes" />
<xsl:strip-space elements="*"/>
  <xsl:template match="/">
    <xsl:apply-templates/> 
  </xsl:template>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="h2[@single='true']">
    <containertypeA>
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </containertypeA>
  </xsl:template> 
  <xsl:template match="h2[not(@single='true') and 
       not(preceding-sibling::h2[1][not(@single='true')])]">
    <containertypeB>
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
      <xsl:for-each select="following-sibling::h2[1][not(@single='true')]">
        <xsl:apply-templates select="." mode="sibling"/>
      </xsl:for-each>
    </containertypeB>
  </xsl:template>
  <xsl:template match="h2" mode="sibling">
    <xsl:apply-templates select="." mode="copy"/>
      <xsl:for-each select="following-sibling::h2[1][not(@single='true')]">
        <xsl:apply-templates select="." mode="sibling"/>
      </xsl:for-each>
  </xsl:template>
  <xsl:template match="h2[not(@single='true') and 
   preceding-sibling::h2[1][not(@single='true')]]" mode="copy">
    <xsl:copy-of select="."/>
  </xsl:template>
  <xsl:template match="h2[not(@single='true') and 
    preceding-sibling::h2[1][not(@single='true')]]"/>
</xsl:transform>

当应用于输入时 XML 产生输出

<h1>
   <containertypeA>
      <h2 single="true"/>
   </containertypeA>
   <containertypeA>
     <h2 single="true"/>
   </containertypeA>
   <containertypeB>
     <h2>1</h2>
   </containertypeB>
   <containertypeA>
     <h2 single="true"/>
   </containertypeA>
   <containertypeB>
     <h2>2</h2>
     <h2>3</h2>
     <h2>4</h2>
   </containertypeB>
   <containertypeA>
     <h2 single="true"/>
   </containertypeA>
   <containertypeB>
     <h2>5</h2>
   </containertypeB>
</h1>

模板

<xsl:template match="h2[@single='true']">

将每个匹配的 h2 复制到 <containertypeA>.
模板

<xsl:template match="h2[not(@single='true') and 
     not(preceding-sibling::h2[1][not(@single='true')])]">

匹配所有没有 @single 属性且值为 true 并且没有第一个前面的兄弟 h2 没有 @single='true' 的所有 h2。此模板将匹配的 h2 包装在 <containertypeB> 中,并将 template mode="sibling" 应用于以下第一个没有 @single='true' 的兄弟:

<xsl:for-each select="following-sibling::h2[1][not(@single='true')]">
  <xsl:apply-templates select="." mode="sibling"/>

<xsl:template match="h2" mode="sibling"> 使用模版复制 h2 模式="copy":

 <xsl:apply-templates select="." mode="copy"/>

并适用于所有没有 @single='true' 的第一个兄弟姐妹:

<xsl:for-each select="following-sibling::h2[1][not(@single='true')]">
  <xsl:apply-templates select="." mode="sibling"/>
</xsl:for-each>

最后,空模板

<xsl:template match="h2[not(@single='true') and 
preceding-sibling::h2[1][not(@single='true')]]"/>

匹配已复制到 <containertypeB>.

中的所有 h2 元素