Извините за некропостинг, но я нашел решение, которое действительно работает, и решил, что должен поделиться им.
1.
По какой-то причине setValidating (false) не работает. В некоторых случаях он по-прежнему загружает внешние файлы DTD. Чтобы предотвратить это, вы должны прикрепить пользовательский EntityResolver, как указано здесь :
XMLReader rdr = spf.newSAXParser().getXMLReader();
rdr.setEntityResolver(new MyCustomEntityResolver());
EntityResolver будет вызываться для каждого запроса внешнего объекта. Возвращение null не будет работать, потому что фреймворк все равно загрузит файл из Интернета после этого. Вместо этого вы можете вернуть пустой поток, который является допустимым DTD, как указано здесь :
private class MyCustomEntityResolver implements EntityResolver {
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new StringReader(""));
}
}
2.
Вы говорите setValidating (false) парсеру SAX, который читает ваш XSLT-код. То есть он не будет проверять ваш XSLT. Когда он сталкивается с функцией document (), он загружает связанный XML-файл, используя другой анализатор, который все еще проверяет его, а также загружает внешние объекты. Чтобы справиться с этим, вы должны прикрепить пользовательский URIResolver к преобразователю:
Transformer transformer = cachedXSLT.newTransformer();
transformer.setURIResolver(new MyCustomURIResolver());
Преобразователь вызовет вашу реализацию URIResolver, когда встретит функцию document (). Ваша реализация должна будет вернуть Source для переданного URI. Самое простое - вернуть StreamSource в соответствии с рекомендациями здесь . Но в вашем случае вы должны проанализировать документ самостоятельно, не допуская проверки и внешних запросов, используя уже настроенный SAXParser (или каждый раз создавать новый).
private class MyCustomURIResolver implements URIResolver {
public Source resolve(String href, String base) {
return new SAXSource(rdr,new InputSource(href));
}
}
Так что вам придется реализовать два пользовательских интерфейса в вашем коде.