Java DTD解析中如何绕过参数实体解析

Java DTD解析中如何绕过参数实体解析,java,xml,dtd,dtd-parsing,Java,Xml,Dtd,Dtd Parsing,我维护了一个Java程序来帮助Mozilla本地化。Mozilla本地化在运行时使用DTD文件等格式,所选语言环境的DTD被注入定义UI的XML文件中,从而生成本地化接口 DTD有时包括PE引用形式的其他文件,如下所示: <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD; 但是,出于我的程序目的,当我解析带有此类PE引用的DTD文件的en-US版本时,我只需要将这些行复制到目标本地化

我维护了一个Java程序来帮助Mozilla本地化。Mozilla本地化在运行时使用DTD文件等格式,所选语言环境的DTD被注入定义UI的XML文件中,从而生成本地化接口

DTD有时包括PE引用形式的其他文件,如下所示:

<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
但是,出于我的程序目的,当我解析带有此类PE引用的DTD文件的en-US版本时,我只需要将这些行复制到目标本地化文件中

我继承了这个程序,它使用绑定在JDK中的SAX 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来处理它,因为它发生在解析行号1、列号2的最开始处

可在以下位置找到有问题的DTD文件:

整个程序的源代码都在这里:

我的SCCE包含上述存储库中的四个文件的简化版本,如果需要,我可以将它们上传到某个地方

在所有这些细节之后,问题是:有没有办法让SAX避免尝试解析PE引用


TIA

我终于找到了解决方案。如果您查看存储库,您会注意到我忘记更新此问题,因为我几个月前提交了修复程序。:-解决方案在于以下代码:

// 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实体,那么这样做就会失败