Sectioning different heading levels

前端 未结 1 707
孤街浪徒
孤街浪徒 2021-01-16 07:18

The goal is to group elements starting with different heading levels into sections nested according to those levels.

Problem is similar to XSLT: moving a grouping ht

相关标签:
1条回答
  • 2021-01-16 07:58

    I would simply let the function group by the current level and stop at the maximum level (which is 6 in HTML):

    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="2.0"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:mf="http://example.org/mf"
      exclude-result-prefixes="xs mf">
    
    <xsl:function name="mf:group" as="node()*">
      <xsl:param name="nodes" as="node()*"/>
      <xsl:param name="level" as="xs:integer"/>
      <xsl:for-each-group select="$nodes" group-starting-with="*[starts-with(local-name(), concat('h', $level))]">
        <xsl:choose>
          <xsl:when test="self::*[starts-with(local-name(), concat('h', $level))]">
            <section level="{$level}">
              <xsl:apply-templates select="."/>
              <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
            </section>
          </xsl:when>
          <xsl:when test="$level lt 6">
            <xsl:sequence select="mf:group(current-group(), $level + 1)"/>
          </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="body">
      <xsl:copy>
        <xsl:sequence select="mf:group(node(), 1)"/>
      </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    Obviously the level to search for could be provided as a parameter instead of hardcoding it in the stylesheet:

    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="2.0"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:mf="http://example.org/mf"
      exclude-result-prefixes="xs mf">
    
    <xsl:param name="max-level" as="xs:integer" select="6"/>
    
    <xsl:param name="name-prefix" as="xs:string" select="'h'"/>
    
    <xsl:output method="html" indent="yes"/>
    
    <xsl:function name="mf:group" as="node()*">
      <xsl:param name="nodes" as="node()*"/>
      <xsl:param name="level" as="xs:integer"/>
      <xsl:for-each-group select="$nodes" group-starting-with="*[starts-with(local-name(), concat($name-prefix, $level))]">
        <xsl:choose>
          <xsl:when test="self::*[starts-with(local-name(), concat($name-prefix, $level))]">
            <section level="{$level}">
              <xsl:apply-templates select="."/>
              <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
            </section>
          </xsl:when>
          <xsl:when test="$level lt $max-level">
            <xsl:sequence select="mf:group(current-group(), $level + 1)"/>
          </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="body">
      <xsl:copy>
        <xsl:sequence select="mf:group(*, 1)"/>
      </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    
    0 讨论(0)
提交回复
热议问题