嵌套for-each实现多级标题章节列表的XSL转换问题求助
解决多级标题XSL转换的方案
嘿,我懂你遇到的麻烦了——硬写嵌套的<xsl:for-each>确实搞不定任意层级的标题,毕竟你没法提前知道文档到底有多少级 heading。给你个用递归模板的解决方案,能完美处理这种动态层级的情况:
首先先补全你给出的XML示例(方便测试和演示):
<Chapters> <Chapter> <Heading1Lvl> <Heading1LvlName>heading1nameFirst</Heading1LvlName> <Heading2Lvl> <Heading2LvlName>heading2name</Heading2LvlName> <Text typeOfText="basic">BasicText</Text> <Heading3Lvl> <Heading3LvlName>heading3name</Heading3LvlName> <Text typeOfText="detailed">DetailedText</Text> </Heading3Lvl> </Heading2Lvl> <Heading2Lvl> <Heading2LvlName>anotherHeading2</Heading2LvlName> </Heading2Lvl> </Heading1Lvl> <Heading1Lvl> <Heading1LvlName>heading1nameSecond</Heading1LvlName> </Heading1Lvl> </Chapter> </Chapters>
然后是对应的XSLT代码,核心用递归模板处理任意深度的标题:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes"/> <!-- 入口模板,匹配根节点,初始化输出结构 --> <xsl:template match="/"> <html> <body> <h1>章节列表</h1> <!-- 启动递归:找到所有第一层标题节点 --> <xsl:apply-templates select="Chapters/Chapter/*[starts-with(local-name(), 'Heading') and ends-with(local-name(), 'Lvl')]"/> </body> </html> </xsl:template> <!-- 递归核心模板:匹配所有标题层级节点 --> <xsl:template match="*[starts-with(local-name(), 'Heading') and ends-with(local-name(), 'Lvl')]"> <!-- 从节点名里提取标题级别数字,比如从Heading2Lvl拿到2 --> <xsl:variable name="level" select="substring-before(substring-after(local-name(), 'Heading'), 'Lvl')"/> <!-- 生成对应级别的HTML标题标签 --> <xsl:element name="h{$level}"> <xsl:value-of select="*[ends-with(local-name(), 'Name')]"/> </xsl:element> <!-- 输出当前标题下的文本内容 --> <xsl:apply-templates select="Text"/> <!-- 递归处理当前标题下的子标题,自动适配任意深度 --> <xsl:apply-templates select="*[starts-with(local-name(), 'Heading') and ends-with(local-name(), 'Lvl')]"/> </xsl:template> <!-- 专门处理Text节点的模板,格式化输出文本 --> <xsl:template match="Text"> <p><xsl:value-of select="."/></p> </xsl:template> </xsl:stylesheet>
关键逻辑说明:
- 递归模板的优势:不像嵌套
for-each只能处理固定层级,这个模板会自动查找当前标题节点下的所有子标题,递归调用自己,不管你的文档有3级还是10级标题都能处理。 - 动态识别标题级别:通过字符串提取从节点名里拿到级别数字,不用硬写
h1、h2,适配所有编号的标题节点。 - 灵活的节点匹配:用
starts-with和ends-with匹配标题节点,就算后续新增Heading4Lvl、Heading5Lvl也不用修改代码。
如果你的XML结构有细微调整(比如子标题的嵌套路径不同),只需要修改递归模板里的select路径就行。
内容的提问来源于stack exchange,提问作者Milousel
相关产品推荐
相关产品推荐

