Menu

DTD reference in file opened with document()

Help
Matt B
2011-08-30
2012-10-08
  • Matt B

    Matt B - 2011-08-30

    I currently have a Java XSLT transformation process that includes an
    EntityResolver attached to an XMLReader for the source XML file. This resolver
    redirects a DTD reference in the source file to a local DTD. In my XSL
    stylesheet, I am referencing an SVG file via a document() function, and I need
    to redirect the SVG's DTD reference from an"http://" to a local "file://"
    location.

    The EntityResolver I have attached to the XMLReader for the source file
    doesn't execute for the stylesheet, and this is where I'm getting stuck. Is it
    possible to attach another instance of my EntityResolver to the transform, and
    if so how do I do that?

    Following is the applicable code I have set up for the transform:

        TransformerFactory tfactory = TransformerFactory.newInstance();
    
        // Test stylesheet processor to see if SAXSource can be used as input source
        if(tfactory.getFeature(SAXSource.FEATURE)){
            SAXTransformerFactory saxFactory = ((SAXTransformerFactory) tfactory);
            TransformerHandler saxHandler = saxFactory.newTransformerHandler(new StreamSource(new File(getStylesheetFO()).toURI().toString()));
            Transformer transformer = saxHandler.getTransformer();
            transformer.setURIResolver(new xslUriResolver());
    
            //set stylesheet parameters
            setXslParameters(transformer,stylesheetArgs,settings);
    
            //set output sink
            Result foResult = new StreamResult(new File(getFoFilename()).toURI().toString());
            saxHandler.setResult(foResult);
    
            //call method to set up XMLReader object
            XMLReader sourceReader = getXMLReader();
    
            //link XMLReader object with contenthandler, dtdhandler, and lexical handler
            sourceReader.setContentHandler(saxHandler);
            sourceReader.setDTDHandler(saxHandler);
            sourceReader.setProperty("[url]http://xml.org/sax/properties/lexical-handler[/url]", saxHandler);
    
            //start XSLT transformation
            sourceReader.parse(new File(getXmlFile()).toURL().toString());
        }
    
        public XMLReader getXMLReader() throws ParserConfigurationException, SAXException{
            SAXParserFactory factory = SAXParserFactory.newInstance();
            xslEntityResolver thisResolver = new xslEntityResolver();
    
            factory.setNamespaceAware(true);
    
            SAXParser parser = factory.newSAXParser();
            XMLReader reader = parser.getXMLReader();
            reader.setEntityResolver(thisResolver);
            return reader;
        }
    
     
  • Michael Kay

    Michael Kay - 2011-09-03

    Sorry for the delay in responding. One answer is to define a URIResolver
    associated with the transformation. This will be called when the document()
    function executes. Your URIResolver should return a SAXSource, whose XMLReader
    is a parser in which an EntityResolver has been set.

    Another option is to set the configuration property setSourceParser() to an
    XMLReader that is a subclass of (or wrapper around) the "real" XML parser; on
    initialisation this can set the EntityResolver property of the real parser as
    required.