You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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属性值。

问题分析

核心问题出在两个地方:

  1. 参数传递不匹配:你的@offset模板用了隧道参数(tunnel="yes"),但在apply-templates时没有把参数标记为隧道参数,导致参数无法传递到目标模板。
  2. 模板上下文与模式不匹配:你用了mode="map"触发模板,但修改@offset的模板没有指定对应模式,同时addrmap节点的默认模板可能没有在该模式下处理属性。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:02:49