如何使用xsl:evaluate获取值并修改addrmap节点的offset属性?
如何用Saxon-EE 9.8修改addrmap节点的offset属性值?
问题背景
你现在在处理带样式表的XML,现有XML结构如下:
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml-model href="register_tool/rules/rules.sch" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?> <addrmap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="register_tool/rules/man_schema.xsd" name="di_do_1430_board" offset="0x0" lsb_size="32"> <enum name="ch_handler_ch_type" bitfield="false"> <element name="be" value="0" offset="0x00000000"/> </enum> <addrmap name="be_sys" offset="0x00000000" offset_xpath="addrmap/enum/element[@name='be']/@offset" lsb_size="24"> <ref name="be_reg_acc" path="blocks/be_reg_acc.xml" ref_name="be_reg_acc" offset="0x0" /> </addrmap> </addrmap>
对应的XSLT片段里,你想用xsl:evaluate解析offset_xpath属性来动态获取偏移量,代码是:
<xsl:choose> <xsl:when test="@offset_xpath"> <xsl:variable name="resolved_offset"><xsl:evaluate xpath="@offset_xpath"></xsl:evaluate></xsl:variable> <xsl:apply-templates mode="map"> <xsl:with-param name="offset" select="rdt:all2dec($resolved_offset)"/> </xsl:apply-templates> </xsl:when> <xsl:otherwise> <xsl:apply-templates mode="map"> <xsl:with-param name="offset" select="rdt:all2dec(@offset)"/> </xsl:apply-templates> </xsl:otherwise> </xsl:choose>
一开始用xsl:evaluate只拿到了#document/fragment,后来用xsl:value-of包裹后成功获取到了值,但你写的修改addrmap节点offset属性的模板虽然被调用了,却没生效,模板代码是:
<xsl:template match="@offset[parent::addrmap]"> <xsl:param name="resolved_offset" tunnel="yes"/> <xsl:attribute name="offset"> <xsl:value-of select="$resolved_offset"/> </xsl:attribute> </xsl:template>
你用的是Saxon-EE 9.8.0.8版本,现在想知道怎么实现修改addrmap节点的offset属性值。
问题分析
核心问题出在两个地方:
- 参数传递不匹配:你的
@offset模板用了隧道参数(tunnel="yes"),但在apply-templates时没有把参数标记为隧道参数,导致参数无法传递到目标模板。 - 模板上下文与模式不匹配:你用了
mode="map"触发模板,但修改@offset的模板没有指定对应模式,同时addrmap节点的默认模板可能没有在该模式下处理属性。 xsl:evaluate的上下文问题:直接使用xsl:evaluate时如果不指定上下文,可能会从当前节点开始解析XPath,导致路径匹配错误。
解决方案
1. 修正xsl:evaluate的使用,确保拿到正确值
xsl:evaluate返回的是节点序列,需要先提取节点的字符串值再转成十进制,同时指定根上下文避免路径错误:
<xsl:when test="@offset_xpath"> <!-- 指定根上下文解析XPath,确保路径正确 --> <xsl:variable name="offset_node" select="xsl:evaluate(xpath='@offset_xpath', context=/)"/> <xsl:variable name="resolved_offset_str" select="$offset_node/string()"/> <xsl:variable name="resolved_offset" select="rdt:all2dec($resolved_offset_str)"/> <!-- 传递隧道参数时必须标记tunnel="yes" --> <xsl:apply-templates mode="map" select="."> <xsl:with-param name="resolved_offset" select="$resolved_offset" tunnel="yes"/> </xsl:apply-templates> </xsl:when>
2. 调整模板匹配与模式
给修改@offset的模板加上对应模式,同时确保addrmap节点在map模式下会处理所有属性:
<!-- 在map模式下匹配addrmap的offset属性 --> <xsl:template match="@offset[parent::addrmap]" mode="map"> <xsl:param name="resolved_offset" tunnel="yes"/> <xsl:attribute name="offset"> <!-- 保持原有十六进制格式,补全8位前缀 --> <xsl:value-of select="concat('0x', format-number($resolved_offset, '00000000'))"/> </xsl:attribute> </xsl:template> <!-- 确保addrmap节点在map模式下复制自身并处理属性/子节点 --> <xsl:template match="addrmap" mode="map"> <xsl:copy> <xsl:apply-templates select="@*" mode="#current"/> <xsl:apply-templates select="node()" mode="#current"/> </xsl:copy> </xsl:template>
3. 完整XSLT示例
整合后的完整样式表如下:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:rdt="http://your-custom-rdt-namespace"> <!-- 通用身份模板,默认复制所有节点和属性 --> <xsl:template match="@*|node()" mode="#all"> <xsl:copy> <xsl:apply-templates select="@*|node()" mode="#current"/> </xsl:copy> </xsl:template> <!-- 处理带有offset_xpath的addrmap节点 --> <xsl:template match="addrmap[@offset_xpath]"> <xsl:choose> <xsl:when test="@offset_xpath"> <xsl:variable name="offset_node" select="xsl:evaluate(xpath='@offset_xpath', context=/)"/> <xsl:variable name="resolved_offset_str" select="$offset_node/string()"/> <xsl:variable name="resolved_offset" select="rdt:all2dec($resolved_offset_str)"/> <xsl:apply-templates mode="map" select="."> <xsl:with-param name="resolved_offset" select="$resolved_offset" tunnel="yes"/> </xsl:apply-templates> </xsl:when> <xsl:otherwise> <xsl:variable name="resolved_offset" select="rdt:all2dec(@offset)"/> <xsl:apply-templates mode="map" select="."> <xsl:with-param name="resolved_offset" select="$resolved_offset" tunnel="yes"/> </xsl:apply-templates> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- 在map模式下修改addrmap的offset属性 --> <xsl:template match="@offset[parent::addrmap]" mode="map"> <xsl:param name="resolved_offset" tunnel="yes"/> <xsl:attribute name="offset"> <xsl:value-of select="concat('0x', format-number($resolved_offset, '00000000'))"/> </xsl:attribute> </xsl:template> </xsl:stylesheet>
这样调整后,就能正确将addrmap节点的offset属性替换为通过offset_xpath解析出的数值了。
内容的提问来源于stack exchange,提问作者Ephreal
相关产品推荐
相关产品推荐

