该方法花费 90% 的时间,有可能会更多一点。但是,SAX 解析器不需要支持 Locator 接口,更不用说 Locator2 以及其他的接口。如果知道正在使用的是 Xerces,第二种方法是使用 XNI。
Xerces Native Interface
使用 XNI 的方法与 SAX 是非常相似的(实际上,在 Xerces 中,SAX 解析器是本机 XNI 解析器之上很薄的一层)。总之,这种方法更容易一些,因为编码作为参数直接传递给 startDocument()。您只需要读取它,如清单 2 所示。
清单 2. 使用 XNI 确定文档的编码
import java.io.IOException; import org.apache.xerces.parsers.*; import org.apache.xerces.xni.*; import org.apache.xerces.xni.parser.*; public class XNIEncodingDetector extends XMLDocumentParser { public static void main(String[] args) throws XNIException, IOException { XNIEncodingDetector parser = new XNIEncodingDetector(); for (int i = 0; i < args.length; i++) { try { XMLInputSource document = new XMLInputSource("", args[i], ""); parser.parse(document); } catch (XNIException ex) { System.out.println(parser.encoding); } } } private String encoding = "unknown"; @Override public void startDocument(XMLLocator locator, String encoding, NamespaceContext context, Augmentations augs) throws XNIException { this.encoding = encoding; throw new XNIException("Early termination"); } }
请注意,因为一些未知的原因,该技术只使用 org.apache.xerces 中实际的 Xerces 类,而不使用与 Sun 的 JDK 6 绑定的 com.sun.org.apache.xerces.internal 中重新打包的 Xerces 类。
XNI 提供了另外一个 SAX 不具有的功能。在少数情况下,在 XML 声明中声明的编码不是实际的编码。SAX 只报告实际编码,但是,XNI 也可以告诉您在 xmlDecl() 方法中声明的编码,如清单 3 所示。
清单 3. 使用 XNI 确定文档的声明的编码和实际的编码
import java.io.IOException; import org.apache.xerces.parsers.*; import org.apache.xerces.xni.*; import org.apache.xerces.xni.parser.*; public class AdvancedXNIEncodingDetector extends XMLDocumentParser { public static void main(String[] args) throws XNIException, IOException { AdvancedXNIEncodingDetector parser = new AdvancedXNIEncodingDetector(); for (int i = 0; i < args.length; i++) { try { XMLInputSource document = new XMLInputSource("", args[i], ""); parser.parse(document); } catch (XNIException ex) { System.out.println("Actual: " + parser.actualEncoding); System.out.println("Declared: " + parser.declaredEncoding); } } } private String actualEncoding = "unknown"; private String declaredEncoding = "none"; @Override public void startDocument(XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs) throws XNIException { this.actualEncoding = encoding; this.declaredEncoding = "none"; // reset } @Override // this method is not called if there's no XML declaration public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) throws XNIException { this.declaredEncoding = encoding; } @Override public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { throw new XNIException("Early termination"); } }
通常情况下,如果声明的编码和实际的编码不同,就表明服务器存在一个 bug。最常见的原因是由于 HTTP Content-type 报头指定的编码与在 XML 声明中声明的编码不同。在本例中,要严格遵守规范,要求优先考虑 HTTP 报头的值。但实际上,很可能 XML 声明中的值是正确的。
结束语
通常情况下,您不需要了解输入文档的编码。只需要用解析器处理输入文档,以 UTF-8 编码输出结果即可。但是,有些情况下需要知道输入编码,SAX 和 XNI 可以提供快速而有效的方法来解决这一问题。 上一页 [1] [2]
|