使用<xsl:for-each-group>进行XSLT 2.0分组</xsl:for-each-group>

时间:2012-10-01 15:21:31

标签: xml xslt xpath xslt-2.0

我正在尝试使用xsl:for-each在XSLT 2.0中对元素进行分组。

以下是我输入的说明:

<root>
     <chapter>
           <heading> heading text </heading>
           <title> title </title>
           <p> 1111 </p>
           <p> 2222 </p>
           <center> text </center>
           <p> 3333 </p>
           <title>  another title </title>
           <p> 4444 </p>
           <center> text </center>
           <p> 5555 </p>
     </chapter>
     <chapter>
          <heading> heading text </heading>
          <title>  another title </title>
          <p> 6666 </p>
          <p> 7777 </p>
          <title>  another title </title>
          <p> 8888 </p>
          <p> 9999 </p>
     </chapter>
<root>

我正在尝试通过匹配每个<title>元素并将每个后续元素分组,直到下一个<title>成为元素<section>来对此文档进行分组。这就是我希望输出看起来像:

<root>
     <chapter>
          <heading> Heading text </heading>
          <section>
               <title>  title </title>
               <p> 1111 </p>
               <p> 2222 </p>
               <center> text </center>
               <p> 3333 </p>
          </section>
          <section>
               <title>  title </title>
               <p> 4444 </p>
               <center> text </center>
               <p> 5555 </p>
          </section>
          <section>
               <title>  title </title>
               <p> 6666 </p>
               <p> 7777 </p>
               <center> text </center>
               <p> 8888 </p>
               <p> 9999 </p>
          </section>
     <chapter>
<root>

我当前的模板无效:

<xsl:template match="chapter">
    <chapter>
      <xsl:for-each-group select="*" group-starting-with="title">
             <section>
                <xsl:copy-of select="current-group()" />
             </section>
      </xsl:for-each-group>
    </chapter>             
</xsl:template>

上面的样式表会对我想要的部分进行分组,但是出于某种原因,它还会将每个<heading>元素分组到自己的<section>中。有什么建议吗?

提前致谢。

3 个答案:

答案 0 :(得分:4)

我会用......

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*" />  

<xsl:template match="/*">
  <root>
    <xsl:for-each-group select="chapter" group-by="heading">
      <chapter>
        <xsl:copy-of select="current-group()[1]/heading" />
        <xsl:for-each-group select="current-group()/(* except heading)"
                            group-starting-with="title">
          <section>
            <xsl:copy-of select="current-group()" />
          </section>
        </xsl:for-each-group>
      </chapter>
    </xsl:for-each-group>
  </root>
</xsl:template>

</xsl:stylesheet>

答案 1 :(得分:4)

我通常使用xsl:在for-each-group的主体中选择,以区分真正以group-starting-with元素开头的组和第一个“真实组”之前的“leading rump”。如果你知道“领先的臀部”只包含一个标题元素,那么你已经获得了许多其他解决方案。另一个更通用的解决方案(因为它不会对臀部中的内容做出任何假设),但是沿着相同的路线,是:

<xsl:copy-of select="title[1]/preceding-sibling::*">
<xsl:for-each-group select="title[1]/(., following-sibling::*)">
  <section>
     <xsl:copy-of select="current-group()"/>
  </section>
</xsl:for-each-group>

答案 2 :(得分:3)

你可能想要

<xsl:copy-of select="current-group()" />

而不是value-of。对于标题,如果您知道每章只有一个heading元素,那么您可以说

<xsl:template match="chapter">
      <xsl:copy-of select="heading" />
      <xsl:for-each-group select="*[not(self::heading)]" group-starting-with="title">
             <section>
                <xsl:copy-of select="current-group()" />
             </section>
      </xsl:for-each-group>             
</xsl:template>

即。单独拉出标题,然后将其从要分组的元素集中排除。