我维护一个Java程序来帮助Mozilla本地化。除了其他格式之外,Mozilla本地化使用DTD文件(在运行时,所选语言环境的DTD被注入到定义UI的XML文件中,从而导致本地化接口)。
DTD有时包含PE引用形式的其他文件,如下所示:
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
但是,出于我的程序目的,当我使用这样的PE引用解析带有美国版本的DTD文件时,我只需要将这些行复制到目标本地化文件中。
我继承了这个程序,它使用SAX(在JDK中捆绑的Xerces)解析DTD的一些聪明(对我而言)技巧:
public class DTDReadHelper extends DefaultHandler2 {
private static final String dummyXml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<!DOCTYPE dialog SYSTEM \"MozillaTranslator\">" +
"<dialog></dialog>";
(...)
@Override
public InputSource resolveEntity(java.lang.String name, java.lang.String publicId,
java.lang.String baseURI, java.lang.String systemId) {
if ((name != null) && (name.startsWith("%"))) {
return new InputSource(new StringReader(""));
} else {
return new InputSource(is);
}
}
问题是在典型的解析过程中会出现两次else分支,因此如果文件小于8192字节则会导致Xerces发生IOException,否则会导致SAXParseException。
我可以处理IOException,因为整个文件在发生时已经被解析了,但是我无法用SAXParseException来做,因为它发生在解析的最开始(lineNumber 1,columnNumber 2)
可以在此处找到“违规”DTD文件:
并且该程序的完整源代码存在于此处:
https://kenai.com/projects/moztrans/sources
我的“SCCE”包含四个文件(上述存储库中的简化版本),如果需要,我可以将它们上传到某处。
在所有这些细节之后,问题是:有没有办法让SAX避免尝试解析PE引用?
TIA
答案 0 :(得分:0)
我终于找到了解决方案(如果你查看存储库,你会注意到我忘了更新这个问题,因为几个月前我提交了修复程序)。 :-)解决方案在于以下代码:
// private static final String brandDummyDtd = "<!ENTITY brandDTD \"\">";
private static final String brandDummyDtd = "";
(...)
@Override
public InputSource resolveEntity(java.lang.String name, java.lang.String publicId,
java.lang.String baseURI, java.lang.String systemId) {
if (name == null) {
switch (systemId) {
// Trick to get a SAX XML Parser to parse a DTD
case "MozillaTranslator":
return new InputSource(is);
// Trick to resolve references to brand.dtd without
// actually having to resolve, load and parse
// the chrome: URI
case "chrome://branding/locale/brand.dtd":
default:
return new InputSource(new ByteArrayInputStream(brandDummyDtd.getBytes()));
}
} else {
return new InputSource(new StringReader(""));
}
}
解决方案是返回一个空的InputSource(brandDummyDtd属性,在顶部定义为private static final)。我已经将注释版本包含在触发resolveEntity方法的实体中,以解释使用此类解决方案不起作用。如果我没记错的话,如果解析的DTD包含一个实际的brandDTD实体,那么这样做会失败。