This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

document() as extension mechanism


Hello,
i recently got some ideas for innovative uses of document() in
conjunction with custom-written URIResolver's and XSL input sources.
(Java only examples, sorry).
Relevant questions are at the end of this post.

1. Read the current date/time.
Refine the following hack to carefully designed and crafted code and
insert it into your URIResolver's resolve method.
    if( href.startsWith("time:") ) {
      SAXSource source = new SAXSource();
      source.setInputSource(new InputSource(
       new StringReader("<time>"+new Date().toString()+"</time>")));
      return source;
    }
Read the current date/time with
    <xsl:value-of select="document('time:foo')/time"/>
The URL could be used to specify a locale, or a host to read from,
or whatever you like (ideas welcome!).

2. Get a directory listing.
You can read the listing into a string and feed it into the processor
via a StringReader as in the example above, but it might be more
interesting to demonstrate how to do this using a customized input
source and XML reader.
Drop this into your URIResolver:
    if( href.startsWith("filelist:") ) {
      return new SAXSource(new FileListXMLReader(),
        new FileListInputSource(
           new File(href.substring("filelist:".length()))));
    }
You'll need an apropriate InputSource (terseness favoured over
robustness):
  import java.io.*;
  import java.util.*;
  import org.xml.sax.*;

  public class FileListInputSource extends InputSource {
    private File dir;
    public FileListInputSource(File d) { dir=d; }
    public String[] list() { return dir.list();  } 
  }
The Reader class is somewhat more elaborated. Getting strings through
the SAX API sucks mightily (is there a better way than shown below?).
The only really interesting routine is parse(InputSource) buried
somewhere in the middle of the following code:
  import java.io.*;
  import java.util.*;
  import org.xml.sax.*;

  public class FileListXMLReader implements XMLReader {
    private int len=128;  private char buf[]=new char[len];
    private synchronized void writeContent
     (ContentHandler contentHandler,String s) throws SAXException {
    if( s.length()>len ) { do {len=2*len;} while( s.length()>len );
      buf=new char[len];  }
    s.getChars(0,s.length(),buf,0);
    contentHandler.characters(buf,0,s.length());
  }
  
  // XML Reader
  private ContentHandler contentHandler;
  private DTDHandler dtdHandler;
  private EntityResolver entityResolver;
  private ErrorHandler errorHandler;
  public ContentHandler getContentHandler() { return contentHandler; }
  public DTDHandler getDTDHandler() { return dtdHandler; }
  public EntityResolver getEntityResolver() { return entityResolver; }
  public ErrorHandler getErrorHandler() { return errorHandler; }
  public boolean getFeature(java.lang.String name)
    throws SAXNotRecognizedException, SAXNotSupportedException
    {
      if( name.equals("http://xml.org/sax/features/namespaces";)
      || name.equals("http://xml.org/sax/features/namespace-prefixes";) ) {
        return true;
      } else {
        throw new SAXNotRecognizedException("not implemented: "+name);
      }
    }
  public java.lang.Object getProperty(java.lang.String name) 
    throws SAXNotRecognizedException, SAXNotSupportedException
     { throw new SAXNotRecognizedException("not implemented: "+name); }
  public void parse(InputSource input)
    throws java.io.IOException, SAXException {
    if( contentHandler==null ) {
      throw new SAXException("No content handler");
    }
    try {
      FileListInputSource source=(FileListInputSource)input;
      Attributes attrs=new org.xml.sax.helpers.AttributesImpl();
      contentHandler.startDocument();
      contentHandler.startElement("","files","files",attrs);
      String list[]=source.list();
      if( list!=null ) {
        for( int i=0;i<list.length;i++ ) {
          contentHandler.startElement("","file","file",attrs);
          writeContent(contentHandler,list[i]);
          contentHandler.endElement("","file","file");
        }
      }
      contentHandler.endElement("","files","files");
      contentHandler.endDocument();
    }
    catch( ClassCastException e ) {
      throw new SAXException("Need filelist input source");
    }
  }
  public void parse(java.lang.String systemId)
    throws java.io.IOException, SAXException {
    // leave this to your imagination, should use new File(systemId).list()
    return;
  }
  public void setContentHandler(ContentHandler handler) { contentHandler=handler; }
  public void setDTDHandler(DTDHandler handler) { dtdHandler=handler; }
  public void setEntityResolver(EntityResolver resolver) { entityResolver=resolver; }
  public void setErrorHandler(ErrorHandler handler) { errorHandler=handler; }
  public void setFeature(java.lang.String name, boolean value) 
    throws SAXNotRecognizedException, SAXNotSupportedException
    {
      if( name.equals("http://xml.org/sax/features/namespaces";)
          || name.equals("http://xml.org/sax/features/namespace-prefixes";) ) {
      } else {
        throw new SAXNotRecognizedException("not implemented: "+name);
      }
    }
  public void setProperty(java.lang.String name, java.lang.Object value)
    throws SAXNotRecognizedException, SAXNotSupportedException
    { throw new SAXNotRecognizedException("not implemented"); }
}

The following snippet will insert a listing of the current directory
of the process into an html-page:
  <xsl:for-each select="document('filelist:.')/files/*">
   <p><xsl:value-of select="."/></p>
  </xsl:for-each>
You can easily extend the XMLReader to provide file lengths,
modification dates, diverse attributes and whatnot to the XSL
processor (use listFiles() instead of list()). If you use TrAX/JAXP
you can also use the FileListXMLReader for as your main document
input source (yes, this can be useful too: directory listing pages,
styled as you like...).

3. Another idea: read parameters of a servlet with document('parameters:').
Unfortunately, the code ist too long to be quoted here :-)

Saxon allows to specify the URI resolver on the command line, therefore
you don't need to deal with the source of of the processor just for
experimenting.
java -classpath ".;saxon.jar" com.icl.saxon.StyleSheet \
 -r MyURIResolver foo.xml foo.xsl
If you use TrAX/JAXP, invoke setURIResolver on your transformer.

Questions:
1. I think this should provide a rather portable way to allow access
to various system ressources at lease for Java-based processors.
What's your opinion?

2. Other ideas?

3. Anybody out there wanting to host a repository for resolvers/sources? :-)

4. Could this be of interest to the standards people?

Regards
J.Pietschmann
--

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]