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

XML缩进移除后空格插入异常的XSL技术求助

问题

移除XML文档缩进时遇到困难,尝试了两种方法:

  • 添加<xsl:strip-space elements="*"/>
  • 对所有文本应用normalize-space

发现必须同时使用二者才能完全移除缩进,但normalize-space会过度删除空格。于是编写了以下XSL代码,试图为除段落开头外的所有文本段前添加空格,却发现部分文本(如示例中的"third text2")前未插入空格,这类问题在文档中普遍存在,怀疑<xsl:strip-space>配置与空格插入存在冲突,请问是什么原因导致无法插入所需空格?

相关代码

XSL 代码

<xsl:template match="p">
    <xsl:variable name="first_text" select="descendant::text()[normalize-space(.) != ''][1]"/>
    <xsl:copy copy-namespaces="no">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="element()|text()" mode="spacing">
            <xsl:with-param name="first_text" select="$first_text" tunnel="yes"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

<xsl:template match="*" mode="spacing">
    <xsl:copy copy-namespaces="no">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates mode="spacing"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="text()" mode="spacing">
    <xsl:param name="first_text" tunnel="yes"/>
    <xsl:choose>
        <xsl:when test="$first_text = .">
            <xsl:value-of select="normalize-space(.)"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="concat('&amp;#32;', normalize-space(.))"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

XML 输入

<topic class="- topic/topic " id="topic_1">
    <title class="- topic/title ">Title</title>
    <body>    
        <p class="- topic/p "><i class="+ topic/ph hi-d/i ">First text1<xref class="- topic/xref "><b class="+ topic/ph hi-d/b ">second text1</b></xref>third text1.</i>
        </p>    
        <p class="- topic/p "><i class="+ topic/ph hi-d/i "><b class="+ topic/ph hi-d/b ">First text2<keyword class="- topic/keyword ">second text2</keyword></b>third text2.</i>
        </p>
    </body>
</topic>

XML 输出(为便于查看已添加缩进)

<topic class="- topic/topic " id="topic_1">
    <title class="- topic/title ">Title</title>
    <body class="- topic/body ">   
        <p class="- topic/p "><i class="+ topic/ph hi-d/i ">First text1<xref class="- topic/xref "><b class="+ topic/ph hi-d/b "> second text1</b></xref> third text1.    </i>    
        </p>   
        <p class="- topic/p "><i class="+ topic/ph hi-d/i "><b class="+ topic/ph hi-d/b ">First text2<keyword class="- topic/keyword "> second text2</keyword></b>third text2.</i>
        </p>
</body>

原因分析与解决方案

核心问题

空格未正确插入的问题,与<xsl:strip-space>无关,主要源于两个代码逻辑错误:

1. 节点判断逻辑错误

原代码用$first_text = .判断当前文本节点是否为段落首文本节点,这是字符串值比较,而非节点身份匹配。这种方式存在两个问题:

  • 若文档中出现与首文本节点内容完全相同的其他文本,会错误跳过空格添加;
  • 极端情况下,文本节点的字符串值可能因空白处理出现意外相等,导致逻辑失效。

2. 空格生成方式错误

原代码用concat('&amp;#32;', normalize-space(.))生成空格,&amp;#32;会被输出为XML实体&#32;,而非实际空格字符。除非XML被解析渲染,否则原始输出中看不到空格,看起来像是未插入空格。

修正方案

步骤1:修正节点身份判断

使用generate-id()函数比较节点唯一标识,确保只有真正的首文本节点跳过空格:

<xsl:when test="generate-id($first_text) = generate-id(.)">

步骤2:直接使用空格字符

将XML实体替换为实际空格字符,确保输出可见的空格:

<xsl:value-of select="concat(' ', normalize-space(.))"/>

完整修正后的XSL代码

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="p">
        <xsl:variable name="first_text" select="descendant::text()[normalize-space(.) != ''][1]"/>
        <xsl:copy copy-namespaces="no">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="element()|text()" mode="spacing">
                <xsl:with-param name="first_text" select="$first_text" tunnel="yes"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*" mode="spacing">
        <xsl:copy copy-namespaces="no">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates mode="spacing"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="text()" mode="spacing">
        <xsl:param name="first_text" tunnel="yes"/>
        <xsl:choose>
            <xsl:when test="generate-id($first_text) = generate-id(.)">
                <xsl:value-of select="normalize-space(.)"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="concat(' ', normalize-space(.))"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

效果验证

修正后,所有非首文本节点前都会正确插入空格,同时<xsl:strip-space>仍能有效移除原始XML的缩进空白,normalize-space也不会破坏必要的文本间距。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 05:27:03