使用 Java 和 UTF-8 编码生成有效的 XML

Posted

技术标签:

【中文标题】使用 Java 和 UTF-8 编码生成有效的 XML【英文标题】:Producing valid XML with Java and UTF-8 encoding 【发布时间】:2010-10-01 09:27:43 【问题描述】:

我正在使用 JAXP 生成和解析一个 XML 文档,其中一些字段是从数据库中加载的。

序列化 XML 的代码:

DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.newDocument();
Element root = doc.createElement("test");
root.setAttribute("version", text);
doc.appendChild(root);

DOMSource domSource = new DOMSource(doc);
TransformerFactory tFactory = TransformerFactory.newInstance();

FileWriter out = new FileWriter("test.xml");
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(domSource, new StreamResult(out)); 

解析 XML 的代码:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("test.xml");

我遇到了以下异常:

[Fatal Error] test.xml:1:4: Invalid byte 1 of 1-byte UTF-8 sequence.
Exception in thread "main" org.xml.sax.SAXParseException: Invalid byte 1 of 1-byte UTF-8 sequence.
    at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
    at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
    at com.test.Test.xml(Test.java:27)
    at com.test.Test.main(Test.java:55)

字符串文本包括 u-umlaut 和 o-umlaut(字符代码 0xFC 和 0xF6)。这些是导致错误的字符。当我自己转义字符串以使用 ü和 ö然后问题就消失了。当我写出 XML 时,其他实体会自动编码。

如何在不自己替换这些字符的情况下正确写入/读取我的输出?

(我已经阅读了以下问题:

How to encode characters from Oracle to XML?

Repairing wrong encoding in XML files)

【问题讨论】:

【参考方案1】:

使用 FileOutputStream 而不是 FileWriter。

后者应用自己的编码,几乎可以肯定不是 UTF-8(取决于您的平台,可能是 Windows-1252 或 IS-8859-1)。

编辑(现在我有时间):

允许将没有序言的 XML 文档编码为 UTF-8 或 UTF-16。序言允许指定其编码(序言只能包含 US-ASCII 字符,因此序言始终可读)。

Reader 处理字符;它将解码底层 InputStream 的字节流。结果,当您将 Reader 传递给解析器时,您是在告诉它您已经处理了编码,因此解析器将忽略序言。当你传递一个 InputStream(它读取字节)时,它不会做这个假设,并且会查看序言来定义编码——或者如果它不存在,则默认为 UTF-8/UTF-16。

我从未尝试过读取以 UTF-16 编码的文件。我怀疑解析器会寻找字节顺序标记 (BOM) 作为文件的前 2 个字节。

【讨论】:

很好很简单,我确实想过改成这个,但放弃了这个想法,因为我没有看到在构造函数中指定编码的方法。效果很好,谢谢。 很好的答案——从现在开始我会一直在 FileWriter 中寻找隐藏的陷阱! 我不想使用文件。我的信息来自数据库。我构建 dom 并将其传递给 Xades 库。【参考方案2】:

好吧,当然0xFC0xF6 不是有效的UTF-8 字符。这些应该被限定为两个字节序列:0x3CBC0x3CB6

问题很可能是字符的原始来源被定义为UTF-8,而实际上并非如此。

【讨论】:

将 FileWriter 更改为 FileOutputStream 确实导致这些字符被编码为两个字节序列:0xC3BC 和 0xC3B6。

以上是关于使用 Java 和 UTF-8 编码生成有效的 XML的主要内容,如果未能解决你的问题,请参考以下文章

JAVA/JS中中文编码转换

Java如何检测替换4个字节的utf-8编码(此范围编码包含emoji)

APNS 是不是理解 UTF-8 编码的有效负载

如何在 Scala 或 Java 中读取具有混合编码的文本文件?

OS X 终端 UTF-8 问题

java如何把string转为utf-8