javajdom-2unknown-host

Avoid SAXBuilder to validate document type DTD


I am trying to build a org.jdom2.Document from a String which I get returned from a org.jfree.graphics2d.svg.SVGGraphics2D. This works neatly as long as my computer is online, but when offline it fails and an UnknownHostException is thrown.

try{
  svgString = svgGraphics.getSVGDocument();
  SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
  svgXMLDocument = builder.build(new ByteArrayInputStream(svgString.getBytes()));
} catch (IOException | JDOMException e) { ... }

Even though creating the SAXBuilderwith the parameter XMLReaders.NONVALIDATING, the builder checks the Doctype and raises an exception when he cannot reach www.w3.org.

Is there a way to really avoid the doctype to be checked? Another Builder to be used?

So far my workaround is to catch the exception, remove the Doctype declaration using String-operations and then repeat the build process.


Solution

  • Processing XML has evolved, and nowadays the "correct" way is to not allow the XML processor to download any external resources, e.g. schema files and DTDs. So you either have to "cache" the external DTD locally or bypass the loading of the DTD. For any of these alternatives, you need to create a special EntityResolver; even if validation is turned off, the parser will try to load the DTD, but it will fail since loading an external resource is forbidden.

    Here is one method to achieve processing the XML while also bypassing the DTD loading:

    private static class MyFactory implements XMLReaderJDOMFactory , EntityResolver{
        @Override
        public XMLReader createXMLReader() throws JDOMException {
            try {
                SAXParserFactory f = SAXParserFactory.newDefaultNSInstance();
                f.setValidating(false);
                f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
                XMLReader r = f.newSAXParser().getXMLReader();
                r.setEntityResolver(this);
                return r;
            } catch (Exception e) {
                throw new JDOMException("error", e);
            }
        }
    
        @Override
        public boolean isValidating() {
            return false;
        }
        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
            return new InputSource(new ByteArrayInputStream("".getBytes()));
        }
    }
    
    public static void main(String[] args) throws Exception {
    
        SAXBuilder builder = new SAXBuilder(new MyFactory());
    
        Document doc = builder.build(...));
    
    }