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

如何修复XSLT实现嵌套XML扁平化并保留原层级结构?

XSLT扁平化嵌套XML的问题修复与通用解决方案

问题背景

使用XSLT扁平化嵌套XML文件时,无法保留原有的<sub-group>层级结构,且<group-name>被错误扁平化,不符合预期输出要求。

输入XML

<?xml version="1.0" encoding="UTF-8"?>
<group xmlns="http://group.com/group">
    <sub-group>
        <group-name>group1</group-name>
        <group-parameter1>
            <group-parameter11>param11</group-parameter11>
            <group-parameter21>param21</group-parameter21>
        </group-parameter1>
        <group-parameter2>
            <group-parameter21>param21</group-parameter21>
        </group-parameter2>
    </sub-group>
    <sub-group>
        <group-name>group2</group-name>
        <group-parameter1>
            <group-parameter11>param11</group-parameter11>
            <group-parameter21>param21</group-parameter21>
        </group-parameter1>
        <group-parameter3>
            <group-parameter31>param31</group-parameter31>
        </group-parameter3>
    </sub-group>
</group>

预期输出

<?xml version="1.0" encoding="UTF-8"?>
<group xmlns="http://group.com/group">
    <sub-group>
        <group-name>group1</group-name>
        <sub-group.group-parameter1.group-parameter11 xmlns="">param11</sub-group.group-parameter1.group-parameter11>
        <sub-group.group-parameter1.group-parameter21 xmlns="">param21</sub-group.group-parameter21>
        <sub-group.group-parameter2.group-parameter21 xmlns="">param21</sub-group.group-parameter2.group-parameter21>
    </sub-group>
    <sub-group>
        <group-name>group2</group-name>
        <sub-group.group-parameter1.group-parameter11 xmlns="">param11</sub-group.group-parameter1.group-parameter11>
        <sub-group.group-parameter1.group-parameter21 xmlns="">param21</sub-group.group-parameter21>
        <sub-group.group-parameter3.group-parameter31 xmlns="">param31</sub-group.group-parameter3.group-parameter31>
    </sub-group>
</group>

当前使用的XSLT代码

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">
    
    <xsl:mode streamable="no"/>
    
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates select="descendant::*[not(*)]"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="text()">
        <xsl:element name="{string-join(ancestor::*[position() lt last()]/name(), '.')}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>
    
</xsl:stylesheet>

当前转换输出

<?xml version="1.0" encoding="UTF-8"?>
<group xmlns="http://group.com/group">
   <sub-group.group-name xmlns="">group1</sub-group.group-name>
   <sub-group.group-parameter1.group-parameter11 xmlns="">param11</sub-group.group-parameter1.group-parameter11>
   <sub-group.group-parameter1.group-parameter21 xmlns="">param21</sub-group.group-parameter1.group-parameter21>
   <sub-group.group-parameter2.group-parameter21 xmlns="">param21</sub-group.group-parameter2.group-parameter21>
   <sub-group.group-name xmlns="">group2</sub-group.group-name>
   <sub-group.group-parameter1.group-parameter11 xmlns="">param11</sub-group.group-parameter1.group-parameter11>
   <sub-group.group-parameter1.group-parameter21 xmlns="">param21</sub-group.group-parameter1.group-parameter21>
   <sub-group.group-parameter3.group-parameter31 xmlns="">param31</sub-group.group-parameter3.group-parameter31>
</group>

问题分析

原XSLT存在两个核心问题:

  1. 直接遍历所有叶子节点,完全丢弃<sub-group>层级结构,导致所有扁平化元素直接挂载在<group>下。
  2. 未区分需要保留原结构的元素(如<group-name>)和需要扁平化的嵌套参数节点,错误地将<group-name>也进行了扁平化处理。

修复后的通用XSLT代码

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:g="http://group.com/group"
    exclude-result-prefixes="#all"
    version="3.0">
    
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <!-- 身份模板:复制所有未被特殊匹配的节点和属性,保留基础结构 -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- 处理需要扁平化的中间节点(如group-parameter1这类含叶子节点的非容器节点) -->
    <xsl:template match="g:*[*[not(*)]]">
        <xsl:apply-templates select=".//*[not(*)]" mode="flatten"/>
    </xsl:template>

    <!-- 扁平化模式:生成带路径的无命名空间元素 -->
    <xsl:template match="*" mode="flatten">
        <xsl:element name="{string-join(ancestor-or-self::*[count(ancestor-or-self::g:sub-group) > 0]/local-name(), '.')}" xmlns="">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

代码说明

  1. 身份模板:保留原XML的核心层级结构(如<group>、<sub-group>、<group-name>),确保结构不丢失。
  2. 中间节点处理模板:自动匹配所有包含叶子节点的非容器节点,不复制自身,直接处理其下的叶子节点。
  3. 扁平化模式模板:为每个叶子节点生成带路径的元素名,路径从最近的<sub-group>开始到当前节点,用点分隔,且元素放在无命名空间下,完全匹配预期输出。

通用性说明

  • 适配其他XML结构时,只需将命名空间前缀g:替换为目标XML对应的命名空间前缀。
  • 若需要保留其他容器节点,修改ancestor-or-self::g:sub-group中的节点名称即可。
  • 逻辑自动识别所有含叶子节点的中间节点并扁平化,无需针对特定参数节点编写规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:03:30