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

XSLT中w元素xml:id生成异常问题求助

问题:XSLT 3.0中w元素的xml:id无法正确继承父元素l的xml:id

我使用的样式表版本是version="3.0",引擎为Saxon PEE 9.9.1.7。需求是让w元素的xml:id由父元素l的xml:id + '_' + w的text()值组成,但实际转换结果不符合预期。

转换前XML示例

<div3 xml:id="ktu1-1_ii">
   <!-- tei elements div4 and lg -->
         <l n="1a">
            <!-- other children -->
            <w>l</w>
         </l>
</div3>

现有XSLT模板代码

<xsl:template match="div3/div4/lg/l">
   <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:if test="not(@xml:id)">
         <xsl:attribute name="xml:id">
            <xsl:value-of select="concat(ancestor::div3/@xml:id, '_l', @n)"/>
         </xsl:attribute>
      </xsl:if>
      <xsl:apply-templates/>
   </xsl:copy>
</xsl:template>


<xsl:template match="l/w">
   <xsl:variable name="xmlid">
      <xsl:value-of select="ancestor::l/@xml:id"/>
   </xsl:variable>
   <xsl:message select="$xmlid"/> <!-- test @xml:id, nothing -->
   <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="pos"></attribute>
      <!-- Calculate xml:id based on parent 'l' xml:id -->
      <xsl:attribute name="xml:id">
         <xsl:value-of select="normalize-space(replace(ancestor::l/@xml:id, ' ', '')) || '_' || replace(., '\s|̊', '')"/> 
      </xsl:attribute>
      <xsl:apply-templates/>
   </xsl:copy>
</xsl:template> 

转换结果

  • l元素结果正确:<l n='1a' xml:id='ktu1-1_ii_l1a'>
  • w元素结果不符合预期:<w xml:id="_l">l</w>,预期应为<w xml:id="ktu1-1_ii_l1a_l">l</w>

错误原因与解决方案

核心问题

XSLT处理节点时,当前节点的上下文是原始XML文档中的节点,而非模板处理后生成的新节点。你在l的模板中动态添加了xml:id属性,但在处理w元素时,ancestor::l/@xml:id访问的是原始XML中l元素的属性——而原始XML里的l并没有xml:id,所以返回空值,最终拼接出_l。

解决方案

有两种可行的处理方式:

方式一:提前计算l的xml:id并传递给子节点

修改l的模板,将计算好的xml:id存储为变量,在调用apply-templates时通过xsl:with-param传递给w的模板:

<xsl:template match="div3/div4/lg/l">
   <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:variable name="l-xml-id">
         <xsl:choose>
            <xsl:when test="@xml:id">
               <xsl:value-of select="@xml:id"/>
            </xsl:when>
            <xsl:otherwise>
               <xsl:value-of select="concat(ancestor::div3/@xml:id, '_l', @n)"/>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:variable>
      <xsl:if test="not(@xml:id)">
         <xsl:attribute name="xml:id" select="$l-xml-id"/>
      </xsl:if>
      <!-- 传递变量给子节点模板 -->
      <xsl:apply-templates>
         <xsl:with-param name="parent-l-id" select="$l-xml-id"/>
      </xsl:apply-templates>
   </xsl:copy>
</xsl:template>

<xsl:template match="l/w">
   <xsl:param name="parent-l-id"/>
   <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="pos"></attribute>
      <xsl:attribute name="xml:id" select="concat($parent-l-id, '_', replace(., '\s|̊', ''))"/>
      <xsl:apply-templates/>
   </xsl:copy>
</xsl:template>

方式二:使用隧道参数(Tunnel Parameter)

如果w元素嵌套较深,使用隧道参数可以避免逐层传递变量:

<xsl:template match="div3/div4/lg/l">
   <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:variable name="l-xml-id">
         <xsl:choose>
            <xsl:when test="@xml:id">
               <xsl:value-of select="@xml:id"/>
            </xsl:when>
            <xsl:otherwise>
               <xsl:value-of select="concat(ancestor::div3/@xml:id, '_l', @n)"/>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:variable>
      <xsl:if test="not(@xml:id)">
         <xsl:attribute name="xml:id" select="$l-xml-id"/>
      </xsl:if>
      <!-- 定义隧道参数 -->
      <xsl:apply-templates>
         <xsl:with-param name="parent-l-id" select="$l-xml-id" tunnel="yes"/>
      </xsl:apply-templates>
   </xsl:copy>
</xsl:template>

<xsl:template match="l/w">
   <!-- 接收隧道参数 -->
   <xsl:param name="parent-l-id" tunnel="yes"/>
   <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="pos"></attribute>
      <xsl:attribute name="xml:id" select="concat($parent-l-id, '_', replace(., '\s|̊', ''))"/>
      <xsl:apply-templates/>
   </xsl:copy>
</xsl:template>

补充说明

  • 两种方式都直接复用了l元素模板中计算好的xml:id值,避免了依赖原始节点的属性。
  • 使用select属性直接赋值给xsl:attribute,比嵌套xsl:value-of更简洁高效,符合XSLT 3.0的最佳实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 21:45:15