Представьте, что у вас есть документ XML, и представьте, что у вас есть DTD, но сам документ на самом деле не определяет DOCTYPE
... Как бы вы вставили объявление DOCTYPE
, предпочтительно указав его в синтаксическом анализаторе (аналогично тому, как вы можете установить схему для документа, который будет проанализирован) или путем вставки необходимых событий SAX через XMLFilter
или тому подобное?
Я нашел много ссылок на EntityResolver
, но это то, что вызывается, когда DOCTYPE
найден во время синтаксического анализа и используется для указания на локальный файл DTD. EntityResolver2
похоже, есть то, что я ищу, но я не нашел примеров использования.
Это самое близкое, что я подобрал до сих пор: (код Groovy, но достаточно близко, чтобы вы могли его понять...)
import org.xml.sax.*
import org.xml.sax.ext.*
import org.xml.sax.helpers.*
class XmlFilter extends XMLFilterImpl {
public XmlFilter( XMLReader reader ) { super(reader) }
@Override public void startDocument() {
super.startDocument()
super.resolveEntity( null,
'file:///./entity.dtd')
println "filter startDocument"
}
}
class MyHandler extends DefaultHandler2 {
public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) {
println "entity: $name, $publicId, $baseURI, $systemId"
return new InputSource(new StringReader('<!ENTITY asdf "¡">'))
}
}
def handler = new MyHandler()
def parser = XMLReaderFactory.createXMLReader()
parser.setFeature 'http://xml.org/sax/features/use-entity-resolver2', true
def filter = new XmlFilter( parser )
filter.setContentHandler( handler )
filter.setEntityResolver( handler )
filter.parse( new InputSource(new StringReader('''<?xml version="1.0" ?>
<test>one &asdf; two! ¡£¢</test>''')) );
Я вижу, что resolveEntity
вызвали, но все равно попали
org.xml.sax.SAXParseException: объект "asdf" упоминался, но не был объявлен.
на com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1231)
в org.xml.sax.helpers.XMLFilterImpl.parse(XMLFilterImpl.java:333)
Я предполагаю, что это связано с тем, что нет способа добавить события SAX, о которых знает парсер, я могу добавлять события только через фильтр, восходящий от парсера, которые передаются в ContentHandler. Таким образом, документ должен быть действительным для XMLReader. Как-нибудь обойти это? Я знаю, что могу изменить необработанный поток, чтобы добавить тип документа, или, возможно, выполнить преобразование, чтобы установить DTD... Есть другие варианты?