package org.basex.build.xml; import static org.basex.util.Token.*; import java.io.IOException; import org.basex.build.Builder; import org.basex.util.Atts; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.DefaultHandler; /** * SAX Parser wrapper. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ final class SAXHandler extends DefaultHandler implements LexicalHandler { /** Temporary attribute array. */ private final Atts atts = new Atts(); /** Builder reference. */ private final Builder builder; /** DTD flag. */ private boolean dtd; /** Element counter. */ int nodes; static { // needed for XMLEntityManager: increase entity limit System.setProperty("entityExpansionLimit", "536870912"); // needed for frequently visited sites: modify user agent System.setProperty("http.agent", "sax"); } /** * Constructor. * @param build builder reference */ SAXHandler(final Builder build) { builder = build; } @Override public void startElement(final String uri, final String ln, final String qn, final Attributes at) throws SAXException { try { finishText(); final int as = at.getLength(); atts.reset(); for(int a = 0; a < as; ++a) { atts.add(token(at.getQName(a)), token(at.getValue(a))); } builder.startElem(token(qn), atts); ++nodes; } catch(final IOException ex) { error(ex); } } @Override public void endElement(final String uri, final String ln, final String qn) throws SAXException { try { finishText(); builder.endElem(); } catch(final IOException ex) { error(ex); } } @Override public void characters(final char[] ch, final int s, final int l) { sb.append(ch, s, l); } @Override public void processingInstruction(final String nm, final String cont) throws SAXException { if(dtd) return; try { finishText(); builder.pi(token(nm + ' ' + cont)); } catch(final IOException ex) { error(ex); } } @Override public void comment(final char[] ch, final int s, final int l) throws SAXException { if(dtd) return; try { finishText(); builder.comment(token(new String(ch, s, l))); } catch(final IOException ex) { error(ex); } } /** Temporary token builder. private final TokenBuilder tb = new TokenBuilder(); */ /** Temporary string builder for high surrogates. */ private final StringBuilder sb = new StringBuilder(); /** Temporary namespaces. */ private final Atts ns = new Atts(); /** * Checks if a text node has to be written. * @throws IOException I/O exception */ private void finishText() throws IOException { final boolean sur = sb.length() != 0; if(sb.length() != 0 || sur) { builder.text(token(sb.toString())); sb.setLength(0); } for(int i = 0; i < ns.size(); ++i) { builder.startNS(ns.name(i), ns.string(i)); } ns.reset(); } /** * Creates and throws a SAX exception for the specified exception. * @param ex exception * @throws SAXException SAX exception */ private static void error(final IOException ex) throws SAXException { final SAXException ioe = new SAXException(ex.getMessage()); ioe.setStackTrace(ex.getStackTrace()); throw ioe; } // EntityResolver /* public InputSource resolveEntity(String pub, String sys) { } */ // DTDHandler /* public void notationDecl(String name, String pub, String sys) { } */ /* public void unparsedEntityDecl(final String name, final String pub, final String sys, final String not) { } */ // ContentHandler /*public void setDocumentLocator(final Locator locator) { } */ @Override public void startPrefixMapping(final String prefix, final String uri) { ns.add(token(prefix), token(uri)); } /*public void endPrefixMapping(final String prefix) { } */ /*public void ignorableWhitespace(char[] ch, int s, int l) { } */ /*public void skippedEntity(final String name) { } */ // ErrorHandler /* public void warning(final SAXParseException ex) { } */ /* public void fatalError(final SAXParseException ex) { } */ // LexicalHandler @Override public void startDTD(final String n, final String pid, final String sid) { dtd = true; } @Override public void endDTD() { dtd = false; } @Override public void endCDATA() { /* ignored. */ } @Override public void endEntity(final String n) { /* ignored. */ } @Override public void startCDATA() { /* ignored. */ } @Override public void startEntity(final String n) { /* ignored. */ } }