我尝试通过仅选择标题节点(如 h1、h2…h9)来制作文档的目录 (TOC)。
这些标题节点应采用级联h[0-9]
-
<ul>
结构,其中依赖于 <li>
的所有 <hN+1>
都应是包含在 <hN>
的 <ul>
中的 <li>
。示例
<hN>
:
document.xsl
那么预期的渲染应该是:
<?xml version="1.0" encoding="UTF-8"?>
<document>
<h1>Lorem <i>arepo</i> ipsum dolor</h1>
<h2>Lorem ipsum dolor</h2>
<p>
Sed ut <i>perspiciatis</i> unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</p>
<h1>sit amet et consectetur</h1>
<h2>Quia adipit</h2>
<h3>aliquam quaerat</h3>
<p>
Sed ut <i>perspiciatis</i> unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</p>
<h2>Erit et nunquam</h2>
</document>
最小工作示例
<ul>
<li>
<span>Lorem <i>arepo</i> ispum dolor</span>
<ul>
<li><span>Lorem ipsum dolor</span></li>
</ul>
<li>
<li>
<span>Sit amet et consectetur</span>
<ul>
<li>
<span>Quia adipit</span>
<ul>
<li>
<span>aliquam quaerat</span>
</li>
<ul>
</li>
<li><span>Erit et nunquam</span></li>
</ul>
<li>
</ul>
maketoc.xslt
当前渲染图
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="document">
<ul>
<xsl:apply-templates select="*[self::h1 | self::h2 | self::h3 | self::h4 | self::h5 | self::h6 | self::h7 | self::h8 | self::h9]"/>
</ul>
</xsl:template>
<xsl:template match="h1 | h2 | h3 | h4 | h5 | h6 | h7 | h8 | h9">
<li>
<span><xsl:value-of select="."/></span>
<ul>
<xsl:apply-templates select="following-sibling::*[1][self::h1 | self::h2 | self::h3 | self::h4 | self::h5 | self::h6 | self::h7 | self::h8 | self::h9]"/>
</ul>
</li>
</xsl:template>
<!-- Ignor anything else -->
<xsl:template match="*"/>
</xsl:stylesheet>
存在的问题
同一兄弟节点中的第一个降序节点会被处理多次。它们的加工程度与深度相同。例如“aliquam quaerat”出现树次,因为他是一个
<ul>
<li>
<span>Lorem arepo ipsum dolor</span>
<ul>
<li>
<span>Lorem ipsum dolor</span>
<ul/>
</li>
</ul>
</li>
<li>
<span>Lorem ipsum dolor</span>
<ul/>
</li>
<li>
<span>sit amet et consectetur</span>
<ul>
<li>
<span>Quia adipit</span>
<ul>
<li>
<span>aliquam quaerat</span>
<ul/>
</li>
</ul>
</li>
</ul>
</li>
<li>
<span>Quia adipit</span>
<ul>
<li>
<span>aliquam quaerat</span>
<ul/>
</li>
</ul>
</li>
<li>
<span>aliquam quaerat</span>
<ul/>
</li>
<li>
<span>Erit et nunquam</span>
<ul/>
</li>
</ul>
<h3>
</ul>
的<li>
体内。不是其兄弟姐妹之间第一个的节点将被视为 <ul>
<h1>
。
<h2>
-
<ul>
结构中,并且后代与其后代密切相关?<li>
:
进行递归分组的任务
for-each-group group-starting-with
<xsl:stylesheet 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="#all"
version="3.0">
<xsl:function name="mf:group" as="node()*">
<xsl:param name="headings" as="element()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$headings" group-starting-with="*[local-name() = 'h' || $level]">
<xsl:if test="self::*[local-name() = 'h' || $level]">
<li>
<span>
<xsl:apply-templates/>
</span>
<xsl:where-populated>
<ul>
<xsl:sequence select="mf:group(tail(current-group()), $level + 1)"/>
</ul>
</xsl:where-populated>
</li>
</xsl:if>
</xsl:for-each-group>
</xsl:function>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="document">
<ul>
<xsl:sequence select="mf:group(*[self::h1 | self::h2 | self::h3 | self::h4 | self::h5 | self::h6 | self::h7 | self::h8 | self::h9], 1)"/>
</ul>
</xsl:template>
</xsl:stylesheet>
有您原始代码中的选择,我可能倾向于将其写为
<xsl:sequence select="mf:group(*[self::h1 | self::h2 | self::h3 | self::h4 | self::h5 | self::h6 | self::h7 | self::h8 | self::h9], 1)"/>
。