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

Java或XSLT 1.0实现XML指定字符转实体的方案咨询

解决XML特殊字符转实体:Java和XSLT 1.0实现方案

我来帮你搞定这个XML特殊字符转实体的问题!之前用正则或者单个replace方法失败,大概率是因为正则没法高效覆盖几百个字符映射,或者多次replace的顺序/覆盖范围没处理好。下面给你两种靠谱的实现方式,任你选:

Java实现方案

这个方法用Map存所有字符-实体映射,然后逐个字符遍历替换,既高效又不会遗漏任何映射,完全避开正则的坑。

import java.util.HashMap;
import java.util.Map;

public class XmlEntityConverter {
    // 初始化你的400+字符-实体映射
    private static final Map<Character, String> ENTITY_MAP = new HashMap<>();

    static {
        ENTITY_MAP.put('☆', "&star;");
        ENTITY_MAP.put('♥', "&heart;");
        ENTITY_MAP.put('"', "&quot;");
        // 这里添加其他所有映射,比如:
        // ENTITY_MAP.put('♦', "&diamond;");
        // ... 剩下的几百个都放这儿
    }

    public static String convertToEntities(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }

        StringBuilder sb = new StringBuilder(input.length());
        // 逐个字符检查,存在映射就替换,否则保留原字符
        for (char c : input.toCharArray()) {
            String entity = ENTITY_MAP.get(c);
            sb.append(entity != null ? entity : c);
        }
        return sb.toString();
    }

    // 测试用例
    public static void main(String[] args) {
        String originalXmlText = "Text ☆ and \"more\" ♥?";
        String convertedText = convertToEntities(originalXmlText);
        System.out.println(convertedText);
        // 输出结果:Text &star; and &quot;more&quot; &heart;?
    }
}

为什么这个方案靠谱?

  • 逐个字符处理,不会出现正则的贪婪匹配、字符范围遗漏问题;
  • 用Map存储映射,维护起来很方便,新增/修改映射直接改静态代码块就行;
  • 性能比多次调用replace好太多,尤其是处理长文本的时候。

XSLT 1.0实现方案

如果你的场景是纯XML处理,不想写Java代码,XSLT 1.0也能搞定。这里给你两种写法:

写法1:直接用递归模板(适合映射不多的情况,或者不想依赖扩展)

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

    <!-- 递归替换字符的模板 -->
    <xsl:template name="replace-entities">
        <xsl:param name="text"/>
        
        <xsl:choose>
            <!-- 替换☆为&star; -->
            <xsl:when test="contains($text, '☆')">
                <xsl:value-of select="substring-before($text, '☆')"/>
                <xsl:text>&amp;star;</xsl:text> <!-- 注意:XSLT里&必须转义成&amp; -->
                <xsl:call-template name="replace-entities">
                    <xsl:with-param name="text" select="substring-after($text, '☆')"/>
                </xsl:call-template>
            </xsl:when>
            <!-- 替换♥为&heart; -->
            <xsl:when test="contains($text, '♥')">
                <xsl:value-of select="substring-before($text, '♥')"/>
                <xsl:text>&amp;heart;</xsl:text>
                <xsl:call-template name="replace-entities">
                    <xsl:with-param name="text" select="substring-after($text, '♥')"/>
                </xsl:call-template>
            </xsl:when>
            <!-- 替换"为&quot; -->
            <xsl:when test="contains($text, '&quot;')">
                <xsl:value-of select="substring-before($text, '&quot;')"/>
                <xsl:text>&amp;quot;</xsl:text>
                <xsl:call-template name="replace-entities">
                    <xsl:with-param name="text" select="substring-after($text, '&quot;')"/>
                </xsl:call-template>
            </xsl:when>
            <!-- 这里继续添加其他所有字符的替换规则 -->
            <xsl:otherwise>
                <xsl:value-of select="$text"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <!-- 匹配XML根节点,处理super-head内容 -->
    <xsl:template match="/root">
        <root>
            <super-head>
                <xsl:call-template name="replace-entities">
                    <xsl:with-param name="text" select="super-head/text()"/>
                </xsl:call-template>
            </super-head>
        </root>
    </xsl:template>
</xsl:stylesheet>

写法2:用EXSLT扩展(适合大量映射,更易维护)

如果有400+映射,写几百个<xsl:when>太麻烦,可以用EXSLT的node-set扩展来批量处理(主流XSLT处理器比如Xalan、Saxon都支持这个扩展):

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

    <!-- 定义所有字符-实体映射 -->
    <xsl:variable name="entity-mappings">
        <mapping char="☆" entity="&amp;star;"/>
        <mapping char="♥" entity="&amp;heart;"/>
        <mapping char='"' entity="&amp;quot;"/>
        <!-- 这里添加剩下的所有映射 -->
    </xsl:variable>

    <!-- 递归批量替换模板 -->
    <xsl:template name="replace-all-entities">
        <xsl:param name="text"/>
        <!-- 将变量中的映射转换为可遍历的节点集 -->
        <xsl:param name="mappings" select="exsl:node-set($entity-mappings)/mapping"/>

        <xsl:choose>
            <xsl:when test="$mappings">
                <xsl:variable name="current-char" select="$mappings[1]/@char"/>
                <xsl:variable name="current-entity" select="$mappings[1]/@entity"/>

                <xsl:choose>
                    <xsl:when test="contains($text, $current-char)">
                        <xsl:value-of select="substring-before($text, $current-char)"/>
                        <xsl:value-of select="$current-entity"/>
                        <!-- 递归处理剩余文本,继续替换当前字符的其他出现 -->
                        <xsl:call-template name="replace-all-entities">
                            <xsl:with-param name="text" select="substring-after($text, $current-char)"/>
                            <xsl:with-param name="mappings" select="$mappings"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <!-- 当前字符不存在,处理下一个映射 -->
                        <xsl:call-template name="replace-all-entities">
                            <xsl:with-param name="text" select="$text"/>
                            <xsl:with-param name="mappings" select="$mappings[position() > 1]"/>
                        </xsl:call-template>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
                <!-- 所有映射处理完,输出剩余文本 -->
                <xsl:value-of select="$text"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <!-- 处理目标XML节点 -->
    <xsl:template match="/root">
        <root>
            <super-head>
                <xsl:call-template name="replace-all-entities">
                    <xsl:with-param name="text" select="super-head/text()"/>
                </xsl:call-template>
            </super-head>
        </root>
    </xsl:template>
</xsl:stylesheet>

XSLT方案注意点

  • XSLT中输出实体时,必须把&转义成&amp;,否则会被解析成实体本身而不是实体字符串;
  • 写法2依赖EXSLT扩展,如果你的处理器不支持,就用写法1。

内容的提问来源于stack exchange,提问作者Kevin B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:12:33