在 SAX 解析器中处理具有依赖性的私有外部 DTD

Handle private external DTD with dependencies in SAX parser

我正在尝试使用 DOCTYPE 中指定的专用外部 DTD 解析 XML 文件,如下所示:

<!DOCTYPE MY1 SYSTEM "my1.dtd">

为了在本地处理此 DTD 以进行验证,我为 XMLReader parser 指定了 EntityResolver:

        //use local DTD
        parser.setEntityResolver(new EntityResolver() {
            @Override
            public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
                if (systemId.contains(my1Dtd)) {
                    return new InputSource(MyClass.class.getResourceAsStream(MY1_DTD_RESOURCE_PATH));
                } else {
                    return null;
                }
            }
        });

这个 InputSource 返回正确,但是有一个与 DTD 相关的问题:在 DTD 内部有对另一个 DTD 的引用。所以我将所有 DTD 放在同一个包中。但是当我部署在 Tomcat FileNotFoundException D:\apache-tomcat-6.0.29\bin\my2.dtd (The system cannot find the file specified) 上的应用程序被抛出时。

我的问题是:我们怎样才能正确指定这个依赖关系?应该用resolveEntity方法构造还是我路径有误(my2.dtdmy1.dtd里面声明为<!ENTITY % MY2 SYSTEM "my2.dtd">,存放在同一个包里)

当解析器需要加载 my2.dtd 文件时,也应该调用 resolveEntity

因此您需要以类似的方式修改它:

 public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
            if (systemId.contains(my1Dtd)) {
                return new InputSource(MyClass.class.getResourceAsStream(MY1_DTD_RESOURCE_PATH));
            } else if (systemId.contains(my2Dtd)) {
                return new InputSource(MyClass.class.getResourceAsStream(MY2_DTD_RESOURCE_PATH));
            } else {
                return null;
            }
        }

但是,为避免此类工作,您应该考虑使用解析器,例如 the Apache resolver. This resolver relies on the OASIS entity resolution / XML catalogs,它允许您创建 XML 格式的目录,由解析器读取,这样您就不会每次你有一个新的 DTD 或将它移动到另一个地方或其他任何地方时都需要修改你的代码。 (这个解析器包与 Apache Xerces 发行版捆绑在一起,如果它已经是您正在使用的解析器的话)。