XSLT设置第2个property元素type属性,Qt实现不生效问题排查
问题描述
需要修改XML中第二个<property>元素的type属性,输入XML如下:
<t> <property>value1</property> <property type="oldtype">value2</property> <property type="oldtype">value3</property> <property type="oldtype">value4</property> </t>
使用的XSLT 1.0代码如下:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:param name="pNewType" select="'newtype'"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="property[2]/@type"> <xsl:attribute name="type"> <xsl:value-of select="$pNewType"/> </xsl:attribute> </xsl:template> </xsl:stylesheet>
这段代码在xsltproc和在线XSLT工具中可以正常生成预期输出,但在Qt的XSLT实现中无效(isValid()返回true,但转换结果与输入一致)。去掉[2]索引时,能正常修改所有property的type属性。预期输出为:
<t> <property>value1</property> <property type="newtype">value2</property> <property type="oldtype">value3</property> <property type="oldtype">value4</property> </t>
询问这种转换方式是否正确,以及如何解决Qt中的问题。
问题分析与解决方案
你写的这段XSLT在标准XSLT 1.0规范里是没问题的,但Qt的XSLT实现(大概率基于旧版libxslt或有自定义兼容逻辑)对直接通过property[2]/@type这种路径匹配属性节点的支持有兼容性问题,这就是为什么在其他工具里正常、Qt里没效果的原因。
给你两个可行的修正方案:
方案1:直接匹配第二个property元素再修改属性
换个思路,先匹配到第二个property元素,在复制它的时候替换type属性,这种写法兼容性更好:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:param name="pNewType" select="'newtype'"/> <!-- 身份模板:默认复制所有节点和属性 --> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <!-- 匹配第二个property元素 --> <xsl:template match="property[2]"> <xsl:copy> <!-- 写入新的type属性 --> <xsl:attribute name="type"> <xsl:value-of select="$pNewType"/> </xsl:attribute> <!-- 复制元素内的文本内容 --> <xsl:apply-templates select="node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
方案2:通过父节点判断匹配属性
如果想保留属性级别的模板匹配,可以通过属性的父节点位置来判断,避免在路径里直接用索引:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:param name="pNewType" select="'newtype'"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <!-- 匹配父节点是第二个property的type属性 --> <xsl:template match="@type[parent::property[2]]"> <xsl:attribute name="type"> <xsl:value-of select="$pNewType"/> </xsl:attribute> </xsl:template> </xsl:stylesheet>
这两种写法都能在Qt的XSLT实现中正常工作,核心是避开了Qt不兼容的路径索引匹配方式,改用更通用的节点匹配逻辑。
内容的提问来源于stack exchange,提问作者Jonas Gillespie
相关产品推荐
相关产品推荐

