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

使用fn:path()选取XML元素:跨h1节点同位置文本替换问题

解决XSLT中节点对应位置文本合并及路径字符串转节点集问题

核心需求

你需要将XML中h1 id="2"及后续h1节点里的文本,合并到h1 id="1"下的同层级节点中,最终得到合并后的文本节点。之前尝试用fn:path()生成路径字符串后无法直接当作节点选择器使用,问题在于字符串不能直接被XSLT解析为节点路径。

推荐方案:基于节点层级定位(无需字符串处理)

不用折腾路径字符串替换,直接通过节点的层级关系定位对应节点更可靠,也更易维护:

  1. 处理h1 id="1"下的目标节点时,先获取该节点相对于父h1的层级结构(即从h1子节点到目标节点的每一层节点名称和位置)。
  2. 对所有其他h1节点,按照这个层级结构找到对应的节点。

完整XSLT示例

针对你的XML结构,以下XSLT可以直接实现需求:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />

  <!-- 匹配h1 id="1"下的p节点,处理文本合并 -->
  <xsl:template match="h1[@id='1']//p">
    <p>
      <!-- 保留原节点文本 -->
      <xsl:value-of select="text()" />
      <!-- 遍历所有其他h1节点,获取对应位置的p文本 -->
      <xsl:for-each select="/h1[@id!='1']">
        <xsl:variable name="target-h1" select="." />
        <!-- 逐层定位对应节点:从h1的子节点开始,复刻原节点的层级路径 -->
        <xsl:variable name="target-p" select="$target-h1">
          <xsl:for-each select="current()/ancestor-or-self::node()[. >> current()/ancestor::h1[@id='1']]">
            <xsl:variable name="node-name" select="local-name()" />
            <xsl:variable name="node-pos" select="count(preceding-sibling::*[local-name()=$node-name]) + 1" />
            <xsl:sequence select="current()[local-name()=$node-name][$node-pos]" />
          </xsl:for-each>
        </xsl:variable>
        <!-- 拼接文本,用/分隔 -->
        <xsl:value-of select="concat('/', $target-p/text())" />
      </xsl:for-each>
    </p>
  </xsl:template>

  <!-- 忽略不需要输出的节点和文本 -->
  <xsl:template match="text()[not(parent::p)]" />
  <xsl:template match="*[not(ancestor-or-self::h1[@id='1']//p)]">
    <xsl:apply-templates />
  </xsl:template>
</xsl:stylesheet>

将这个XSLT应用到你的XML上,会输出期望的结果:

<p>text/translated text</p>

备选方案:用XSLT 3.0的xsl:evaluate解析路径字符串

如果你使用支持XSLT 3.0的处理器(比如Saxon),可以直接把路径字符串转换成节点集。调整你的路径替换逻辑后,用xsl:evaluate执行路径:

<xsl:variable name="original-path" select="path()" />
<!-- 替换路径中的h1[1]为目标h1的位置,比如h1[2] -->
<xsl:variable name="target-path" select="replace($original-path, '/h1\[1\]', '/h1[2]')" />
<xsl:variable name="target-node" as="node()">
  <xsl:evaluate xpath="$target-path" context-item="/" />
</xsl:variable>
<!-- 之后就可以使用$target-node获取对应节点的文本了 -->

注意要处理好路径中的特殊字符(比如方括号转义),以及命名空间的问题(如果你的XML有命名空间,路径里的前缀要对应)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 15:35:20