如何在Java中读取格式良好的XML,但跳过模式?

2022-09-03 12:59:38

我想读取一个包含架构声明的 XML 文件。

这就是我想做的,读它。我不在乎它是否有效,但我希望它能很好地形成。

问题是读取器正在尝试读取架构文件,但失败了。

我甚至不想尝试。

我尝试过禁用验证,但它仍然坚持尝试读取架构文件。

理想情况下,我想用现有的Java 5 JDK来做到这一点。

以下是我到目前为止所拥有的非常简单的内容:

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setValidating(false);
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(file);

这是我回来的例外:

java.lang.RuntimeException: java.io.IOException: Server returned HTTP response code: 503 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd

是的,这恰好是一个XHTML模式,但这不是一个“XHTML”问题,而是一个XML问题。只是指出这一点,这样人们就不会分心。而且,在这种情况下,W3C基本上是在说“不要要求这个东西,这是一个愚蠢的想法”,我同意。但是,同样,这是问题的细节,而不是问题的根源。我根本不想要求它。


答案 1

该引用不是针对架构的,而是针对 DTD 的

DTD 文件可以包含的不仅仅是结构规则。它们还可以包含实体引用。XML 解析器必须加载和解析 DTD 引用,因为它们可能包含可能影响文档解析方式和文件内容的实体引用(您可以拥有字符甚至整个文本短语的实体引用)。

如果要避免加载和分析引用的 DTD,可以提供自己的实体解析器并测试引用的 DTD,并确定是加载 DTD 文件的本地副本还是仅返回 null。

自定义实体解析器上引用的答案中的代码示例:

   builder.setEntityResolver(new EntityResolver() {
        @Override
        public InputSource resolveEntity(String publicId, String systemId)
                throws SAXException, IOException {
            if (systemId.contains("foo.dtd")) {
                return new InputSource(new StringReader(""));
            } else {
                return null;
            }
        }
    });

答案 2

最简单的答案是这个单行,在创建DocumentBuilderFactory后调用:

dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

无耻地从使 DocumentBuilder.parse 忽略 DTD 引用


推荐