Сначала прочитайте DTD в строковую переменную.
Тогда сделай
builder.setEntityResolver(
(sysId, PubId) -> new InputSource(new StringReader(dtd)));
Или, если вы хотите быть более осторожным, попросите EntityResolver проверить, что systemId и / или publicId соответствуют ожиданиям, прежде чем возвращать содержимое dtd
.
Обратите внимание, что это по-прежнему будет включать в себя разбор DTD каждый раз, это просто экономит стоимость извлечения его из сети.
Также важно: создание экземпляра синтаксического анализатора XML требует значительных затрат (а создание экземпляра DocumentBuilderFactory еще больше). Убедитесь, что вы используете как фабрику, так и парсер.