嵌套分组标题

时间:2016-11-17 12:17:44

标签: xslt xslt-1.0 xslt-2.0

我尝试按标题对元素进行分组。 我目前的解决方案有一个缺点。下一个标题及其内容嵌套在前一个的body标签中。 是否可以仅嵌套body标签中的内容而不是下一组? 有没有人有想法或建议? 它应该看起来像所需的结果。

来源

<?xml version="1.0" encoding="UTF-8"?>
<html>
<title>headline</title>
<body>
  <h1 name="d1e25">H1</h1>
  <p>p</p>
  <h2 name="d1e25">H2</h2>
  <p>p</p>
  <h3 name="d1e25">H3</h3>
  <p>p</p>
  <h3 name="d1e25">H3</h3>
  <p>p</p>
  <h4 name="d1e25">H4</h4>
  <p>p</p>
  <h2 name="d1e25">H2</h2>
  <table></table>
  </body>
</html>

我的转型

<xsl:transform 
  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:output method="xml" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

  <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="*[local-name() eq concat('h', $level)]">
      <xsl:choose>
        <xsl:when test="self::*[local-name() eq concat('h', $level)]">
          <topic>
          <xsl:attribute name="id"><xsl:copy-of select="@name"/></xsl:attribute>
            <xsl:element name="title"><xsl:value-of select="." /></xsl:element>
            <body>
              <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/> 
            </body>
          </topic>
        </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="/html">
   <topic>
     <xsl:attribute name="id">
       <xsl:attribute name="id" select="generate-id()" />
     </xsl:attribute>
       <xsl:copy-of select="title"/>
     <xsl:apply-templates select="body"/>
   </topic>   
  </xsl:template>

  <xsl:template match="body">
    <xsl:sequence select="mf:group(*, 1)"/>
  </xsl:template>

</xsl:transform>

我从以下帖子中得到了这个 grouping following-siblings with same name and same attributes causes exception in saxon

我的结果

<topic id="d1e1">
   <title>headline</title>
   <topic id="d1e25">
      <title>H1</title>
      <body>
         <p>p</p>
         <topic id="d1e25">
            <title>H2</title>
            <body>
               <p>p</p>
               <topic id="d1e25">
                  <title>H3</title>
                  <body>
                     <p>p</p>
                  </body>
               </topic>
               <topic id="d1e25">
                  <title>H3</title>
                  <body>
                     <p>p</p>
                     <topic id="d1e25">
                        <title>H4</title>
                        <body>
                           <p>p</p>
                        </body>
                     </topic>
                  </body>
               </topic>
            </body>
         </topic>
         <topic id="d1e25">
            <title>H2</title>
            <body>
               <table/>
            </body>
         </topic>
      </body>
   </topic>
</topic>

期望的结果

<topic id="d1e1">
   <title>headline</title>
   <topic id="d1e25">
      <title>H1</title>
      <body>
         <p>p</p>
         <topic id="d1e25">
            <title>H2</title>
            <body>
               <p>p</p>
               <topic id="d1e25">
                  <title>H3</title>
                  <body>
                     <p>p</p>
                  </body>
               </topic>
               <topic id="d1e25">
                  <title>H3</title>
                  <body>
                     <p>p</p>
                     <topic id="d1e25">
                        <title>H4</title>
                        <body>
                           <p>p</p>
                        </body>
                     </topic>
                  </body>
               </topic>
            </body>
         </topic>
         <topic id="d1e25">
            <title>H2</title>
            <body>
               <table/>
            </body>
         </topic>
      </body>
   </topic>
</topic>

1 个答案:

答案 0 :(得分:0)

我有一个解决方案

我的转型

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform 
  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:output method="xml" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

 <xsl:strip-space elements="*"/>

 <xsl:template match="html">
   <document><xsl:apply-templates/></document>
 </xsl:template>

 <xsl:template match="body">
   <xsl:apply-templates select="h1" />
 </xsl:template>

 <xsl:key name="next-headings" match="h6"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2 or
                                               self::h3 or self::h4 or
                                               self::h5][1])" />
 <xsl:key name="next-headings" match="h5"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2 or
                                               self::h3 or self::h4][1])" />
 <xsl:key name="next-headings" match="h4"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2 or
                                               self::h3][1])" />
 <xsl:key name="next-headings" match="h3"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2][1])" />
 <xsl:key name="next-headings" match="h2"
          use="generate-id(preceding-sibling::h1[1])" />

 <xsl:key name="immediate-nodes"
          match="node()[not(self::h1 | self::h2 | self::h3 | self::h4 |
                           self::h5 | self::h6)]"
          use="generate-id(preceding-sibling::*[self::h1 or self::h2 or
                                               self::h3 or self::h4 or
                                               self::h5 or self::h6][1])" />

 <xsl:template match="h1 | h2 | h3 | h4 | h5 | h6">
   <xsl:variable name="vLevel" select="substring-after(name(), 'h')" />
   <topic>
      <xsl:element name="title">
        <xsl:apply-templates />
      </xsl:element>
      <body>
      <xsl:apply-templates select="key('immediate-nodes', generate-id())" />
      </body>
      <xsl:apply-templates select="key('next-headings', generate-id())" />
   </topic>
 </xsl:template>

 <xsl:template match="/*/*/node()" priority="-20">
   <xsl:copy-of select="." />
 </xsl:template>

</xsl:transform>

<强>结果

<document>
   <topic>
      <title>H1</title>
      <body>
         <p>p</p>
      </body>
      <topic>
         <title>H2</title>
         <body>
            <p>p</p>
         </body>
         <topic>
            <title>H3</title>
            <body>
               <p>p</p>
            </body>
         </topic>
         <topic>
            <title>H3</title>
            <body>
               <p>p</p>
            </body>
            <topic>
               <title>H4</title>
               <body>
                  <p>p</p>
               </body>
            </topic>
         </topic>
      </topic>
      <topic>
         <title>H2</title>
         <body>
            <table/>
         </body>
      </topic>
   </topic>
</document>