首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Xerces UTF8Reader中引起UTF8Reader的编码问题

Xerces UTF8Reader中引起UTF8Reader的编码问题
EN

Stack Overflow用户
提问于 2015-06-05 22:18:26
回答 2查看 5.3K关注 0票数 4

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

这份文件没有DTD。Notepad++将其定位为"ANSI as UTF-8“。火狐将其定位为“西部”。我记得在大学里一个不那么令人惊叹的演讲中,UTF-8被设计成与单字节编码系统向后兼容。我还看到了在这张图表上,字节序列e2 80 9d实际上是“右双引号”的代表,但是即使我看不到编码问题,我也认为存在一个编码问题。

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

下面是在十六进制编辑器中出现双引号的文件段:

我尝试了以下几点:

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

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

我还尝试将这个智能引号字符添加到以前可解析的文档中。正如预期的那样,它使解析器抛出相同的异常。

堆栈跟踪:

代码语言:javascript
复制
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)

..。

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

代码语言:javascript
复制
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

堆栈跟踪:

代码语言:javascript
复制
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)

然而,

代码语言:javascript
复制
CDAUtil.load(new FileInputStream(new File("ccd.xml")));

作品

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-06-08 13:22:32

你没有告诉我们你是如何把文件传递给Xerces的。你可以用不同的方式做不同的事情,结果也不同。您可以阅读有关xml编码问题的更详细说明( 这里 )。

我建议你做以下一件:

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

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

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

如果要传递字符串,则第一行是无用的,因为您传递的是一个字符流,并且不需要进行编码。

如果要使用字符串,必须将文件作为InputStream读取并转换为指定字符集的读取器(类似于InputStreamReader inputStreamReader= new InputStreamReader(xmlFileInputStream,"UTF-8");)

我的猜测是,您得到了错误,因为您没有指定字符集,而Java获取了您的操作系统(Windows1252)。

票数 6
EN

Stack Overflow用户

发布于 2015-06-08 13:27:47

只有当输入文件中有实际的UTF-8编码错误时,我才能得到该错误消息。因此,我假设文件中存在一个您找不到的实际错误。

这是我的测试代码:

代码语言:javascript
复制
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

public class ParseAXml {
  public static void main(String argv[]) throws Exception {
    String xmlFile = argv[0];
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document document = builder.parse(xmlFile);
    System.out.println("Parsed Successfully");
  }
}

当我传递给它一个正确的文件时--就像你拥有的那样包含智能引号--我得到了预期的Parsed Successfully消息。这是我的常规测试文件:

代码语言:javascript
复制
$ hexdump -C tmp.xml
00000000  3c 3f 78 6d 6c 20 76 65  72 73 69 6f 6e 3d 22 31  |<?xml version="1|
00000010  2e 30 22 20 65 6e 63 6f  64 69 6e 67 3d 22 55 54  |.0" encoding="UT|
00000020  46 2d 38 22 3f 3e 0a 3c  74 68 69 6e 67 3e 3c 61  |F-8"?>.<thing><a|
00000030  3e 54 68 69 73 20 e2 80  9c 71 75 6f 74 65 e2 80  |>This ...quote..|
00000040  9d 20 63 6f 75 6c 64 20  67 65 74 20 74 72 69 63  |. could get tric|
00000050  6b 79 3c 2f 61 3e 3c 2f  74 68 69 6e 67 3e 0a     |ky</a></thing>.|
0000005f

当我测试一个包含错误的文件时--在偏移量0x38处损坏字节--我得到了您看到的异常:

代码语言:javascript
复制
$ java ParseAXml tmp.err.xml
Exception in thread "main" 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:2807)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
    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:177)
    at ParseAXml.main(ParseAXml.java:10)

因此,为了帮助您,我编写了一个简短的java程序,试图查找格式错误的字节:

代码语言:javascript
复制
import java.nio.*;
import java.nio.charset.*;
import java.io.*;

public class FindBadUTF8 {
  public static void main(String argv[]) throws Exception {
    String filename = argv[0];
    InputStream inStream = new FileInputStream(filename);

    CharsetDecoder d=Charset.forName("UTF-8").newDecoder();
    CharBuffer out = CharBuffer.allocate(1);
    ByteBuffer in = ByteBuffer.allocate(10);
    in.clear();
    long offset = 0L;
    while (true) {
      int read = inStream.read();
      if (read != -1) {
        in.put((byte)read);
      }
      out.clear();
      in.flip();
      CoderResult cr = d.decode(in, out, (read == -1));
      if (cr.isError()) {
        if (read != -1) {
          System.out.println("Error at offset " + offset + ": " + cr);
          return;
        } else {
          System.out.println("Error at end-of-file: " + cr);
          return;
        }
      }
      if (cr.isUnderflow()) {
        in.position(in.limit());
        in.limit(in.capacity());
      } else {
        in.clear();
      }
      if (read == -1) {
        break;
      }
      offset += 1L;
    }
    System.out.println("OK");
  }
}

当该程序针对我的示例文件运行时,其中出现了一个错误,它给了我如下信息:

代码语言:javascript
复制
$ java FindBadUTF8 tmp.err.xml
Error at offset 56: MALFORMED[2]

实际上,偏移量56 (在十六进制中是0x38 )是I错误的字节:

代码语言:javascript
复制
$ hexdump -C tmp.err.xml
00000000  3c 3f 78 6d 6c 20 76 65  72 73 69 6f 6e 3d 22 31  |<?xml version="1|
00000010  2e 30 22 20 65 6e 63 6f  64 69 6e 67 3d 22 55 54  |.0" encoding="UT|
00000020  46 2d 38 22 3f 3e 0a 3c  74 68 69 6e 67 3e 3c 61  |F-8"?>.<thing><a|
00000030  3e 54 68 69 73 20 e2 80  ff 71 75 6f 74 65 e2 80  |>This ...quote..|
00000040  9d 20 63 6f 75 6c 64 20  67 65 74 20 74 72 69 63  |. could get tric|
00000050  6b 79 3c 2f 61 3e 3c 2f  74 68 69 6e 67 3e 0a     |ky</a></thing>.|
0000005f
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30676624

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档