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

基于XSLT 2.0实现扁平XML到嵌套层级XML的结构转换

用XSLT 2.0实现扁平XML到嵌套层级XML的转换

需求说明

需要将扁平结构的XML转换为嵌套层级结构,核心逻辑是利用每个<product>元素的parent-id属性构建层级关系:当某一<product>的parent-id属性值与另一<product>的id属性值匹配时,前者作为子元素嵌套在后者内部。

此前尝试结合key和for-each-group实现,但未能成功结合递归逻辑。目前已有一段经修正(将prod_family改为product_family)的XSLT 1.0代码可运行,现寻求更简洁高效的XSLT 2.0实现方案。

输入XML

<?xml version="1.0" encoding="UTF-8"?>
<products>
    <productlist>
        <product id="prod_lmo" parent-id="product_family"><prodname>LMO</prodname></product>
        <product id="prod_sdf" parent-id="product_family"><prodname>SDF</prodname></product>
        <product id="prod_sdfg" parent-id="prod_sdf"><prodname>SDFg</prodname></product>
        <product id="prod_abc123" parent-id="prod_abc"><prodname>ABC-123</prodname></product>
        <product id="prod_sdfh" parent-id="prod_sdfg"><prodname>SDF-h</prodname></product>
        <product id="prod_family" parent-id="root"><prodname>Product Family</prodname></product>
        <product id="prod_sdfj" parent-id="prod_sdfh"><prodname>SDF-j</prodname></product>
        <product id="prod_lmao" parent-id="prod_lmo"><prodname>LMAO</prodname></product>
        <product id="prod_elo" parent-id="product_family"><prodname>ELO</prodname></product>
        <product id="prod_lmfao" parent-id="prod_lmo"><prodname>LMFAO</prodname></product>
        <product id="prod_abc" parent-id="product_family"><prodname>ABC</prodname></product>
    </productlist>
</products>

期望输出XML

<?xml version="1.0" encoding="UTF-8"?>
<products>
    <productlist>
        <product id="product_family" parent-id="root"><prodname>Product Family</prodname>
            <product id="prod_elo" parent-id="product_family"><prodname>ELO</prodname></product>
            <product id="prod_lmo" parent-id="product_family"><prodname>LMO</prodname>
                <product id="prod_lmao" parent-id="prod_lmo"><prodname>LMAO</prodname></product>
                <product id="prod_lmfao" parent-id="prod_lmo"><prodname>LMFAO</prodname></product>
            </product>
            <product id="prod_sdf" parent-id="product_family"><prodname>SDF</prodname>
                <product id="prod_sdfg" parent-id="prod_sdf"><prodname>SDFg</prodname>
                    <product id="prod_sdfh" parent-id="prod_sdfg"><prodname>SDF-h</prodname>
                        <product id="prod_sdfj" parent-id="prod_sdfh"><prodname>SDF-j</prodname></product>
                    </product>
                </product>
            </product>        
            <product id="prod_abc" parent-id="product_family"><prodname>ABC</prodname>
                <product id="prod_abc123" parent-id="prod_abc"><prodname>ABC-123</prodname></product>
            </product>
        </product>
    </productlist>
</products>

现有XSLT 1.0代码

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

  <xsl:key name="children" match="product" use="@parentid"/>
  
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="products/productlist">
    <products>
      <productlist>
        <xsl:for-each select="product[@parentid='root']">
          <product>
            <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
            <xsl:attribute name="pid"><xsl:value-of select="@parentid"/></xsl:attribute>
            <xsl:copy-of select="prodname"/>
            
            <xsl:for-each select="key('children', @id)">              
              <product>
                <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                <xsl:attribute name="pid"><xsl:value-of select="@parentid"/></xsl:attribute>
                <xsl:copy-of select="prodname"/>
                
                <xsl:for-each select="key('children', @id)">
                  <product>
                    <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                    <xsl:attribute name="pid"><xsl:value-of select="@parentid"/></xsl:attribute>
                    <xsl:copy-of select="prodname"/>
                    
                    <xsl:for-each select="key('children', @id)">
                      <product>
                        <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                        <xsl:attribute name="pid"><xsl:value-of select="@parentid"/></xsl:attribute>
                        <xsl:copy-of select="prodname"/>    
                      </product>             
                    </xsl:for-each>
                    
                  </product>             
                </xsl:for-each>
              </product>             
            </xsl:for-each>
                
          </product>
        </xsl:for-each>
      </productlist>
    </products>
  </xsl:template>
</xsl:stylesheet>

XSLT 2.0解决方案

实现思路

利用<xsl:key>建立parent-id到对应子<product>元素的映射,通过递归模板处理任意深度的层级结构,无需硬编码层级数,比XSLT 1.0方案更灵活、易维护。

完整XSLT 2.0代码

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

  <!-- 建立parent-id到子product元素的索引 -->
  <xsl:key name="child-products" match="product" use="@parent-id"/>
  
  <!-- 身份模板:复制所有未被特殊模板匹配的节点 -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <!-- 处理productlist节点,只保留根节点(parent-id为root的product) -->
  <xsl:template match="productlist">
    <xsl:copy>
      <xsl:apply-templates select="key('child-products', 'root')"/>
    </xsl:copy>
  </xsl:template>
  
  <!-- 处理product节点,递归添加子元素 -->
  <xsl:template match="product">
    <xsl:copy>
      <!-- 复制当前product的所有属性和子节点 -->
      <xsl:apply-templates select="@*|node()"/>
      <!-- 递归处理当前product的所有子product -->
      <xsl:apply-templates select="key('child-products', @id)"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

代码说明

  1. 索引建立:<xsl:key>将所有<product>按parent-id分组,快速查找指定父ID对应的子元素;
  2. 身份模板:默认复制所有节点,保证XML结构的完整性;
  3. productlist处理:仅筛选出parent-id="root"的根节点,作为层级结构的起点;
  4. 递归模板:处理每个<product>时,先复制自身内容,再递归处理其所有子元素,自动适配任意深度的层级。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 09:45:56