-
Notifications
You must be signed in to change notification settings - Fork 20
Description
(This is with XmlResolver 6.0.2)
If I pass an org.apache.xerces.parsers.SAXParser an org.xml.sax.ext.EntityResolver2 interface it will call EntityResolver2.getExternalSubset(String, String) if the XML file has no DTD declaration for example.
If the EntityResolver2 interface is implemented by org.xmlresolver.adapters.SAXAdapter and there is no entry for the Document element root name in the catalog and org.xmlresolver.ResolverFeature.ALWAYS_RESOLVE is set to true (the default) SAXAdapter will return the document which is being parsed (if that document has an associated URI in the InputSource). Apart from not being what is intended, this causes an error to be thrown by the parser because the XML input file is not a DTD, and we get something like
net.sf.saxon.s9api.SaxonApiException: org.xml.sax.SAXParseException; systemId: file:///Users/johnf/dev26/core/xml-compare-main/target/test-classes/white-box/unstaged-data/xmlresolver/EntityResolver2_1.xml; lineNumber: 2; columnNumber: 2; The markup declarations contained or pointed to by the document type declaration must be well-formed.
Since org.xmlresolver.XMLResolver.getEntityResolver() is implemented by calling org.xmlresolver.XMLResolver.getEntityResolver2() and implements both org.xml.sax.ext.EntityResolver2 and org.xml.sax.EntityResolver interfaces, we can't avoid using an EntityResolver2 without wrapping inside a class that doesn't implement EntityResolver2. The other choice is to turn ALWAYS_RESOLVE off, which we can't do in other circumstances, and since ours is a third party JAR we can't edit the catalogs that are used.
(The old catalog resolver only implemented EntityResolver and therefore did not have this problem.)
`
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.transform.sax.SAXSource;
import org.apache.xerces.parsers.SAXParser;
import org.testng.annotations.Test;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.ext.EntityResolver2;
import org.xmlresolver.ResolverFeature;
import org.xmlresolver.XMLResolver;
import org.xmlresolver.XMLResolverConfiguration;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.XdmNode;
public void testEntityResolver2_withURI() throws Exception {
File testFile = new File(DataDir, "EntityResolver2_1.xml");
InputSource is= new InputSource(testFile.getAbsolutePath());
Processor p = new Processor(true);
DocumentBuilder docBuilder = p.newDocumentBuilder();
SAXParser parser= new SAXParser();
XMLResolverConfiguration resolverConfig = new XMLResolverConfiguration();
resolverConfig.setFeature(ResolverFeature.ALWAYS_RESOLVE, true);
XMLResolver resolver = new XMLResolver(resolverConfig);
parser.setEntityResolver(resolver.getEntityResolver());
XdmNode n= docBuilder.build(new SAXSource(parser, is));
}`
The file is simply
<StandardXmlRootElement/>
By wrapping I mean something like the following
`
private static final class MaskEntityResolver2Functionality implements EntityResolver {
private final EntityResolver2 wrappedResolver;
private MaskEntityResolver2Functionality(EntityResolver2 wrappedResolver) {
assert wrappedResolver!=null : "Must wrap something";
this.wrappedResolver= wrappedResolver;
}
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
return wrappedResolver.resolveEntity(publicId, systemId);
}
}
`