在Xerces UTF8Reader中编码导致MalformedByteSequenceException的问题

kwi*_*ess 4 java xml xerces character-encoding xml-parsing

我遇到com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException了一个XML文件.我使用调试器逐步完成了Xerces代码,并缩小了这个区域的范围.我能够通过删除文档中的"智能引号"字符来确定该文档变得可解析.

该文件没有DTD.Notepad ++将其固定为"ANSI as UTF-8".Firefox将其视为"西方".我记得在大学里一个不那么令人惊叹的讲座中,UTF-8被设计为向后兼容单字节编码系统.我也看到在这个图表中,字节序列e2 80 9d实际上代表了"正确的双引号",但即使我看不到编码问题,我也认为有一个.

我从Xerces获得的异常消息是Invalid byte 3 of 3-byte UTF-8 sequence.它从UTF8Reader的invalidByte(3, 3, b2)第435行的调用中被抛出.当我试图完全理解这种方法的逻辑时,我的大脑开始融化我的耳朵,所以我可能会遗漏一些东西,但正如我在上面提到的字节3(0x90).至少上面的序列,根据UTF-8表是有效的.

以下是在十六进制编辑器中显示双引号的文件段:XML细分

我尝试过以下方法:

  • 强制使用UTF-8通过Charset.forName("UTF-8")加载字符串
  • 添加DTD <?xml version="1.0" encoding="UTF-8"?>
  • 在Notepad ++中打开文件,并通过其UI将其编码为UTF-8
  • 以上各种组合,有时反复

表示为无效的字节似乎是63(0x3F?) eclipse截图

我也尝试将这个智能引号字符添加到以前可解析的文档中.正如所料,它使解析器抛出相同的异常.

堆栈跟踪:

com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 3 of 3-byte UTF-8 sequence.
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:687)
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:435)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1753)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipChar(XMLEntityScanner.java:1426)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2815)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
    at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
Run Code Online (Sandbox Code Playgroud)

...

更新: 我仍然需要找到一种方法来安全地将其转换为String.我使用Notepad ++将文件编码为UTF-8.下面的代码成功地将字节加载到String中(我在Eclipse中调试时可以看到在String中读取XML),但现在我得到了带有不同参数的MalformedByteSequenceException.这一次,我可以发布我正在使用的代码和XML:

File file = new File("ccd.xml");

byte[] ccdBytes = org.apache.commons.io.FileUtils.readFileToByteArray(file);
String ccdString = new String(ccdBytes, Charset.forName("UTF-8"));

CDAUtil.load(new ByteArrayInputStream(IOUtils.toByteArray(ccdString))); //method that's doing the parsing
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪:

Exception in thread "main" com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence.
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:687)
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:557)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1753)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipChar(XMLEntityScanner.java:1426)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2815)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
    at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
    at org.openhealthtools.mdht.emf.runtime.resource.impl.FleXMLLoadImpl.load(FleXMLLoadImpl.java:55)
    at org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doLoad(XMLResourceImpl.java:180)
    at org.eclipse.emf.ecore.resource.impl.ResourceImpl.load(ResourceImpl.java:1494)
    at org.openhealthtools.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:268)
    at org.openhealthtools.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:250)
    at org.openhealthtools.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:238)
Run Code Online (Sandbox Code Playgroud)

然而,

CDAUtil.load(new FileInputStream(new File("ccd.xml")));
Run Code Online (Sandbox Code Playgroud)

作品

Gio*_*nni 6

您没有告诉我们您如何将文件传递给Xerces.你可以用不同的方式做不同的结果.您可以在此处阅读有关xml编码问题的更详细说明

我建议你做以下事情:

  1. 使用notedpad ++打开文件,<?xml version="1.0" encoding="UTF-8"?>如果缺少则添加为第一行
  2. 在Notepad ++中转换为UTF-8(没有bom)(它应该在格式菜单中,但我使用的是意大利语版本的notepad ++,所以我猜测菜单翻译)
  3. 保存文件
  4. 在Java中将其打开为InputStream,即将一个InputStream传递给xml解析器而不是作为Reader子类

这应该可以解决问题,如果您可以通过将文件传递给解析器的代码,则更容易找到问题.

这些步骤解决了这个问题,因为只有在使用InputStream(即字节流)时,解析器才会考虑带有编码声明的xml中的第一行.如果您读取字节流,则需要编码声明,以指定如何将字节转换为字符.

如果你传递一个String,那么第一行是无用的,因为你传递的是一串字符而不需要编码.

如果要使用String,则必须将该文件作为InputStream读取并转换为指定charset的Reader(有些事情InputStreamReader inputStreamReader= new InputStreamReader(xmlFileInputStream,"UTF-8");)

我的猜测是你得到了错误,因为你没有指定charset而Java选择了你的一个操作系统(Windows-1252).