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

如何阻止javax.xml.transform.Transformer在UTF-8编码下替换非BMP字符

阻止javax.xml.transform.Transformer在UTF-8编码下转非BMP Unicode字符为数值引用

背景

我希望生成包含非BMP Unicode字符的UTF-8编码XML文件。

问题现象

使用以下Java代码生成XML文件时,非BMP Unicode字符被自动替换为数值字符引用,不符合预期。

测试代码

package xml;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class XMLClass {

    static String names[] = {"𠀋一郎", "𠮷野","辻󠄀","👨‍👩‍👦"};

    public static void main(String[] args) {

        DocumentBuilder documentBuilder = null;
        try {
            documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        Document document = documentBuilder.newDocument();
        document.setXmlStandalone(true);

        Element list = document.createElement("list");
        document.appendChild(list);
        for (int i = 0; i < names.length; i++) {
            Element name = (Element) document.createElement("name").cloneNode(false);
            list.appendChild(name);
            name.appendChild(document.createTextNode(names[i]));
        }

        File file = new File("NameList.xml");
        write(file, document);
    }


    public static boolean write(File file, Document document) {

        Transformer transformer = null;
        try {
             TransformerFactory transformerFactory = TransformerFactory.newInstance();
             transformer = transformerFactory.newTransformer();
        } catch (TransformerConfigurationException e) {
             e.printStackTrace();
             return false;
        }

        transformer.setOutputProperty("indent", "yes");
        // non-BMP characters written in characters (no numeric character reference style)
        // when you set encoding UTF-16
        transformer.setOutputProperty("encoding", "UTF-8");
        transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2");

        try {
             transformer.transform(new DOMSource(document), new StreamResult(
                       file));
        } catch (TransformerException e) {
             e.printStackTrace();
             return false;
        }

        return true;
   }
}

期望输出

<?xml version="1.0" encoding="UTF-8"?><list>
<name>𠀋一郎</name>
<name>𠮷野</name>
<name>辻󠄀</name>
<name>👨‍👩‍👦</name>
</list>

实际输出

<?xml version="1.0" encoding="UTF-8"?><list>
<name>&#131083;一郎</name>
<name>&#134071;野</name>
<name>辻&#917760;</name>
<name>&#128104;‍&#128105;‍&#128102;</name>
</list>

核心问题

当指定使用UTF-8编码时,如何阻止javax.xml.transform.Transformer将非BMP Unicode字符替换为数值字符引用?

解决方案

要让Transformer直接输出非BMP Unicode字符,只需在配置Transformer时添加Xalan特定的输出属性,同时确保输出流的编码明确为UTF-8:

修改后的write方法

import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
// ... 保留原有导入

public static boolean write(File file, Document document) {

    Transformer transformer = null;
    try {
         TransformerFactory transformerFactory = TransformerFactory.newInstance();
         transformer = transformerFactory.newTransformer();
    } catch (TransformerConfigurationException e) {
         e.printStackTrace();
         return false;
    }

    transformer.setOutputProperty("indent", "yes");
    transformer.setOutputProperty("encoding", "UTF-8");
    // 关键:设置此属性以保留非BMP Unicode字符
    transformer.setOutputProperty("{http://xml.apache.org/xalan}characters", "true");
    transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2");

    try {
         // 明确指定UTF-8编码的Writer,避免编码不一致
         try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
             transformer.transform(new DOMSource(document), new StreamResult(writer));
         }
    } catch (TransformerException | IOException e) {
         e.printStackTrace();
         return false;
    }

    return true;
}

说明

  • {http://xml.apache.org/xalan}characters属性设置为true后,JDK默认的Xalan Transformer会直接输出原始Unicode字符,而非将非BMP字符转为数值引用。
  • 使用OutputStreamWriter明确指定UTF-8编码,确保文件实际编码与XML声明中的编码一致,避免潜在的乱码或编码冲突问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 23:31:02