XSLT中匹配属性时如何获取该属性的值?
解决XSLT中匹配属性节点时修改属性值的问题
嘿,我来帮你捋清楚这个问题!你遇到的核心问题不是.的含义,而是模板的结构写错了——当你匹配的是属性节点时,<xsl:copy>的用法和你想的不一样,而且属性节点本身不能包含子属性,这直接导致你的choose逻辑根本没生效。
问题出在哪?
首先明确:当你的模板匹配的是属性节点(比如mathml:mi/@mathvariant)时,.确实代表这个属性的值,test=".='bold'"的判断逻辑是对的。但你的模板结构有两个致命问题:
- 属性节点是XML中的叶子节点,它不能包含任何子节点(包括其他属性)。你在
<xsl:copy>(复制原属性)内部又尝试创建同名的mathvariant属性,这是违反XML规则的,处理器会直接忽略这部分无效代码。 <xsl:copy>已经复制了原属性的完整内容(包括原属性名和值),之后再添加同名属性完全是多余且冲突的。
正确的写法
我们可以直接针对属性节点生成新的属性值,或者换个思路匹配包含该属性的元素节点来处理,两种方法都能解决问题:
方法1:直接匹配属性节点,生成修改后的属性
去掉<xsl:copy>,直接输出修改后的属性即可:
<xsl:template match="mathml:mi/@mathvariant"> <xsl:attribute name="mathvariant"> <xsl:choose> <xsl:when test=".='bold'">bold-sans-serif</xsl:when> <xsl:when test=".='italic'">sans-serif-italic</xsl:when> <xsl:otherwise> <!-- 如果是其他值,保留原属性值 --> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template>
这个模板会匹配所有mathml:mi元素的mathvariant属性,根据原属性值生成新的属性内容,完全替换原属性。
方法2:匹配包含属性的元素节点(更灵活)
如果你还需要处理该元素的其他内容或属性,可以匹配mathml:mi元素,然后单独处理目标属性:
<xsl:template match="mathml:mi"> <xsl:copy> <!-- 复制除了mathvariant之外的所有属性 --> <xsl:copy-of select="@*[not(local-name()='mathvariant')]"/> <!-- 处理mathvariant属性 --> <xsl:if test="@mathvariant"> <xsl:attribute name="mathvariant"> <xsl:choose> <xsl:when test="@mathvariant='bold'">bold-sans-serif</xsl:when> <xsl:when test="@mathvariant='italic'">sans-serif-italic</xsl:when> <xsl:otherwise> <xsl:value-of select="@mathvariant"/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:if> <!-- 处理元素的子节点 --> <xsl:apply-templates/> </xsl:copy> </xsl:template>
这种方法更通用,能同时处理元素的其他属性和子节点,避免遗漏内容。
总结
.在属性节点上下文确实代表属性的值,你的判断逻辑是对的,错在模板结构;- 属性节点不能包含子节点,所以不要在
<xsl:copy>(复制属性)内部再创建属性; - 直接生成新属性或者匹配父元素处理,都是可行的解决方案。
内容的提问来源于stack exchange,提问作者B. Schrag
相关产品推荐
相关产品推荐

