如何通过XSLT使新DITA结构中的audience属性传递至输出?
问题描述
我之前成功更新过XSLT脚本,能把audience属性添加到输出里,但现在需要调整输出的显示方式,却没法让转换脚本正确获取该属性了。
原输入与原脚本
原输入内容:
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE bookmap PUBLIC "-//OASIS//DTD DITA BookMap//EN" "bookmap.dtd" []> <bookmap> <topicgroup> <topichead navtitle="Arkansas Property and Casualty Adjuster Law" locktitle="yes" audience="Arkansas"> <topicgroup> <mapref href="Qbank/maps/Adj_Unit_AR.ditamap" format="ditamap"/> </topicgroup> </topichead> </topicgroup> </bookmap>
原脚本相关部分:
<xsl:template match="*[contains(@class,' mapgroup-d/topichead ')]"> <topichead> <xsl:attribute name="navtitle"> <xsl:value-of select="@navtitle"/> </xsl:attribute> <xsl:choose> <xsl:when test="@audience"> <xsl:attribute name="audience"> <xsl:value-of select="@audience"/> </xsl:attribute> </xsl:when> <xsl:otherwise /> </xsl:choose> </topichead> </xsl:template>
新输入与问题脚本
现在输入结构变了,audience属性移到了<chapter>标签上:
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE bookmap PUBLIC "-//OASIS//DTD DITA BookMap//EN" "bookmap.dtd" []> <bookmap> <chapter navtitle="Alabama Property and Casualty Adjuster Law" locktitle="yes" audience="Alabama"> <topicgroup> <topicgroup> <mapref href="Qbank/maps/Adj_Unit_AL.ditamap" format="ditamap"/> </topicgroup> </topicgroup> </chapter> </bookmap>
我尝试了下面的脚本,但没法提取到audience属性,请问哪里出错了?
<xsl:template match="*[contains(@class,' mapgroup-d/topichead ')]"> <topichead> <xsl:attribute name="navtitle"> <xsl:value-of select="@navtitle"/> </xsl:attribute> <xsl:choose> <xsl:when test="bookmap/chapter/@audience"> <xsl:attribute name="audience"> <xsl:value-of select="@audience"/> </xsl:attribute> </xsl:when> <xsl:otherwise /> </xsl:choose> </topichead> </xsl:template>
问题分析与修正
你的脚本有两个核心错误:
- 模板匹配目标不匹配新输入:原模板匹配的是
topichead元素,但新输入里根本不存在topichead节点,这个模板根本不会被触发,自然无法处理属性。 - XPath选择逻辑错误:即使模板能触发,
bookmap/chapter/@audience是错误的路径写法(缺少根节点前缀/),且xsl:value-of里的@audience还是取当前节点的属性,而当前节点(如果是topichead)并没有这个属性,应该指向chapter节点的属性。
修正后的脚本
假设你需要把<chapter>的audience属性转移到输出的<topichead>中,正确的脚本如下:
<xsl:template match="*[contains(@class,' bookmap/chapter ')]"> <topichead> <!-- 复制chapter的navtitle属性 --> <xsl:attribute name="navtitle"> <xsl:value-of select="@navtitle"/> </xsl:attribute> <!-- 提取并添加chapter的audience属性 --> <xsl:if test="@audience"> <xsl:attribute name="audience"> <xsl:value-of select="@audience"/> </xsl:attribute> </xsl:if> <!-- 保留原chapter下的子节点结构 --> <xsl:apply-templates/> </topichead> </xsl:template>
补充说明
- 用
xsl:if替代xsl:choose更简洁,仅处理存在audience属性的情况。 - 模板匹配目标改为
chapter元素(通过DITA标准的class属性bookmap/chapter),这样才能捕获到带有audience属性的节点。 xsl:apply-templates用来处理chapter下的子节点,保证原结构里的topicgroup等内容能正常转换。
如果你的场景需要在现有topichead模板中获取上层chapter的属性,可将XPath调整为ancestor::*[contains(@class,' bookmap/chapter ')]/@audience,但前提是topichead确实处于chapter的层级之下。
内容的提问来源于stack exchange,提问作者pantherfan
相关产品推荐
相关产品推荐

