XML文档读取为Latin1,但一半转换为UTF-8



我正在为一个奇怪的问题而绞尽脑汁,我知道会有一个明显的答案,但我看不出我的生命。这都与编码有关。在代码之前,有一个简单的描述:我想接收一个latin (ISO-8859-1)编码的XML文档,然后通过HttpURLConnection完全不加修改地发送。我有一个小的测试类和显示问题的原始XML。XML文件包含一个拉丁字符0xa2(一个美分字符),它是无效的UTF-8 -我故意使用它作为我的测试用例。XML声明是ISO-8859-1。我可以毫不费力地阅读它,但是当我想转换org。www。dom时。文档到一个byte[]数组以发送HttpURLConnection, 0xa2字符被转换为UTF-8编码的分字符(0xc2 0xa2),并且声明保持为ISO-8859-1。换句话说,它被转换成两个字符——完全错误。

执行此操作的代码:

FileInputStream input = new FileInputStream( "input-file" );
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware( true );
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse( input );
Source source = new DOMSource( document );
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Result result = new StreamResult( baos );
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform( source, result );
byte[] bytes = baos.toByteArray();
FileOutputStream fos = new FileOutputStream( "output-file" );
fos.write( bytes );

我现在只是把它写进一个文件,同时我弄清楚到底是什么在转换这个字符。输入文件包含0xa2,输出文件包含0xc2 0xa2。解决这个问题的一种方法是将这一行放在最后第二个块中:

transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");

然而,并不是我将要处理的所有XML文档都是Latin1;事实上,当它们进入时,大多数将是UTF-8。我假设我不需要计算出编码是什么这样我就可以把它输入到转换器中?我是说,它当然应该自己解决问题,而我只是做错了什么?

我有一个想法,我可以查询文档来找出编码,因此额外的行可以做到这一点:

transformer.setOutputProperty(OutputKeys.ENCODING, document.getInputEncoding());

然而,我随后确定这个不是的答案,因为document.getInputEncoding()返回一个不同的字符串,如果我在linux机器上的终端中运行它,与我在Mac上的Eclipse中运行它相比。

任何提示将不胜感激。我完全接受我错过了一些明显的东西。

是的,默认情况下,xml文档是用utf-8编写的,因此您需要显式地告诉Transformer使用不同的编码。最后的编辑是这样做的"技巧",它总是匹配输入XML编码:

transformer.setOutputProperty(OutputKeys.ENCODING, document.getXmlEncoding());
唯一的问题是,你真的需要来维护输入编码吗?

为什么不直接用一个正常的FileInputStream打开它,并将字节直接从它流到输出流呢?为什么你需要加载成DOM格式在内存中,如果你只是发送它字节对字节的HttpURLConnection?

编辑:根据javadoc for Document,您可能应该使用Document . getxmlencoding()来获取与XML prolog中的编码匹配的内容。

这可能会有帮助-这对于评论来说太长了,但不是真正的答案。来自规范:

encoding属性指定要使用的首选编码输出结果树。需要尊重XSLT处理器UTF-8和UTF-16的值。对于其他值,如果XSLT处理程序不支持指定的编码,如果可能表示错误;如果它如果不提示错误,则应使用UTF-8或UTF-16代替。

你可能想用"encoding=junk"来测试一下,看看它是怎么做的。

Java的有效值在这里描述。参见IANA字符集

最新更新