3.9 Handle SAX

3.9.1 outline

Apply the specified content-handler and filters on the XML content.

<sax name="..." xml="..." content-handler="..."  
                          lexical-handler="..." >  
   <script element="..." > ... </script>  
   ...  
   <script element="..." > ... </script>  
</sax>

If provided, the name attribute is associated to the outcome. If omitted, the output file name from the command line is assumed. If such file name is not provided, the standard I/O stream is assumed.

If the xml attribute is not internally defined (within the hash table), a file name is assumed. If not provided, it stands for the input file name provided in the command line.

The content-handler attribute gets a comma seperated list of classes names. The first argument refers to a content handler, the other arguments refer to filters. A content handler gets five arguments: output stream, an HashMap refering to the different scripts enclosed by the sax instruction, a method, log stream, and a boolean trace indicator. A filter and a lexical-constractor gets three arguments: output stream, log stream, and a boolean trace indicator.

The sax instruction applies the filters and the content handler on the provided xml string. The script elements offer definitions of scripts delivered to the content handler. The ScriptsManager content handler of the distribution (Section 11), for instance, invokes these scripts when their corresponding named elemets are encountered.

<..xtpipes entries..>+
 | sax
 -_-_-

<..xtpipes.dtd..>+
 <!ELEMENT sax (#PCDATA | script)*  >
 <!ELEMENT script (#PCDATA <.xtpipes entries.> )*  >
 <!ATTLIST sax
           name            CDATA #IMPLIED
           xml             CDATA #IMPLIED
           content-handler CDATA #REQUIRED
           lexical-handler CDATA #IMPLIED
 >
 <!ATTLIST script
           element CDATA #REQUIRED
 >
 -_-_-

<..execute sax..>
 String errMsg = "";
 try{
    <.load xml into input source.>
    <.String [] className = ....>
    <.ch := content handler.>
    <.get sax reader.>
    XMLReader reader = saxReader;
    <.insert sax filters.>
    errMsg = "setContentHandler( "
             + className[0].trim() + " )";
    saxReader.setContentHandler( (org.xml.sax.ContentHandler) ch );
    <.saxReader += lexical handler.>
    <.saxReader := ignore DOCTYPE statement.>
    if( inputSource==null ){
        <.open sax input file.>
    } else {
        errMsg = "xtpipes sax parsing error";
        saxReader.parse( inputSource );
    }
    <.store chars into map.>
    saxReaderStack.push( reader );
 } catch ( java.io.FileNotFoundException e ){
    instructionErr( node, errMsg
                    + "could not find file: " + e.getMessage(), 19 );
 } catch ( ClassNotFoundException e ){
    instructionErr( node, errMsg
                    + " class not found: "
                    + e.getMessage() + "\n classpath = "
                    + System.getProperty("java.class.path")
                    + " ---", 22 );
 } catch ( java.lang.reflect.InvocationTargetException e ){
    instructionErr( node, errMsg + ": " + e.getCause(), 23 );
 } catch ( Exception e ){
    Xtpipes.logWriter.flush();
    e.printStackTrace();
    instructionErr( node, errMsg + ": " + e.toString(), 29 );
 }
 -_-_-

<..open sax input file..>
 errMsg = "While parsing file " + xml + ": ";
 InputStream inputStream = null;
 if( Xtpipes.ml2xml == null ){
    if( Xtpipes.trace ){
        Xtpipes.logWriter.println(
          "No request for ml2xml configuration (command line option -x)" );
    }
    <.inputStream := ml2xml-less imput.>
 } else {
    <.inputStream := (InputStream) new Ml2xml(filename, "foo.m2x").>
 }
 saxReader.parse( new InputSource(inputStream) );
 <.Ml2xml close files.>
 -_-_-

<..inputStream := ml2xml-less imput..>
 try{
     inputStream = (InputStream) (new File(xml).toURI().toURL().openStream());
 } catch ( java.io.FileNotFoundException ioe ){
     try{
        URL url = null;
        try {
            url = new URL(xml);
        } catch ( java.net.MalformedURLException fnf ){
            url = new File(xml).toURI().toURL();
        }
        inputStream = (InputStream) (url.openStream());
     } catch ( java.io.FileNotFoundException fnf ){
         inputStream = (InputStream)
            (
               new File( new File(xml).toURI().toURL().toString() )
               . toURI().toURL()
               . openStream()
            );
 }   }
 -_-_-

3.9.2 SAX Reader

The sax reader is pushed into the stack when its job is done, for use in other sax instructions. The stack is needed because nested sax instructions need unspecified number of readers. The filters may change the sax readers, so the readers need saving for later storing them in the stacks.

<..get sax reader..>
 XMLReader saxReader;
 if( saxReaderStack.empty() ){
    SAXParser saxParser = saxFactory.newSAXParser();
    saxReader = saxParser.getXMLReader();
    <.saxReader := ignore DOCTYPE statement.>
 } else {
    saxReader = (XMLReader) saxReaderStack.pop();
 }
 -_-_-

<..xtpipes initialization..>+
 saxFactory = SAXParserFactory.newInstance();
 saxFactory.setValidating(false);
 -_-_-

<..xtpipes fields..>+
 private static Stack <XMLReader> saxReaderStack;
 -_-_-

<..init fields..>+
 saxReaderStack = new Stack <XMLReader> ();
 -_-_-