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

如何使用XSLT 2.0将平级引用XML转换为分层XML

解决平级XML节点通过ID引用生成分层结构的XSLT 2.0方案

我来帮你搞定这个问题!你的场景是典型的基于ID引用构建层级结构的需求,之前递归模板没成功,大概率是没利用好XSLT的key来高效查找节点,加上没处理好referenceID里多ID的拆分逻辑。

首先提个小细节:你给出的原始XML缺少根节点,这是无效的XML,我们需要先给它套一个根节点,比如<Root>,调整后的原始XML如下:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
  <Data id="1" referenceID="2 3"> Text1 </Data>
  <Data id="2" referenceID="4"> Text2 </Data>
  <Data id="3" referenceID="5"> Text3 </Data>
  <Data id="4"> Text4 </Data>
  <Data id="5"> Text5 </Data>
</Root>

接下来是实现需求的XSLT 2.0代码,我会逐段解释:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- 定义key,通过id快速查找对应的Data节点 -->
  <xsl:key name="data-by-id" match="Data" use="@id"/>

  <!-- 主模板:匹配根节点,启动层级构建 -->
  <xsl:template match="/Root">
    <xsl:call-template name="build-level">
      <!-- 传入顶层节点:这里是id为1的Data,你可以根据实际情况调整 -->
      <xsl:with-param name="node" select="key('data-by-id', '1')"/>
      <!-- 初始层级为1 -->
      <xsl:with-param name="level" select="1"/>
    </xsl:call-template>
  </xsl:template>

  <!-- 递归模板:构建层级结构 -->
  <xsl:template name="build-level">
    <xsl:param name="node"/>
    <xsl:param name="level"/>

    <!-- 生成对应层级的元素,比如Level1、Level2 -->
    <xsl:element name="Level{$level}">
      <!-- 输出当前节点的文本内容(去掉多余空格) -->
      <xsl:value-of select="normalize-space($node/text())"/>
      
      <!-- 处理当前节点的referenceID:如果存在则拆分ID并递归 -->
      <xsl:if test="$node/@referenceID">
        <!-- 用tokenize拆分空格分隔的ID序列 -->
        <xsl:variable name="ref-ids" select="tokenize($node/@referenceID, '\s+')"/>
        <!-- 遍历每个引用ID,找到对应节点并递归调用模板 -->
        <xsl:for-each select="$ref-ids">
          <xsl:call-template name="build-level">
            <xsl:with-param name="node" select="key('data-by-id', .)"/>
            <xsl:with-param name="level" select="$level + 1"/>
          </xsl:call-template>
        </xsl:for-each>
      </xsl:if>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

关键逻辑解释:

  • <xsl:key>定义:相当于给所有Data节点建立了一个“索引”,通过id可以瞬间找到对应的节点,比遍历所有节点效率高很多,尤其是节点数量多的时候。
  • 递归模板build-level:
    1. 接收两个参数:当前要处理的Data节点,以及当前的层级数。
    2. 用<xsl:element name="Level{$level}">动态生成对应层级的元素(比如层级1生成<Level1>,层级2生成<Level2>)。
    3. 用tokenize()函数把referenceID里的空格分隔ID拆分成序列,这是XSLT 2.0新增的实用特性,完美解决多ID的处理问题。
    4. 遍历每个拆分后的ID,找到对应的Data节点,然后递归调用自身,层级数加1,以此构建嵌套结构。

转换后的输出结果:

<?xml version="1.0" encoding="UTF-8"?>
<Level1>Text1
   <Level2>Text2
      <Level3>Text4</Level3>
   </Level2>
   <Level2>Text3
      <Level3>Text5</Level3>
   </Level2>
</Level1>

如果你的顶层节点不是固定的id=1,而是需要自动找到所有未被其他节点引用的节点,只需要修改主模板里的select逻辑即可:

<xsl:with-param name="node" select="Data[not(key('data-by-id', //Data/@referenceID))]"/>

这样就能自动定位所有没有被引用的顶层节点,适配更复杂的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:37:33