You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@xalan.apache.org by Alex Roytman <ro...@smart.net> on 2001/03/06 22:37:55 UTC

Xalan2: Insufficiensy of SAXSource to create Templates with newTemplates(Source). Demo project attached

Hello everyone,

This is the problem as I see it:

The problem I am trying to show here is in insufficiency of data for
newTemplates(Source styleSrc) to successfully create a Templates object
when
1. styleSrc is SAXSource
2. styleSrc.getSystemId() SHOULD NOT BE USED  as system Id for stylesheet to
resolve external references
something like newTemplates(Source styleSrc, String styleSystemId)  might
work


Please read comments in sample source code or even better compile and run
attached project

Following sample suppose to transforms hello.xsl and alex.xml into another
stylesheet
I want to return it as SAXSource which is better than directly returning
Templates instance

hello.xsl |
           > transform > [dynamically generated stylesheet]
alex.xml  |
> output

XML File


below is sample source. Whole project is attached too

Alex


package xalantest;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.XMLReader;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;
import org.xml.sax.XMLFilter;

import javax.xml.transform.*;
import javax.xml.transform.sax.*;
import javax.xml.transform.stream.*;

/*
This sample suppose to generate a stylesheet by another stylesheet to an xml
file
It does not work hovewer
There are of course other ways to achieve the same functionality but I
wanted to return
a Source rather than Templates object so it can be used with all TraX API
*/

public class Xalan2test {
  private final static SAXTransformerFactory transformerFactory =
    (SAXTransformerFactory)SAXTransformerFactory.newInstance();
  private final static SAXParserFactory parserFactory =
SAXParserFactory.newInstance();

  static {
    parserFactory.setNamespaceAware(true);
  }

  public static Templates getTemplates(String styleId, String xmlId) throws
Exception {
    Templates style = transformerFactory.newTemplates(new
StreamSource(styleId));
    if (xmlId != null) {
      TemplatesHandler templatesHandler =
transformerFactory.newTemplatesHandler();
      //Setting systemId is crucial for resolving external references
      //When we call transformerFactory.newTemplates(Source saxSrc) and pass
SAXSource saxSrc I believe
      //new I believe it uses saxSrc.getSystemId() or such to set systemID
for its internal TemplatesHandler
      //BUT SAXSource's systemId is not neceserilly systemId we want for
TemplatesHandler (see getTemplatesSource)
      //See how I work around it in getTemplates(SAXSource src, String
systemId)
      templatesHandler.setSystemId(styleId);
      style.newTransformer().transform(new StreamSource(xmlId), new
SAXResult(templatesHandler));
      return templatesHandler.getTemplates();
    } else {
      return style;
    }
  }


  public static Source getTemplatesSource(String styleId, String xmlId)
throws Exception {
    XMLReader reader = parserFactory.newSAXParser().getXMLReader();
    reader.setFeature("http://apache.org/xml/features/validation/dynamic",
true);
    Templates style = transformerFactory.newTemplates(new
StreamSource(styleId));
    XMLFilter styleReader = transformerFactory.newXMLFilter(style);
    //in this simple case we could skip setting parent because it is just a
parser
    //but in other cases parent is some special filter or chain of filters
    styleReader.setParent(reader);
    InputSource xmlInputSource = new InputSource(xmlId);
    Source styleSource = new SAXSource(styleReader, xmlInputSource);
    //There is a logical problem in SAXSource I believe
    //I would expect that calling styleSource.setSystemId(styleId) on
SAXSource will set systemId
    //(we need systemId so TemplatesHandler would have proper context to
resolve all external references)
    //for the stylesheet instead it calls setSystemId(styleId) on
xmlInputSource and overrides its systemId
    //When we use chain of XMLFilters xmlInputSource gets passed through the
chain of XMLFilters and
    //gets processed by the very first one and systemId we supplied for
xmlInputSource is used by that filter
    //The TemplatesHandler (which is the last in the chain( have to deal
with source which has no systemId
    //and will not be able to resolve external references
    return styleSource;
  }

  public static Templates getTemplates(SAXSource src, String systemId)
throws Exception {
    TemplatesHandler templatesHandler =
transformerFactory.newTemplatesHandler();
    //Setting systemId is crucial for resolving external references
    //systemId here is not the same as src.getSystemId() which is really
    //src.inputSource.getSystemId()
    templatesHandler.setSystemId(systemId);
    src.getXMLReader().setContentHandler(templatesHandler);
    src.getXMLReader().parse(src.getInputSource());
    return templatesHandler.getTemplates();
  }


  //there is a strange problem here
  //it outputs DTD as a part of stylesheet
  public static void print(Source src) throws Exception {
    Transformer trans = transformerFactory.newTransformer();
    trans.setOutputProperty("indent", "yes");
    trans.transform(src, new StreamResult(System.out));
    System.out.println("\n\n\n");
  }

  public static void main(String[] args) {
    //please set it to point to your directory
    String base = "file:/work/jbproject/xalantest/";
    String styleId = base + "style/hello.xsl";
    String xmlMetaId = base + "meta/alex.xml";
    String xmlDataId = base + "data/data.xml";
    try {
      Templates style;

      //Get stylesheet source. This source suppose to return result of
transformation
      //XML for xmlMetaId with stylesheet for styleId
      Source src = Xalan2test.getTemplatesSource(styleId, xmlMetaId);

      //print its content. Note it outputs DTD also. Should transformer
filter pass DTD events on?
      Xalan2test.print(src);

      //it does not work
      //blows with message: SystemId Unknown; Line 0; Column 0; SystemId
Unknown; Line 0; Column 0; SystemId Unknown;
      /* UNCOMMENT TO TEST
        style = transformerFactory.newTemplates(src);
      */

      style = Xalan2test.getTemplates((SAXSource)src, styleId);

      //this is how I would do it if I did not want to return Templates
object directly
      //and do not need to return SAXSource
      /*
        style = Xalan2test.getTemplates(styleId, xmlMetaId);
      */

      style.newTransformer().transform(new StreamSource(xmlDataId), new
StreamResult(System.out));
    } catch (Exception ex) {
      ex.printStackTrace();
    }

  }
}