Java 如何让SAX解析器根据xml声明确定编码?

Java 如何让SAX解析器根据xml声明确定编码?,java,xml,encoding,sax,xml-parsing,Java,Xml,Encoding,Sax,Xml Parsing,我试图解析来自不同来源的xml文件(对此我几乎没有控制权)。它们中的大多数是用UTF-8编码的,使用以下代码段不会引起任何问题: SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); FeedHandler handler = new FeedHandler(); InputSource is = new InputSource(getInputS

我试图解析来自不同来源的xml文件(对此我几乎没有控制权)。它们中的大多数是用UTF-8编码的,使用以下代码段不会引起任何问题:

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
FeedHandler handler = new FeedHandler();
InputSource is = new InputSource(getInputStream());
parser.parse(is, handler);
因为SAX默认为UTF-8,所以这很好。然而,一些文件声明:

<?xml version="1.0" encoding="ISO-8859-1"?>
SAX将使用正确的编码

如何让SAX自动检测xml声明中的正确编码,而无需专门设置它?我需要这个,因为我手头不知道文件的编码是什么

提前感谢,,
艾伦

我自己找到了答案

SAX解析器在内部和从InputSource文档使用InputSource:

SAX解析器将使用 InputSource对象,以确定如何 读取XML输入。如果有 字符流可用,解析器 将直接读取该流, 忽略任何文本编码 在该流中找到声明。如果 没有字符流,但是 有一个字节流,解析器 将使用该字节流,使用 在InputSource中指定的编码 否则(如果未指定编码) 自动检测字符编码 使用类似于中的算法 XML规范。如果两者都不是 不支持字符流或字节流 如果可用,解析器将尝试 打开到资源的URI连接 由系统标识符标识

因此,基本上,您需要将字符流传递给解析器,以便它选择正确的编码。请参阅下面的解决方案:

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
FeedHandler handler = new FeedHandler();
Reader isr = new InputStreamReader(getInputStream());
InputSource is = new InputSource();
is.setCharacterStream(isr);
parser.parse(is, handler);
当希望Sax自动检测编码时,使用InputStream作为参数

如果要设置特定的编码,请使用具有指定编码或方法的读卡器

为什么??因为需要原始数据,而不是转换为字符


本主题中的问题是:如何让SAX解析器根据xml声明确定编码?我发现Allan对这个问题的回答有误导性,根据Jörn Horstmann的评论和我后来的经验,我提供了另一个答案。

在不指定字符集的情况下构建InputStreamReader将使用您机器的默认字符集,可能是iso-8859-1。正如您所引用的,当使用characterstream时,xml中的编码decl将被忽略,因此此代码仅适用于iso-8859-1文档。您的原始代码实际上应该已经工作了,也许您可以将异常或您看到的问题添加到您的问题中。当使用字节流而不在InputSource上设置编码时,xml解析器应该自动检测编码,如中所述。基本上,如果我不使用“is.setCharacterStream()”,我会得到一个无效的令牌异常。这可能对您有效,但Jörn是正确的。您引用的文档是相关且正确的。它告诉您InputStream的原始代码是正确的。错误就在文档本身中。如果您使用一种变通方法,如重写编码或以XML规范以外的其他方式自动检测编码,就像您使用InputStreamReader一样,您应该记录这一事实。是的:关键点是,只有当
InputSource
是从
InputStream
实例构造的时,SAX才会从
PI检测编码;如果从
读卡器
构建,它将不起作用(因为
读卡器
的要点是其输出是“后解码”)。也就是说:
newinputsource(getInputStream())
是正确的。另外,是否有库使用上述算法只解析XML声明?我这样问是因为我不能直接使用Sax,但我想从XML中提取编码信息。这应该是公认的解决方案。InputStream没有编码信息,因此SAX通过尝试从XML文件读取编码属性来确定编码本身。这在使用XSLTTTransformer时也有效。是否有可能获得xml序言的属性“encoding”的确切内容?Xerces定位器不工作。
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
FeedHandler handler = new FeedHandler();
Reader isr = new InputStreamReader(getInputStream());
InputSource is = new InputSource();
is.setCharacterStream(isr);
parser.parse(is, handler);