XSLT 2.0:从线性<h1> - </h1> <h2> - </h2> <h3>标签系统构建树</h3>

时间:2014-05-19 13:05:58

标签: xml xslt-2.0

我试图弄清楚如何在XSLT 2.0中建立来自标头标签系统的节点树(&lt; h1&gt;等) 通常,在xhtml中,标头标签不是嵌套的。要构建目录,在XSLT中拥有树结构会更方便。 我怀疑我可以使用递归来做到这一点。 所以我的XML文件有xhtml样式的标题标记,我想构建一个包含嵌套目录的xhtml文件,使用&lt; ol&gt;或者&lt; ul&gt;。

<h1>header 1.0</h1>
  <h2>header 2.1</h2>
  <h2>header 2.2</h2>
    <h3>header 3.1</h3>
    <h3>header 3.2</h3>
  <h2>header 2.3</h2>
</h1>

结果:

<ol>
   <li> header 1.0
      <ol>
        <li>header 2.1</li>
        <li>header 2.2
           <ol>
              <li>header 3.1</li>
              <li>header 3.2></li>
           </ol>
        </li>
        <li>header 2.3</li>
      </ol>
    </li>
 </ol>

到目前为止,我有类似的内容:

<xsl:variable name="toc">
<xsl:apply-templates select="h1"/>
</xsl:variable>

<xsl:template match="h[123]">
<xsl:copy>
      <!-- something with name() here? -->
  <xsl:if test="next() ne  .">
    <xsl:apply-templates select="next()"/>
  </xsl:if>
</xsl:copy>
</xsl:template>

(为清楚起见,我遗漏了清单的内容) 当然,它不起作用。我可以在这里使用一些帮助......

2 个答案:

答案 0 :(得分:3)

我会用for-each-group来处理这种事情,但如果你有三个以上的标题,它会有点重复:

<ol>
  <xsl:for-each-group select="h1|h2|h3" group-starting-with="h1">
    <li><xsl:value-of select="." /><!-- . is the group leader (the h1) -->
      <xsl:if test="current-group()[2]">
        <ol>
          <!-- current-group() except . is the rest (h2s and h3s) -->
          <xsl:for-each-group select="current-group() except ."
                              group-starting-with="h2">
            <li><xsl:value-of select="." /><!-- . is the h2 -->
              <xsl:if test="current-group()[2]">
                <ol>
                  <!-- current-group() except . will all be h3s (if any) -->
                  <xsl:for-each select="current-group() except .">
                    <li><xsl:value-of select="." /></li>
                  </xsl:for-each>
                </ol>
              </xsl:if>
            </li>
          </xsl:for-each-group>
        </ol>
      </xsl:if>
    </li>
  </xsl:for-each-group>
</ol>

进一步思考这个问题,你可以让整个事情递归以减少重复

<xsl:template name="toc">
  <xsl:param name="nodes" />
  <xsl:param name="level" />
  <ol>
    <xsl:for-each-group select="$nodes"
                group-starting-with="*[local-name() = concat('h',$level)]">
      <li><xsl:value-of select="." />
        <xsl:if test="current-group()[2]">
          <xsl:call-template name="toc">
            <xsl:with-param name="nodes" select="current-group() except ." />
            <xsl:with-param name="level" select="$level + 1"/>
          </xsl:call-template>
        </xsl:if>
      </li>
    </xsl:for-each-group>
  </ol>
</xsl:template>

并使用

启动该过程
<xsl:call-template name="toc">
  <xsl:with-param name="nodes" select="h1|h2|h3" />
  <xsl:with-param name="level" select="1" />
</xsl:call-template>

答案 1 :(得分:0)

您输入的XHTML格式不正确。我假设您实际上有一个合法的XHTML文档。我稍微更改了编号,因此更容易理解。假设这代表了您拥有的文档的相关部分:

<html>
  <body>
    <h1>header 1</h1>
    <h2>header 1.1</h2>
    <h2>header 1.2</h2>
    <h3>header 1.2.1</h3>
    <h3>header 1.2.2</h3>
    <h2>header 1.3</h2>
    <h3>header 1.3.1</h3>
    <h1>header 2</h1>
    <h2>header 2.1</h2>
    <h2>header 2.2</h2>
    <h3>header 2.2.1</h3>
    <h3>header 2.3.2</h3>
    <h2>header 2.3</h2>
  </body>
</html>

您必须将h1h2h3视为不同级别,并创建嵌套列表(如果它们有子级别)。这是另一种样式表,可以产生您期望的结果:

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

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

    <xsl:template match="h3">
        <li><xsl:value-of select="."/></li>
    </xsl:template>

    <xsl:template match="h1">
        <li><xsl:value-of select="."/>
            <xsl:call-template name="add-sublevel">
                <xsl:with-param name="sub-levels" 
                                select="following::h2[preceding::h1[1] is current()]"/>
            </xsl:call-template></li>
    </xsl:template>

    <xsl:template match="h2">
        <li><xsl:value-of select="."/>
            <xsl:call-template name="add-sublevel">
                <xsl:with-param name="sub-levels" 
                                select="following::h3[preceding::h2[1] is current()]"/>
            </xsl:call-template></li>
    </xsl:template>

    <xsl:template name="add-sublevel">
        <xsl:param name="sub-levels"/>
        <xsl:if test="$sub-levels">
            <ol><xsl:apply-templates select="$sub-levels"/></ol>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

结果将是:

<ol>
   <li>header 1
      <ol>
         <li>header 1.1</li>
         <li>header 1.2
            <ol>
               <li>header 1.2.1</li>
               <li>header 1.2.2</li>
            </ol>
         </li>
         <li>header 1.3
            <ol>
               <li>header 1.3.1</li>
            </ol>
         </li>
      </ol>
   </li>
   <li>header 2
      <ol>
         <li>header 2.1</li>
         <li>header 2.2
            <ol>
               <li>header 2.2.1</li>
               <li>header 2.3.2</li>
            </ol>
         </li>
         <li>header 2.3</li>
      </ol>
   </li>
</ol>