package ca.umontreal.iro.rali; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.PrintStream; import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.Collections; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import javax.xml.parsers.ParserConfigurationException; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * Show the XPath expressions corresponding to paths going from the root to leaves in an XML documents * using a Pull parser * * @author Guy Lapalme, Université de Montréal, 2009 * */ public class Explore { // for computing xpath statistics /** * To keep the count of each XPath expression */ private static SortedMap pathCounts; private static XMLStreamReader xmlsr=null; // Pull parser private static PrintStream out=null; // Print stream corresponding to the output protected static long setInputOutput(){ long fileLength=-1; try{ // create input InputStream input; if(Options.inputFileName==null){ input=System.in; } else { File file=new File(Options.inputFileName); fileLength=file.length(); input=new FileInputStream(file); } XMLInputFactory inputFactory=XMLInputFactory.newInstance(); inputFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, true); inputFactory.setProperty(XMLInputFactory.IS_COALESCING,true); xmlsr=inputFactory.createXMLStreamReader(input); if(!xmlsr.hasNext()){ System.err.println("Empty input file:"+(Options.inputFileName==null?"Standard input" :Options.inputFileName)); System.exit(1); } while(xmlsr.hasNext()&&!xmlsr.isStartElement()){ // skip to root element Explore.ignore(xmlsr); xmlsr.next(); } // get namespaces at root node int nsCount=xmlsr.getNamespaceCount(); for(int i=0;i(); SpineDocument spineDoc = new SpineDocument(); Document doc = spineDoc.getDoc(); while(xmlsr.hasNext()){ switch (xmlsr.getEventType()){ case XMLStreamConstants.CHARACTERS: case XMLStreamConstants.COMMENT: case XMLStreamConstants.START_ELEMENT: case XMLStreamConstants.PROCESSING_INSTRUCTION: if(xmlsr.isWhiteSpace()) ignore(xmlsr); else { // add a new node at the bottom of the spine document boolean isElem=xmlsr.isStartElement(); Node elem=Explore.readNode(xmlsr,doc); spineDoc.addBottom(elem); if(Options.debug && isElem) Debug.dumpElem("start element",elem); String xPathString=spineDoc.buildXPath(doc.getDocumentElement()); if(Options.debug) System.out.println("xPathString="+xPathString); if(Options.sortAlpha || Options.sortFreq){// insert into the frequency table if(xPathString!=null){ PathCount c = pathCounts.get(xPathString); if(c==null) pathCounts.put(xPathString, c=new PathCount(xPathString)); else c.bump(); } } else out.println(xPathString); // output the xpath if(!isElem) spineDoc.removeBottom(); // a "non-element" is immediately removed } break; case XMLStreamConstants.END_ELEMENT: if(Options.debug) Debug.dumpElem("end element",spineDoc.getBottom()); spineDoc.removeBottom(); // remove last element from the spine document break; default: ignore(xmlsr); } xmlsr.next(); } // end of reading the file // output namespace prefixes if(Options.showNamespaces){ out.println(Options.nsContext); } // output statistics if(Options.sortFreq || Options.sortAlpha){ String fmt="%10d:%s\n"; if(Options.sortFreq){ ArrayList freqs = new ArrayList(pathCounts.values()); Collections.sort(freqs, PathCount.decVal); for(PathCount c:freqs) out.format(fmt,c.getVal(),c.getPath()); } else if (Options.sortAlpha) { for(Map.Entry e :pathCounts.entrySet()) out.format(fmt,e.getValue().getVal(),e.getValue().getPath()); } } } catch(Throwable e){ System.err.format("Line %d : %.1f M used\n",xmlsr.getLocation().getLineNumber(), ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()/1000000.0); e.printStackTrace(); } return fileLength; } /** * Read a Node (created with the doc) from pull parser reader * We read only the start of an element or a single text/comment/processing-intruction node * * @param reader pull parser * @param doc document used to create new nodes * @return the Document node that was read from the input * @throws XMLStreamException */ protected static Node readNode(XMLStreamReader reader,Document doc) throws XMLStreamException{ Node n=null; switch (reader.getEventType()){ case XMLStreamConstants.START_ELEMENT: // adapted from startElement() in StaxUtils.java String nodeName=reader.getLocalName(); n=doc.createElementNS(reader.getNamespaceURI(),nodeName); if(reader.getPrefix()!=null)n.setPrefix(reader.getPrefix()); int nbAttrs=reader.getAttributeCount(); for(int i=0;i 0) name = prefix + ":" + name; Attr attr = doc.createAttributeNS(reader.getAttributeNamespace(i), name); attr.setValue(reader.getAttributeValue(i)); ((Element)n).setAttributeNode(attr); } break; case XMLStreamConstants.CHARACTERS: n=doc.createTextNode(reader.getText()); break; case XMLStreamConstants.PROCESSING_INSTRUCTION: n=doc.createProcessingInstruction(reader.getPITarget(), reader.getPIData()); break; case XMLStreamConstants.COMMENT: n=doc.createComment(reader.getText()); break; default: System.err.println("pullNode should not be called with a "+XMLStreamConstantsNames[reader.getEventType()]); System.exit(1); } return n; } // array indices taken from // ...JavaDocumentation/api/constant-values.html#javax.xml.stream.XMLStreamConstants protected static String[] XMLStreamConstantsNames = { "","START_ELEMENT", "END_ELEMENT", "PROCESSING_INSTRUCTION", "CHARACTERS", "COMMENT", "SPACE", "START_DOCUMENT", "END_DOCUMENT", "ENTITY_REFERENCE", "ATTRIBUTE", "DTD", "CDATA", "NAMESPACE", "NOTATION_DECLARATION", "ENTITY_DECLARATION" }; /** * ignore the token (if debugging is enabled, it prints the token skipped) * * @param xmlsr * @throws XMLStreamException */ protected static void ignore(XMLStreamReader xmlsr) throws XMLStreamException{ if(Options.debug){ if(xmlsr.isWhiteSpace()) System.out.println("ignore WHITESPACE"); else System.out.println("ignore:"+XMLStreamConstantsNames[xmlsr.getEventType()]); } } }