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

XSLT1.0属性值XPath替换错误排查:同名属性不同层级路径解析异常问题

问题分析与解决方案

你的问题核心在于递归处理占位符时丢失了原始上下文节点,导致XPath路径的计算基准完全错误。

错误原因详解

当前的expand模板在替换占位符时,递归调用自身时传递的是属性值(比如../@*[name()=$name]),这会让模板的上下文从原来的元素节点(比如<slot>)直接变成这个属性节点。后续再处理其他占位符时,所有的../都是相对于这个属性节点,而非原始的元素节点,自然就会拿到错误的属性值。

举个具体的例子:处理<slot>的title属性时,原本{../../@attr3}应该基于<slot>元素向上找两层(到<desc>节点)取它的attr3值(555),但你的代码递归后上下文变成了属性节点,../../../指向了错误的层级,最后只能拿到<slot>自己的attr3值(333),导致三个占位符都被替换成了同一个值。

修正后的XSLT代码

我们需要给expand模板新增一个参数,用来保存原始的上下文节点(也就是包含当前属性的元素节点),所有XPath的计算都基于这个节点,不会因为递归而偏移:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:msxsl="urn:schemas-microsoft-com:xslt"> 
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="node()"> 
 <xsl:copy> 
 <xsl:apply-templates select="@*|node()"/> 
 </xsl:copy> 
</xsl:template> 

<xsl:template match="@*"> 
 <xsl:attribute name="{name()}"> 
 <xsl:call-template name="expand"> 
 <xsl:with-param name="text" select="."/> 
 <xsl:with-param name="context" select=".."/> <!-- 传递属性所属的元素节点作为固定上下文 --> 
 </xsl:call-template> 
 </xsl:attribute> 
</xsl:template> 

<xsl:template name="expand"> 
 <xsl:param name="text"/> 
 <xsl:param name="context"/> <!-- 保存原始上下文节点,全程不变 --> 
 <xsl:choose> 
 <!-- 统一处理所有{...}格式的占位符 --> 
 <xsl:when test="contains($text, '{') and contains(substring-after($text, '{'), '}')"> 
 <xsl:value-of select="substring-before($text, '{')"/> 
 <!-- 提取大括号内的完整XPath表达式 --> 
 <xsl:variable name="xpath" select="substring-before(substring-after($text, '{'), '}')"/> 
 <!-- 基于固定上下文计算XPath对应的属性值 --> 
 <xsl:variable name="value" select="$context/$xpath"/> 
 <!-- 递归处理占位符解析后的文本(支持嵌套占位符) --> 
 <xsl:call-template name="expand"> 
 <xsl:with-param name="text" select="$value"/> 
 <xsl:with-param name="context" select="$context"/> 
 </xsl:call-template> 
 <!-- 递归处理剩余未解析的文本 --> 
 <xsl:call-template name="expand"> 
 <xsl:with-param name="text" select="substring-after($text, '}')"/> 
 <xsl:with-param name="context" select="$context"/> 
 </xsl:call-template> 
 </xsl:when> 
 <xsl:otherwise> 
 <xsl:value-of select="$text"/> 
 </xsl:otherwise> 
 </xsl:choose> 
</xsl:template> 
</xsl:stylesheet>

关键修正点

  1. 新增context参数:调用expand时,把属性所属的元素节点(select="..")传递进去,后续所有XPath计算都基于这个固定节点,不会因递归改变上下文。
  2. 统一解析占位符:不再区分{@}、{../@}等不同格式,直接提取大括号内的完整XPath表达式,用$context/$xpath计算对应值,适配任意层级的相对路径。
  3. 递归保留上下文:每次递归调用expand都传递$context参数,确保路径计算的基准始终正确。

用这个修正后的XSLT转换,就能得到你预期的结果:<slot>的title属性会正确替换为555+444-333,其他属性的替换也完全符合要求。

内容的提问来源于stack exchange,提问作者eliasum

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 18:47:44