使用 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】:好吧,当然0xFC
和0xF6
不是有效的UTF-8
字符。这些应该被限定为两个字节序列:0x3CBC
和 0x3CB6
。
问题很可能是字符的原始来源被定义为UTF-8
,而实际上并非如此。
【讨论】:
将 FileWriter 更改为 FileOutputStream 确实导致这些字符被编码为两个字节序列:0xC3BC 和 0xC3B6。以上是关于使用 Java 和 UTF-8 编码生成有效的 XML的主要内容,如果未能解决你的问题,请参考以下文章
Java如何检测替换4个字节的utf-8编码(此范围编码包含emoji)