在 java 中解析 xml 时如何缓存 dtd 文件

How to cache a dtd file when parsing xml in java

我正在解析几百万个 xml 格式如下的文件:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE test-document PUBLIC "-//TEST//TEST DOC//EN" "https://somerandomurl.com/test.dtd">
<test-document>...</test-document>

每次我解析文件时,都会下载相同的 https://somerandomurl.com/test.dtd 文件,这会消耗大量带宽,而且似乎没有必要。有没有办法存储文件并让我的代码重定向我的本地副本?我无法编辑 xml 文件,所以它必须在我的代码中。给定以下 java 代码,什么是实现这种事情的合理方法?

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
factory.setValidating(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource("file.xml"));//My final document object.

如果您只想缓存下载的 DTD 文件,可以使用 XML 目录。特别是,您将在目录文件的解析规则中指定,如下所示

<catalog
  Xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
  <system
    systemId="https://somerandomurl.com/test.dtd"
    uri="file://mydir/test.dtd"/>
</catalog>

具有系统标识符 https://somerandomurl.com/test.dtd 的实体被解析为文件 /mydir/test.dtd,该文件应包含由 https 链接到的 DTD 文件的下载本地副本:URL。

链接

首先将 DTD 读入字符串变量。

然后做

builder.setEntityResolver(
     (sysId, PubId) -> new InputSource(new StringReader(dtd)));

或者,如果您想更加小心,请让您的 EntityResolver 在返回 dtd.

的内容之前检查 systemId and/or publicId 是否符合预期

请注意,这仍将涉及每次解析 DTD,它只是节省了从网络中获取它的成本。

也很重要: 实例化 XML 解析器的成本很高(实例化 DocumentBuilderFactory 的成本更大)。确保重用工厂和解析器。