package ca.umontreal.iro.rali; import java.io.PrintStream; import java.util.SortedMap; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.ext.DefaultHandler2; /** * handle SAX parsing events to print the XPath expressions corresponding to paths going * from the root to leaves in an XML documents * * @author Guy Lapalme, Université de Montréal, 2009 * */ public class ExploreSAXHandler extends DefaultHandler2{ PrintStream out; SortedMap pathCounts; SpineDocument spineDoc; Document doc; StringBuilder chars; /** * Initialize local variables * * @param out outputStream * @param pathCounts map to keep track of the count of XPath expressions * @throws ParserConfigurationException */ ExploreSAXHandler(PrintStream out, SortedMap pathCounts) throws ParserConfigurationException { this.out=out; this.pathCounts=pathCounts; spineDoc= new SpineDocument(); doc = spineDoc.getDoc(); chars=new StringBuilder(); } /** * Create a text node from the content of the chars array, add it to the spine document * and print the resulting XPath * This is called whenever a non-text node is encountered in the input * * @throws SAXException */ private void flushText(){ if(chars.length()>0){ String s = chars.toString(); chars.setLength(0); addAndShow(doc.createTextNode(s)); spineDoc.removeBottom(); } } /** * Add a new node the the spine document and print the resulting XPath * * @param n */ private void addAndShow(Node n){ spineDoc.addBottom(n); 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 } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) */ public void startElement(String uri, String localName,String raw, Attributes attrs) throws SAXException { flushText(); Element e = doc.createElementNS(uri,localName); if(Options.debug) Debug.dumpElem("start element",e); for(int i=attrs.getLength()-1;i>=0;i--){ String qname=attrs.getQName(i); int dp=qname.indexOf(':'); if(dp>=0) e.setAttributeNS(qname.substring(0,dp),qname.substring(dp+1),attrs.getValue(i)); else e.setAttributeNS(null,qname, attrs.getValue(i)); } addAndShow(e); } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String) */ public void endElement(String uri, String localName, String raw) throws SAXException { if(Options.debug) System.out.println("end element:"+localName+";"); flushText(); spineDoc.removeBottom(); } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int) */ public void characters(char[] ch, int start, int length) throws SAXException { String s = new String(ch,start,length).trim(); if(Options.debug) System.out.println("characters:"+s+";"); if(s.length()>0){ chars.append(s); } } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#processingInstruction(java.lang.String, java.lang.String) */ public void processingInstruction(String target, String data) throws SAXException { flushText(); addAndShow(doc.createProcessingInstruction(target, data)); spineDoc.removeBottom(); } /* (non-Javadoc) * @see org.xml.sax.ext.DefaultHandler2#comment(char[], int, int) */ public void comment(char[] ch, int start, int length) throws SAXException { flushText(); addAndShow(doc.createComment(new String(ch,start,length))); spineDoc.removeBottom(); } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#startPrefixMapping(java.lang.String, java.lang.String) */ public void startPrefixMapping(String prefix,String uri) throws SAXException { if(Options.debug)System.out.println("startPrefixMapping:"+prefix+"="+uri); Options.nsContext.addPrefixURI(prefix, uri); } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#endPrefixMapping(java.lang.String) */ public void endPrefixMapping(String prefix) throws SAXException{ if(Options.debug)System.out.println("endPrefixMapping:"+prefix); // Options.nsContext.removePrefix(prefix); } // error handling... private void message(String mess,SAXParseException e) throws SAXException{ System.out.println("\n"+mess+ "\n Line:"+e.getLineNumber()+ "\n URI:" +e.getSystemId()+ "\n Message:"+e.getMessage()); } public void fatalError(SAXParseException e) throws SAXException{ message("Fatal error",e); } public void error(SAXParseException e) throws SAXException{ message("Error",e); } public void warning(SAXParseException e) throws SAXException{ message("Warning",e); } }