我试图弄清楚如何在XSLT 2.0中建立来自标头标签系统的节点树(< h1>等) 通常,在xhtml中,标头标签不是嵌套的。要构建目录,在XSLT中拥有树结构会更方便。 我怀疑我可以使用递归来做到这一点。 所以我的XML文件有xhtml样式的标题标记,我想构建一个包含嵌套目录的xhtml文件,使用< ol>或者< ul>。
<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>
(为清楚起见,我遗漏了清单的内容) 当然,它不起作用。我可以在这里使用一些帮助......
答案 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>
您必须将h1
,h2
和h3
视为不同级别,并创建嵌套列表(如果它们有子级别)。这是另一种样式表,可以产生您期望的结果:
<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>