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

如何在XSL中正确移除全局变量中的空元素

XSL处理全局变量时丢失子节点仅保留文本的问题修复

问题原因

  1. $b变量的无效包裹:你在$b中用<xsl:copy>包裹$a的处理,$a本身就是Data元素,这会生成一个无名父节点,导致后续模板处理逻辑混乱。
  2. 模式不匹配:空元素移除的模板属于默认模式,而trim模式的模板内部调用<xsl:apply-templates>时未指定模式,触发了XSL默认模板——默认模板会递归输出所有文本节点、忽略元素节点,最终导致子元素丢失,仅拼接文本内容。
  3. 根模板标签笔误:根模板中闭合标签写了<IMFRoot>,和开头的<Root>不匹配,破坏XML结构合法性。

修正后的XSL代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:f="f:f"
                exclude-result-prefixes="f xs xsl">
    
    <xsl:output indent="yes" omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="vPop" as="element()*">
    <!-- Variables to be generated -->
    </xsl:variable>

    <xsl:variable name="seq" select="f:subTree($vPop/@path/concat(.,'/',string(..)))"/>

    <xsl:variable name="a">
        <xsl:apply-templates select="$seq" mode="format"/>
    </xsl:variable>

    <!-- 修正$b的处理:直接对$a的节点应用trim模式,无需额外包裹 -->
    <xsl:variable name="b">
        <xsl:apply-templates select="$a/node()" mode="trim"/>
    </xsl:variable>

    <!-- trim模式的身份模板:复制非空节点 -->
    <xsl:template match="node()|@*" mode="trim">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" mode="trim"/>
        </xsl:copy>
    </xsl:template>

    <!-- trim模式下移除空元素:匹配没有属性、子元素、注释、处理指令且文本为空的元素 -->
    <xsl:template match="*[not(@*|*|comment()|processing-instruction()) and normalize-space()='']" mode="trim"/>

    <xsl:template match="Data" mode="format">
        <Data>
           <!-- Some xsl:for-each and xsl:copy-of here -->
        </Data>
    </xsl:template>

    <!-- 修正根模板的闭合标签笔误 -->
    <xsl:template match="/">
        <xsl:for-each select="Root">
            <Root>
                <xsl:for-each select="Info">
                    <Info>
                        <xsl:copy-of select="./*"></xsl:copy-of>
                    </Info>
                </xsl:for-each>
                <xsl:copy-of select="$b"/>
            </Root>
        </xsl:for-each>
    </xsl:template>

    <xsl:function name="f:subTree" as="node()*">
        <xsl:param name="pPaths" as="xs:string*"/>

        <xsl:for-each-group select="$pPaths" group-adjacent=
                "substring-before(substring-after(concat(., '/'), '/'), '/')">
            <xsl:if test="current-grouping-key()">
                <xsl:choose>
                    <xsl:when test=
                                      "substring-after(current-group()[1], current-grouping-key())">
                        <xsl:element name=
                                             "{substring-before(concat(current-grouping-key(), '['), '[')}">
                            <xsl:sequence select=
                                                  "f:subTree(for $s in current-group()
                         return
                            concat('/',substring-after(substring($s, 2),'/'))
                             )
            "/>
                        </xsl:element>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="current-grouping-key()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:if>
        </xsl:for-each-group>
    </xsl:function>
</xsl:stylesheet>

关键修改点

  • $b变量优化:移除多余的<xsl:copy>,直接对$a的子节点应用trim模式,确保处理对象是Data元素本身。
  • trim模式对齐:将空元素移除的模板指定为trim模式,同时在身份模板内部调用时明确指定mode="trim",保证递归处理时始终遵循trim规则,避免触发默认模板。
  • 标签错误修正:将根模板中的<IMFRoot>改为<Root>,保证XML结构合法。

验证效果

处理你提供的输入后,会生成符合预期的结果:

<Root>
    <Info>
        <Name>Stack</Name>
    </Info>
    <Data>
        <Mode>Auto</Mode>
        <Class>
            <Details>
                <Version>1.0.0</Version>
            </Details>
            <Package>com</Package>
        </Class>
    </Data>
</Root>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:18:04