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

使用XSLT展平嵌套XML元素的属性问题求助

用XSLT合并属性值展平嵌套XML元素树

我来帮你搞定这个嵌套XML展平的问题!核心思路是递归遍历嵌套的node元素,把路径上的属性值拼接成完整路径,同时提取目标节点的value值。下面直接上可运行的方案,包括基础场景和复杂情况的处理。

先明确场景示例

输入XML(嵌套结构)

<root>
  <node id="A">
    <node id="B" value="123"/>
    <node id="C">
      <node id="D" value="456"/>
      <node id="E">
        <node id="F" value="789"/>
      </node>
    </node>
  </node>
</root>

期望输出(展平结构)

<flattened>
  <item path="A/B" value="123"/>
  <item path="A/C/D" value="456"/>
  <item path="A/C/E/F" value="789"/>
</flattened>

实现XSLT代码(兼容XSLT 1.0/2.0)

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

  <!-- 初始化:创建输出根节点,选中所有带value属性的node -->
  <xsl:template match="/">
    <flattened>
      <xsl:apply-templates select="//node[@value]"/>
    </flattened>
  </xsl:template>

  <!-- 处理每个带value的node,生成展平后的item元素 -->
  <xsl:template match="node[@value]">
    <item>
      <!-- 调用递归模板拼接完整路径 -->
      <xsl:attribute name="path">
        <xsl:call-template name="build-full-path">
          <xsl:with-param name="current-node" select="."/>
        </xsl:call-template>
      </xsl:attribute>
      <!-- 直接提取当前node的value属性 -->
      <xsl:attribute name="value" select="@value"/>
    </item>
  </xsl:template>

  <!-- 递归模板:从当前node向上遍历父节点,拼接id路径 -->
  <xsl:template name="build-full-path">
    <xsl:param name="current-node"/>
    <xsl:param name="temp-path" select="''"/>

    <!-- 如果当前节点有父级node,继续向上递归 -->
    <xsl:if test="$current-node/parent::node">
      <xsl:call-template name="build-full-path">
        <xsl:with-param name="current-node" select="$current-node/parent::node"/>
        <xsl:with-param name="temp-path" select="concat('/', $current-node/@id, $temp-path)"/>
      </xsl:call-template>
    </xsl:if>

    <!-- 拼接最终路径:顶层node直接输出id,后续节点去掉开头的斜杠 -->
    <xsl:choose>
      <xsl:when test="not($current-node/parent::node)">
        <xsl:value-of select="$current-node/@id"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="substring($temp-path, 2)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- 忽略XML中的空白文本节点,避免输出冗余内容 -->
  <xsl:template match="text()"/>
</xsl:stylesheet>

代码工作原理拆解

  1. 根模板:匹配整个XML文档,创建输出的flattened根元素,然后选中所有带有value属性的node元素进行处理。
  2. 带value的node处理模板:为每个符合条件的node生成item元素,调用递归模板生成path属性,同时直接复制value属性。
  3. 递归路径拼接模板:从当前node开始,向上遍历所有父级node,把每个节点的id拼接到路径前面,最终生成从顶层到当前节点的完整路径。
  4. 空白节点处理:忽略XML中的空白文本,避免输出多余的空行或空格。

复杂场景适配

如果你的XML存在特殊情况,可以做以下调整:

  • 只处理最深层带value的node:把select="//node[@value]"改成select="//node[@value and not(node)]",这样只会选择没有子node的带value节点。
  • node没有id属性:在拼接路径时加判断,比如用concat('/', if($current-node/@id) then $current-node/@id else 'unknown', $temp-path),给无id的节点加默认标识。
  • 自定义路径分隔符:把递归模板里的concat('/', $current-node/@id, $temp-path)改成你需要的分隔符,比如.或-,比如concat('.', $current-node/@id, $temp-path)。
  • 中间节点也带value:当前模板会自动处理所有带value的节点,不管它有没有子节点。比如某个node自己有value同时还有子node,输出会同时包含这个节点和它的子节点的展平记录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:10:51