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

如何用XSLT将源XML作为文本值嵌入转换后的XML中?

用XSLT实现动态XML转换并保留原内容

完全可以通过XSLT实现你的需求,不管源XML的元素结构是否已知,都能动态处理并生成包含原内容文本副本的目标XML。以下是具体实现方案:

源XML示例

<root>
    <item>
        <a>Text&amp;A</a>
        <b>Text&amp;B</b>
        <c>Text&amp;C</c>
    </item>
    <item>
        <a>TextA</a>
        <b>TextB</b>
        <c>TextC</c>
    </item>
</root>

期望转换结果

<root>
    <item>
        <ab>Text&amp;A Text&amp;B</ab>
        <orig>
            &lt;a&gt;Text&amp;amp;A&lt;/a&gt;
            &lt;b&gt;Text&amp;amp;B&lt;/b&gt;
            &lt;c&gt;Text&amp;amp;C&lt;/c&gt;
        </orig>
    </item>
    <item>
        <ab>TextA TextB</ab>
        <orig>
            &lt;a&gt;TextA&lt;/a&gt;
            &lt;b&gt;TextB&lt;/b&gt;
            &lt;c&gt;TextC&lt;/c&gt;
        </orig>
    </item>
</root>

XSLT实现代码(XSLT 2.0+)

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- 匹配根节点,直接复制 -->
    <xsl:template match="/root">
        <xsl:copy>
            <xsl:apply-templates select="item"/>
        </xsl:copy>
    </xsl:template>

    <!-- 处理每个item节点 -->
    <xsl:template match="item">
        <xsl:copy>
            <!-- 生成ab元素,拼接a和b的文本内容 -->
            <ab>
                <xsl:value-of select="concat(a, ' ', b)"/>
            </ab>
            <!-- 生成orig元素,序列化当前item的所有子节点 -->
            <orig>
                <xsl:value-of select="serialize(*, map{'method':'xml', 'indent':true()})" disable-output-escaping="no"/>
            </orig>
        </xsl:copy>
    </xsl:template>

    <!-- 兜底模板:匹配未明确处理的节点,避免默认复制 -->
    <xsl:template match="text()|@*"/>
</xsl:stylesheet>

关键说明

  • 动态序列化原内容:使用XSLT 2.0的serialize函数,可以将任意节点序列化为XML文本,自动处理转义(比如把<转成&lt;,&转成&amp;),完全不需要预知源节点的结构。
  • 生成ab元素:直接通过concat(a, ' ', b)拼接指定节点的文本,若后续需要调整,只需修改这部分逻辑即可。
  • 兜底模板:避免默认的节点复制行为,确保只处理我们明确指定的内容。

兼容XSLT 1.0的方案(无serialize函数时)

如果只能用XSLT 1.0,可以通过递归模板实现节点的转义序列化:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/root">
        <xsl:copy>
            <xsl:apply-templates select="item"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="item">
        <xsl:copy>
            <ab>
                <xsl:value-of select="concat(a, ' ', b)"/>
            </ab>
            <orig>
                <xsl:apply-templates select="*" mode="serialize"/>
            </orig>
        </xsl:copy>
    </xsl:template>

    <!-- 递归序列化节点的模板 -->
    <xsl:template match="*" mode="serialize">
        <!-- 输出转义的起始标签 -->
        <xsl:text>&lt;</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
        <!-- 处理子节点:文本或嵌套元素 -->
        <xsl:apply-templates mode="serialize"/>
        <!-- 输出转义的结束标签 -->
        <xsl:text>&lt;/</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
        <!-- 添加换行和缩进,模拟格式化 -->
        <xsl:text>&#10;            </xsl:text>
    </xsl:template>

    <!-- 转义文本内容中的特殊字符 -->
    <xsl:template match="text()" mode="serialize">
        <xsl:call-template name="escape-xml">
            <xsl:with-param name="text" select="."/>
        </xsl:call-template>
    </xsl:template>

    <!-- 转义XML特殊字符的模板 -->
    <xsl:template name="escape-xml">
        <xsl:param name="text"/>
        <xsl:choose>
            <xsl:when test="contains($text, '&amp;')">
                <xsl:value-of select="substring-before($text, '&amp;')"/>
                <xsl:text>&amp;amp;</xsl:text>
                <xsl:call-template name="escape-xml">
                    <xsl:with-param name="text" select="substring-after($text, '&amp;')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains($text, '&lt;')">
                <xsl:value-of select="substring-before($text, '&lt;')"/>
                <xsl:text>&amp;lt;</xsl:text>
                <xsl:call-template name="escape-xml">
                    <xsl:with-param name="text" select="substring-after($text, '&lt;')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains($text, '&gt;')">
                <xsl:value-of select="substring-before($text, '&gt;')"/>
                <xsl:text>&amp;gt;</xsl:text>
                <xsl:call-template name="escape-xml">
                    <xsl:with-param name="text" select="substring-after($text, '&gt;')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$text"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="text()|@*"/>
</xsl:stylesheet>

这个XSLT 1.0版本通过递归处理每个节点和文本,手动完成XML特殊字符的转义,同样能实现动态保留原内容的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 12:23:19