package ca.umontreal.iro.rali; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; /** * Extract nodes from an XML document corresponding to an XPath expression * using a SAX Parser * * @author Guy Lapalme, Université de Montréal, 2009 * */ public class ExtractSAX { private static InputStream input=null; private static XMLStreamWriter xmlsw=null; // Output stream writer private static OutputStream output=null; private static PrintStream out=null; // Print stream corresponding to the output private static Transformer trans=null; // Transformer of each output element private static Result transResult=null; // Output of the transformation, is linked to the output file /** * Set up and initialize the SAX parser and stream writer output file * * @return the number of bytes in the input file */ protected static long setInputOutput(){ long fileLength=-1; try{ // create input if(Options.inputFileName==null){ input=System.in; } else { File file=new File(Options.inputFileName); fileLength=file.length(); input=new FileInputStream(file); } // create output if(Options.outputFileName==null){ output=System.out; out=System.out; } else { output=new FileOutputStream(Options.outputFileName); out=new PrintStream(Options.outputFileName); } XMLOutputFactory outputFactory=XMLOutputFactory.newInstance(); xmlsw=outputFactory.createXMLStreamWriter(output); } catch (FileNotFoundException e){ e.printStackTrace(); } catch (XMLStreamException e){ e.printStackTrace(); } return fileLength; } /** * Create a new XML document for each node matching the XPath expression given by the -xp parameter * in order to save on memory each node is transformed one by one as the input file is read */ static protected long execute(){ long fileLength=setInputOutput(); try { Document outputDoc=null; // DOM structure built when a final XSL stylesheet is specified Element outputRoot=null; // root of the outputDoc Document Source xsltSource =null; // Source of the transformation : will be linked to the skeleton document TransformerFactory transFact; // Factory for the transformation of each output element Examine.count=0; // configure XML output XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); xmlsw=outputFactory.createXMLStreamWriter(output,"UTF-8"); // create the XSL transformer factory transFact = TransformerFactory.newInstance(); // local stylesheet if(Options.xsltFile==null){ trans = transFact.newTransformer(); // identity transformer } else { xsltSource = new StreamSource(Options.xsltFile); trans = transFact.newTransformer(xsltSource); } trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"yes"); trans.setOutputProperty(OutputKeys.INDENT,Options.prettyPrint?"yes":"no"); for(Map.Entry e:Options.xslParams.entrySet()) trans.setParameter(e.getKey(), e.getValue()); // global stylesheet if(Options.xsltFileFinal==null) transResult = new StreamResult(output); else { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); outputDoc = builder.newDocument(); outputRoot = outputDoc.createElementNS(null, Options.rootName); outputDoc.appendChild(outputRoot); transResult = new DOMResult(outputRoot); } // if(Options.xsltFileFinal==null){ if(Options.rootName!=null){ // create the root document xmlsw.writeStartDocument("UTF-8","1.0");xmlsw.writeCharacters("\n"); xmlsw.writeStartElement(Options.rootName); for(Map.Entrye:Options.nsContext.getAllPrefixesURI()) xmlsw.writeNamespace(e.getKey(), e.getValue()); xmlsw.writeCharacters("\n"); } xmlsw.setNamespaceContext(Options.nsContext); } // read the file and create a spine document //XMLParser creation SAXParserFactory factory; SAXParser saxParser; factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); saxParser = factory.newSAXParser(); DefaultHandler h = new ExtractSAXHandler(out,trans,transResult); // to receive comment events... saxParser.setProperty("http://xml.org/sax/properties/lexical-handler", h); try { saxParser.parse(input,h); // parse the file } catch (SAXException e){ // ignore only the exception on the maximum number of results if(!e.getMessage().equals("max number of results")) throw e; } if(Options.onlyCount) out.println(Examine.count); else if(Options.xsltFileFinal!=null){ /// final transformation // add namespaces prefixes to root for(Map.Entry e:Options.nsContext.getAllPrefixesURI()){ String key = e.getKey(); outputRoot.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns"+((key==null|| key.length()==0)?"":(":"+key)), e.getValue()); } xsltSource = new StreamSource(Options.xsltFileFinal); trans = transFact.newTransformer(xsltSource); trans.setOutputProperty(OutputKeys.INDENT,Options.prettyPrint?"yes":"no"); for(Map.Entry e:Options.xslParams.entrySet()) trans.setParameter(e.getKey(), e.getValue()); trans.transform(new DOMSource(outputDoc), new StreamResult(output)); } else if(Options.rootName!=null) xmlsw.writeEndElement(); xmlsw.writeCharacters("\n"); xmlsw.close(); if(Options.statistics){ System.err.println("XPath processor:"+XPath.getXPathProvider()); System.err.println("XSL Transformer:"+trans.getClass().getName()); } } catch (ParserConfigurationException e) { System.err.println("Bad parser configuration"); e.printStackTrace(); } catch (XMLStreamException e){ e.printStackTrace(); } catch (TransformerException e){ e.printStackTrace(); } catch (SAXParseException e) { System.err.println(Options.inputFileName+" is not well-formed"); System.err.println(e.getMessage()+ " at line "+e.getLineNumber()+ ", column "+e.getColumnNumber()); e.printStackTrace(); } catch (SAXException e){ System.err.println(e.getMessage()); e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } return fileLength; } }