Java/XML/SAX

Материал из Java эксперт
Версия от 07:19, 1 июня 2010; Admin (обсуждение | вклад) (1 версия)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Accessing character data (CDATA) of XML element

     
 
import java.util.Stack;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class Main extends DefaultHandler {
  private Stack currentElement = new Stack();
  public void startElement(String uri, String localName, String qName, Attributes attrs)
      throws SAXException {
    currentElement.push(qName);
  }
  public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
    currentElement.pop();
  }
  public void characters(char[] ch, int start, int length) throws SAXException {
    String cdata = new String(ch, start, length);
    System.out.println("Element "" + currentElement.peek() + "" contains text: " + cdata);
  }
  public static void main(String[] args) throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setValidating(true);
    SAXParser parser = factory.newSAXParser();
    parser.parse("sample.xml", new Main());
  }
}





Accessing features of the SAX parser implementation

     
 
import javax.xml.parsers.SAXParserFactory;
public class Main {
  public static void main(String[] argv) throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    String features[] = { "http://xml.org/sax/features/namespaces",
        "http://xml.org/sax/features/namespace-prefixes",
        "http://xml.org/sax/features/string-interning", "http://xml.org/sax/features/validation",
        "http://xml.org/sax/features/external-general-entities",
        "http://xml.org/sax/features/external-parameter-entities",
        "http://xml.org/sax/features/lexical-handler/parameter-entities", };
    for (int i = 0; i < features.length; i++) {
      System.out.print("\t- "" + features[i] + "" is ");
      System.out.println(""" + factory.getFeature(features[i]) + """);
    }
  }
}





A Content Handler to Output a Sorted List

     
import java.io.PrintWriter;
import java.util.Vector;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
public class MyTextHandler implements ContentHandler {
  private boolean insideNameElement = false;
  private boolean insidePhoneElement = false;
  private boolean insideEmailElement = false;
  private Person person;
  private Vector personVec;
  private PrintWriter out;
  public MyTextHandler(PrintWriter out) {
    this.out = out;
    personVec = new Vector();
  }
  public void setDocumentLocator(Locator locator) {
  }
  public void startDocument() {
    putCols(" name", " phone", " email");
    putCols(" ----", " -----", " -----");
  }
  public void endDocument() {
    int k1 = 1;
    while (k1 < personVec.size()) {
      int k0 = k1 - 1;
      Person p0 = (Person) personVec.elementAt(k0);
      Person p1 = (Person) personVec.elementAt(k1);
      if (p0.getName().rupareTo(p1.getName()) > 0) {
        personVec.setElementAt(p0, k1);
        personVec.setElementAt(p1, k0);
        if (k1 > 1)
          k1--;
      } else {
        k1++;
      }
    }
    for (int i = 0; i < personVec.size(); i++) {
      Person p = (Person) personVec.elementAt(i);
      putCols(p.getName(), p.getPhone(), p.getEmail());
    }
  }
  public void startPrefixMapping(String prefix, String uri) {
  }
  public void endPrefixMapping(String prefix) {
  }
  public void startElement(String namespaceURI, String localName,
      String qName, Attributes atts) {
    if (localName.equals("person")) {
      person = new Person();
    } else if (localName.equals("name")) {
      insideNameElement = true;
    } else if (localName.equals("phone")) {
      insidePhoneElement = true;
    } else if (localName.equals("email")) {
      insideEmailElement = true;
    }
  }
  public void endElement(String namespaceURI, String localName, String qName) {
    if (localName.equals("person")) {
      if (person != null)
        personVec.addElement(person);
    } else if (localName.equals("name")) {
      insideNameElement = false;
    } else if (localName.equals("phone")) {
      insidePhoneElement = false;
    } else if (localName.equals("email")) {
      insideEmailElement = false;
    }
  }
  public void characters(char[] ch, int start, int length) {
    String str = "";
    for (int i = start; i < start + length; i++)
      str += ch[i];
    if (insideNameElement)
      person.setName(str);
    else if (insidePhoneElement)
      person.setPhone(str);
    else if (insideEmailElement)
      person.setEmail(str);
  }
  public void ignorableWhitespace(char[] ch, int start, int length) {
  }
  public void processingInstruction(String target, String data) {
  }
  public void skippedEntity(String name) {
  }
  private void putCols(String col1, String col2, String col3) {
    String lout = col1;
    while (lout.length() < 25)
      lout += " ";
    lout += col2;
    while (lout.length() < 50)
      lout += " ";
    lout += col3;
    out.println(lout);
  }
}
// A Class for Holding Person Information
class Person {
  private String name = null;
  private String phone = null;
  private String email = null;
  public void setName(String value) {
    name = value;
  }
  public void setPhone(String value) {
    phone = value;
  }
  public void setEmail(String value) {
    email = value;
  }
  public String getName() {
    if (name == null)
      return ("none");
    return (name);
  }
  public String getPhone() {
    if (phone == null)
      return ("none");
    return (phone);
  }
  public String getEmail() {
    if (email == null)
      return ("none");
    return (email);
  }
}
//Example XML document
/*
 An XML Document Containing a Simple Contact List
Start example
<?xml version="1.0" standalone="yes"?>
<folks>
    <person>
        <phone>306 555-9999</phone>
        <email>joe@webserver.net</email>
        <name>Wang, Joe</name>
    </person>
    <person>
        <phone>704 555-0000</phone>
        <name>Pet, Rob</name>
        <email>rob@server.ru</email>
    </person>
</folks>
*/





A Content Handler to Output a Sorted List as HTML

     
import java.io.PrintWriter;
import java.util.Vector;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
public class MyHtmlHandler implements ContentHandler {
  private boolean insideNameElement = false;
  private boolean insidePhoneElement = false;
  private boolean insideEmailElement = false;
  private Person person;
  private Vector personVec;
  private PrintWriter out;
  public MyHtmlHandler(PrintWriter out) {
    this.out = out;
    personVec = new Vector();
  }
  public void setDocumentLocator(Locator locator) {
  }
  public void startDocument() {
  }
  public void endDocument() {
    int k1 = 1;
    while (k1 < personVec.size()) {
      int k0 = k1 - 1;
      Person p0 = (Person) personVec.elementAt(k0);
      Person p1 = (Person) personVec.elementAt(k1);
      if (p0.getName().rupareTo(p1.getName()) > 0) {
        personVec.setElementAt(p0, k1);
        personVec.setElementAt(p1, k0);
        if (k1 > 1)
          k1--;
      } else {
        k1++;
      }
    }
    out.println("<html>");
    out.println("<head>");
    out.println("  <title>Persons</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<center><h1>Persons</h1><center>");
    out.println("<hr>");
    out.println("<center>");
    out.println("<table border cellspacing=0 cellpadding=5>");
    out.println("  <caption align=top>");
    out.println("    A List of Names with Phone and Email");
    out.println("  </caption>");
    out.println("  <tr>");
    out.println("    <th>Name</th>");
    out.println("    <th>Phone</th>");
    out.println("    <th>Email</th>");
    out.println("  </tr>");
    for (int i = 0; i < personVec.size(); i++) {
      Person p = (Person) personVec.elementAt(i);
      out.println("  <tr>");
      out.println("    <td>" + p.getName() + "</td>");
      out.println("    <td>" + p.getPhone() + "</td>");
      out.println("    <td>" + p.getEmail() + "</td>");
      out.println("  </tr>");
    }
    out.println("</table>");
    out.println("</center>");
    out.println("</body>");
    out.println("</html>");
  }
  public void startPrefixMapping(String prefix, String uri) {
  }
  public void endPrefixMapping(String prefix) {
  }
  public void startElement(String namespaceURI, String localName,
      String qName, Attributes atts) {
    if (localName.equals("person")) {
      person = new Person();
    } else if (localName.equals("name")) {
      insideNameElement = true;
    } else if (localName.equals("phone")) {
      insidePhoneElement = true;
    } else if (localName.equals("email")) {
      insideEmailElement = true;
    }
  }
  public void endElement(String namespaceURI, String localName, String qName) {
    if (localName.equals("person")) {
      if (person != null)
        personVec.addElement(person);
    } else if (localName.equals("name")) {
      insideNameElement = false;
    } else if (localName.equals("phone")) {
      insidePhoneElement = false;
    } else if (localName.equals("email")) {
      insideEmailElement = false;
    }
  }
  public void characters(char[] ch, int start, int length) {
    String str = "";
    for (int i = start; i < start + length; i++)
      str += ch[i];
    if (insideNameElement)
      person.setName(str);
    else if (insidePhoneElement)
      person.setPhone(str);
    else if (insideEmailElement)
      person.setEmail(str);
  }
  public void ignorableWhitespace(char[] ch, int start, int length) {
  }
  public void processingInstruction(String target, String data) {
  }
  public void skippedEntity(String name) {
  }
}
class Person {
  private String name = null;
  private String phone = null;
  private String email = null;
  public void setName(String value) {
    name = value;
  }
  public void setPhone(String value) {
    phone = value;
  }
  public void setEmail(String value) {
    email = value;
  }
  public String getName() {
    if (name == null)
      return ("none");
    return (name);
  }
  public String getPhone() {
    if (phone == null)
      return ("none");
    return (phone);
  }
  public String getEmail() {
    if (email == null)
      return ("none");
    return (email);
  }
}
//Example XML document
/*
 * An XML Document Containing a Simple Contact List Start example
 * 
 * <?xml version="1.0" standalone="yes"?>
 * 
 * <folks> <person> <phone>306 555-9999 </phone> <email>joe@webserver.net
 * </email> <name>Yin, Wang </name> </person> <person> <phone>704 555-0000
 * </phone> <name>Pet, Rob </name> <email>rob@server.ru </email> </person>
 * </folks>
 *  
 */





A Program to Display the Input from a SAX Parser

     
//Example XML document
/*  An XML Document
<?xml version="1.0" standalone="yes"?>
<person>
     <name>Joe Wang</name>
     <phone type="home">306 555-9999</phone>
     <email>joe@yoursite.net;</email>
</person>

*/
import java.io.IOException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
public class SAXDump {
  static public void main(String[] arg) {
    String filename = null;
    if (arg.length == 1) {
      filename = arg[0];
    } else {
      usage();
    }
    // Create a new factory that will create the parser.
    SAXParserFactory spf = SAXParserFactory.newInstance();
    // Create the XMLReader to be used to parse the document.
    XMLReader reader = null;
    try {
      SAXParser parser = spf.newSAXParser();
      reader = parser.getXMLReader();
    } catch (Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    // Specify the error handler and the content handler.
    reader.setErrorHandler(new MyErrorHandler());
    reader.setContentHandler(new MyContentHandler());
    // Use the XMLReader to parse the entire file.
    try {
      InputSource is = new InputSource(filename);
      reader.parse(is);
    } catch (SAXException e) {
      System.exit(1);
    } catch (IOException e) {
      System.err.println(e);
      System.exit(1);
    }
  }
  private static void usage() {
    System.err.println("Usage: SAXDump <filename>");
    System.exit(1);
  }
}
class MyContentHandler implements ContentHandler {
  private Locator locator;
  /**
   * The name and of the SAX document and the current location within the
   * document.
   */
  public void setDocumentLocator(Locator locator) {
    this.locator = locator;
    System.out.println("-" + locator.getLineNumber() + "---Document ID: "
        + locator.getSystemId());
  }
  /** The parsing of a document has started.. */
  public void startDocument() {
    System.out.println("-" + locator.getLineNumber()
        + "---Document parse started");
  }
  /** The parsing of a document has completed.. */
  public void endDocument() {
    System.out.println("-" + locator.getLineNumber()
        + "---Document parse ended");
  }
  /** The start of a namespace scope */
  public void startPrefixMapping(String prefix, String uri) {
    System.out.println("-" + locator.getLineNumber()
        + "---Namespace scope begins");
    System.out.println("     " + prefix + "=\"" + uri + "\"");
  }
  /** The end of a namespace scope */
  public void endPrefixMapping(String prefix) {
    System.out.println("-" + locator.getLineNumber()
        + "---Namespace scope ends");
    System.out.println("     " + prefix);
  }
  /** The opening tag of an element. */
  public void startElement(String namespaceURI, String localName,
      String qName, Attributes atts) {
    System.out.println("-" + locator.getLineNumber()
        + "---Opening tag of an element");
    System.out.println("       Namespace: " + namespaceURI);
    System.out.println("      Local name: " + localName);
    System.out.println("  Qualified name: " + qName);
    for (int i = 0; i < atts.getLength(); i++) {
      System.out.println("       Attribute: " + atts.getQName(i) + "=\""
          + atts.getValue(i) + "\"");
    }
  }
  /** The closing tag of an element. */
  public void endElement(String namespaceURI, String localName, String qName) {
    System.out.println("-" + locator.getLineNumber()
        + "---Closing tag of an element");
    System.out.println("       Namespace: " + namespaceURI);
    System.out.println("      Local name: " + localName);
    System.out.println("  Qualified name: " + qName);
  }
  /** Character data. */
  public void characters(char[] ch, int start, int length) {
    System.out.println("-" + locator.getLineNumber() + "---Character data");
    showCharacters(ch, start, length);
  }
  /** Ignorable whitespace character data. */
  public void ignorableWhitespace(char[] ch, int start, int length) {
    System.out.println("-" + locator.getLineNumber() + "---Whitespace");
    showCharacters(ch, start, length);
  }
  /** Processing Instruction */
  public void processingInstruction(String target, String data) {
    System.out.println("-" + locator.getLineNumber()
        + "---Processing Instruction");
    System.out.println("         Target: " + target);
    System.out.println("           Data: " + data);
  }
  /** A skipped entity. */
  public void skippedEntity(String name) {
    System.out.println("-" + locator.getLineNumber() + "---Skipped Entity");
    System.out.println("           Name: " + name);
  }
  /**
   * Internal method to format arrays of characters so the special whitespace
   * characters will show.
   */
  public void showCharacters(char[] ch, int start, int length) {
    System.out.print("        \"");
    for (int i = start; i < start + length; i++)
      switch (ch[i]) {
      case "\n":
        System.out.print("\\n");
        break;
      case "\r":
        System.out.print("\\r");
        break;
      case "\t":
        System.out.print("\\t");
        break;
      default:
        System.out.print(ch[i]);
        break;
      }
    System.out.println("\"");
  }
}
class MyErrorHandler implements ErrorHandler {
  public void warning(SAXParseException e) throws SAXException {
    show("Warning", e);
    throw (e);
  }
  public void error(SAXParseException e) throws SAXException {
    show("Error", e);
    throw (e);
  }
  public void fatalError(SAXParseException e) throws SAXException {
    show("Fatal Error", e);
    throw (e);
  }
  private void show(String type, SAXParseException e) {
    System.out.println(type + ": " + e.getMessage());
    System.out.println("Line " + e.getLineNumber() + " Column "
        + e.getColumnNumber());
    System.out.println("System ID: " + e.getSystemId());
  }
}





Configuring SAX parser factory to produce alternate parser

     
 
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class Main {
  public static void main(String[] args) throws Exception {
    System.setProperty("avax.xml.parsers.SAXParserFactory", "org.apache.xerces.parsers.SAXParser");
    SAXParserFactory factory = SAXParserFactory.newInstance();
    SAXParser parser = factory.newSAXParser();
  }
}





Create Xml Reader

   
/** 
 * 
 * The ObjectStyle Group Software License, version 1.1
 * ObjectStyle Group - http://objectstyle.org/
 * 
 * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
 * of the software. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if any,
 *    must include the following acknowlegement:
 *    "This product includes software developed by independent contributors
 *    and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
 *    or promote products derived from this software without prior written
 *    permission. For written permission, email
 *    "andrus at objectstyle dot org".
 * 
 * 5. Products derived from this software may not be called "ObjectStyle"
 *    or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
 *    names without prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS"" AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 * 
 * This software consists of voluntary contributions made by many
 * individuals and hosted on ObjectStyle Group web site.  For more
 * information on the ObjectStyle Group, please see
 * <http://objectstyle.org/>.
 */
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.ruparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
/**
 * Contains various unorganized static utility methods used across Cayenne.
 * 
 * @author Andrei Adamchik
 */
public class Util {
  /**
   * Creates an XMLReader with default feature set. Note that all Cayenne internal XML
   * parsers should probably use XMLReader obtained via this method for consistency
   * sake, and can customize feature sets as needed.
   */
  public static XMLReader createXmlReader() throws SAXException,
          ParserConfigurationException {
      SAXParserFactory spf = SAXParserFactory.newInstance();
      // Create a JAXP SAXParser
      SAXParser saxParser = spf.newSAXParser();
      // Get the encapsulated SAX XMLReader
      XMLReader reader = saxParser.getXMLReader();
      // set default features
      reader.setFeature("http://xml.org/sax/features/namespaces", true);
      return reader;
  }
}





Duplicates XML Files

     
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
public class SAXCopy {
  static public void main(String[] arg) {
    String infilename = null;
    String outfilename = null;
    if (arg.length == 2) {
      infilename = arg[0];
      outfilename = arg[1];
    } else {
      usage();
    }
    try {
      SAXParserFactory spf = SAXParserFactory.newInstance();
      SAXParser parser = spf.newSAXParser();
      XMLReader reader = parser.getXMLReader();
      reader.setErrorHandler(new MyErrorHandler());
      FileOutputStream fos = new FileOutputStream(outfilename);
      PrintWriter out = new PrintWriter(fos);
      MyCopyHandler duper = new MyCopyHandler(out);
      reader.setContentHandler(duper);
      InputSource is = new InputSource(infilename);
      reader.parse(is);
      out.close();
    } catch (SAXException e) {
      System.exit(1);
    } catch (ParserConfigurationException e) {
      System.err.println(e);
      System.exit(1);
    } catch (IOException e) {
      System.err.println(e);
      System.exit(1);
    }
  }
  private static void usage() {
    System.err.println("Usage: SAXCopy <infile> <outfile>");
    System.exit(1);
  }
}
class MyCopyHandler implements ContentHandler {
  private boolean namespaceBegin = false;
  private String currentNamespace;
  private String currentNamespaceUri;
  private Locator locator;
  private PrintWriter out;
  public MyCopyHandler(PrintWriter out) {
    this.out = out;
  }
  public void setDocumentLocator(Locator locator) {
    this.locator = locator;
  }
  public void startDocument() {
    out.println("<?xml version=\"1.0\"?>");
    out.println();
  }
  public void endDocument() {
  }
  public void startPrefixMapping(String prefix, String uri) {
    namespaceBegin = true;
    currentNamespace = prefix;
    currentNamespaceUri = uri;
  }
  public void endPrefixMapping(String prefix) {
  }
  public void startElement(String namespaceURI, String localName,
      String qName, Attributes atts) {
    out.print("<" + qName);
    if (namespaceBegin) {
      out.print(" xmlns:" + currentNamespace + "=\""
          + currentNamespaceUri + "\"");
      namespaceBegin = false;
    }
    for (int i = 0; i < atts.getLength(); i++) {
      out.print(" " + atts.getQName(i) + "=\\" + atts.getValue(i) + "\"");
    }
    out.print(">");
  }
  public void endElement(String namespaceURI, String localName, String qName) {
    out.print("</" + qName + ">");
  }
  public void characters(char[] ch, int start, int length) {
    for (int i = start; i < start + length; i++)
      out.print(ch[i]);
  }
  public void ignorableWhitespace(char[] ch, int start, int length) {
    for (int i = start; i < start + length; i++)
      out.print(ch[i]);
  }
  public void processingInstruction(String target, String data) {
    out.print("<?" + target + " " + data + "?>");
  }
  public void skippedEntity(String name) {
    out.print("&" + name + ";");
  }
}
class MyErrorHandler implements ErrorHandler {
  public void warning(SAXParseException e) throws SAXException {
    show("Warning", e);
    throw (e);
  }
  public void error(SAXParseException e) throws SAXException {
    show("Error", e);
    throw (e);
  }
  public void fatalError(SAXParseException e) throws SAXException {
    show("Fatal Error", e);
    throw (e);
  }
  private void show(String type, SAXParseException e) {
    System.out.println(type + ": " + e.getMessage());
    System.out.println("Line " + e.getLineNumber() + " Column "
        + e.getColumnNumber());
    System.out.println("System ID: " + e.getSystemId());
  }
}
//Example XML document
/*  An XML Document
<?xml version="1.0" standalone="yes"?>
<person>
     <name>Joe Wang</name>
     <phone type="home">306 555-9999</phone>
     <email>joe@yoursite.net;</email>
</person>

*/





Extracting attribute values from XML elements

     
 
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class Main {
  public static void main(String[] argv) throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    SAXParser parser = factory.newSAXParser();
    SaxHandler handler = new SaxHandler();
    parser.parse("sample.xml", handler);
  }
}
class SaxHandler extends DefaultHandler {
  public void startElement(String uri, String localName, String qName, Attributes attrs)
      throws SAXException {
    if (qName.equals("order")) {
      String date = attrs.getValue("date");
      String number = attrs.getValue("number");
      System.out.println("Order #" + number + " date is "" + date + """);
    }
  }
}





Filter to write an XML document from a SAX event stream

   

//XMLWriter.java - serialize an XML document.
//Written by David Megginson, david@megginson.ru
//NO WARRANTY!  This class is in the public domain.
//Modified by John Cowan and Leigh Klotz for the TagSoup project.  Still in the public domain.
//New features:
//  it is a LexicalHandler
//  it prints a comment if the LexicalHandler#comment method is called
//  it supports certain XSLT output properties using get/setOutputProperty
//$Id: XMLWriter.java,v 1.1 2004/01/28 05:35:43 joe Exp $
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.NamespaceSupport;
import org.xml.sax.helpers.XMLFilterImpl;
import org.xml.sax.ext.LexicalHandler;
/**
 * Filter to write an XML document from a SAX event stream.
 * 
 * <p>
 * This class can be used by itself or as part of a SAX event stream: it takes
 * as input a series of SAX2 ContentHandler events and uses the information in
 * those events to write an XML document. Since this class is a filter, it can
 * also pass the events on down a filter chain for further processing (you can
 * use the XMLWriter to take a snapshot of the current state at any point in a
 * filter chain), and it can be used directly as a ContentHandler for a SAX2
 * XMLReader.
 * </p>
 * 
 * <p>
 * The client creates a document by invoking the methods for standard SAX2
 * events, always beginning with the {@link #startDocument startDocument} method
 * and ending with the {@link #endDocument endDocument} method. There are
 * convenience methods provided so that clients to not have to create empty
 * attribute lists or provide empty strings as parameters; for example, the
 * method invocation
 * </p>
 * 
 * <pre>
 * w.startElement(&quot;foo&quot;);
 * </pre>
 * 
 * <p>
 * is equivalent to the regular SAX2 ContentHandler method
 * </p>
 * 
 * <pre>
 * w.startElement(&quot;&quot;, &quot;foo&quot;, &quot;&quot;, new AttributesImpl());
 * </pre>
 * 
 * <p>
 * Except that it is more efficient because it does not allocate a new empty
 * attribute list each time. The following code will send a simple XML document
 * to standard output:
 * </p>
 * 
 * <pre>
 * XMLWriter w = new XMLWriter();
 * 
 * w.startDocument();
 * w.startElement(&quot;greeting&quot;);
 * w.characters(&quot;Hello, world!&quot;);
 * w.endElement(&quot;greeting&quot;);
 * w.endDocument();
 * </pre>
 * 
 * <p>
 * The resulting document will look like this:
 * </p>
 * 
 * <pre>
 *  &lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
 * 
 *  &lt;greeting&gt;Hello, world!&lt;/greeting&gt;
 * </pre>
 * 
 * <p>
 * In fact, there is an even simpler convenience method, <var>dataElement</var>,
 * designed for writing elements that contain only character data, so the code
 * to generate the document could be shortened to
 * </p>
 * 
 * <pre>
 * XMLWriter w = new XMLWriter();
 * 
 * w.startDocument();
 * w.dataElement(&quot;greeting&quot;, &quot;Hello, world!&quot;);
 * w.endDocument();
 * </pre>
 * 
 * <h2>Whitespace</h2>
 * 
 * <p>
 * According to the XML Recommendation, <em>all</em> whitespace in an XML
 * document is potentially significant to an application, so this class never
 * adds newlines or indentation. If you insert three elements in a row, as in
 * </p>
 * 
 * <pre>
 * w.dataElement(&quot;item&quot;, &quot;1&quot;);
 * w.dataElement(&quot;item&quot;, &quot;2&quot;);
 * w.dataElement(&quot;item&quot;, &quot;3&quot;);
 * </pre>
 * 
 * <p>
 * you will end up with
 * </p>
 * 
 * <pre>
 *  &lt;item&gt;1&lt;/item&gt;&lt;item&gt;3&lt;/item&gt;&lt;item&gt;3&lt;/item&gt;
 * </pre>
 * 
 * <p>
 * You need to invoke one of the <var>characters</var> methods explicitly to
 * add newlines or indentation. Alternatively, you can use
 * {@link com.megginson.sax.DataWriter DataWriter}, which is derived from this
 * class -- it is optimized for writing purely data-oriented (or field-oriented)
 * XML, and does automatic linebreaks and indentation (but does not support
 * mixed content properly).
 * </p>
 * 
 * 
 * <h2>Namespace Support</h2>
 * 
 * <p>
 * The writer contains extensive support for XML Namespaces, so that a client
 * application does not have to keep track of prefixes and supply <var>xmlns</var>
 * attributes. By default, the XML writer will generate Namespace declarations
 * in the form _NS1, _NS2, etc., wherever they are needed, as in the following
 * example:
 * </p>
 * 
 * <pre>
 * w.startDocument();
 * w.emptyElement(&quot;http://www.foo.ru/ns/&quot;, &quot;foo&quot;);
 * w.endDocument();
 * </pre>
 * 
 * <p>
 * The resulting document will look like this:
 * </p>
 * 
 * <pre>
 *  &lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
 * 
 *  &lt;_NS1:foo xmlns:_NS1=&quot;http://www.foo.ru/ns/&quot;/&gt;
 * </pre>
 * 
 * <p>
 * In many cases, document authors will prefer to choose their own prefixes
 * rather than using the (ugly) default names. The XML writer allows two methods
 * for selecting prefixes:
 * </p>
 * 
 * <ol>
 * <li>the qualified name</li>
 * <li>the {@link #setPrefix setPrefix} method.</li>
 * </ol>
 * 
 * <p>
 * Whenever the XML writer finds a new Namespace URI, it checks to see if a
 * qualified (prefixed) name is also available; if so it attempts to use the
 * name"s prefix (as long as the prefix is not already in use for another
 * Namespace URI).
 * </p>
 * 
 * <p>
 * Before writing a document, the client can also pre-map a prefix to a
 * Namespace URI with the setPrefix method:
 * </p>
 * 
 * <pre>
 * w.setPrefix(&quot;http://www.foo.ru/ns/&quot;, &quot;foo&quot;);
 * w.startDocument();
 * w.emptyElement(&quot;http://www.foo.ru/ns/&quot;, &quot;foo&quot;);
 * w.endDocument();
 * </pre>
 * 
 * <p>
 * The resulting document will look like this:
 * </p>
 * 
 * <pre>
 *  &lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
 * 
 *  &lt;foo:foo xmlns:foo=&quot;http://www.foo.ru/ns/&quot;/&gt;
 * </pre>
 * 
 * <p>
 * The default Namespace simply uses an empty string as the prefix:
 * </p>
 * 
 * <pre>
 * w.setPrefix(&quot;http://www.foo.ru/ns/&quot;, &quot;&quot;);
 * w.startDocument();
 * w.emptyElement(&quot;http://www.foo.ru/ns/&quot;, &quot;foo&quot;);
 * w.endDocument();
 * </pre>
 * 
 * <p>
 * The resulting document will look like this:
 * </p>
 * 
 * <pre>
 *  &lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
 * 
 *  &lt;foo xmlns=&quot;http://www.foo.ru/ns/&quot;/&gt;
 * </pre>
 * 
 * <p>
 * By default, the XML writer will not declare a Namespace until it is actually
 * used. Sometimes, this approach will create a large number of Namespace
 * declarations, as in the following example:
 * </p>
 * 
 * <pre>
 *  &lt;xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
 * 
 *  &lt;rdf:RDF xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
 *   &lt;rdf:Description about=&quot;http://www.foo.ru/ids/books/12345&quot;&gt;
 *    &lt;dc:title xmlns:dc=&quot;http://www.purl.org/dc/&quot;&gt;A Dark Night&lt;/dc:title&gt;
 *    &lt;dc:creator xmlns:dc=&quot;http://www.purl.org/dc/&quot;&gt;Jane Smith&lt;/dc:title&gt;
 *    &lt;dc:date xmlns:dc=&quot;http://www.purl.org/dc/&quot;&gt;2000-09-09&lt;/dc:title&gt;
 *   &lt;/rdf:Description&gt;
 *  &lt;/rdf:RDF&gt;
 * </pre>
 * 
 * <p>
 * The "rdf" prefix is declared only once, because the RDF Namespace is used by
 * the root element and can be inherited by all of its descendants; the "dc"
 * prefix, on the other hand, is declared three times, because no higher element
 * uses the Namespace. To solve this problem, you can instruct the XML writer to
 * predeclare Namespaces on the root element even if they are not used there:
 * </p>
 * 
 * <pre>
 * w.forceNSDecl(&quot;http://www.purl.org/dc/&quot;);
 * </pre>
 * 
 * <p>
 * Now, the "dc" prefix will be declared on the root element even though it"s
 * not needed there, and can be inherited by its descendants:
 * </p>
 * 
 * <pre>
 *  &lt;xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
 * 
 *  &lt;rdf:RDF xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;
 *              xmlns:dc=&quot;http://www.purl.org/dc/&quot;&gt;
 *   &lt;rdf:Description about=&quot;http://www.foo.ru/ids/books/12345&quot;&gt;
 *    &lt;dc:title&gt;A Dark Night&lt;/dc:title&gt;
 *    &lt;dc:creator&gt;Jane Smith&lt;/dc:title&gt;
 *    &lt;dc:date&gt;2000-09-09&lt;/dc:title&gt;
 *   &lt;/rdf:Description&gt;
 *  &lt;/rdf:RDF&gt;
 * </pre>
 * 
 * <p>
 * This approach is also useful for declaring Namespace prefixes that be used by
 * qualified names appearing in attribute values or character data.
 * </p>
 * 
 * @author David Megginson, david@megginson.ru
 * @version 0.2
 * @see org.xml.sax.XMLFilter
 * @see org.xml.sax.ContentHandler
 */
public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
  // //////////////////////////////////////////////////////////////////
  // Constructors.
  // //////////////////////////////////////////////////////////////////
  /**
   * Create a new XML writer.
   * 
   * <p>
   * Write to standard output.
   * </p>
   */
  public XMLWriter() {
    init(null);
  }
  /**
   * Create a new XML writer.
   * 
   * <p>
   * Write to the writer provided.
   * </p>
   * 
   * @param writer
   *            The output destination, or null to use standard output.
   */
  public XMLWriter(Writer writer) {
    init(writer);
  }
  /**
   * Create a new XML writer.
   * 
   * <p>
   * Use the specified XML reader as the parent.
   * </p>
   * 
   * @param xmlreader
   *            The parent in the filter chain, or null for no parent.
   */
  public XMLWriter(XMLReader xmlreader) {
    super(xmlreader);
    init(null);
  }
  /**
   * Create a new XML writer.
   * 
   * <p>
   * Use the specified XML reader as the parent, and write to the specified
   * writer.
   * </p>
   * 
   * @param xmlreader
   *            The parent in the filter chain, or null for no parent.
   * @param writer
   *            The output destination, or null to use standard output.
   */
  public XMLWriter(XMLReader xmlreader, Writer writer) {
    super(xmlreader);
    init(writer);
  }
  /**
   * Internal initialization method.
   * 
   * <p>
   * All of the public constructors invoke this method.
   * 
   * @param writer
   *            The output destination, or null to use standard output.
   */
  private void init(Writer writer) {
    setOutput(writer);
    nsSupport = new NamespaceSupport();
    prefixTable = new Hashtable();
    forcedDeclTable = new Hashtable();
    doneDeclTable = new Hashtable();
    outputProperties = new Properties();
  }
  // //////////////////////////////////////////////////////////////////
  // Public methods.
  // //////////////////////////////////////////////////////////////////
  /**
   * Reset the writer.
   * 
   * <p>
   * This method is especially useful if the writer throws an exception before
   * it is finished, and you want to reuse the writer for a new document. It
   * is usually a good idea to invoke {@link #flush flush} before resetting
   * the writer, to make sure that no output is lost.
   * </p>
   * 
   * <p>
   * This method is invoked automatically by the
   * {@link #startDocument startDocument} method before writing a new
   * document.
   * </p>
   * 
   * <p>
   * <strong>Note:</strong> this method will <em>not</em> clear the prefix
   * or URI information in the writer or the selected output writer.
   * </p>
   * 
   * @see #flush
   */
  public void reset() {
    elementLevel = 0;
    prefixCounter = 0;
    nsSupport.reset();
  }
  /**
   * Flush the output.
   * 
   * <p>
   * This method flushes the output stream. It is especially useful when you
   * need to make certain that the entire document has been written to output
   * but do not want to close the output stream.
   * </p>
   * 
   * <p>
   * This method is invoked automatically by the
   * {@link #endDocument endDocument} method after writing a document.
   * </p>
   * 
   * @see #reset
   */
  public void flush() throws IOException {
    output.flush();
  }
  /**
   * Set a new output destination for the document.
   * 
   * @param writer
   *            The output destination, or null to use standard output.
   * @return The current output writer.
   * @see #flush
   */
  public void setOutput(Writer writer) {
    if (writer == null) {
      output = new OutputStreamWriter(System.out);
    } else {
      output = writer;
    }
  }
  /**
   * Specify a preferred prefix for a Namespace URI.
   * 
   * <p>
   * Note that this method does not actually force the Namespace to be
   * declared; to do that, use the {@link  #forceNSDecl(java.lang.String)
   * forceNSDecl} method as well.
   * </p>
   * 
   * @param uri
   *            The Namespace URI.
   * @param prefix
   *            The preferred prefix, or "" to select the default Namespace.
   * @see #getPrefix
   * @see #forceNSDecl(java.lang.String)
   * @see #forceNSDecl(java.lang.String,java.lang.String)
   */
  public void setPrefix(String uri, String prefix) {
    prefixTable.put(uri, prefix);
  }
  /**
   * Get the current or preferred prefix for a Namespace URI.
   * 
   * @param uri
   *            The Namespace URI.
   * @return The preferred prefix, or "" for the default Namespace.
   * @see #setPrefix
   */
  public String getPrefix(String uri) {
    return (String) prefixTable.get(uri);
  }
  /**
   * Force a Namespace to be declared on the root element.
   * 
   * <p>
   * By default, the XMLWriter will declare only the Namespaces needed for an
   * element; as a result, a Namespace may be declared many places in a
   * document if it is not used on the root element.
   * </p>
   * 
   * <p>
   * This method forces a Namespace to be declared on the root element even if
   * it is not used there, and reduces the number of xmlns attributes in the
   * document.
   * </p>
   * 
   * @param uri
   *            The Namespace URI to declare.
   * @see #forceNSDecl(java.lang.String,java.lang.String)
   * @see #setPrefix
   */
  public void forceNSDecl(String uri) {
    forcedDeclTable.put(uri, Boolean.TRUE);
  }
  /**
   * Force a Namespace declaration with a preferred prefix.
   * 
   * <p>
   * This is a convenience method that invokes {@link #setPrefix setPrefix}
   * then {@link #forceNSDecl(java.lang.String) forceNSDecl}.
   * </p>
   * 
   * @param uri
   *            The Namespace URI to declare on the root element.
   * @param prefix
   *            The preferred prefix for the Namespace, or "" for the default
   *            Namespace.
   * @see #setPrefix
   * @see #forceNSDecl(java.lang.String)
   */
  public void forceNSDecl(String uri, String prefix) {
    setPrefix(uri, prefix);
    forceNSDecl(uri);
  }
  // //////////////////////////////////////////////////////////////////
  // Methods from org.xml.sax.ContentHandler.
  // //////////////////////////////////////////////////////////////////
  /**
   * Write the XML declaration at the beginning of the document.
   * 
   * Pass the event on down the filter chain for further processing.
   * 
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the XML declaration, or if a
   *                handler further down the filter chain raises an exception.
   * @see org.xml.sax.ContentHandler#startDocument
   */
  public void startDocument() throws SAXException {
    reset();
    if (!("yes".equals(outputProperties.getProperty(OMIT_XML_DECLARATION,
        "no"))))
      write("<?xml version=\"1.0\" standalone=\"yes\"?>\n\n");
    super.startDocument();
  }
  /**
   * Write a newline at the end of the document.
   * 
   * Pass the event on down the filter chain for further processing.
   * 
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the newline, or if a handler
   *                further down the filter chain raises an exception.
   * @see org.xml.sax.ContentHandler#endDocument
   */
  public void endDocument() throws SAXException {
    write("\n");
    super.endDocument();
    try {
      flush();
    } catch (IOException e) {
      throw new SAXException(e);
    }
  }
  /**
   * Write a start tag.
   * 
   * Pass the event on down the filter chain for further processing.
   * 
   * @param uri
   *            The Namespace URI, or the empty string if none is available.
   * @param localName
   *            The element"s local (unprefixed) name (required).
   * @param qName
   *            The element"s qualified (prefixed) name, or the empty string
   *            is none is available. This method will use the qName as a
   *            template for generating a prefix if necessary, but it is not
   *            guaranteed to use the same qName.
   * @param atts
   *            The element"s attribute list (must not be null).
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the start tag, or if a
   *                handler further down the filter chain raises an exception.
   * @see org.xml.sax.ContentHandler#startElement
   */
  public void startElement(String uri, String localName, String qName,
      Attributes atts) throws SAXException {
    elementLevel++;
    nsSupport.pushContext();
    write("<");
    writeName(uri, localName, qName, true);
    writeAttributes(atts);
    if (elementLevel == 1) {
      forceNSDecls();
    }
    writeNSDecls();
    write(">");
    if ("html".equals(outputProperties.getProperty(METHOD, "xml"))
        && (localName.equals("script") || localName.equals("style"))) {
      cdataElement = true;
    }
    super.startElement(uri, localName, qName, atts);
  }
  /**
   * Write an end tag.
   * 
   * Pass the event on down the filter chain for further processing.
   * 
   * @param uri
   *            The Namespace URI, or the empty string if none is available.
   * @param localName
   *            The element"s local (unprefixed) name (required).
   * @param qName
   *            The element"s qualified (prefixed) name, or the empty string
   *            is none is available. This method will use the qName as a
   *            template for generating a prefix if necessary, but it is not
   *            guaranteed to use the same qName.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the end tag, or if a handler
   *                further down the filter chain raises an exception.
   * @see org.xml.sax.ContentHandler#endElement
   */
  public void endElement(String uri, String localName, String qName)
      throws SAXException {
    if (!("html".equals(outputProperties.getProperty(METHOD, "xml"))
        && uri.equals("http://www.w3.org/1999/xhtml") && (localName
        .equals("area")
        || localName.equals("base")
        || localName.equals("basefont")
        || localName.equals("br")
        || localName.equals("col")
        || localName.equals("frame")
        || localName.equals("hr")
        || localName.equals("img")
        || localName.equals("input")
        || localName.equals("isindex")
        || localName.equals("link")
        || localName.equals("meta") || localName.equals("param")))) {
      write("</");
      writeName(uri, localName, qName, true);
      write(">");
    }
    if (elementLevel == 1) {
      write("\n");
    }
    cdataElement = false;
    super.endElement(uri, localName, qName);
    nsSupport.popContext();
    elementLevel--;
  }
  /**
   * Write character data.
   * 
   * Pass the event on down the filter chain for further processing.
   * 
   * @param ch
   *            The array of characters to write.
   * @param start
   *            The starting position in the array.
   * @param length
   *            The number of characters to write.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the characters, or if a
   *                handler further down the filter chain raises an exception.
   * @see org.xml.sax.ContentHandler#characters
   */
  public void characters(char ch[], int start, int len) throws SAXException {
    if (!cdataElement) {
      writeEsc(ch, start, len, false);
    } else {
      for (int i = start; i < start + len; i++) {
        write(ch[i]);
      }
    }
    super.characters(ch, start, len);
  }
  /**
   * Write ignorable whitespace.
   * 
   * Pass the event on down the filter chain for further processing.
   * 
   * @param ch
   *            The array of characters to write.
   * @param start
   *            The starting position in the array.
   * @param length
   *            The number of characters to write.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the whitespace, or if a
   *                handler further down the filter chain raises an exception.
   * @see org.xml.sax.ContentHandler#ignorableWhitespace
   */
  public void ignorableWhitespace(char ch[], int start, int length)
      throws SAXException {
    writeEsc(ch, start, length, false);
    super.ignorableWhitespace(ch, start, length);
  }
  /**
   * Write a processing instruction.
   * 
   * Pass the event on down the filter chain for further processing.
   * 
   * @param target
   *            The PI target.
   * @param data
   *            The PI data.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the PI, or if a handler
   *                further down the filter chain raises an exception.
   * @see org.xml.sax.ContentHandler#processingInstruction
   */
  public void processingInstruction(String target, String data)
      throws SAXException {
    write("<?");
    write(target);
    write(" ");
    write(data);
    write("?>");
    if (elementLevel < 1) {
      write("\n");
    }
    super.processingInstruction(target, data);
  }
  // //////////////////////////////////////////////////////////////////
  // Additional markup.
  // //////////////////////////////////////////////////////////////////
  /**
   * Write an empty element.
   * 
   * This method writes an empty element tag rather than a start tag followed
   * by an end tag. Both a {@link #startElement startElement} and an
   * {@link #endElement endElement} event will be passed on down the filter
   * chain.
   * 
   * @param uri
   *            The element"s Namespace URI, or the empty string if the
   *            element has no Namespace or if Namespace processing is not
   *            being performed.
   * @param localName
   *            The element"s local name (without prefix). This parameter must
   *            be provided.
   * @param qName
   *            The element"s qualified name (with prefix), or the empty
   *            string if none is available. This parameter is strictly
   *            advisory: the writer may or may not use the prefix attached.
   * @param atts
   *            The element"s attribute list.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the empty tag, or if a
   *                handler further down the filter chain raises an exception.
   * @see #startElement
   * @see #endElement
   */
  public void emptyElement(String uri, String localName, String qName,
      Attributes atts) throws SAXException {
    nsSupport.pushContext();
    write("<");
    writeName(uri, localName, qName, true);
    writeAttributes(atts);
    if (elementLevel == 1) {
      forceNSDecls();
    }
    writeNSDecls();
    write("/>");
    super.startElement(uri, localName, qName, atts);
    super.endElement(uri, localName, qName);
  }
  // //////////////////////////////////////////////////////////////////
  // Convenience methods.
  // //////////////////////////////////////////////////////////////////
  /**
   * Start a new element without a qname or attributes.
   * 
   * <p>
   * This method will provide a default empty attribute list and an empty
   * string for the qualified name. It invokes {@link  #startElement(String,
   * String, String, Attributes)} directly.
   * </p>
   * 
   * @param uri
   *            The element"s Namespace URI.
   * @param localName
   *            The element"s local name.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the start tag, or if a
   *                handler further down the filter chain raises an exception.
   * @see #startElement(String, String, String, Attributes)
   */
  public void startElement(String uri, String localName) throws SAXException {
    startElement(uri, localName, "", EMPTY_ATTS);
  }
  /**
   * Start a new element without a qname, attributes or a Namespace URI.
   * 
   * <p>
   * This method will provide an empty string for the Namespace URI, and empty
   * string for the qualified name, and a default empty attribute list. It
   * invokes #startElement(String, String, String, Attributes)} directly.
   * </p>
   * 
   * @param localName
   *            The element"s local name.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the start tag, or if a
   *                handler further down the filter chain raises an exception.
   * @see #startElement(String, String, String, Attributes)
   */
  public void startElement(String localName) throws SAXException {
    startElement("", localName, "", EMPTY_ATTS);
  }
  /**
   * End an element without a qname.
   * 
   * <p>
   * This method will supply an empty string for the qName. It invokes
   * {@link #endElement(String, String, String)} directly.
   * </p>
   * 
   * @param uri
   *            The element"s Namespace URI.
   * @param localName
   *            The element"s local name.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the end tag, or if a handler
   *                further down the filter chain raises an exception.
   * @see #endElement(String, String, String)
   */
  public void endElement(String uri, String localName) throws SAXException {
    endElement(uri, localName, "");
  }
  /**
   * End an element without a Namespace URI or qname.
   * 
   * <p>
   * This method will supply an empty string for the qName and an empty string
   * for the Namespace URI. It invokes
   * {@link #endElement(String, String, String)} directly.
   * </p>
   * 
   * @param localName
   *            The element"s local name.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the end tag, or if a handler
   *                further down the filter chain raises an exception.
   * @see #endElement(String, String, String)
   */
  public void endElement(String localName) throws SAXException {
    endElement("", localName, "");
  }
  /**
   * Add an empty element without a qname or attributes.
   * 
   * <p>
   * This method will supply an empty string for the qname and an empty
   * attribute list. It invokes
   * {@link #emptyElement(String, String, String, Attributes)} directly.
   * </p>
   * 
   * @param uri
   *            The element"s Namespace URI.
   * @param localName
   *            The element"s local name.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the empty tag, or if a
   *                handler further down the filter chain raises an exception.
   * @see #emptyElement(String, String, String, Attributes)
   */
  public void emptyElement(String uri, String localName) throws SAXException {
    emptyElement(uri, localName, "", EMPTY_ATTS);
  }
  /**
   * Add an empty element without a Namespace URI, qname or attributes.
   * 
   * <p>
   * This method will supply an empty string for the qname, and empty string
   * for the Namespace URI, and an empty attribute list. It invokes
   * {@link #emptyElement(String, String, String, Attributes)} directly.
   * </p>
   * 
   * @param localName
   *            The element"s local name.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the empty tag, or if a
   *                handler further down the filter chain raises an exception.
   * @see #emptyElement(String, String, String, Attributes)
   */
  public void emptyElement(String localName) throws SAXException {
    emptyElement("", localName, "", EMPTY_ATTS);
  }
  /**
   * Write an element with character data content.
   * 
   * <p>
   * This is a convenience method to write a complete element with character
   * data content, including the start tag and end tag.
   * </p>
   * 
   * <p>
   * This method invokes
   * {@link #startElement(String, String, String, Attributes)}, followed by
   * {@link #characters(String)}, followed by
   * {@link #endElement(String, String, String)}.
   * </p>
   * 
   * @param uri
   *            The element"s Namespace URI.
   * @param localName
   *            The element"s local name.
   * @param qName
   *            The element"s default qualified name.
   * @param atts
   *            The element"s attributes.
   * @param content
   *            The character data content.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the empty tag, or if a
   *                handler further down the filter chain raises an exception.
   * @see #startElement(String, String, String, Attributes)
   * @see #characters(String)
   * @see #endElement(String, String, String)
   */
  public void dataElement(String uri, String localName, String qName,
      Attributes atts, String content) throws SAXException {
    startElement(uri, localName, qName, atts);
    characters(content);
    endElement(uri, localName, qName);
  }
  /**
   * Write an element with character data content but no attributes.
   * 
   * <p>
   * This is a convenience method to write a complete element with character
   * data content, including the start tag and end tag. This method provides
   * an empty string for the qname and an empty attribute list.
   * </p>
   * 
   * <p>
   * This method invokes
   * {@link #startElement(String, String, String, Attributes)}, followed by
   * {@link #characters(String)}, followed by
   * {@link #endElement(String, String, String)}.
   * </p>
   * 
   * @param uri
   *            The element"s Namespace URI.
   * @param localName
   *            The element"s local name.
   * @param content
   *            The character data content.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the empty tag, or if a
   *                handler further down the filter chain raises an exception.
   * @see #startElement(String, String, String, Attributes)
   * @see #characters(String)
   * @see #endElement(String, String, String)
   */
  public void dataElement(String uri, String localName, String content)
      throws SAXException {
    dataElement(uri, localName, "", EMPTY_ATTS, content);
  }
  /**
   * Write an element with character data content but no attributes or
   * Namespace URI.
   * 
   * <p>
   * This is a convenience method to write a complete element with character
   * data content, including the start tag and end tag. The method provides an
   * empty string for the Namespace URI, and empty string for the qualified
   * name, and an empty attribute list.
   * </p>
   * 
   * <p>
   * This method invokes
   * {@link #startElement(String, String, String, Attributes)}, followed by
   * {@link #characters(String)}, followed by
   * {@link #endElement(String, String, String)}.
   * </p>
   * 
   * @param localName
   *            The element"s local name.
   * @param content
   *            The character data content.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the empty tag, or if a
   *                handler further down the filter chain raises an exception.
   * @see #startElement(String, String, String, Attributes)
   * @see #characters(String)
   * @see #endElement(String, String, String)
   */
  public void dataElement(String localName, String content)
      throws SAXException {
    dataElement("", localName, "", EMPTY_ATTS, content);
  }
  /**
   * Write a string of character data, with XML escaping.
   * 
   * <p>
   * This is a convenience method that takes an XML String, converts it to a
   * character array, then invokes {@link #characters(char[], int, int)}.
   * </p>
   * 
   * @param data
   *            The character data.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the string, or if a handler
   *                further down the filter chain raises an exception.
   * @see #characters(char[], int, int)
   */
  public void characters(String data) throws SAXException {
    char ch[] = data.toCharArray();
    characters(ch, 0, ch.length);
  }
  // //////////////////////////////////////////////////////////////////
  // Internal methods.
  // //////////////////////////////////////////////////////////////////
  /**
   * Force all Namespaces to be declared.
   * 
   * This method is used on the root element to ensure that the predeclared
   * Namespaces all appear.
   */
  private void forceNSDecls() {
    Enumeration prefixes = forcedDeclTable.keys();
    while (prefixes.hasMoreElements()) {
      String prefix = (String) prefixes.nextElement();
      doPrefix(prefix, null, true);
    }
  }
  /**
   * Determine the prefix for an element or attribute name.
   * 
   * TODO: this method probably needs some cleanup.
   * 
   * @param uri
   *            The Namespace URI.
   * @param qName
   *            The qualified name (optional); this will be used to indicate
   *            the preferred prefix if none is currently bound.
   * @param isElement
   *            true if this is an element name, false if it is an attribute
   *            name (which cannot use the default Namespace).
   */
  private String doPrefix(String uri, String qName, boolean isElement) {
    String defaultNS = nsSupport.getURI("");
    if ("".equals(uri)) {
      if (isElement && defaultNS != null)
        nsSupport.declarePrefix("", "");
      return null;
    }
    String prefix;
    if (isElement && defaultNS != null && uri.equals(defaultNS)) {
      prefix = "";
    } else {
      prefix = nsSupport.getPrefix(uri);
    }
    if (prefix != null) {
      return prefix;
    }
    prefix = (String) doneDeclTable.get(uri);
    if (prefix != null
        && ((!isElement || defaultNS != null) && "".equals(prefix) || nsSupport
            .getURI(prefix) != null)) {
      prefix = null;
    }
    if (prefix == null) {
      prefix = (String) prefixTable.get(uri);
      if (prefix != null
          && ((!isElement || defaultNS != null) && "".equals(prefix) || nsSupport
              .getURI(prefix) != null)) {
        prefix = null;
      }
    }
    if (prefix == null && qName != null && !"".equals(qName)) {
      int i = qName.indexOf(":");
      if (i == -1) {
        if (isElement && defaultNS == null) {
          prefix = "";
        }
      } else {
        prefix = qName.substring(0, i);
      }
    }
    for (; prefix == null || nsSupport.getURI(prefix) != null; prefix = "__NS"
        + ++prefixCounter)
      ;
    nsSupport.declarePrefix(prefix, uri);
    doneDeclTable.put(uri, prefix);
    return prefix;
  }
  /**
   * Write a raw character.
   * 
   * @param c
   *            The character to write.
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the character, this method
   *                will throw an IOException wrapped in a SAXException.
   */
  private void write(char c) throws SAXException {
    try {
      output.write(c);
    } catch (IOException e) {
      throw new SAXException(e);
    }
  }
  /**
   * Write a raw string.
   * 
   * @param s
   * @exception org.xml.sax.SAXException
   *                If there is an error writing the string, this method will
   *                throw an IOException wrapped in a SAXException
   */
  private void write(String s) throws SAXException {
    try {
      output.write(s);
    } catch (IOException e) {
      throw new SAXException(e);
    }
  }
  /**
   * Write out an attribute list, escaping values.
   * 
   * The names will have prefixes added to them.
   * 
   * @param atts
   *            The attribute list to write.
   * @exception org.xml.SAXException
   *                If there is an error writing the attribute list, this
   *                method will throw an IOException wrapped in a
   *                SAXException.
   */
  private void writeAttributes(Attributes atts) throws SAXException {
    int len = atts.getLength();
    for (int i = 0; i < len; i++) {
      char ch[] = atts.getValue(i).toCharArray();
      write(" ");
      writeName(atts.getURI(i), atts.getLocalName(i), atts.getQName(i),
          false);
      write("=\"");
      writeEsc(ch, 0, ch.length, true);
      write(""");
    }
  }
  /**
   * Write an array of data characters with escaping.
   * 
   * @param ch
   *            The array of characters.
   * @param start
   *            The starting position.
   * @param length
   *            The number of characters to use.
   * @param isAttVal
   *            true if this is an attribute value literal.
   * @exception org.xml.SAXException
   *                If there is an error writing the characters, this method
   *                will throw an IOException wrapped in a SAXException.
   */
  private void writeEsc(char ch[], int start, int length, boolean isAttVal)
      throws SAXException {
    for (int i = start; i < start + length; i++) {
      switch (ch[i]) {
      case "&":
        write("&amp;");
        break;
      case "<":
        write("&lt;");
        break;
      case ">":
        write("&gt;");
        break;
      case "\"":
        if (isAttVal) {
          write("&quot;");
        } else {
          write("\"");
        }
        break;
      default:
        write(ch[i]);
      }
    }
  }
  /**
   * Write out the list of Namespace declarations.
   * 
   * @exception org.xml.sax.SAXException
   *                This method will throw an IOException wrapped in a
   *                SAXException if there is an error writing the Namespace
   *                declarations.
   */
  private void writeNSDecls() throws SAXException {
    Enumeration prefixes = nsSupport.getDeclaredPrefixes();
    while (prefixes.hasMoreElements()) {
      String prefix = (String) prefixes.nextElement();
      String uri = nsSupport.getURI(prefix);
      if (uri == null) {
        uri = "";
      }
      char ch[] = uri.toCharArray();
      write(" ");
      if ("".equals(prefix)) {
        write("xmlns=\"");
      } else {
        write("xmlns:");
        write(prefix);
        write("=\"");
      }
      writeEsc(ch, 0, ch.length, true);
      write("\"");
    }
  }
  /**
   * Write an element or attribute name.
   * 
   * @param uri
   *            The Namespace URI.
   * @param localName
   *            The local name.
   * @param qName
   *            The prefixed name, if available, or the empty string.
   * @param isElement
   *            true if this is an element name, false if it is an attribute
   *            name.
   * @exception org.xml.sax.SAXException
   *                This method will throw an IOException wrapped in a
   *                SAXException if there is an error writing the name.
   */
  private void writeName(String uri, String localName, String qName,
      boolean isElement) throws SAXException {
    String prefix = doPrefix(uri, qName, isElement);
    if (prefix != null && !"".equals(prefix)) {
      write(prefix);
      write(":");
    }
    if (localName != null && !"".equals(localName)) {
      write(localName);
    } else {
      int i = qName.indexOf(":");
      write(qName.substring(i + 1, qName.length()));
    }
  }
  // //////////////////////////////////////////////////////////////////
  // Default LexicalHandler implementation
  // //////////////////////////////////////////////////////////////////
  public void comment(char[] ch, int start, int length) throws SAXException {
    write("<!--");
    for (int i = start; i < start + length; i++) {
      write(ch[i]);
      if (ch[i] == "-" && i + 1 <= start + length && ch[i + 1] == "-")
        write(" ");
    }
    write("-->");
  }
  public void endCDATA() throws SAXException {
  }
  public void endDTD() throws SAXException {
  }
  public void endEntity(String name) throws SAXException {
  }
  public void startCDATA() throws SAXException {
  }
  public void startDTD(String name, String publicId, String systemId)
      throws SAXException {
  }
  public void startEntity(String name) throws SAXException {
  }
  // //////////////////////////////////////////////////////////////////
  // Output properties
  // //////////////////////////////////////////////////////////////////
  public String getOutputProperty(String key) {
    return outputProperties.getProperty(key);
  }
  public void setOutputProperty(String key, String value) {
    outputProperties.setProperty(key, value);
  }
  // //////////////////////////////////////////////////////////////////
  // Constants.
  // //////////////////////////////////////////////////////////////////
  private final Attributes EMPTY_ATTS = new AttributesImpl();
  public static final String CDATA_SECTION_ELEMENTS = "cdata-section-elements";
  public static final String DOCTYPE_PUBLIC = "doctype-public";
  public static final String DOCTYPE_SYSTEM = "doctype-system";
  public static final String ENCODING = "encoding";
  public static final String INDENT = "indent";
  public static final String MEDIA_TYPE = "media-type";
  public static final String METHOD = "method";
  public static final String OMIT_XML_DECLARATION = "omit-xml-declaration";
  public static final String STANDALONE = "standalone";
  public static final String VERSION = "version";
  // //////////////////////////////////////////////////////////////////
  // Internal state.
  // //////////////////////////////////////////////////////////////////
  private Hashtable prefixTable;
  private Hashtable forcedDeclTable;
  private Hashtable doneDeclTable;
  private int elementLevel = 0;
  private Writer output;
  private NamespaceSupport nsSupport;
  private int prefixCounter = 0;
  private Properties outputProperties;
  private boolean cdataElement = false;
}
// end of XMLWriter.java





Handling SAX errors during parsing

     
 
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
public class Main {
  public static void main(String[] argv) throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setValidating(true);
    SAXParser parser = factory.newSAXParser();
    SaxHandler handler = new SaxHandler();
    parser.parse("sample.xml", handler);
  }
}
class SaxHandler extends DefaultHandler {
  public void startElement(String uri, String localName, String qName, Attributes attrs)
      throws SAXException {
    if (qName.equals("order")) {
    }
  }
  public void error(SAXParseException ex) throws SAXException {
    System.out.println("ERROR: [at " + ex.getLineNumber() + "] " + ex);
  }
  public void fatalError(SAXParseException ex) throws SAXException {
    System.out.println("FATAL_ERROR: [at " + ex.getLineNumber() + "] " + ex);
  }
  public void warning(SAXParseException ex) throws SAXException {
    System.out.println("WARNING: [at " + ex.getLineNumber() + "] " + ex);
  }
}





Parsing XML Files with SAX

     
/*
<PHONEBOOK>
<PERSON>
 <NAME>Joe Wang</NAME>
 <EMAIL>joe@yourserver.ru</EMAIL>
 <TELEPHONE>202-999-9999</TELEPHONE>
 <WEB>www.jexp.ru</WEB>
</PERSON>
<PERSON>
 <NAME>Karol</name>
 <EMAIL>karol@yourserver.ru</EMAIL>
 <TELEPHONE>306-999-9999</TELEPHONE>
 <WEB>www.jexp.ru</WEB>
</PERSON>
<PERSON>
 <NAME>Green</NAME>
 <EMAIL>green@yourserver.ru</EMAIL>
 <TELEPHONE>202-414-9999</TELEPHONE>
 <WEB>www.jexp.ru</WEB>
</PERSON>
</PHONEBOOK>
*/
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class NameLister {
  public static void main(String args[]) {
    if (args.length != 1) {
      System.err.println("Usage: java NameLister xmlfile.xml");
      System.exit(-1);
    }
    try {
      SAXParserFactory factory = SAXParserFactory.newInstance();
      SAXParser saxParser = factory.newSAXParser();
      DefaultHandler handler = new DefaultHandler() {
        boolean name = false;
        public void startElement(String uri, String localName,
            String qName, Attributes attributes)
            throws SAXException {
          if (qName.equalsIgnoreCase("NAME")) {
            name = true;
          }
        }
        public void characters(char ch[], int start, int length)
            throws SAXException {
          if (name) {
            System.out.println("Name: "
                + new String(ch, start, length));
            name = false;
          }
        }
      };
      saxParser.parse(args[0], handler);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}





Produce a SAX stream from a DOM Document

 
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* $Id: DOM2SAX.java 627367 2008-02-13 12:03:30Z maxberger $ */

import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.AttributesImpl;
/**
 * Helper class that produces a SAX stream from a DOM Document.
 * <p>
 * Part of the code here copied and adapted from Apache Xalan-J, 
 * src/org/apache/xalan/xsltc/trax/DOM2SAX.java
 */
public class DOM2SAX {
    private static final String EMPTYSTRING = "";
    private static final String XMLNS_PREFIX = "xmlns";
    private ContentHandler contentHandler;
    private LexicalHandler lexicalHandler;
    
    private Map prefixes = new java.util.HashMap();
    
    /**
     * Main constructor
     * @param handler the ContentHandler to send SAX events to
     */
    public DOM2SAX(ContentHandler handler) {
        this.contentHandler = handler;
        if (handler instanceof LexicalHandler) {
            this.lexicalHandler = (LexicalHandler)handler;
        }
    }
    
    /**
     * Writes the given document using the given ContentHandler.
     * @param doc DOM document
     * @param fragment if false no startDocument() and endDocument() calls are issued.
     * @throws SAXException In case of a problem while writing XML
     */
    public void writeDocument(Document doc, boolean fragment) throws SAXException {
        if (!fragment) {
            contentHandler.startDocument();
        }
        for (Node n = doc.getFirstChild(); n != null;
                n = n.getNextSibling()) {
            writeNode(n);
        }
        if (!fragment) {
            contentHandler.endDocument();
        }
    }
    /**
     * Begin the scope of namespace prefix. Forward the event to the SAX handler
     * only if the prefix is unknown or it is mapped to a different URI.
     */
    private boolean startPrefixMapping(String prefix, String uri)
            throws SAXException {
        boolean pushed = true;
        Stack uriStack = (Stack)prefixes.get(prefix);
        if (uriStack != null) {
            if (uriStack.isEmpty()) {
                contentHandler.startPrefixMapping(prefix, uri);
                uriStack.push(uri);
            } else {
                final String lastUri = (String) uriStack.peek();
                if (!lastUri.equals(uri)) {
                    contentHandler.startPrefixMapping(prefix, uri);
                    uriStack.push(uri);
                } else {
                    pushed = false;
                }
            }
        } else {
            contentHandler.startPrefixMapping(prefix, uri);
            uriStack = new Stack();
            prefixes.put(prefix, uriStack);
            uriStack.push(uri);
        }
        return pushed;
    }
    /*
     * End the scope of a name prefix by popping it from the stack and passing
     * the event to the SAX Handler.
     */
    private void endPrefixMapping(String prefix) throws SAXException {
        final Stack uriStack = (Stack)prefixes.get(prefix);
        if (uriStack != null) {
            contentHandler.endPrefixMapping(prefix);
            uriStack.pop();
        }
    }
    /**
     * If the DOM was created using a DOM 1.0 API, the local name may be null.
     * If so, get the local name from the qualified name before generating the
     * SAX event.
     */
    private static String getLocalName(Node node) {
        final String localName = node.getLocalName();
        if (localName == null) {
            final String qname = node.getNodeName();
            final int col = qname.lastIndexOf(":");
            return (col > 0) ? qname.substring(col + 1) : qname;
        }
        return localName;
    }
    /**
     * Writes a node using the given writer.
     * @param node node to serialize
     * @throws SAXException In case of a problem while writing XML
     */
    private void writeNode(Node node) 
                throws SAXException {
        if (node == null) {
            return;
        }
        switch (node.getNodeType()) {
        case Node.ATTRIBUTE_NODE: // handled by ELEMENT_NODE
        case Node.DOCUMENT_FRAGMENT_NODE:
        case Node.DOCUMENT_TYPE_NODE:
        case Node.ENTITY_NODE:
        case Node.ENTITY_REFERENCE_NODE:
        case Node.NOTATION_NODE:
            // These node types are ignored!!!
            break;
        case Node.CDATA_SECTION_NODE:
            final String cdata = node.getNodeValue();
            if (lexicalHandler != null) {
                lexicalHandler.startCDATA();
                contentHandler.characters(cdata.toCharArray(), 0, cdata.length());
                lexicalHandler.endCDATA();
            } else {
                // in the case where there is no lex handler, we still
                // want the text of the cdate to make its way through.
                contentHandler.characters(cdata.toCharArray(), 0, cdata.length());
            }
            break;
        case Node.ruMENT_NODE: // should be handled!!!
            if (lexicalHandler != null) {
                final String value = node.getNodeValue();
                lexicalHandler.rument(value.toCharArray(), 0, value.length());
            }
            break;
        case Node.DOCUMENT_NODE:
            contentHandler.startDocument();
            Node next = node.getFirstChild();
            while (next != null) {
                writeNode(next);
                next = next.getNextSibling();
            }
            contentHandler.endDocument();
            break;
        case Node.ELEMENT_NODE:
            String prefix;
            List pushedPrefixes = new java.util.ArrayList();
            final AttributesImpl attrs = new AttributesImpl();
            final NamedNodeMap map = node.getAttributes();
            final int length = map.getLength();
            // Process all namespace declarations
            for (int i = 0; i < length; i++) {
                final Node attr = map.item(i);
                final String qnameAttr = attr.getNodeName();
                // Ignore everything but NS declarations here
                if (qnameAttr.startsWith(XMLNS_PREFIX)) {
                    final String uriAttr = attr.getNodeValue();
                    final int colon = qnameAttr.lastIndexOf(":");
                    prefix = (colon > 0) ? qnameAttr.substring(colon + 1)
                            : EMPTYSTRING;
                    if (startPrefixMapping(prefix, uriAttr)) {
                        pushedPrefixes.add(prefix);
                    }
                }
            }
            // Process all other attributes
            for (int i = 0; i < length; i++) {
                final Node attr = map.item(i);
                final String qnameAttr = attr.getNodeName();
                // Ignore NS declarations here
                if (!qnameAttr.startsWith(XMLNS_PREFIX)) {
                    final String uriAttr = attr.getNamespaceURI();
                    // Uri may be implicitly declared
                    if (uriAttr != null) {
                        final int colon = qnameAttr.lastIndexOf(":");
                        prefix = (colon > 0) ? qnameAttr.substring(0, colon)
                                : EMPTYSTRING;
                        if (startPrefixMapping(prefix, uriAttr)) {
                            pushedPrefixes.add(prefix);
                        }
                    }
                    // Add attribute to list
                    attrs.addAttribute(attr.getNamespaceURI(),
                            getLocalName(attr), qnameAttr, "CDATA", attr
                                    .getNodeValue());
                }
            }
            // Now process the element itself
            final String qname = node.getNodeName();
            final String uri = node.getNamespaceURI();
            final String localName = getLocalName(node);
            // Uri may be implicitly declared
            if (uri != null) {
                final int colon = qname.lastIndexOf(":");
                prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING;
                if (startPrefixMapping(prefix, uri)) {
                    pushedPrefixes.add(prefix);
                }
            }
            // Generate SAX event to start element
            contentHandler.startElement(uri, localName, qname, attrs);
            // Traverse all child nodes of the element (if any)
            next = node.getFirstChild();
            while (next != null) {
                writeNode(next);
                next = next.getNextSibling();
            }
            // Generate SAX event to close element
            contentHandler.endElement(uri, localName, qname);
            // Generate endPrefixMapping() for all pushed prefixes
            final int nPushedPrefixes = pushedPrefixes.size();
            for (int i = 0; i < nPushedPrefixes; i++) {
                endPrefixMapping((String)pushedPrefixes.get(i));
            }
            break;
        case Node.PROCESSING_INSTRUCTION_NODE:
            contentHandler.processingInstruction(node.getNodeName(), node.getNodeValue());
            break;
        case Node.TEXT_NODE:
            final String data = node.getNodeValue();
            contentHandler.characters(data.toCharArray(), 0, data.length());
            break;
        default:
            //nop
        }
    }
    
}





Provides a complete trace of SAX2 events for files parsed.

 
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import org.xml.sax.AttributeList;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.DocumentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.ParserAdapter;
import org.xml.sax.helpers.ParserFactory;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.ext.DeclHandler;
import org.xml.sax.ext.LexicalHandler;
/**
 * Provides a complete trace of SAX2 events for files parsed. This is
 * useful for making sure that a SAX parser implementation faithfully
 * communicates all information in the document to the SAX handlers.
 *
 * @author Andy Clark, IBM
 * @author Arnaud Le Hors, IBM
 *
 * @version $Id: DocumentTracer.java 447686 2006-09-19 02:38:34Z mrglavas $
 */
public class DocumentTracer
    extends DefaultHandler
    implements ContentHandler, DTDHandler, ErrorHandler, // SAX2
               DeclHandler, LexicalHandler, // SAX2 extensions
               DocumentHandler // deprecated in SAX2
    {
    //
    // Constants
    //
    // feature ids
    /** Namespaces feature id (http://xml.org/sax/features/namespaces). */
    protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces";
    
    /** Namespace prefixes feature id (http://xml.org/sax/features/namespace-prefixes). */
    protected static final String NAMESPACE_PREFIXES_FEATURE_ID = "http://xml.org/sax/features/namespace-prefixes";
    /** Validation feature id (http://xml.org/sax/features/validation). */
    protected static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation";
    /** Schema validation feature id (http://apache.org/xml/features/validation/schema). */
    protected static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema";
    /** Schema full checking feature id (http://apache.org/xml/features/validation/schema-full-checking). */
    protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking";
    
    /** Honour all schema locations feature id (http://apache.org/xml/features/honour-all-schemaLocations). */
    protected static final String HONOUR_ALL_SCHEMA_LOCATIONS_ID = "http://apache.org/xml/features/honour-all-schemaLocations";
    
    /** Validate schema annotations feature id (http://apache.org/xml/features/validate-annotations) */
    protected static final String VALIDATE_ANNOTATIONS_ID = "http://apache.org/xml/features/validate-annotations";
    
    /** Dynamic validation feature id (http://apache.org/xml/features/validation/dynamic). */
    protected static final String DYNAMIC_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/dynamic";
    
    /** Load external DTD feature id (http://apache.org/xml/features/nonvalidating/load-external-dtd). */
    protected static final String LOAD_EXTERNAL_DTD_FEATURE_ID = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
    
    /** XInclude feature id (http://apache.org/xml/features/xinclude). */
    protected static final String XINCLUDE_FEATURE_ID = "http://apache.org/xml/features/xinclude";
    
    /** XInclude fixup base URIs feature id (http://apache.org/xml/features/xinclude/fixup-base-uris). */
    protected static final String XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID = "http://apache.org/xml/features/xinclude/fixup-base-uris";
    
    /** XInclude fixup language feature id (http://apache.org/xml/features/xinclude/fixup-language). */
    protected static final String XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID = "http://apache.org/xml/features/xinclude/fixup-language";
    // property ids
    /** Lexical handler property id (http://xml.org/sax/properties/lexical-handler). */
    protected static final String LEXICAL_HANDLER_PROPERTY_ID = "http://xml.org/sax/properties/lexical-handler";
    // default settings
    /** Default parser name. */
    protected static final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
    /** Default namespaces support (true). */
    protected static final boolean DEFAULT_NAMESPACES = true;
    
    /** Default namespace prefixes (false). */
    protected static final boolean DEFAULT_NAMESPACE_PREFIXES = false;
    /** Default validation support (false). */
    protected static final boolean DEFAULT_VALIDATION = false;
    
    /** Default load external DTD (true). */
    protected static final boolean DEFAULT_LOAD_EXTERNAL_DTD = true;
    /** Default Schema validation support (false). */
    protected static final boolean DEFAULT_SCHEMA_VALIDATION = false;
    /** Default Schema full checking support (false). */
    protected static final boolean DEFAULT_SCHEMA_FULL_CHECKING = false;
    
    /** Default honour all schema locations (false). */
    protected static final boolean DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS = false;
    
    /** Default validate schema annotations (false). */
    protected static final boolean DEFAULT_VALIDATE_ANNOTATIONS = false;
    
    /** Default dynamic validation support (false). */
    protected static final boolean DEFAULT_DYNAMIC_VALIDATION = false;
    
    /** Default XInclude processing support (false). */
    protected static final boolean DEFAULT_XINCLUDE = false;
    
    /** Default XInclude fixup base URIs support (true). */
    protected static final boolean DEFAULT_XINCLUDE_FIXUP_BASE_URIS = true;
    
    /** Default XInclude fixup language support (true). */
    protected static final boolean DEFAULT_XINCLUDE_FIXUP_LANGUAGE = true;
    //
    // Data
    //
    /** Print writer. */
    protected PrintWriter fOut;
    /** Indent level. */
    protected int fIndent;
    //
    // Constructors
    //
    /** Default constructor. */
    public DocumentTracer() {
        setOutput(new PrintWriter(System.out));
    } // <init>()
    //
    // Public methods
    //
    /** Sets the output stream for printing. */
    public void setOutput(OutputStream stream, String encoding)
        throws UnsupportedEncodingException {
        if (encoding == null) {
            encoding = "UTF8";
        }
        Writer writer = new OutputStreamWriter(stream, encoding);
        fOut = new PrintWriter(writer);
    } // setOutput(OutputStream,String)
    /** Sets the output writer. */
    public void setOutput(Writer writer) {
        fOut = writer instanceof PrintWriter
             ? (PrintWriter)writer : new PrintWriter(writer);
    } // setOutput(Writer)
    //
    // ContentHandler and DocumentHandler methods
    //
    /** Set document locator. */
    public void setDocumentLocator(Locator locator) {
        printIndent();
        fOut.print("setDocumentLocator(");
        fOut.print("locator=");
        fOut.print(locator);
        fOut.println(")");
        fOut.flush();
    } // setDocumentLocator(Locator)
    /** Start document. */
    public void startDocument() throws SAXException {
        fIndent = 0;
        printIndent();
        fOut.println("startDocument()");
        fOut.flush();
        fIndent++;
    } // startDocument()
    /** Processing instruction. */
    public void processingInstruction(String target, String data)
        throws SAXException {
        printIndent();
        fOut.print("processingInstruction(");
        fOut.print("target=");
        printQuotedString(target);
        fOut.print(",");
        fOut.print("data=");
        printQuotedString(data);
        fOut.println(")");
        fOut.flush();
    } // processingInstruction(String,String)
    /** Characters. */
    public void characters(char[] ch, int offset, int length)
        throws SAXException {
        printIndent();
        fOut.print("characters(");
        fOut.print("text=");
        printQuotedString(ch, offset, length);
        fOut.println(")");
        fOut.flush();
    } // characters(char[],int,int)
    /** Ignorable whitespace. */
    public void ignorableWhitespace(char[] ch, int offset, int length)
        throws SAXException {
        printIndent();
        fOut.print("ignorableWhitespace(");
        fOut.print("text=");
        printQuotedString(ch, offset, length);
        fOut.println(")");
        fOut.flush();
    } // ignorableWhitespace(char[],int,int)
    /** End document. */
    public void endDocument() throws SAXException {
        fIndent--;
        printIndent();
        fOut.println("endDocument()");
        fOut.flush();
    } // endDocument()
    //
    // ContentHandler methods
    //
    /** Start prefix mapping. */
    public void startPrefixMapping(String prefix, String uri)
        throws SAXException {
        printIndent();
        fOut.print("startPrefixMapping(");
        fOut.print("prefix=");
        printQuotedString(prefix);
        fOut.print(",");
        fOut.print("uri=");
        printQuotedString(uri);
        fOut.println(")");
        fOut.flush();
    } // startPrefixMapping(String,String)
    /** Start element. */
    public void startElement(String uri, String localName, String qname,
                             Attributes attributes) throws SAXException {
        printIndent();
        fOut.print("startElement(");
        fOut.print("uri=");
        printQuotedString(uri);
        fOut.print(",");
        fOut.print("localName=");
        printQuotedString(localName);
        fOut.print(",");
        fOut.print("qname=");
        printQuotedString(qname);
        fOut.print(",");
        fOut.print("attributes=");
        if (attributes == null) {
            fOut.println("null");
        }
        else {
            fOut.print("{");
            int length = attributes.getLength();
            for (int i = 0; i < length; i++) {
                if (i > 0) {
                    fOut.print(",");
                }
                String attrLocalName = attributes.getLocalName(i);
                String attrQName = attributes.getQName(i);
                String attrURI = attributes.getURI(i);
                String attrType = attributes.getType(i);
                String attrValue = attributes.getValue(i);
                fOut.print("{");
                fOut.print("uri=");
                printQuotedString(attrURI);
                fOut.print(",");
                fOut.print("localName=");
                printQuotedString(attrLocalName);
                fOut.print(",");
                fOut.print("qname=");
                printQuotedString(attrQName);
                fOut.print(",");
                fOut.print("type=");
                printQuotedString(attrType);
                fOut.print(",");
                fOut.print("value=");
                printQuotedString(attrValue);
                fOut.print("}");
            }
            fOut.print("}");
        }
        fOut.println(")");
        fOut.flush();
        fIndent++;
    } // startElement(String,String,String,Attributes)
    /** End element. */
    public void endElement(String uri, String localName, String qname)
        throws SAXException {
        fIndent--;
        printIndent();
        fOut.print("endElement(");
        fOut.print("uri=");
        printQuotedString(uri);
        fOut.print(",");
        fOut.print("localName=");
        printQuotedString(localName);
        fOut.print(",");
        fOut.print("qname=");
        printQuotedString(qname);
        fOut.println(")");
        fOut.flush();
    } // endElement(String,String,String)
    /** End prefix mapping. */
    public void endPrefixMapping(String prefix) throws SAXException {
        printIndent();
        fOut.print("endPrefixMapping(");
        fOut.print("prefix=");
        printQuotedString(prefix);
        fOut.println(")");
        fOut.flush();
    } // endPrefixMapping(String)
    /** Skipped entity. */
    public void skippedEntity(String name) throws SAXException {
        printIndent();
        fOut.print("skippedEntity(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.println(")");
        fOut.flush();
    } // skippedEntity(String)
    //
    // DocumentHandler methods
    //
    /** Start element. */
    public void startElement(String name, AttributeList attributes)
        throws SAXException {
        printIndent();
        fOut.print("startElement(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.print(",");
        fOut.print("attributes=");
        if (attributes == null) {
            fOut.println("null");
        }
        else {
            fOut.print("{");
            int length = attributes.getLength();
            for (int i = 0; i < length; i++) {
                if (i > 0) {
                    System.out.print(",");
                }
                String attrName = attributes.getName(i);
                String attrType = attributes.getType(i);
                String attrValue = attributes.getValue(i);
                fOut.print("{");
                fOut.print("name=");
                printQuotedString(attrName);
                fOut.print(",");
                fOut.print("type=");
                printQuotedString(attrType);
                fOut.print(",");
                fOut.print("value=");
                printQuotedString(attrValue);
                fOut.print("}");
            }
            fOut.print("}");
        }
        fOut.println(")");
        fOut.flush();
        fIndent++;
    } // startElement(String,AttributeList)
    /** End element. */
    public void endElement(String name) throws SAXException {
        fIndent--;
        printIndent();
        fOut.print("endElement(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.println(")");
        fOut.flush();
    } // endElement(String)
    //
    // DTDHandler methods
    //
    /** Notation declaration. */
    public void notationDecl(String name, String publicId, String systemId)
        throws SAXException {
        printIndent();
        fOut.print("notationDecl(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.print(",");
        fOut.print("publicId=");
        printQuotedString(publicId);
        fOut.print(",");
        fOut.print("systemId=");
        printQuotedString(systemId);
        fOut.println(")");
        fOut.flush();
    } // notationDecl(String,String,String)
    /** Unparsed entity declaration. */
    public void unparsedEntityDecl(String name,
                                   String publicId, String systemId,
                                   String notationName) throws SAXException {
        printIndent();
        fOut.print("unparsedEntityDecl(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.print(",");
        fOut.print("publicId=");
        printQuotedString(publicId);
        fOut.print(",");
        fOut.print("systemId=");
        printQuotedString(systemId);
        fOut.print(",");
        fOut.print("notationName=");
        printQuotedString(notationName);
        fOut.println(")");
        fOut.flush();
    } // unparsedEntityDecl(String,String,String,String)
    //
    // LexicalHandler methods
    //
    /** Start DTD. */
    public void startDTD(String name, String publicId, String systemId)
        throws SAXException {
        printIndent();
        fOut.print("startDTD(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.print(",");
        fOut.print("publicId=");
        printQuotedString(publicId);
        fOut.print(",");
        fOut.print("systemId=");
        printQuotedString(systemId);
        fOut.println(")");
        fOut.flush();
        fIndent++;
    } // startDTD(String,String,String)
    /** Start entity. */
    public void startEntity(String name) throws SAXException {
        printIndent();
        fOut.print("startEntity(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.println(")");
        fOut.flush();
        fIndent++;
    } // startEntity(String)
    /** Start CDATA section. */
    public void startCDATA() throws SAXException {
        printIndent();
        fOut.println("startCDATA()");
        fOut.flush();
        fIndent++;
    } // startCDATA()
    /** End CDATA section. */
    public void endCDATA() throws SAXException {
        fIndent--;
        printIndent();
        fOut.println("endCDATA()");
        fOut.flush();
    } // endCDATA()
    /** Comment. */
    public void comment(char[] ch, int offset, int length)
        throws SAXException {
        printIndent();
        fOut.print("comment(");
        fOut.print("text=");
        printQuotedString(ch, offset, length);
        fOut.println(")");
        fOut.flush();
    } // comment(char[],int,int)
    /** End entity. */
    public void endEntity(String name) throws SAXException {
        fIndent--;
        printIndent();
        fOut.print("endEntity(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.println(")");
    } // endEntity(String)
    /** End DTD. */
    public void endDTD() throws SAXException {
        fIndent--;
        printIndent();
        fOut.println("endDTD()");
        fOut.flush();
    } // endDTD()
    //
    // DeclHandler methods
    //
    /** Element declaration. */
    public void elementDecl(String name, String contentModel)
        throws SAXException {
        printIndent();
        fOut.print("elementDecl(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.print(",");
        fOut.print("contentModel=");
        printQuotedString(contentModel);
        fOut.println(")");
        fOut.flush();
    } // elementDecl(String,String)
    /** Attribute declaration. */
    public void attributeDecl(String elementName, String attributeName,
                              String type, String valueDefault,
                              String value) throws SAXException {
        printIndent();
        fOut.print("attributeDecl(");
        fOut.print("elementName=");
        printQuotedString(elementName);
        fOut.print(",");
        fOut.print("attributeName=");
        printQuotedString(attributeName);
        fOut.print(",");
        fOut.print("type=");
        printQuotedString(type);
        fOut.print(",");
        fOut.print("valueDefault=");
        printQuotedString(valueDefault);
        fOut.print(",");
        fOut.print("value=");
        printQuotedString(value);
        fOut.println(")");
        fOut.flush();
    } // attributeDecl(String,String,String,String,String)
    /** Internal entity declaration. */
    public void internalEntityDecl(String name, String text)
        throws SAXException {
        printIndent();
        fOut.print("internalEntityDecl(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.print(",");
        fOut.print("text=");
        printQuotedString(text);
        fOut.println(")");
        fOut.flush();
    } // internalEntityDecl(String,String)
    /** External entity declaration. */
    public void externalEntityDecl(String name,
                                   String publicId, String systemId)
        throws SAXException {
        printIndent();
        fOut.print("externalEntityDecl(");
        fOut.print("name=");
        printQuotedString(name);
        fOut.print(",");
        fOut.print("publicId=");
        printQuotedString(publicId);
        fOut.print(",");
        fOut.print("systemId=");
        printQuotedString(systemId);
        fOut.println(")");
        fOut.flush();
    } // externalEntityDecl(String,String,String)
    //
    // ErrorHandler methods
    //
    /** Warning. */
    public void warning(SAXParseException ex) throws SAXException {
        printError("Warning", ex);
    } // warning(SAXParseException)
    /** Error. */
    public void error(SAXParseException ex) throws SAXException {
        printError("Error", ex);
    } // error(SAXParseException)
    /** Fatal error. */
    public void fatalError(SAXParseException ex) throws SAXException {
        printError("Fatal Error", ex);
        throw ex;
    } // fatalError(SAXParseException)
    //
    // Protected methods
    //
    /** Print quoted string. */
    protected void printQuotedString(String s) {
        if (s == null) {
            fOut.print("null");
            return;
        }
        fOut.print(""");
        int length = s.length();
        for (int i = 0; i < length; i++) {
            char c = s.charAt(i);
            normalizeAndPrint(c);
        }
        fOut.print(""");
    } // printQuotedString(String)
    /** Print quoted string. */
    protected void printQuotedString(char[] ch, int offset, int length) {
        fOut.print(""");
        for (int i = 0; i < length; i++) {
            normalizeAndPrint(ch[offset + i]);
        }
        fOut.print(""");
    } // printQuotedString(char[],int,int)
    /** Normalize and print. */
    protected void normalizeAndPrint(char c) {
        switch (c) {
            case "\n": {
                fOut.print("\\n");
                break;
            }
            case "\r": {
                fOut.print("\\r");
                break;
            }
            case "\t": {
                fOut.print("\\t");
                break;
            }
            case "\\": {
                fOut.print("\\\\");
                break;
            }
            case """: {
                fOut.print("\\\"");
                break;
            }
            default: {
                fOut.print(c);
            }
        }
    } // normalizeAndPrint(char)
    /** Prints the error message. */
    protected void printError(String type, SAXParseException ex) {
        System.err.print("[");
        System.err.print(type);
        System.err.print("] ");
        String systemId = ex.getSystemId();
        if (systemId != null) {
            int index = systemId.lastIndexOf("/");
            if (index != -1)
                systemId = systemId.substring(index + 1);
            System.err.print(systemId);
        }
        System.err.print(":");
        System.err.print(ex.getLineNumber());
        System.err.print(":");
        System.err.print(ex.getColumnNumber());
        System.err.print(": ");
        System.err.print(ex.getMessage());
        System.err.println();
        System.err.flush();
    } // printError(String,SAXParseException)
    /** Prints the indent. */
    protected void printIndent() {
        for (int i = 0; i < fIndent; i++) {
            fOut.print(" ");
        }
    }
    //
    // MAIN
    //
    /** Main. */
    public static void main(String[] argv) throws Exception {
        // is there anything to do?
        if (argv.length == 0) {
            printUsage();
            System.exit(1);
        }
        // variables
        DocumentTracer tracer = new DocumentTracer();
        PrintWriter out = new PrintWriter(System.out);
        XMLReader parser = null;
        boolean namespaces = DEFAULT_NAMESPACES;
        boolean namespacePrefixes = DEFAULT_NAMESPACE_PREFIXES;
        boolean validation = DEFAULT_VALIDATION;
        boolean externalDTD = DEFAULT_LOAD_EXTERNAL_DTD;
        boolean schemaValidation = DEFAULT_SCHEMA_VALIDATION;
        boolean schemaFullChecking = DEFAULT_SCHEMA_FULL_CHECKING;
        boolean honourAllSchemaLocations = DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS;
        boolean validateAnnotations = DEFAULT_VALIDATE_ANNOTATIONS;
        boolean dynamicValidation = DEFAULT_DYNAMIC_VALIDATION;
        boolean xincludeProcessing = DEFAULT_XINCLUDE;
        boolean xincludeFixupBaseURIs = DEFAULT_XINCLUDE_FIXUP_BASE_URIS;
        boolean xincludeFixupLanguage = DEFAULT_XINCLUDE_FIXUP_LANGUAGE;
        // process arguments
        for (int i = 0; i < argv.length; i++) {
            String arg = argv[i];
            if (arg.startsWith("-")) {
                String option = arg.substring(1);
                if (option.equals("p")) {
                    // get parser name
                    if (++i == argv.length) {
                        System.err.println("error: Missing argument to -p option.");
                    }
                    String parserName = argv[i];
                    // create parser
                    try {
                        parser = XMLReaderFactory.createXMLReader(parserName);
                    }
                    catch (Exception e) {
                        try {
                            Parser sax1Parser = ParserFactory.makeParser(parserName);
                            parser = new ParserAdapter(sax1Parser);
                            System.err.println("warning: Features and properties not supported on SAX1 parsers.");
                        }
                        catch (Exception ex) {
                            parser = null;
                            System.err.println("error: Unable to instantiate parser ("+parserName+")");
                        }
                    }
                    continue;
                }
                if (option.equalsIgnoreCase("n")) {
                    namespaces = option.equals("n");
                    continue;
                }
                if (option.equalsIgnoreCase("np")) {
                    namespacePrefixes = option.equals("np");
                    continue;
                }
                if (option.equalsIgnoreCase("v")) {
                    validation = option.equals("v");
                    continue;
                }
                if (option.equalsIgnoreCase("xd")) {
                    externalDTD = option.equals("xd");
                    continue;
                }
                if (option.equalsIgnoreCase("s")) {
                    schemaValidation = option.equals("s");
                    continue;
                }
                if (option.equalsIgnoreCase("f")) {
                    schemaFullChecking = option.equals("f");
                    continue;
                }
                if (option.equalsIgnoreCase("hs")) {
                    honourAllSchemaLocations = option.equals("hs");
                    continue;
                }
                if (option.equalsIgnoreCase("va")) {
                    validateAnnotations = option.equals("va");
                    continue;
                }
                if (option.equalsIgnoreCase("dv")) {
                    dynamicValidation = option.equals("dv");
                    continue;
                }
                if (option.equalsIgnoreCase("xi")) {
                    xincludeProcessing = option.equals("xi");
                    continue;
                }
                if (option.equalsIgnoreCase("xb")) {
                    xincludeFixupBaseURIs = option.equals("xb");
                    continue;
                }
                if (option.equalsIgnoreCase("xl")) {
                    xincludeFixupLanguage = option.equals("xl");
                    continue;
                }
                if (option.equals("h")) {
                    printUsage();
                    continue;
                }
            }
            // use default parser?
            if (parser == null) {
                // create parser
                try {
                    parser = XMLReaderFactory.createXMLReader(DEFAULT_PARSER_NAME);
                }
                catch (Exception e) {
                    System.err.println("error: Unable to instantiate parser ("+DEFAULT_PARSER_NAME+")");
                    continue;
                }
            }
            // set parser features
            try {
                parser.setFeature(NAMESPACES_FEATURE_ID, namespaces);
            }
            catch (SAXException e) {
                System.err.println("warning: Parser does not support feature ("+NAMESPACES_FEATURE_ID+")");
            }
            try {
                parser.setFeature(NAMESPACE_PREFIXES_FEATURE_ID, namespacePrefixes);
            }
            catch (SAXException e) {
                System.err.println("warning: Parser does not support feature ("+NAMESPACE_PREFIXES_FEATURE_ID+")");
            }
            try {
                parser.setFeature(VALIDATION_FEATURE_ID, validation);
            }
            catch (SAXException e) {
                System.err.println("warning: Parser does not support feature ("+VALIDATION_FEATURE_ID+")");
            }
            try {
                parser.setFeature(LOAD_EXTERNAL_DTD_FEATURE_ID, externalDTD);
            }
            catch (SAXNotRecognizedException e) {
                System.err.println("warning: Parser does not recognize feature ("+LOAD_EXTERNAL_DTD_FEATURE_ID+")");
            }
            catch (SAXNotSupportedException e) {
                System.err.println("warning: Parser does not support feature ("+LOAD_EXTERNAL_DTD_FEATURE_ID+")");
            }
            try {
                parser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, schemaValidation);
            }
            catch (SAXNotRecognizedException e) {
                System.err.println("warning: Parser does not recognize feature ("+SCHEMA_VALIDATION_FEATURE_ID+")");
            }
            catch (SAXNotSupportedException e) {
                System.err.println("warning: Parser does not support feature ("+SCHEMA_VALIDATION_FEATURE_ID+")");
            }
            try {
                parser.setFeature(SCHEMA_FULL_CHECKING_FEATURE_ID, schemaFullChecking);
            }
            catch (SAXNotRecognizedException e) {
                System.err.println("warning: Parser does not recognize feature ("+SCHEMA_FULL_CHECKING_FEATURE_ID+")");
            }
            catch (SAXNotSupportedException e) {
                System.err.println("warning: Parser does not support feature ("+SCHEMA_FULL_CHECKING_FEATURE_ID+")");
            }
            try {
                parser.setFeature(HONOUR_ALL_SCHEMA_LOCATIONS_ID, honourAllSchemaLocations);
            }
            catch (SAXNotRecognizedException e) {
                System.err.println("warning: Parser does not recognize feature ("+HONOUR_ALL_SCHEMA_LOCATIONS_ID+")");
            }
            catch (SAXNotSupportedException e) {
                System.err.println("warning: Parser does not support feature ("+HONOUR_ALL_SCHEMA_LOCATIONS_ID+")");
            }
            try {
                parser.setFeature(VALIDATE_ANNOTATIONS_ID, validateAnnotations);
            }
            catch (SAXNotRecognizedException e) {
                System.err.println("warning: Parser does not recognize feature ("+VALIDATE_ANNOTATIONS_ID+")");
            }
            catch (SAXNotSupportedException e) {
                System.err.println("warning: Parser does not support feature ("+VALIDATE_ANNOTATIONS_ID+")");
            }
            try {
                parser.setFeature(DYNAMIC_VALIDATION_FEATURE_ID, dynamicValidation);
            }
            catch (SAXNotRecognizedException e) {
                System.err.println("warning: Parser does not recognize feature ("+DYNAMIC_VALIDATION_FEATURE_ID+")");
            }
            catch (SAXNotSupportedException e) {
                System.err.println("warning: Parser does not support feature ("+DYNAMIC_VALIDATION_FEATURE_ID+")");
            }
            try {
                parser.setFeature(XINCLUDE_FEATURE_ID, xincludeProcessing);
            }
            catch (SAXNotRecognizedException e) {
                System.err.println("warning: Parser does not recognize feature ("+XINCLUDE_FEATURE_ID+")");
            }
            catch (SAXNotSupportedException e) {
                System.err.println("warning: Parser does not support feature ("+XINCLUDE_FEATURE_ID+")");
            }
            try {
                parser.setFeature(XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID, xincludeFixupBaseURIs);
            }
            catch (SAXNotRecognizedException e) {
                System.err.println("warning: Parser does not recognize feature ("+XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID+")");
            }
            catch (SAXNotSupportedException e) {
                System.err.println("warning: Parser does not support feature ("+XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID+")");
            }
            try {
                parser.setFeature(XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID, xincludeFixupLanguage);
            }
            catch (SAXNotRecognizedException e) {
                System.err.println("warning: Parser does not recognize feature ("+XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID+")");
            }
            catch (SAXNotSupportedException e) {
                System.err.println("warning: Parser does not support feature ("+XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID+")");
            }
            // set handlers
            parser.setDTDHandler(tracer);
            parser.setErrorHandler(tracer);
            if (parser instanceof XMLReader) {
                parser.setContentHandler(tracer);
                try {
                    parser.setProperty("http://xml.org/sax/properties/declaration-handler", tracer);
                }
                catch (SAXException e) {
                    e.printStackTrace(System.err);
                }
                try {
                    parser.setProperty("http://xml.org/sax/properties/lexical-handler", tracer);
                }
                catch (SAXException e) {
                    e.printStackTrace(System.err);
                }
            }
            else {
                ((Parser)parser).setDocumentHandler(tracer);
            }
            // parse file
            try {
                parser.parse(arg);
            }
            catch (SAXParseException e) {
                // ignore
            }
            catch (Exception e) {
                System.err.println("error: Parse error occurred - "+e.getMessage());
                if (e instanceof SAXException) {
                    Exception nested = ((SAXException)e).getException();
                    if (nested != null) {
                     e = nested;
                    }
                }
                e.printStackTrace(System.err);
            }
        }
    } // main(String[])
    //
    // Private static methods
    //
    /** Prints the usage. */
    private static void printUsage() {
        System.err.println("usage: java sax.DocumentTracer (options) uri ...");
        System.err.println();
        System.err.println("options:");
        System.err.println("  -p name     Select parser by name.");
        System.err.println("  -n  | -N    Turn on/off namespace processing.");
        System.err.println("  -np | -NP   Turn on/off namespace prefixes.");
        System.err.println("              NOTE: Requires use of -n.");
        System.err.println("  -v  | -V    Turn on/off validation.");
        System.err.println("  -xd | -XD   Turn on/off loading of external DTDs.");
        System.err.println("              NOTE: Always on when -v in use and not supported by all parsers.");
        System.err.println("  -s  | -S    Turn on/off Schema validation support.");
        System.err.println("              NOTE: Not supported by all parsers.");
        System.err.println("  -f  | -F    Turn on/off Schema full checking.");
        System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
        System.err.println("  -hs | -HS   Turn on/off honouring of all schema locations.");
        System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
        System.err.println("  -va | -VA   Turn on/off validation of schema annotations.");
        System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
        System.err.println("  -dv | -DV   Turn on/off dynamic validation.");
        System.err.println("              NOTE: Not supported by all parsers.");
        System.err.println("  -xi | -XI   Turn on/off XInclude processing.");
        System.err.println("              NOTE: Not supported by all parsers.");
        System.err.println("  -xb | -XB   Turn on/off base URI fixup during XInclude processing.");
        System.err.println("              NOTE: Requires use of -xi and not supported by all parsers.");
        System.err.println("  -xl | -XL   Turn on/off language fixup during XInclude processing.");
        System.err.println("              NOTE: Requires use of -xi and not supported by all parsers.");
        System.err.println("  -h          This help screen.");
        System.err.println();
        System.err.println("defaults:");
        System.err.println("  Parser:     "+DEFAULT_PARSER_NAME);
        System.err.print("  Namespaces: ");
        System.err.println(DEFAULT_NAMESPACES ? "on" : "off");
        System.err.print("  Prefixes:   ");
        System.err.println(DEFAULT_NAMESPACE_PREFIXES ? "on" : "off");
        System.err.print("  Validation: ");
        System.err.println(DEFAULT_VALIDATION ? "on" : "off");
        System.err.print("  Load External DTD: ");
        System.err.println(DEFAULT_LOAD_EXTERNAL_DTD ? "on" : "off");
        System.err.print("  Schema:     ");
        System.err.println(DEFAULT_SCHEMA_VALIDATION ? "on" : "off");
        System.err.print("  Schema full checking:            ");
        System.err.println(DEFAULT_SCHEMA_FULL_CHECKING ? "on" : "off");
        System.err.print("  Honour all schema locations:     ");
        System.err.println(DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS ? "on" : "off");
        System.err.print("  Validate annotations:            ");
        System.err.println(DEFAULT_VALIDATE_ANNOTATIONS ? "on" : "off");
        System.err.print("  Dynamic:    ");
        System.err.println(DEFAULT_DYNAMIC_VALIDATION ? "on" : "off");
        System.err.print("  XInclude:   ");
        System.err.println(DEFAULT_XINCLUDE ? "on" : "off");
        System.err.print("  XInclude base URI fixup:  ");
        System.err.println(DEFAULT_XINCLUDE_FIXUP_BASE_URIS ? "on" : "off");
        System.err.print("  XInclude language fixup:  ");
        System.err.println(DEFAULT_XINCLUDE_FIXUP_LANGUAGE ? "on" : "off");
    } // printUsage()
} // class DocumentTracer





Register a SAX2 ContentHandler and receive callbacks to print information about the document.

 
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.PrintWriter;
import org.xml.sax.Attributes;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.ParserAdapter;
import org.xml.sax.helpers.ParserFactory;
import org.xml.sax.helpers.XMLReaderFactory;
/**
 * A sample SAX2 counter. This sample program illustrates how to register a SAX2
 * ContentHandler and receive the callbacks in order to print information about
 * the document. The output of this program shows the time and count of
 * elements, attributes, ignorable whitespaces, and characters appearing in the
 * document.
 * <p>
 * This class is useful as a "poor-man"s" performance tester to compare the
 * speed and accuracy of various SAX parsers. However, it is important to note
 * that the first parse time of a parser will include both VM class load time
 * and parser initialization that would not be present in subsequent parses with
 * the same file.
 * <p>
 * <strong>Note:</strong> The results produced by this program should never be
 * accepted as true performance measurements.
 * 
 * @author Andy Clark, IBM
 * 
 * @version $Id: Counter.java 447686 2006-09-19 02:38:34Z mrglavas $
 */
public class Counter extends DefaultHandler {
  //
  // Constants
  //
  // feature ids
  /** Namespaces feature id (http://xml.org/sax/features/namespaces). */
  protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces";
  /**
   * Namespace prefixes feature id
   * (http://xml.org/sax/features/namespace-prefixes).
   */
  protected static final String NAMESPACE_PREFIXES_FEATURE_ID = "http://xml.org/sax/features/namespace-prefixes";
  /** Validation feature id (http://xml.org/sax/features/validation). */
  protected static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation";
  /**
   * Schema validation feature id
   * (http://apache.org/xml/features/validation/schema).
   */
  protected static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema";
  /**
   * Schema full checking feature id
   * (http://apache.org/xml/features/validation/schema-full-checking).
   */
  protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking";
  /**
   * Honour all schema locations feature id
   * (http://apache.org/xml/features/honour-all-schemaLocations).
   */
  protected static final String HONOUR_ALL_SCHEMA_LOCATIONS_ID = "http://apache.org/xml/features/honour-all-schemaLocations";
  /**
   * Validate schema annotations feature id
   * (http://apache.org/xml/features/validate-annotations)
   */
  protected static final String VALIDATE_ANNOTATIONS_ID = "http://apache.org/xml/features/validate-annotations";
  /**
   * Dynamic validation feature id
   * (http://apache.org/xml/features/validation/dynamic).
   */
  protected static final String DYNAMIC_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/dynamic";
  /** XInclude feature id (http://apache.org/xml/features/xinclude). */
  protected static final String XINCLUDE_FEATURE_ID = "http://apache.org/xml/features/xinclude";
  /**
   * XInclude fixup base URIs feature id
   * (http://apache.org/xml/features/xinclude/fixup-base-uris).
   */
  protected static final String XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID = "http://apache.org/xml/features/xinclude/fixup-base-uris";
  /**
   * XInclude fixup language feature id
   * (http://apache.org/xml/features/xinclude/fixup-language).
   */
  protected static final String XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID = "http://apache.org/xml/features/xinclude/fixup-language";
  // default settings
  /** Default parser name. */
  protected static final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
  /** Default repetition (1). */
  protected static final int DEFAULT_REPETITION = 1;
  /** Default namespaces support (true). */
  protected static final boolean DEFAULT_NAMESPACES = true;
  /** Default namespace prefixes (false). */
  protected static final boolean DEFAULT_NAMESPACE_PREFIXES = false;
  /** Default validation support (false). */
  protected static final boolean DEFAULT_VALIDATION = false;
  /** Default Schema validation support (false). */
  protected static final boolean DEFAULT_SCHEMA_VALIDATION = false;
  /** Default Schema full checking support (false). */
  protected static final boolean DEFAULT_SCHEMA_FULL_CHECKING = false;
  /** Default honour all schema locations (false). */
  protected static final boolean DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS = false;
  /** Default validate schema annotations (false). */
  protected static final boolean DEFAULT_VALIDATE_ANNOTATIONS = false;
  /** Default dynamic validation support (false). */
  protected static final boolean DEFAULT_DYNAMIC_VALIDATION = false;
  /** Default XInclude processing support (false). */
  protected static final boolean DEFAULT_XINCLUDE = false;
  /** Default XInclude fixup base URIs support (true). */
  protected static final boolean DEFAULT_XINCLUDE_FIXUP_BASE_URIS = true;
  /** Default XInclude fixup language support (true). */
  protected static final boolean DEFAULT_XINCLUDE_FIXUP_LANGUAGE = true;
  /** Default memory usage report (false). */
  protected static final boolean DEFAULT_MEMORY_USAGE = false;
  /** Default "tagginess" report (false). */
  protected static final boolean DEFAULT_TAGGINESS = false;
  //
  // Data
  //
  /** Number of elements. */
  protected long fElements;
  /** Number of attributes. */
  protected long fAttributes;
  /** Number of characters. */
  protected long fCharacters;
  /** Number of ignorable whitespace characters. */
  protected long fIgnorableWhitespace;
  /** Number of characters of tags. */
  protected long fTagCharacters;
  /** Number of other content characters for the "tagginess" calculation. */
  protected long fOtherCharacters;
  //
  // Constructors
  //
  /** Default constructor. */
  public Counter() {
  } // <init>()
  //
  // Public methods
  //
  /** Prints the results. */
  public void printResults(PrintWriter out, String uri, long time, long memory, boolean tagginess,
      int repetition) {
    // filename.xml: 631 ms (4 elems, 0 attrs, 78 spaces, 0 chars)
    out.print(uri);
    out.print(": ");
    if (repetition == 1) {
      out.print(time);
    } else {
      out.print(time);
      out.print("/");
      out.print(repetition);
      out.print("=");
      out.print(time / repetition);
    }
    out.print(" ms");
    if (memory != Long.MIN_VALUE) {
      out.print(", ");
      out.print(memory);
      out.print(" bytes");
    }
    out.print(" (");
    out.print(fElements);
    out.print(" elems, ");
    out.print(fAttributes);
    out.print(" attrs, ");
    out.print(fIgnorableWhitespace);
    out.print(" spaces, ");
    out.print(fCharacters);
    out.print(" chars)");
    if (tagginess) {
      out.print(" ");
      long totalCharacters = fTagCharacters + fOtherCharacters + fCharacters + fIgnorableWhitespace;
      long tagValue = fTagCharacters * 100 / totalCharacters;
      out.print(tagValue);
      out.print("% tagginess");
    }
    out.println();
    out.flush();
  } // printResults(PrintWriter,String,long)
  //
  // ContentHandler methods
  //
  /** Start document. */
  public void startDocument() throws SAXException {
    fElements = 0;
    fAttributes = 0;
    fCharacters = 0;
    fIgnorableWhitespace = 0;
    fTagCharacters = 0;
  } // startDocument()
  /** Start element. */
  public void startElement(String uri, String local, String raw, Attributes attrs)
      throws SAXException {
    fElements++;
    fTagCharacters++; // open angle bracket
    fTagCharacters += raw.length();
    if (attrs != null) {
      int attrCount = attrs.getLength();
      fAttributes += attrCount;
      for (int i = 0; i < attrCount; i++) {
        fTagCharacters++; // space
        fTagCharacters += attrs.getQName(i).length();
        fTagCharacters++; // "="
        fTagCharacters++; // open quote
        fOtherCharacters += attrs.getValue(i).length();
        fTagCharacters++; // close quote
      }
    }
    fTagCharacters++; // close angle bracket
  } // startElement(String,String,StringAttributes)
  /** Characters. */
  public void characters(char ch[], int start, int length) throws SAXException {
    fCharacters += length;
  } // characters(char[],int,int);
  /** Ignorable whitespace. */
  public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
    fIgnorableWhitespace += length;
  } // ignorableWhitespace(char[],int,int);
  /** Processing instruction. */
  public void processingInstruction(String target, String data) throws SAXException {
    fTagCharacters += 2; // "<?"
    fTagCharacters += target.length();
    if (data != null && data.length() > 0) {
      fTagCharacters++; // space
      fOtherCharacters += data.length();
    }
    fTagCharacters += 2; // "?>"
  } // processingInstruction(String,String)
  //
  // ErrorHandler methods
  //
  /** Warning. */
  public void warning(SAXParseException ex) throws SAXException {
    printError("Warning", ex);
  } // warning(SAXParseException)
  /** Error. */
  public void error(SAXParseException ex) throws SAXException {
    printError("Error", ex);
  } // error(SAXParseException)
  /** Fatal error. */
  public void fatalError(SAXParseException ex) throws SAXException {
    printError("Fatal Error", ex);
    // throw ex;
  } // fatalError(SAXParseException)
  //
  // Protected methods
  //
  /** Prints the error message. */
  protected void printError(String type, SAXParseException ex) {
    System.err.print("[");
    System.err.print(type);
    System.err.print("] ");
    if (ex == null) {
      System.out.println("!!!");
    }
    String systemId = ex.getSystemId();
    if (systemId != null) {
      int index = systemId.lastIndexOf("/");
      if (index != -1)
        systemId = systemId.substring(index + 1);
      System.err.print(systemId);
    }
    System.err.print(":");
    System.err.print(ex.getLineNumber());
    System.err.print(":");
    System.err.print(ex.getColumnNumber());
    System.err.print(": ");
    System.err.print(ex.getMessage());
    System.err.println();
    System.err.flush();
  } // printError(String,SAXParseException)
  //
  // MAIN
  //
  /** Main program entry point. */
  public static void main(String argv[]) {
    // is there anything to do?
    if (argv.length == 0) {
      printUsage();
      System.exit(1);
    }
    // variables
    Counter counter = new Counter();
    PrintWriter out = new PrintWriter(System.out);
    XMLReader parser = null;
    int repetition = DEFAULT_REPETITION;
    boolean namespaces = DEFAULT_NAMESPACES;
    boolean namespacePrefixes = DEFAULT_NAMESPACE_PREFIXES;
    boolean validation = DEFAULT_VALIDATION;
    boolean schemaValidation = DEFAULT_SCHEMA_VALIDATION;
    boolean schemaFullChecking = DEFAULT_SCHEMA_FULL_CHECKING;
    boolean honourAllSchemaLocations = DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS;
    boolean validateAnnotations = DEFAULT_VALIDATE_ANNOTATIONS;
    boolean dynamicValidation = DEFAULT_DYNAMIC_VALIDATION;
    boolean xincludeProcessing = DEFAULT_XINCLUDE;
    boolean xincludeFixupBaseURIs = DEFAULT_XINCLUDE_FIXUP_BASE_URIS;
    boolean xincludeFixupLanguage = DEFAULT_XINCLUDE_FIXUP_LANGUAGE;
    boolean memoryUsage = DEFAULT_MEMORY_USAGE;
    boolean tagginess = DEFAULT_TAGGINESS;
    // process arguments
    for (int i = 0; i < argv.length; i++) {
      String arg = argv[i];
      if (arg.startsWith("-")) {
        String option = arg.substring(1);
        if (option.equals("p")) {
          // get parser name
          if (++i == argv.length) {
            System.err.println("error: Missing argument to -p option.");
            continue;
          }
          String parserName = argv[i];
          // create parser
          try {
            parser = XMLReaderFactory.createXMLReader(parserName);
          } catch (Exception e) {
            try {
              Parser sax1Parser = ParserFactory.makeParser(parserName);
              parser = new ParserAdapter(sax1Parser);
              System.err.println("warning: Features and properties not supported on SAX1 parsers.");
            } catch (Exception ex) {
              parser = null;
              System.err.println("error: Unable to instantiate parser (" + parserName + ")");
            }
          }
          continue;
        }
        if (option.equals("x")) {
          if (++i == argv.length) {
            System.err.println("error: Missing argument to -x option.");
            continue;
          }
          String number = argv[i];
          try {
            int value = Integer.parseInt(number);
            if (value < 1) {
              System.err.println("error: Repetition must be at least 1.");
              continue;
            }
            repetition = value;
          } catch (NumberFormatException e) {
            System.err.println("error: invalid number (" + number + ").");
          }
          continue;
        }
        if (option.equalsIgnoreCase("n")) {
          namespaces = option.equals("n");
          continue;
        }
        if (option.equalsIgnoreCase("np")) {
          namespacePrefixes = option.equals("np");
          continue;
        }
        if (option.equalsIgnoreCase("v")) {
          validation = option.equals("v");
          continue;
        }
        if (option.equalsIgnoreCase("s")) {
          schemaValidation = option.equals("s");
          continue;
        }
        if (option.equalsIgnoreCase("f")) {
          schemaFullChecking = option.equals("f");
          continue;
        }
        if (option.equalsIgnoreCase("hs")) {
          honourAllSchemaLocations = option.equals("hs");
          continue;
        }
        if (option.equalsIgnoreCase("va")) {
          validateAnnotations = option.equals("va");
          continue;
        }
        if (option.equalsIgnoreCase("dv")) {
          dynamicValidation = option.equals("dv");
          continue;
        }
        if (option.equalsIgnoreCase("xi")) {
          xincludeProcessing = option.equals("xi");
          continue;
        }
        if (option.equalsIgnoreCase("xb")) {
          xincludeFixupBaseURIs = option.equals("xb");
          continue;
        }
        if (option.equalsIgnoreCase("xl")) {
          xincludeFixupLanguage = option.equals("xl");
          continue;
        }
        if (option.equalsIgnoreCase("m")) {
          memoryUsage = option.equals("m");
          continue;
        }
        if (option.equalsIgnoreCase("t")) {
          tagginess = option.equals("t");
          continue;
        }
        if (option.equals("-rem")) {
          if (++i == argv.length) {
            System.err.println("error: Missing argument to -# option.");
            continue;
          }
          System.out.print("# ");
          System.out.println(argv[i]);
          continue;
        }
        if (option.equals("h")) {
          printUsage();
          continue;
        }
        System.err.println("error: unknown option (" + option + ").");
        continue;
      }
      // use default parser?
      if (parser == null) {
        // create parser
        try {
          parser = XMLReaderFactory.createXMLReader(DEFAULT_PARSER_NAME);
        } catch (Exception e) {
          System.err.println("error: Unable to instantiate parser (" + DEFAULT_PARSER_NAME + ")");
          continue;
        }
      }
      // set parser features
      try {
        parser.setFeature(NAMESPACES_FEATURE_ID, namespaces);
      } catch (SAXException e) {
        System.err.println("warning: Parser does not support feature (" + NAMESPACES_FEATURE_ID
            + ")");
      }
      try {
        parser.setFeature(NAMESPACE_PREFIXES_FEATURE_ID, namespacePrefixes);
      } catch (SAXException e) {
        System.err.println("warning: Parser does not support feature ("
            + NAMESPACE_PREFIXES_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(VALIDATION_FEATURE_ID, validation);
      } catch (SAXException e) {
        System.err.println("warning: Parser does not support feature (" + VALIDATION_FEATURE_ID
            + ")");
      }
      try {
        parser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, schemaValidation);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + SCHEMA_VALIDATION_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + SCHEMA_VALIDATION_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(SCHEMA_FULL_CHECKING_FEATURE_ID, schemaFullChecking);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + SCHEMA_FULL_CHECKING_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + SCHEMA_FULL_CHECKING_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(HONOUR_ALL_SCHEMA_LOCATIONS_ID, honourAllSchemaLocations);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + HONOUR_ALL_SCHEMA_LOCATIONS_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + HONOUR_ALL_SCHEMA_LOCATIONS_ID + ")");
      }
      try {
        parser.setFeature(VALIDATE_ANNOTATIONS_ID, validateAnnotations);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature (" + VALIDATE_ANNOTATIONS_ID
            + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature (" + VALIDATE_ANNOTATIONS_ID
            + ")");
      }
      try {
        parser.setFeature(DYNAMIC_VALIDATION_FEATURE_ID, dynamicValidation);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + DYNAMIC_VALIDATION_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + DYNAMIC_VALIDATION_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(XINCLUDE_FEATURE_ID, xincludeProcessing);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature (" + XINCLUDE_FEATURE_ID
            + ")");
      } catch (SAXNotSupportedException e) {
        System.err
            .println("warning: Parser does not support feature (" + XINCLUDE_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID, xincludeFixupBaseURIs);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID, xincludeFixupLanguage);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID + ")");
      }
      // parse file
      parser.setContentHandler(counter);
      parser.setErrorHandler(counter);
      try {
        long timeBefore = System.currentTimeMillis();
        long memoryBefore = Runtime.getRuntime().freeMemory();
        for (int j = 0; j < repetition; j++) {
          parser.parse(arg);
        }
        long memoryAfter = Runtime.getRuntime().freeMemory();
        long timeAfter = System.currentTimeMillis();
        long time = timeAfter - timeBefore;
        long memory = memoryUsage ? memoryBefore - memoryAfter : Long.MIN_VALUE;
        counter.printResults(out, arg, time, memory, tagginess, repetition);
      } catch (SAXParseException e) {
        // ignore
      } catch (Exception e) {
        System.err.println("error: Parse error occurred - " + e.getMessage());
        Exception se = e;
        if (e instanceof SAXException) {
          se = ((SAXException) e).getException();
        }
        if (se != null)
          se.printStackTrace(System.err);
        else
          e.printStackTrace(System.err);
      }
    }
  } // main(String[])
  //
  // Private static methods
  //
  /** Prints the usage. */
  private static void printUsage() {
    System.err.println("usage: java sax.Counter (options) uri ...");
    System.err.println();
    System.err.println("options:");
    System.err.println("  -p name     Select parser by name.");
    System.err.println("  -x number   Select number of repetitions.");
    System.err.println("  -n  | -N    Turn on/off namespace processing.");
    System.err.println("  -np | -NP   Turn on/off namespace prefixes.");
    System.err.println("              NOTE: Requires use of -n.");
    System.err.println("  -v  | -V    Turn on/off validation.");
    System.err.println("  -s  | -S    Turn on/off Schema validation support.");
    System.err.println("              NOTE: Not supported by all parsers.");
    System.err.println("  -f  | -F    Turn on/off Schema full checking.");
    System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
    System.err.println("  -hs | -HS   Turn on/off honouring of all schema locations.");
    System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
    System.err.println("  -va | -VA   Turn on/off validation of schema annotations.");
    System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
    System.err.println("  -dv | -DV   Turn on/off dynamic validation.");
    System.err.println("              NOTE: Not supported by all parsers.");
    System.err.println("  -xi | -XI   Turn on/off XInclude processing.");
    System.err.println("              NOTE: Not supported by all parsers.");
    System.err.println("  -xb | -XB   Turn on/off base URI fixup during XInclude processing.");
    System.err.println("              NOTE: Requires use of -xi and not supported by all parsers.");
    System.err.println("  -xl | -XL   Turn on/off language fixup during XInclude processing.");
    System.err.println("              NOTE: Requires use of -xi and not supported by all parsers.");
    System.err.println("  -m  | -M    Turn on/off memory usage report");
    System.err.println("  -t  | -T    Turn on/off \"tagginess\" report.");
    System.err.println("  --rem text  Output user defined comment before next parse.");
    System.err.println("  -h          This help screen.");
    System.err.println();
    System.err.println("defaults:");
    System.err.println("  Parser:     " + DEFAULT_PARSER_NAME);
    System.err.println("  Repetition: " + DEFAULT_REPETITION);
    System.err.print("  Namespaces: ");
    System.err.println(DEFAULT_NAMESPACES ? "on" : "off");
    System.err.print("  Prefixes:   ");
    System.err.println(DEFAULT_NAMESPACE_PREFIXES ? "on" : "off");
    System.err.print("  Validation: ");
    System.err.println(DEFAULT_VALIDATION ? "on" : "off");
    System.err.print("  Schema:     ");
    System.err.println(DEFAULT_SCHEMA_VALIDATION ? "on" : "off");
    System.err.print("  Schema full checking:            ");
    System.err.println(DEFAULT_SCHEMA_FULL_CHECKING ? "on" : "off");
    System.err.print("  Honour all schema locations:     ");
    System.err.println(DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS ? "on" : "off");
    System.err.print("  Validate annotations:            ");
    System.err.println(DEFAULT_VALIDATE_ANNOTATIONS ? "on" : "off");
    System.err.print("  Dynamic:    ");
    System.err.println(DEFAULT_DYNAMIC_VALIDATION ? "on" : "off");
    System.err.print("  XInclude:   ");
    System.err.println(DEFAULT_XINCLUDE ? "on" : "off");
    System.err.print("  XInclude base URI fixup:  ");
    System.err.println(DEFAULT_XINCLUDE_FIXUP_BASE_URIS ? "on" : "off");
    System.err.print("  XInclude language fixup:  ");
    System.err.println(DEFAULT_XINCLUDE_FIXUP_LANGUAGE ? "on" : "off");
    System.err.print("  Memory:     ");
    System.err.println(DEFAULT_MEMORY_USAGE ? "on" : "off");
    System.err.print("  Tagginess:  ");
    System.err.println(DEFAULT_TAGGINESS ? "on" : "off");
    System.err.println();
    System.err.println("notes:");
    System.err
        .println("  The speed and memory results from this program should NOT be used as the");
    System.err
        .println("  basis of parser performance comparison! Real analytical methods should be");
    System.err
        .println("  used. For better results, perform multiple document parses within the same");
    System.err
        .println("  virtual machine to remove class loading from parse time and memory usage.");
    System.err.println();
    System.err
        .println("  The \"tagginess\" measurement gives a rough estimate of the percentage of");
    System.err.println("  markup versus content in the XML document. The percent tagginess of a ");
    System.err.println("  document is equal to the minimum amount of tag characters required for ");
    System.err.println("  elements, attributes, and processing instructions divided by the total");
    System.err
        .println("  amount of characters (characters, ignorable whitespace, and tag characters)");
    System.err.println("  in the document.");
    System.err.println();
    System.err.println("  Not all features are supported by different parsers.");
  } // printUsage()
} // class Counter





SAX2 writer: register a SAX2 ContentHandler and receive the callbacks in order to print a document that is parsed.

 
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.ParserAdapter;
import org.xml.sax.helpers.ParserFactory;
import org.xml.sax.helpers.XMLReaderFactory;
/**
 * A sample SAX2 writer. This sample program illustrates how to register a SAX2
 * ContentHandler and receive the callbacks in order to print a document that is
 * parsed.
 * 
 * @author Andy Clark, IBM
 * 
 * @version $Id: Writer.java 447686 2006-09-19 02:38:34Z mrglavas $
 */
public class Writer extends DefaultHandler implements LexicalHandler {
  //
  // Constants
  //
  // feature ids
  /** Namespaces feature id (http://xml.org/sax/features/namespaces). */
  protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces";
  /**
   * Namespace prefixes feature id
   * (http://xml.org/sax/features/namespace-prefixes).
   */
  protected static final String NAMESPACE_PREFIXES_FEATURE_ID = "http://xml.org/sax/features/namespace-prefixes";
  /** Validation feature id (http://xml.org/sax/features/validation). */
  protected static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation";
  /**
   * Schema validation feature id
   * (http://apache.org/xml/features/validation/schema).
   */
  protected static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema";
  /**
   * Schema full checking feature id
   * (http://apache.org/xml/features/validation/schema-full-checking).
   */
  protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking";
  /**
   * Honour all schema locations feature id
   * (http://apache.org/xml/features/honour-all-schemaLocations).
   */
  protected static final String HONOUR_ALL_SCHEMA_LOCATIONS_ID = "http://apache.org/xml/features/honour-all-schemaLocations";
  /**
   * Validate schema annotations feature id
   * (http://apache.org/xml/features/validate-annotations)
   */
  protected static final String VALIDATE_ANNOTATIONS_ID = "http://apache.org/xml/features/validate-annotations";
  /**
   * Generate synthetic schema annotations feature id
   * (http://apache.org/xml/features/generate-synthetic-annotations).
   */
  protected static final String GENERATE_SYNTHETIC_ANNOTATIONS_ID = "http://apache.org/xml/features/generate-synthetic-annotations";
  /**
   * Dynamic validation feature id
   * (http://apache.org/xml/features/validation/dynamic).
   */
  protected static final String DYNAMIC_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/dynamic";
  /**
   * Load external DTD feature id
   * (http://apache.org/xml/features/nonvalidating/load-external-dtd).
   */
  protected static final String LOAD_EXTERNAL_DTD_FEATURE_ID = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
  /** XInclude feature id (http://apache.org/xml/features/xinclude). */
  protected static final String XINCLUDE_FEATURE_ID = "http://apache.org/xml/features/xinclude";
  /**
   * XInclude fixup base URIs feature id
   * (http://apache.org/xml/features/xinclude/fixup-base-uris).
   */
  protected static final String XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID = "http://apache.org/xml/features/xinclude/fixup-base-uris";
  /**
   * XInclude fixup language feature id
   * (http://apache.org/xml/features/xinclude/fixup-language).
   */
  protected static final String XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID = "http://apache.org/xml/features/xinclude/fixup-language";
  // property ids
  /**
   * Lexical handler property id
   * (http://xml.org/sax/properties/lexical-handler).
   */
  protected static final String LEXICAL_HANDLER_PROPERTY_ID = "http://xml.org/sax/properties/lexical-handler";
  // default settings
  /** Default parser name. */
  protected static final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
  /** Default namespaces support (true). */
  protected static final boolean DEFAULT_NAMESPACES = true;
  /** Default namespace prefixes (false). */
  protected static final boolean DEFAULT_NAMESPACE_PREFIXES = false;
  /** Default validation support (false). */
  protected static final boolean DEFAULT_VALIDATION = false;
  /** Default load external DTD (true). */
  protected static final boolean DEFAULT_LOAD_EXTERNAL_DTD = true;
  /** Default Schema validation support (false). */
  protected static final boolean DEFAULT_SCHEMA_VALIDATION = false;
  /** Default Schema full checking support (false). */
  protected static final boolean DEFAULT_SCHEMA_FULL_CHECKING = false;
  /** Default honour all schema locations (false). */
  protected static final boolean DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS = false;
  /** Default validate schema annotations (false). */
  protected static final boolean DEFAULT_VALIDATE_ANNOTATIONS = false;
  /** Default generate synthetic schema annotations (false). */
  protected static final boolean DEFAULT_GENERATE_SYNTHETIC_ANNOTATIONS = false;
  /** Default dynamic validation support (false). */
  protected static final boolean DEFAULT_DYNAMIC_VALIDATION = false;
  /** Default XInclude processing support (false). */
  protected static final boolean DEFAULT_XINCLUDE = false;
  /** Default XInclude fixup base URIs support (true). */
  protected static final boolean DEFAULT_XINCLUDE_FIXUP_BASE_URIS = true;
  /** Default XInclude fixup language support (true). */
  protected static final boolean DEFAULT_XINCLUDE_FIXUP_LANGUAGE = true;
  /** Default canonical output (false). */
  protected static final boolean DEFAULT_CANONICAL = false;
  //
  // Data
  //
  /** Print writer. */
  protected PrintWriter fOut;
  /** Canonical output. */
  protected boolean fCanonical;
  /** Element depth. */
  protected int fElementDepth;
  /** Document locator. */
  protected Locator fLocator;
  /** Processing XML 1.1 document. */
  protected boolean fXML11;
  /** In CDATA section. */
  protected boolean fInCDATA;
  //
  // Constructors
  //
  /** Default constructor. */
  public Writer() {
  } // <init>()
  //
  // Public methods
  //
  /** Sets whether output is canonical. */
  public void setCanonical(boolean canonical) {
    fCanonical = canonical;
  } // setCanonical(boolean)
  /** Sets the output stream for printing. */
  public void setOutput(OutputStream stream, String encoding) throws UnsupportedEncodingException {
    if (encoding == null) {
      encoding = "UTF8";
    }
    java.io.Writer writer = new OutputStreamWriter(stream, encoding);
    fOut = new PrintWriter(writer);
  } // setOutput(OutputStream,String)
  /** Sets the output writer. */
  public void setOutput(java.io.Writer writer) {
    fOut = writer instanceof PrintWriter ? (PrintWriter) writer : new PrintWriter(writer);
  } // setOutput(java.io.Writer)
  //
  // ContentHandler methods
  //
  /** Set Document Locator. */
  public void setDocumentLocator(Locator locator) {
    fLocator = locator;
  } // setDocumentLocator(Locator)
  /** Start document. */
  public void startDocument() throws SAXException {
    fElementDepth = 0;
    fXML11 = false;
    fInCDATA = false;
  } // startDocument()
  /** Processing instruction. */
  public void processingInstruction(String target, String data) throws SAXException {
    if (fElementDepth > 0) {
      fOut.print("<?");
      fOut.print(target);
      if (data != null && data.length() > 0) {
        fOut.print(" ");
        fOut.print(data);
      }
      fOut.print("?>");
      fOut.flush();
    }
  } // processingInstruction(String,String)
  /** Start element. */
  public void startElement(String uri, String local, String raw, Attributes attrs)
      throws SAXException {
    // Root Element
    if (fElementDepth == 0) {
      if (fLocator != null) {
        fXML11 = "1.1".equals(getVersion());
        fLocator = null;
      }
      // The XML declaration cannot be printed in startDocument because
      // the version reported by the Locator cannot be relied on until after
      // the XML declaration in the instance document has been read.
      if (!fCanonical) {
        if (fXML11) {
          fOut.println("<?xml version=\"1.1\" encoding=\"UTF-8\"?>");
        } else {
          fOut.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        }
        fOut.flush();
      }
    }
    fElementDepth++;
    fOut.print("<");
    fOut.print(raw);
    if (attrs != null) {
      attrs = sortAttributes(attrs);
      int len = attrs.getLength();
      for (int i = 0; i < len; i++) {
        fOut.print(" ");
        fOut.print(attrs.getQName(i));
        fOut.print("=\"");
        normalizeAndPrint(attrs.getValue(i), true);
        fOut.print(""");
      }
    }
    fOut.print(">");
    fOut.flush();
  } // startElement(String,String,String,Attributes)
  /** Characters. */
  public void characters(char ch[], int start, int length) throws SAXException {
    if (!fInCDATA) {
      normalizeAndPrint(ch, start, length, false);
    } else {
      for (int i = 0; i < length; ++i) {
        fOut.print(ch[start + i]);
      }
    }
    fOut.flush();
  } // characters(char[],int,int);
  /** Ignorable whitespace. */
  public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
    characters(ch, start, length);
    fOut.flush();
  } // ignorableWhitespace(char[],int,int);
  /** End element. */
  public void endElement(String uri, String local, String raw) throws SAXException {
    fElementDepth--;
    fOut.print("</");
    fOut.print(raw);
    fOut.print(">");
    fOut.flush();
  } // endElement(String)
  //
  // ErrorHandler methods
  //
  /** Warning. */
  public void warning(SAXParseException ex) throws SAXException {
    printError("Warning", ex);
  } // warning(SAXParseException)
  /** Error. */
  public void error(SAXParseException ex) throws SAXException {
    printError("Error", ex);
  } // error(SAXParseException)
  /** Fatal error. */
  public void fatalError(SAXParseException ex) throws SAXException {
    printError("Fatal Error", ex);
    throw ex;
  } // fatalError(SAXParseException)
  //
  // LexicalHandler methods
  //
  /** Start DTD. */
  public void startDTD(String name, String publicId, String systemId) throws SAXException {
  } // startDTD(String,String,String)
  /** End DTD. */
  public void endDTD() throws SAXException {
  } // endDTD()
  /** Start entity. */
  public void startEntity(String name) throws SAXException {
  } // startEntity(String)
  /** End entity. */
  public void endEntity(String name) throws SAXException {
  } // endEntity(String)
  /** Start CDATA section. */
  public void startCDATA() throws SAXException {
    if (!fCanonical) {
      fOut.print("<![CDATA[");
      fInCDATA = true;
    }
  } // startCDATA()
  /** End CDATA section. */
  public void endCDATA() throws SAXException {
    if (!fCanonical) {
      fInCDATA = false;
      fOut.print("]]&gt;");
    }
  } // endCDATA()
  /** Comment. */
  public void comment(char ch[], int start, int length) throws SAXException {
    if (!fCanonical && fElementDepth > 0) {
      fOut.print("<!--");
      for (int i = 0; i < length; ++i) {
        fOut.print(ch[start + i]);
      }
      fOut.print("-->");
      fOut.flush();
    }
  } // comment(char[],int,int)
  //
  // Protected methods
  //
  /** Returns a sorted list of attributes. */
  protected Attributes sortAttributes(Attributes attrs) {
    AttributesImpl attributes = new AttributesImpl();
    int len = (attrs != null) ? attrs.getLength() : 0;
    for (int i = 0; i < len; i++) {
      String name = attrs.getQName(i);
      int count = attributes.getLength();
      int j = 0;
      while (j < count) {
        if (name.rupareTo(attributes.getQName(j)) < 0) {
          break;
        }
        j++;
      }
      attributes.insertAttributeAt(j, name, attrs.getType(i), attrs.getValue(i));
    }
    return attributes;
  } // sortAttributes(AttributeList):AttributeList
  /** Normalizes and prints the given string. */
  protected void normalizeAndPrint(String s, boolean isAttValue) {
    int len = (s != null) ? s.length() : 0;
    for (int i = 0; i < len; i++) {
      char c = s.charAt(i);
      normalizeAndPrint(c, isAttValue);
    }
  } // normalizeAndPrint(String,boolean)
  /** Normalizes and prints the given array of characters. */
  protected void normalizeAndPrint(char[] ch, int offset, int length, boolean isAttValue) {
    for (int i = 0; i < length; i++) {
      normalizeAndPrint(ch[offset + i], isAttValue);
    }
  } // normalizeAndPrint(char[],int,int,boolean)
  /** Normalizes and print the given character. */
  protected void normalizeAndPrint(char c, boolean isAttValue) {
    switch (c) {
    case "<": {
      fOut.print("&lt;");
      break;
    }
    case ">": {
      fOut.print("&gt;");
      break;
    }
    case "&": {
      fOut.print("&amp;");
      break;
    }
    case """: {
      // A """ that appears in character data
      // does not need to be escaped.
      if (isAttValue) {
        fOut.print("&quot;");
      } else {
        fOut.print("\"");
      }
      break;
    }
    case "\r": {
      // If CR is part of the document"s content, it
      // must not be printed as a literal otherwise
      // it would be normalized to LF when the document
      // is reparsed.
      fOut.print("&#xD;");
      break;
    }
    case "\n": {
      if (fCanonical) {
        fOut.print("&#xA;");
        break;
      }
      // else, default print char
    }
    default: {
      // In XML 1.1, control chars in the ranges [#x1-#x1F, #x7F-#x9F] must be
      // escaped.
      //
      // Escape space characters that would be normalized to #x20 in attribute
      // values
      // when the document is reparsed.
      //
      // Escape NEL (0x85) and LSEP (0x2028) that appear in content
      // if the document is XML 1.1, since they would be normalized to LF
      // when the document is reparsed.
      if (fXML11
          && ((c >= 0x01 && c <= 0x1F && c != 0x09 && c != 0x0A) || (c >= 0x7F && c <= 0x9F) || c == 0x2028)
          || isAttValue && (c == 0x09 || c == 0x0A)) {
        fOut.print("&#x");
        fOut.print(Integer.toHexString(c).toUpperCase());
        fOut.print(";");
      } else {
        fOut.print(c);
      }
    }
    }
  } // normalizeAndPrint(char,boolean)
  /** Prints the error message. */
  protected void printError(String type, SAXParseException ex) {
    System.err.print("[");
    System.err.print(type);
    System.err.print("] ");
    String systemId = ex.getSystemId();
    if (systemId != null) {
      int index = systemId.lastIndexOf("/");
      if (index != -1)
        systemId = systemId.substring(index + 1);
      System.err.print(systemId);
    }
    System.err.print(":");
    System.err.print(ex.getLineNumber());
    System.err.print(":");
    System.err.print(ex.getColumnNumber());
    System.err.print(": ");
    System.err.print(ex.getMessage());
    System.err.println();
    System.err.flush();
  } // printError(String,SAXParseException)
  /** Extracts the XML version from the Locator. */
  protected String getVersion() {
    if (fLocator == null) {
      return null;
    }
    String version = null;
    Method getXMLVersion = null;
    try {
      getXMLVersion = fLocator.getClass().getMethod("getXMLVersion", new Class[] {});
      // If Locator implements Locator2, this method will exist.
      if (getXMLVersion != null) {
        version = (String) getXMLVersion.invoke(fLocator, (Object[]) null);
      }
    } catch (Exception e) {
      // Either this locator object doesn"t have
      // this method, or we"re on an old JDK.
    }
    return version;
  } // getVersion()
  //
  // Main
  //
  /** Main program entry point. */
  public static void main(String argv[]) {
    // is there anything to do?
    if (argv.length == 0) {
      printUsage();
      System.exit(1);
    }
    // variables
    Writer writer = null;
    XMLReader parser = null;
    boolean namespaces = DEFAULT_NAMESPACES;
    boolean namespacePrefixes = DEFAULT_NAMESPACE_PREFIXES;
    boolean validation = DEFAULT_VALIDATION;
    boolean externalDTD = DEFAULT_LOAD_EXTERNAL_DTD;
    boolean schemaValidation = DEFAULT_SCHEMA_VALIDATION;
    boolean schemaFullChecking = DEFAULT_SCHEMA_FULL_CHECKING;
    boolean honourAllSchemaLocations = DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS;
    boolean validateAnnotations = DEFAULT_VALIDATE_ANNOTATIONS;
    boolean generateSyntheticAnnotations = DEFAULT_GENERATE_SYNTHETIC_ANNOTATIONS;
    boolean dynamicValidation = DEFAULT_DYNAMIC_VALIDATION;
    boolean xincludeProcessing = DEFAULT_XINCLUDE;
    boolean xincludeFixupBaseURIs = DEFAULT_XINCLUDE_FIXUP_BASE_URIS;
    boolean xincludeFixupLanguage = DEFAULT_XINCLUDE_FIXUP_LANGUAGE;
    boolean canonical = DEFAULT_CANONICAL;
    // process arguments
    for (int i = 0; i < argv.length; i++) {
      String arg = argv[i];
      if (arg.startsWith("-")) {
        String option = arg.substring(1);
        if (option.equals("p")) {
          // get parser name
          if (++i == argv.length) {
            System.err.println("error: Missing argument to -p option.");
          }
          String parserName = argv[i];
          // create parser
          try {
            parser = XMLReaderFactory.createXMLReader(parserName);
          } catch (Exception e) {
            try {
              Parser sax1Parser = ParserFactory.makeParser(parserName);
              parser = new ParserAdapter(sax1Parser);
              System.err.println("warning: Features and properties not supported on SAX1 parsers.");
            } catch (Exception ex) {
              parser = null;
              System.err.println("error: Unable to instantiate parser (" + parserName + ")");
              e.printStackTrace(System.err);
            }
          }
          continue;
        }
        if (option.equalsIgnoreCase("n")) {
          namespaces = option.equals("n");
          continue;
        }
        if (option.equalsIgnoreCase("np")) {
          namespacePrefixes = option.equals("np");
          continue;
        }
        if (option.equalsIgnoreCase("v")) {
          validation = option.equals("v");
          continue;
        }
        if (option.equalsIgnoreCase("xd")) {
          externalDTD = option.equals("xd");
          continue;
        }
        if (option.equalsIgnoreCase("s")) {
          schemaValidation = option.equals("s");
          continue;
        }
        if (option.equalsIgnoreCase("f")) {
          schemaFullChecking = option.equals("f");
          continue;
        }
        if (option.equalsIgnoreCase("hs")) {
          honourAllSchemaLocations = option.equals("hs");
          continue;
        }
        if (option.equalsIgnoreCase("va")) {
          validateAnnotations = option.equals("va");
          continue;
        }
        if (option.equalsIgnoreCase("ga")) {
          generateSyntheticAnnotations = option.equals("ga");
          continue;
        }
        if (option.equalsIgnoreCase("dv")) {
          dynamicValidation = option.equals("dv");
          continue;
        }
        if (option.equalsIgnoreCase("xi")) {
          xincludeProcessing = option.equals("xi");
          continue;
        }
        if (option.equalsIgnoreCase("xb")) {
          xincludeFixupBaseURIs = option.equals("xb");
          continue;
        }
        if (option.equalsIgnoreCase("xl")) {
          xincludeFixupLanguage = option.equals("xl");
          continue;
        }
        if (option.equalsIgnoreCase("c")) {
          canonical = option.equals("c");
          continue;
        }
        if (option.equals("h")) {
          printUsage();
          continue;
        }
      }
      // use default parser?
      if (parser == null) {
        // create parser
        try {
          parser = XMLReaderFactory.createXMLReader(DEFAULT_PARSER_NAME);
        } catch (Exception e) {
          System.err.println("error: Unable to instantiate parser (" + DEFAULT_PARSER_NAME + ")");
          e.printStackTrace(System.err);
          continue;
        }
      }
      // set parser features
      try {
        parser.setFeature(NAMESPACES_FEATURE_ID, namespaces);
      } catch (SAXException e) {
        System.err.println("warning: Parser does not support feature (" + NAMESPACES_FEATURE_ID
            + ")");
      }
      try {
        parser.setFeature(NAMESPACE_PREFIXES_FEATURE_ID, namespacePrefixes);
      } catch (SAXException e) {
        System.err.println("warning: Parser does not support feature ("
            + NAMESPACE_PREFIXES_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(VALIDATION_FEATURE_ID, validation);
      } catch (SAXException e) {
        System.err.println("warning: Parser does not support feature (" + VALIDATION_FEATURE_ID
            + ")");
      }
      try {
        parser.setFeature(LOAD_EXTERNAL_DTD_FEATURE_ID, externalDTD);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + LOAD_EXTERNAL_DTD_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + LOAD_EXTERNAL_DTD_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, schemaValidation);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + SCHEMA_VALIDATION_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + SCHEMA_VALIDATION_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(SCHEMA_FULL_CHECKING_FEATURE_ID, schemaFullChecking);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + SCHEMA_FULL_CHECKING_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + SCHEMA_FULL_CHECKING_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(HONOUR_ALL_SCHEMA_LOCATIONS_ID, honourAllSchemaLocations);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + HONOUR_ALL_SCHEMA_LOCATIONS_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + HONOUR_ALL_SCHEMA_LOCATIONS_ID + ")");
      }
      try {
        parser.setFeature(VALIDATE_ANNOTATIONS_ID, validateAnnotations);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature (" + VALIDATE_ANNOTATIONS_ID
            + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature (" + VALIDATE_ANNOTATIONS_ID
            + ")");
      }
      try {
        parser.setFeature(GENERATE_SYNTHETIC_ANNOTATIONS_ID, generateSyntheticAnnotations);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + GENERATE_SYNTHETIC_ANNOTATIONS_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + GENERATE_SYNTHETIC_ANNOTATIONS_ID + ")");
      }
      try {
        parser.setFeature(DYNAMIC_VALIDATION_FEATURE_ID, dynamicValidation);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + DYNAMIC_VALIDATION_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + DYNAMIC_VALIDATION_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(XINCLUDE_FEATURE_ID, xincludeProcessing);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature (" + XINCLUDE_FEATURE_ID
            + ")");
      } catch (SAXNotSupportedException e) {
        System.err
            .println("warning: Parser does not support feature (" + XINCLUDE_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID, xincludeFixupBaseURIs);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID + ")");
      }
      try {
        parser.setFeature(XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID, xincludeFixupLanguage);
      } catch (SAXNotRecognizedException e) {
        System.err.println("warning: Parser does not recognize feature ("
            + XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID + ")");
      } catch (SAXNotSupportedException e) {
        System.err.println("warning: Parser does not support feature ("
            + XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID + ")");
      }
      // setup writer
      if (writer == null) {
        writer = new Writer();
        try {
          writer.setOutput(System.out, "UTF8");
        } catch (UnsupportedEncodingException e) {
          System.err.println("error: Unable to set output. Exiting.");
          System.exit(1);
        }
      }
      // set parser
      parser.setContentHandler(writer);
      parser.setErrorHandler(writer);
      try {
        parser.setProperty(LEXICAL_HANDLER_PROPERTY_ID, writer);
      } catch (SAXException e) {
        // ignore
      }
      // parse file
      writer.setCanonical(canonical);
      try {
        parser.parse(arg);
      } catch (SAXParseException e) {
        // ignore
      } catch (Exception e) {
        System.err.println("error: Parse error occurred - " + e.getMessage());
        if (e instanceof SAXException) {
          Exception nested = ((SAXException) e).getException();
          if (nested != null) {
            e = nested;
          }
        }
        e.printStackTrace(System.err);
      }
    }
  } // main(String[])
  //
  // Private static methods
  //
  /** Prints the usage. */
  private static void printUsage() {
    System.err.println("usage: java sax.Writer (options) uri ...");
    System.err.println();
    System.err.println("options:");
    System.err.println("  -p name     Select parser by name.");
    System.err.println("  -n  | -N    Turn on/off namespace processing.");
    System.err.println("  -np | -NP   Turn on/off namespace prefixes.");
    System.err.println("              NOTE: Requires use of -n.");
    System.err.println("  -v  | -V    Turn on/off validation.");
    System.err.println("  -xd | -XD   Turn on/off loading of external DTDs.");
    System.err
        .println("              NOTE: Always on when -v in use and not supported by all parsers.");
    System.err.println("  -s  | -S    Turn on/off Schema validation support.");
    System.err.println("              NOTE: Not supported by all parsers.");
    System.err.println("  -f  | -F    Turn on/off Schema full checking.");
    System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
    System.err.println("  -hs | -HS   Turn on/off honouring of all schema locations.");
    System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
    System.err.println("  -va | -VA   Turn on/off validation of schema annotations.");
    System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
    System.err.println("  -ga | -GA   Turn on/off generation of synthetic schema annotations.");
    System.err.println("              NOTE: Requires use of -s and not supported by all parsers.");
    System.err.println("  -dv | -DV   Turn on/off dynamic validation.");
    System.err.println("              NOTE: Not supported by all parsers.");
    System.err.println("  -xi | -XI   Turn on/off XInclude processing.");
    System.err.println("              NOTE: Not supported by all parsers.");
    System.err.println("  -xb | -XB   Turn on/off base URI fixup during XInclude processing.");
    System.err.println("              NOTE: Requires use of -xi and not supported by all parsers.");
    System.err.println("  -xl | -XL   Turn on/off language fixup during XInclude processing.");
    System.err.println("              NOTE: Requires use of -xi and not supported by all parsers.");
    System.err.println("  -c | -C     Turn on/off Canonical XML output.");
    System.err.println("              NOTE: This is not W3C canonical output.");
    System.err.println("  -h          This help screen.");
    System.err.println();
    System.err.println("defaults:");
    System.err.println("  Parser:     " + DEFAULT_PARSER_NAME);
    System.err.print("  Namespaces: ");
    System.err.println(DEFAULT_NAMESPACES ? "on" : "off");
    System.err.print("  Prefixes:   ");
    System.err.println(DEFAULT_NAMESPACE_PREFIXES ? "on" : "off");
    System.err.print("  Validation: ");
    System.err.println(DEFAULT_VALIDATION ? "on" : "off");
    System.err.print("  Load External DTD: ");
    System.err.println(DEFAULT_LOAD_EXTERNAL_DTD ? "on" : "off");
    System.err.print("  Schema:     ");
    System.err.println(DEFAULT_SCHEMA_VALIDATION ? "on" : "off");
    System.err.print("  Schema full checking:     ");
    System.err.println(DEFAULT_SCHEMA_FULL_CHECKING ? "on" : "off");
    System.err.print("  Dynamic:    ");
    System.err.println(DEFAULT_DYNAMIC_VALIDATION ? "on" : "off");
    System.err.print("  Canonical:  ");
    System.err.println(DEFAULT_CANONICAL ? "on" : "off");
    System.err.print("  Honour all schema locations:       ");
    System.err.println(DEFAULT_HONOUR_ALL_SCHEMA_LOCATIONS ? "on" : "off");
    System.err.print("  Validate Annotations:              ");
    System.err.println(DEFAULT_VALIDATE_ANNOTATIONS ? "on" : "off");
    System.err.print("  Generate Synthetic Annotations:    ");
    System.err.println(DEFAULT_GENERATE_SYNTHETIC_ANNOTATIONS ? "on" : "off");
    System.err.print("  XInclude:   ");
    System.err.println(DEFAULT_XINCLUDE ? "on" : "off");
    System.err.print("  XInclude base URI fixup:  ");
    System.err.println(DEFAULT_XINCLUDE_FIXUP_BASE_URIS ? "on" : "off");
    System.err.print("  XInclude language fixup:  ");
    System.err.println(DEFAULT_XINCLUDE_FIXUP_LANGUAGE ? "on" : "off");
  } // printUsage()
} // class Writer
class AttributesImpl implements Attributes {
  //
  // Data
  //
  /** Head node. */
  private ListNode head;
  /** Tail node. */
  private ListNode tail;
  /** Length. */
  private int length;
  //
  // Attributes methods
  //
  /** Returns the number of attributes. */
  public int getLength() {
    return length;
  }
  /** Returns the index of the specified attribute. */
  public int getIndex(String raw) {
    ListNode place = head;
    int index = 0;
    while (place != null) {
      if (place.raw.equals(raw)) {
        return index;
      }
      index++;
      place = place.next;
    }
    return -1;
  }
  /** Returns the index of the specified attribute. */
  public int getIndex(String uri, String local) {
    ListNode place = head;
    int index = 0;
    while (place != null) {
      if (place.uri.equals(uri) && place.local.equals(local)) {
        return index;
      }
      index++;
      place = place.next;
    }
    return -1;
  }
  /** Returns the attribute URI by index. */
  public String getURI(int index) {
    ListNode node = getListNodeAt(index);
    return node != null ? node.uri : null;
  } // getURI(int):String
  /** Returns the attribute local name by index. */
  public String getLocalName(int index) {
    ListNode node = getListNodeAt(index);
    return node != null ? node.local : null;
  } // getLocalName(int):String
  /** Returns the attribute raw name by index. */
  public String getQName(int index) {
    ListNode node = getListNodeAt(index);
    return node != null ? node.raw : null;
  } // getQName(int):String
  /** Returns the attribute type by index. */
  public String getType(int index) {
    ListNode node = getListNodeAt(index);
    return (node != null) ? node.type : null;
  } // getType(int):String
  /** Returns the attribute type by uri and local. */
  public String getType(String uri, String local) {
    ListNode node = getListNode(uri, local);
    return (node != null) ? node.type : null;
  } // getType(String,String):String
  /** Returns the attribute type by raw name. */
  public String getType(String raw) {
    ListNode node = getListNode(raw);
    return (node != null) ? node.type : null;
  } // getType(String):String
  /** Returns the attribute value by index. */
  public String getValue(int index) {
    ListNode node = getListNodeAt(index);
    return (node != null) ? node.value : null;
  } // getType(int):String
  /** Returns the attribute value by uri and local. */
  public String getValue(String uri, String local) {
    ListNode node = getListNode(uri, local);
    return (node != null) ? node.value : null;
  } // getType(String):String
  /** Returns the attribute value by raw name. */
  public String getValue(String raw) {
    ListNode node = getListNode(raw);
    return (node != null) ? node.value : null;
  } // getType(String):String
  //
  // Public methods
  //
  /** Adds an attribute. */
  public void addAttribute(String raw, String type, String value) {
    addAttribute(null, null, raw, type, value);
  }
  /** Adds an attribute. */
  public void addAttribute(String uri, String local, String raw, String type, String value) {
    ListNode node = new ListNode(uri, local, raw, type, value);
    if (length == 0) {
      head = node;
    } else {
      tail.next = node;
    }
    tail = node;
    length++;
  } // addAttribute(String,StringString,String,String)
  /** Inserts an attribute. */
  public void insertAttributeAt(int index, String raw, String type, String value) {
    insertAttributeAt(index, null, null, raw, type, value);
  }
  /** Inserts an attribute. */
  public void insertAttributeAt(int index, String uri, String local, String raw, String type,
      String value) {
    // if list is empty, add attribute
    if (length == 0 || index >= length) {
      addAttribute(uri, local, raw, type, value);
      return;
    }
    // insert at beginning of list
    ListNode node = new ListNode(uri, local, raw, type, value);
    if (index < 1) {
      node.next = head;
      head = node;
    } else {
      ListNode prev = getListNodeAt(index - 1);
      node.next = prev.next;
      prev.next = node;
    }
    length++;
  } // insertAttributeAt(int,String,String,String,String,String)
  /** Removes an attribute. */
  public void removeAttributeAt(int index) {
    if (length == 0) {
      return;
    }
    if (index == 0) {
      head = head.next;
      if (head == null) {
        tail = null;
      }
      length--;
    } else {
      ListNode prev = getListNodeAt(index - 1);
      ListNode node = getListNodeAt(index);
      if (node != null) {
        prev.next = node.next;
        if (node == tail) {
          tail = prev;
        }
        length--;
      }
    }
  } // removeAttributeAt(int)
  /** Removes the specified attribute. */
  public void removeAttribute(String raw) {
    removeAttributeAt(getIndex(raw));
  }
  /** Removes the specified attribute. */
  public void removeAttribute(String uri, String local) {
    removeAttributeAt(getIndex(uri, local));
  }
  //
  // Private methods
  //
  /** Returns the node at the specified index. */
  private ListNode getListNodeAt(int i) {
    for (ListNode place = head; place != null; place = place.next) {
      if (--i == -1) {
        return place;
      }
    }
    return null;
  } // getListNodeAt(int):ListNode
  /** Returns the first node with the specified uri and local. */
  public ListNode getListNode(String uri, String local) {
    if (uri != null && local != null) {
      ListNode place = head;
      while (place != null) {
        if (place.uri != null && place.local != null && place.uri.equals(uri)
            && place.local.equals(local)) {
          return place;
        }
        place = place.next;
      }
    }
    return null;
  } // getListNode(String,String):ListNode
  /** Returns the first node with the specified raw name. */
  private ListNode getListNode(String raw) {
    if (raw != null) {
      for (ListNode place = head; place != null; place = place.next) {
        if (place.raw != null && place.raw.equals(raw)) {
          return place;
        }
      }
    }
    return null;
  } // getListNode(String):ListNode
  //
  // Object methods
  //
  /** Returns a string representation of this object. */
  public String toString() {
    StringBuffer str = new StringBuffer();
    str.append("[");
    str.append("len=");
    str.append(length);
    str.append(", {");
    for (ListNode place = head; place != null; place = place.next) {
      str.append(place.toString());
      if (place.next != null) {
        str.append(", ");
      }
    }
    str.append("}]");
    return str.toString();
  } // toString():String
  //
  // Classes
  //
  /**
   * An attribute node.
   */
  static class ListNode {
    //
    // Data
    //
    /** Attribute uri. */
    public String uri;
    /** Attribute local. */
    public String local;
    /** Attribute raw. */
    public String raw;
    /** Attribute type. */
    public String type;
    /** Attribute value. */
    public String value;
    /** Next node. */
    public ListNode next;
    //
    // Constructors
    //
    /** Constructs a list node. */
    public ListNode(String uri, String local, String raw, String type, String value) {
      this.uri = uri;
      this.local = local;
      this.raw = raw;
      this.type = type;
      this.value = value;
    } // <init>(String,String,String,String,String)
    //
    // Object methods
    //
    /** Returns string representation of this object. */
    public String toString() {
      return raw != null ? raw : local;
    }
  } // class ListNode
} // class AttributesImpl





SAX Checker

     
//Example XML document
/*  An XML Document
<?xml version="1.0" standalone="yes"?>
<person>
     <name>Joe Wang</name>
     <phone type="home">306 555-9999</phone>
     <email>joe@yoursite.net;</email>
</person>

*/
import java.io.IOException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
public class SAXCheck {
  static public void main(String[] arg) {
    String filename = null;
    boolean validate = false;
    if (arg.length == 1) {
      filename = arg[0];
    } else if (arg.length == 2) {
      if (!arg[0].equals("-v"))
        usage();
      validate = true;
      filename = arg[1];
    } else {
      usage();
    }
    // Create a new factory to create parsers that will
    // validate or not, according to the flag setting.
    SAXParserFactory spf = SAXParserFactory.newInstance();
    spf.setValidating(validate);
    // Create the XMLReader to be used to check for errors.
    XMLReader reader = null;
    try {
      SAXParser parser = spf.newSAXParser();
      reader = parser.getXMLReader();
    } catch (Exception e) {
      System.err.println(e);
      System.exit(1);
    }
    // Install an error handler in the reader.
    reader.setErrorHandler(new MyErrorHandler());
    // Use the XMLReader to parse the entire file.
    try {
      InputSource is = new InputSource(filename);
      reader.parse(is);
    } catch (SAXException e) {
      System.exit(1);
    } catch (IOException e) {
      System.err.println(e);
      System.exit(1);
    }
  }
  private static void usage() {
    System.err.println("Usage: SAXCheck [-v] <filename>");
    System.exit(1);
  }
}
class MyErrorHandler implements ErrorHandler {
  public void warning(SAXParseException e) throws SAXException {
    show("Warning", e);
    throw (e);
  }
  public void error(SAXParseException e) throws SAXException {
    show("Error", e);
    throw (e);
  }
  public void fatalError(SAXParseException e) throws SAXException {
    show("Fatal Error", e);
    throw (e);
  }
  private void show(String type, SAXParseException e) {
    System.out.println(type + ": " + e.getMessage());
    System.out.println("Line " + e.getLineNumber() + " Column "
        + e.getColumnNumber());
    System.out.println("System ID: " + e.getSystemId());
  }
}





SAX Demo

     
/*
 * Copyright (c) 2000 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 2nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book (recommended),
 * visit http://www.davidflanagan.ru/javaexamples2.
 */
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.AttributeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
 * 
 * This class implements the HandlerBase helper class, which means that it
 * defines all the "callback" methods that the SAX parser will invoke to notify
 * the application. In this example we override the methods that we require.
 * 
 * This example uses full package names in places to help keep the JAXP and SAX
 * APIs distinct.
 */
public class SAXDemo extends org.xml.sax.HandlerBase {
  /** The main method sets things up for parsing */
  public static void main(String[] args) throws IOException, SAXException,
      ParserConfigurationException {
    // Create a JAXP "parser factory" for creating SAX parsers
    javax.xml.parsers.SAXParserFactory spf = SAXParserFactory.newInstance();
    // Configure the parser factory for the type of parsers we require
    spf.setValidating(false); // No validation required
    // Now use the parser factory to create a SAXParser object
    // Note that SAXParser is a JAXP class, not a SAX class
    javax.xml.parsers.SAXParser sp = spf.newSAXParser();
    // Create a SAX input source for the file argument
    org.xml.sax.InputSource input = new InputSource(new FileReader(args[0]));
    // Give the InputSource an absolute URL for the file, so that
    // it can resolve relative URLs in a <!DOCTYPE> declaration, e.g.
    input.setSystemId("file://" + new File(args[0]).getAbsolutePath());
    // Create an instance of this class; it defines all the handler methods
    SAXDemo handler = new SAXDemo();
    // Finally, tell the parser to parse the input and notify the handler
    sp.parse(input, handler);
    // Instead of using the SAXParser.parse() method, which is part of the
    // JAXP API, we could also use the SAX1 API directly. Note the
    // difference between the JAXP class javax.xml.parsers.SAXParser and
    // the SAX1 class org.xml.sax.Parser
    //
    // org.xml.sax.Parser parser = sp.getParser(); // Get the SAX parser
    // parser.setDocumentHandler(handler); // Set main handler
    // parser.setErrorHandler(handler); // Set error handler
    // parser.parse(input); // Parse!
  }
  StringBuffer accumulator = new StringBuffer(); // Accumulate parsed text
  String servletName; // The name of the servlet
  String servletClass; // The class name of the servlet
  String servletId; // Value of id attribute of <servlet> tag
  // When the parser encounters plain text (not XML elements), it calls
  // this method, which accumulates them in a string buffer
  public void characters(char[] buffer, int start, int length) {
    accumulator.append(buffer, start, length);
  }
  // Every time the parser encounters the beginning of a new element, it
  // calls this method, which resets the string buffer
  public void startElement(String name, AttributeList attributes) {
    accumulator.setLength(0); // Ready to accumulate new text
    // If its a servlet tag, look for id attribute
    if (name.equals("servlet"))
      servletId = attributes.getValue("id");
  }
  // When the parser encounters the end of an element, it calls this method
  public void endElement(String name) {
    if (name.equals("servlet-name")) {
      // After </servlet-name>, we know the servlet name saved up
      servletName = accumulator.toString().trim();
    } else if (name.equals("servlet-class")) {
      // After </servlet-class>, we"ve got the class name accumulated
      servletClass = accumulator.toString().trim();
    } else if (name.equals("servlet")) {
      // Assuming the document is valid, then when we parse </servlet>,
      // we know we"ve got a servlet name and class name to print out
      System.out.println("Servlet " + servletName
          + ((servletId != null) ? " (id=" + servletId + ")" : "")
          + ": " + servletClass);
    }
  }
  /** This method is called when warnings occur */
  public void warning(SAXParseException exception) {
    System.err.println("WARNING: line " + exception.getLineNumber() + ": "
        + exception.getMessage());
  }
  /** This method is called when errors occur */
  public void error(SAXParseException exception) {
    System.err.println("ERROR: line " + exception.getLineNumber() + ": "
        + exception.getMessage());
  }
  /** This method is called when non-recoverable errors occur. */
  public void fatalError(SAXParseException exception) throws SAXException {
    System.err.println("FATAL: line " + exception.getLineNumber() + ": "
        + exception.getMessage());
    throw (exception);
  }
}
// Sample XML file
/*
 * <?xml version="1.0" encoding="ISO-8859-1"?>
 * 
 * <web> <s id="hello_servlet_id"> <name>hello </name> <class>Hello </class>
 * </s>
 * 
 * </web>
 *  
 */





Sax to DOM converter

  
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */
// Revised from xmlbeans
import org.w3c.dom.Node;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.rument;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.ContentHandler;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.ext.LexicalHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import java.util.Stack;
import java.util.Vector;
public class Sax2Dom
        extends DefaultHandler
        implements ContentHandler, LexicalHandler
{
    public static final String EMPTYSTRING = "";
    public static final String XML_PREFIX = "xml";
    public static final String XMLNS_PREFIX = "xmlns";
    public static final String XMLNS_STRING = "xmlns:";
    public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
    private Node _root = null;
    private Document _document = null;
    private Stack _nodeStk = new Stack();
    private Vector _namespaceDecls = null;
    public Sax2Dom() throws ParserConfigurationException
    {
        final DocumentBuilderFactory factory =
                DocumentBuilderFactory.newInstance();
        _document = factory.newDocumentBuilder().newDocument();
        _root = _document;
    }
    public Sax2Dom(Node root) throws ParserConfigurationException
    {
        _root = root;
        if (root instanceof Document)
        {
            _document = (Document) root;
        }
        else if (root != null)
        {
            _document = root.getOwnerDocument();
        }
        else
        {
            final DocumentBuilderFactory factory =
                    DocumentBuilderFactory.newInstance();
            _document = factory.newDocumentBuilder().newDocument();
            _root = _document;
        }
    }
    public Node getDOM()
    {
        return _root;
    }
    public void characters(char[] ch, int start, int length)
    {
        final Node last = (Node) _nodeStk.peek();
        // No text nodes can be children of root (DOM006 exception)
        if (last != _document)
        {
            final String text = new String(ch, start, length);
            last.appendChild(_document.createTextNode(text));
        }
    }
    public void startDocument()
    {
        _nodeStk.push(_root);
    }
    public void endDocument()
    {
        _nodeStk.pop();
    }
    public void startElement(String namespace, String localName, String qName,
                             Attributes attrs)
    {
        final Element tmp = (Element) _document.createElementNS(namespace, qName);
        // Add namespace declarations first
        if (_namespaceDecls != null)
        {
            final int nDecls = _namespaceDecls.size();
            for (int i = 0; i < nDecls; i++)
            {
                final String prefix = (String) _namespaceDecls.elementAt(i++);
                if (prefix == null || prefix.equals(EMPTYSTRING))
                {
                    tmp.setAttributeNS(XMLNS_URI, XMLNS_PREFIX,
                            (String) _namespaceDecls.elementAt(i));
                }
                else
                {
                    tmp.setAttributeNS(XMLNS_URI, XMLNS_STRING + prefix,
                            (String) _namespaceDecls.elementAt(i));
                }
            }
            _namespaceDecls.clear();
        }
        // Add attributes to element
        final int nattrs = attrs.getLength();
        for (int i = 0; i < nattrs; i++)
        {
            if (attrs.getLocalName(i) == null)
            {
                tmp.setAttribute(attrs.getQName(i), attrs.getValue(i));
            }
            else
            {
                tmp.setAttributeNS(attrs.getURI(i), attrs.getQName(i),
                        attrs.getValue(i));
            }
        }
        // Append this new node onto current stack node
        Node last = (Node) _nodeStk.peek();
        last.appendChild(tmp);
        // Push this node onto stack
        _nodeStk.push(tmp);
    }
    public void endElement(String namespace, String localName, String qName)
    {
        _nodeStk.pop();
    }
    public void startPrefixMapping(String prefix, String uri)
    {
        if (_namespaceDecls == null)
        {
            _namespaceDecls = new Vector(2);
        }
        _namespaceDecls.addElement(prefix);
        _namespaceDecls.addElement(uri);
    }
    public void endPrefixMapping(String prefix)
    {
        // do nothing
    }
    /**
     * This class is only used internally so this method should never
     * be called.
     */
    public void ignorableWhitespace(char[] ch, int start, int length)
    {
    }
    /**
     * adds processing instruction node to DOM.
     */
    public void processingInstruction(String target, String data)
    {
        final Node last = (Node) _nodeStk.peek();
        ProcessingInstruction pi = _document.createProcessingInstruction(
                target, data);
        if (pi != null) last.appendChild(pi);
    }
    /**
     * This class is only used internally so this method should never
     * be called.
     */
    public void setDocumentLocator(Locator locator)
    {
    }
    /**
     * This class is only used internally so this method should never
     * be called.
     */
    public void skippedEntity(String name)
    {
    }

    /**
     * Lexical Handler method to create comment node in DOM tree.
     */
    public void comment(char[] ch, int start, int length)
    {
        final Node last = (Node) _nodeStk.peek();
        Comment comment = _document.createComment(new String(ch, start, length));
        if (comment != null) last.appendChild(comment);
    }
    // Lexical Handler methods- not implemented
    public void startCDATA()
    {
    }
    public void endCDATA()
    {
    }
    public void startEntity(java.lang.String name)
    {
    }
    public void endEntity(String name)
    {
    }
    public void startDTD(String name, String publicId, String systemId)
            throws SAXException
    {
    }
    public void endDTD()
    {
    }
}





SAX Tree Validator

     
/*-- 
 Copyright (C) 2001 Brett McLaughlin.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions, and the following disclaimer.
 
 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions, and the disclaimer that follows 
    these conditions in the documentation and/or other materials 
    provided with the distribution.
 3. The name "Java and XML" must not be used to endorse or promote products
    derived from this software without prior written permission.  For
    written permission, please contact brett@newInstance.ru.
 
 In addition, we request (but do not require) that you include in the 
 end-user documentation provided with the redistribution and/or in the 
 software itself an acknowledgement equivalent to the following:
     "This product includes software developed for the
      "Java and XML" book, by Brett McLaughlin (O"Reilly & Associates)."
 THIS SOFTWARE IS PROVIDED ``AS IS"" AND ANY EXPRESSED OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.
 */
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
// This is an XML book - no need for explicit Swing imports
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
/**
 * <b><code>SAXTreeValidator</code></b> uses Swing to graphically
 *   display an XML document, and performs validation.
 */
public class SAXTreeValidator extends JFrame {
    /** Default parser to use */
    private String vendorParserClass = 
        "org.apache.xerces.parsers.SAXParser";
    /** The base tree to render */
    private JTree jTree;
    /** Tree model to use */
    DefaultTreeModel defaultTreeModel;
    /**
     * <p> This initializes the needed Swing settings. </p>
     */
    public SAXTreeValidator() {
        // Handle Swing setup
        super("SAX Tree Validator");
        setSize(600, 450);
    }
    /**
     * <p> This will construct the tree using Swing. </p>
     *
     * @param filename <code>String</code> path to XML document.
     */
    public void init(String xmlURI) throws IOException, SAXException {
        DefaultMutableTreeNode base = 
            new DefaultMutableTreeNode("XML Document: " + 
                xmlURI);
        
        // Build the tree model
        defaultTreeModel = new DefaultTreeModel(base);
        jTree = new JTree(defaultTreeModel);
        // Construct the tree hierarchy
        buildTree(defaultTreeModel, base, xmlURI);
        // Display the results
        getContentPane().add(new JScrollPane(jTree), 
            BorderLayout.CENTER);
    }
    /**
     * <p>This handles building the Swing UI tree.</p>
     *
     * @param treeModel Swing component to build upon.
     * @param base tree node to build on.
     * @param xmlURI URI to build XML document from.
     * @throws <code>IOException</code> - when reading the XML URI fails.
     * @throws <code>SAXException</code> - when errors in parsing occur.
     */
    public void buildTree(DefaultTreeModel treeModel, 
                          DefaultMutableTreeNode base, String xmlURI) 
        throws IOException, SAXException {
        // Create instances needed for parsing
        XMLReader reader = 
            XMLReaderFactory.createXMLReader(vendorParserClass);
        ContentHandler jTreeContentHandler = 
            new JValidatorContentHandler(treeModel, base);
        ErrorHandler jTreeErrorHandler = new JValidatorErrorHandler();
        // Register content handler
        reader.setContentHandler(jTreeContentHandler);
        // Register error handler
        reader.setErrorHandler(jTreeErrorHandler);
        // Turn on validation
        reader.setFeature("http://xml.org/sax/features/validation", true);
        reader.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true);
        // Parse
        InputSource inputSource = 
            new InputSource(xmlURI);
        reader.parse(inputSource);
    }
    /**
     * <p> Static entry point for running the viewer. </p>
     */
    public static void main(String[] args) {
        try {
            if (args.length != 1) {
                System.out.println(
                    "Usage: java SAXTreeViewer " +
                    "[XML Document URI]");
                System.exit(0);
            }
            SAXTreeValidator viewer = new SAXTreeValidator();
            viewer.init(args[0]);
            viewer.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/**
 * <b><code>JValidatorContentHandler</code></b> implements the SAX
 *   <code>ContentHandler</code> interface and defines callback
 *   behavior for the SAX callbacks associated with an XML
 *   document"s content, bulding up JTree nodes.
 */
class JValidatorContentHandler implements ContentHandler {
    /** Hold onto the locator for location information */
    private Locator locator;
    /** Store URI to prefix mappings */
    private Map namespaceMappings;
    /** Tree Model to add nodes to */
    private DefaultTreeModel treeModel;
    /** Current node to add sub-nodes to */
    private DefaultMutableTreeNode current;
    /**
     * <p> Set up for working with the JTree. </p>
     *
     * @param treeModel tree to add nodes to.
     * @param base node to start adding sub-nodes to.
     */
    public JValidatorContentHandler(DefaultTreeModel treeModel, 
                               DefaultMutableTreeNode base) {
        this.treeModel = treeModel;
        this.current = base;
        this.namespaceMappings = new HashMap();
    }
    /**
     * <p>
     *  Provide reference to <code>Locator</code> which provides
     *    information about where in a document callbacks occur.
     * </p>
     *
     * @param locator <code>Locator</code> object tied to callback
     *        process
     */
    public void setDocumentLocator(Locator locator) {
        // Save this for later use
        this.locator = locator;
    }
    /**
     * <p>
     *  This indicates the start of a Document parse-this precedes
     *    all callbacks in all SAX Handlers with the sole exception
     *    of <code>{@link #setDocumentLocator}</code>.
     * </p>
     *
     * @throws <code>SAXException</code> when things go wrong
     */
    public void startDocument() throws SAXException {
        // No visual events occur here
    }
    /**
     * <p>
     *  This indicates the end of a Document parse-this occurs after
     *    all callbacks in all SAX Handlers.</code>.
     * </p>
     *
     * @throws <code>SAXException</code> when things go wrong
     */
    public void endDocument() throws SAXException {
        // No visual events occur here
    }
    /**
     * <p>
     *   This indicates that a processing instruction (other than
     *     the XML declaration) has been encountered.
     * </p>
     *
     * @param target <code>String</code> target of PI
     * @param data <code>String</code containing all data sent to the PI.
     *               This typically looks like one or more attribute value
     *               pairs.
     * @throws <code>SAXException</code> when things go wrong
     */
    public void processingInstruction(String target, String data)
        throws SAXException {
        DefaultMutableTreeNode pi = 
            new DefaultMutableTreeNode("PI (target = "" + target +
                                       "", data = "" + data + "")");
        current.add(pi);
    }
    /**
     * <p>
     *   This indicates the beginning of an XML Namespace prefix
     *     mapping. Although this typically occurs within the root element
     *     of an XML document, it can occur at any point within the
     *     document. Note that a prefix mapping on an element triggers
     *     this callback <i>before</i> the callback for the actual element
     *     itself (<code>{@link #startElement}</code>) occurs.
     * </p>
     *
     * @param prefix <code>String</code> prefix used for the namespace
     *                being reported
     * @param uri <code>String</code> URI for the namespace
     *               being reported
     * @throws <code>SAXException</code> when things go wrong
     */
    public void startPrefixMapping(String prefix, String uri) {
        // No visual events occur here.
        namespaceMappings.put(uri, prefix);
    }
    /**
     * <p>
     *   This indicates the end of a prefix mapping, when the namespace
     *     reported in a <code>{@link #startPrefixMapping}</code> callback
     *     is no longer available.
     * </p>
     *
     * @param prefix <code>String</code> of namespace being reported
     * @throws <code>SAXException</code> when things go wrong
     */
    public void endPrefixMapping(String prefix) {
        // No visual events occur here.
        for (Iterator i = namespaceMappings.keySet().iterator(); 
             i.hasNext(); ) {
            String uri = (String)i.next();
            String thisPrefix = (String)namespaceMappings.get(uri);
            if (prefix.equals(thisPrefix)) {
                namespaceMappings.remove(uri);
                break;
            }
        }
    }
    /**
     * <p>
     *   This reports the occurrence of an actual element. It includes
     *     the element"s attributes, with the exception of XML vocabulary
     *     specific attributes, such as
     *     <code>xmlns:[namespace prefix]</code> and
     *     <code>xsi:schemaLocation</code>.
     * </p>
     *
     * @param namespaceURI <code>String</code> namespace URI this element
     *               is associated with, or an empty <code>String</code>
     * @param localName <code>String</code> name of element (with no
     *               namespace prefix, if one is present)
     * @param qName <code>String</code> XML 1.0 version of element name:
     *                [namespace prefix]:[localName]
     * @param atts <code>Attributes</code> list for this element
     * @throws <code>SAXException</code> when things go wrong
     */
    public void startElement(String namespaceURI, String localName,
                             String qName, Attributes atts)
        throws SAXException {
        DefaultMutableTreeNode element = 
            new DefaultMutableTreeNode("Element: " + localName);
        current.add(element);
        current = element;
        // Determine namespace
        if (namespaceURI.length() > 0) {
            String prefix = 
                (String)namespaceMappings.get(namespaceURI);
            if (prefix.equals("")) {
                prefix = "[None]";
            }
            DefaultMutableTreeNode namespace =
                new DefaultMutableTreeNode("Namespace: prefix = "" +
                    prefix + "", URI = "" + namespaceURI + """);
            current.add(namespace);
        }
        // Process attributes
        for (int i=0; i<atts.getLength(); i++) {
            DefaultMutableTreeNode attribute =
                new DefaultMutableTreeNode("Attribute (name = "" +
                                           atts.getLocalName(i) + 
                                           "", value = "" +
                                           atts.getValue(i) + "")");
            String attURI = atts.getURI(i);
            if (attURI.length() > 0) {
                String attPrefix = 
                    (String)namespaceMappings.get(namespaceURI);
                if (attPrefix.equals("")) {
                    attPrefix = "[None]";
                }
                DefaultMutableTreeNode attNamespace =
                    new DefaultMutableTreeNode("Namespace: prefix = "" +
                        attPrefix + "", URI = "" + attURI + """);
                attribute.add(attNamespace);            
            }
            current.add(attribute);
        }
    }
    /**
     * <p>
     *   Indicates the end of an element
     *     (<code>&lt;/[element name]&gt;</code>) is reached. Note that
     *     the parser does not distinguish between empty
     *     elements and non-empty elements, so this occurs uniformly.
     * </p>
     *
     * @param namespaceURI <code>String</code> URI of namespace this
     *                element is associated with
     * @param localName <code>String</code> name of element without prefix
     * @param qName <code>String</code> name of element in XML 1.0 form
     * @throws <code>SAXException</code> when things go wrong
     */
    public void endElement(String namespaceURI, String localName,
                           String qName)
        throws SAXException {
        // Walk back up the tree
        current = (DefaultMutableTreeNode)current.getParent();
    }
    /**
     * <p>
     *   This reports character data (within an element).
     * </p>
     *
     * @param ch <code>char[]</code> character array with character data
     * @param start <code>int</code> index in array where data starts.
     * @param length <code>int</code> index in array where data ends.
     * @throws <code>SAXException</code> when things go wrong
     */
    public void characters(char[] ch, int start, int length)
        throws SAXException {
        String s = new String(ch, start, length);
        DefaultMutableTreeNode data =
            new DefaultMutableTreeNode("Character Data: "" + s + """);
        current.add(data);
    }
    /**
     * <p>
     * This reports whitespace that can be ignored in the
     * originating document. This is typically invoked only when
     * validation is ocurring in the parsing process.
     * </p>
     *
     * @param ch <code>char[]</code> character array with character data
     * @param start <code>int</code> index in array where data starts.
     * @param end <code>int</code> index in array where data ends.
     * @throws <code>SAXException</code> when things go wrong
     */
    public void ignorableWhitespace(char[] ch, int start, int length)
        throws SAXException {
        
        // This is ignorable, so don"t display it
    }
    /**
     * <p>
     *   This reports an entity that is skipped by the parser. This
     *     should only occur for non-validating parsers, and then is still
     *     implementation-dependent behavior.
     * </p>
     *
     * @param name <code>String</code> name of entity being skipped
     * @throws <code>SAXException</code> when things go wrong
     */
    public void skippedEntity(String name) throws SAXException {
        DefaultMutableTreeNode skipped =
            new DefaultMutableTreeNode("Skipped Entity: "" + name + """);
        current.add(skipped);
    }
}
/**
 * <b><code>JValidatorErrorHandler</code></b> implements the SAX
 *   <code>ErrorHandler</code> interface and defines callback
 *   behavior for the SAX callbacks associated with an XML
 *   document"s warnings and errors.
 */
class JValidatorErrorHandler implements ErrorHandler {
    /**
     * <p>
     * This will report a warning that has occurred; this indicates
     *   that while no XML rules were "broken", something appears
     *   to be incorrect or missing.
     * </p>
     *
     * @param exception <code>SAXParseException</code> that occurred.
     * @throws <code>SAXException</code> when things go wrong 
     */
    public void warning(SAXParseException exception)
        throws SAXException {
            
        System.out.println("**Parsing Warning**\n" +
                           "  Line:    " + 
                              exception.getLineNumber() + "\n" +
                           "  URI:     " + 
                              exception.getSystemId() + "\n" +
                           "  Message: " + 
                              exception.getMessage());        
        throw new SAXException("Warning encountered");
    }
    /**
     * <p>
     * This will report an error that has occurred; this indicates
     *   that a rule was broken, typically in validation, but that
     *   parsing can reasonably continue.
     * </p>
     *
     * @param exception <code>SAXParseException</code> that occurred.
     * @throws <code>SAXException</code> when things go wrong 
     */
    public void error(SAXParseException exception)
        throws SAXException {
        
        System.out.println("**Parsing Error**\n" +
                           "  Line:    " + 
                              exception.getLineNumber() + "\n" +
                           "  URI:     " + 
                              exception.getSystemId() + "\n" +
                           "  Message: " + 
                              exception.getMessage());
        throw new SAXException("Error encountered");
    }
    /**
     * <p>
     * This will report a fatal error that has occurred; this indicates
     *   that a rule has been broken that makes continued parsing either
     *   impossible or an almost certain waste of time.
     * </p>
     *
     * @param exception <code>SAXParseException</code> that occurred.
     * @throws <code>SAXException</code> when things go wrong 
     */
    public void fatalError(SAXParseException exception)
        throws SAXException {
    
        System.out.println("**Parsing Fatal Error**\n" +
                           "  Line:    " + 
                              exception.getLineNumber() + "\n" +
                           "  URI:     " + 
                              exception.getSystemId() + "\n" +
                           "  Message: " + 
                              exception.getMessage());        
        throw new SAXException("Fatal Error encountered");
    }
}
// Demo file: book.xml
/*
<?xml version="1.0"?>
<!DOCTYPE book SYSTEM "DTD/JavaXML.dtd">
<!-- Java and XML Contents -->
<book xmlns="http://www.oreilly.ru/javaxml2" xmlns:ora="http://www.oreilly.ru" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.oreilly.ru/javaxml2 XSD/contents.xsd 
                          http://www.oreilly.ru XSD/contents-ora.xsd">
  <title ora:series="Java">Java and XML</title>
  <!-- Chapter List -->
  <contents>
    <chapter title="Introduction" number="1">
      <topic name="XML Matters"/>
      <topic name="What"s Important"/>
      <topic name="The Essentials"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="Nuts and Bolts" number="2">
      <topic name="The Basics"/>
      <topic name="Constraints"/>
      <topic name="Transformations"/>
      <topic name="And More..."/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="SAX" number="3">
      <topic name="Getting Prepared"/>
      <topic name="SAX Readers"/>
      <topic name="Content Handlers"/>
      <topic name="Gotcha!"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="Advanced SAX" number="4">
      <topic name="Properties and Features"/>
      <topic name="More Handlers"/>
      <topic name="Filters and Writers"/>
      <topic name="Even More Handlers"/>
      <topic name="Gotcha!"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="DOM" number="5">
      <topic name="The Document Object Model"/>
      <topic name="Serialization"/>
      <topic name="Mutability"/>
      <topic name="Gotcha!"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="Advanced DOM" number="6">
      <topic name="DOM and Mutation"/>
      <topic name="Namespaces and DOM Level 2"/>
      <topic name="DOM and HTML"/>
      <topic name="DOM Level 3"/>
      <topic name="Gotcha!"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="JDOM" number="7">
      <topic name="The Basics"/>
      <topic name="PropsToXML"/>
      <topic name="XMLProperties"/>
      <topic name="Is JDOM a Standard?"/>
      <topic name="Gotcha!"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="Advanced JDOM" number="8">
      <topic name="The Whole Ball of Wax"/>
      <topic name="JDOM and Factories"/>
      <topic name="Wrappers and Decorators"/>
      <topic name="Gotcha!"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="JAXP" number="9">
      <topic name="API or Abstraction?"/>
      <topic name="JAXP 1.0"/>
      <topic name="JAXP 1.1"/>
      <topic name="Gotcha!"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="Web Publishing Frameworks" number="10">
      <topic name="Selecting a Framework"/>
      <topic name="Installation"/>
      <topic name="Using a Publishing Framework"/>
      <topic name="XSP"/>
      <topic name="Cocoon 2.0 and Beyond"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="XML-RPC" number="11">
      <topic name="RPC Versus RMI"/>
      <topic name="Saying Hello"/>
      <topic name="The Real World"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="SOAP" number="12">
      <topic name="Starting Out"/>
      <topic name="Setting Up"/>
      <topic name="Getting Dirty"/>
      <topic name="Going Further"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="Web Services" number="13">
      <topic name="Web Services"/>
      <topic name="UDDI"/>
      <topic name="WSDL"/>
      <topic name="Putting It All Together"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="Content Syndication" number="14">
      <topic name="The Foobar Public Library"/>
      <topic name="mytechbooks.ruI"/>
      <topic name="Push Versus Pull"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="XML Data Binding" number="15">
      <topic name="First Principles"/>
      <topic name="Castor"/>
      <topic name="Zeus"/>
      <topic name="JAXB"/>
      <topic name="What&apos;s Next?"/>
    </chapter>
    <chapter title="Looking Forward" number="16">
      <topic name="XLink"/>
      <topic name="XPointer"/>
      <topic name="XML Schema Bindings"/>
      <topic name="And the Rest..."/>
      <topic name="What&apos;s Next?"/>
    </chapter>
  </contents>
  <ora:copyright>&OReillyCopyright;</ora:copyright>
</book>

*/





Simple lister - extract name and children tags

     
/*
 * Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
 * All rights reserved. Software written by Ian F. Darwin and others.
 * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS""
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
 * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
 * pioneering role in inventing and promulgating (and standardizing) the Java 
 * language and environment is gratefully acknowledged.
 * 
 * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
 * inventing predecessor languages C and C++ is also gratefully acknowledged.
 */
import java.io.IOException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
/**
 * Simple lister - extract name and children tags from a user file. Version for
 * SAX 2.0
 * 
 * @author Ian Darwin
 * @version $Id: SAXLister.java,v 1.12 2004/03/14 17:19:18 ian Exp $
 */
public class SAXLister {
  public static void main(String[] args) throws Exception {
    new SAXLister(args);
  }
  public SAXLister(String[] args) throws SAXException, IOException {
    XMLReader parser = XMLReaderFactory.createXMLReader();
    // should load properties rather than hardcoding class name
    parser.setContentHandler(new PeopleHandler());
    parser.parse(args.length == 1 ? args[0] : "people.xml");
  }
  /**
   * Inner class provides DocumentHandler
   */
  class PeopleHandler extends DefaultHandler {
    boolean person = false;
    boolean email = false;
    public void startElement(String nsURI, String localName,
        String rawName, Attributes attributes) throws SAXException {
      // Consult rawName since we aren"t using xmlns prefixes here.
      if (rawName.equalsIgnoreCase("name"))
        person = true;
      if (rawName.equalsIgnoreCase("email"))
        email = true;
    }
    public void characters(char[] ch, int start, int length) {
      if (person) {
        System.out.println("Person:  " + new String(ch, start, length));
        person = false;
      } else if (email) {
        System.out.println("Email: " + new String(ch, start, length));
        email = false;
      }
    }
  }
}





Using XML locator to indicate current parser position

     
 
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
class SampleOfXmlLocator extends DefaultHandler {
  private Locator locator;
  public void setDocumentLocator(Locator locator) {
    this.locator = locator;
  }
  public void startElement(String uri, String localName, String qName, Attributes attrs)
      throws SAXException {
    if (qName.equals("order")) {
      System.out.println("here process element start");
    } else {
      String location = "";
      if (locator != null) {
        location = locator.getSystemId(); // XML-document name;
        location += " line " + locator.getLineNumber();
        location += ", column " + locator.getColumnNumber();
        location += ": ";
      }
      throw new SAXException(location + "Illegal element");
    }
  }
  public static void main(String[] args) throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setValidating(true);
    SAXParser parser = factory.newSAXParser();
    parser.parse("sample.xml", new SampleOfXmlLocator());
  }
}





Utility class for xml/sax handling

   
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import java.io.*;
import java.util.*;
import javax.xml.transform.*;
import javax.xml.transform.sax.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.*;
import org.xml.sax.helpers.AttributesImpl;
/**
 * Utility class for xml/sax handling.
 * It provides support for "older" sax implementations (like the default one shipped with JDK 1.4.2)
 * which have bugs in the namespace handling.
 */
public class IOUtils {
    /** The transformer factory. */
    private static final SAXTransformerFactory FACTORY = (SAXTransformerFactory) TransformerFactory.newInstance();
    /** The URI for xml namespaces */
    private static final String XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace";
    /**
     * Parse a file and send the sax events to the content handler.
     * @param file
     * @param handler
     * @throws IOException
     * @throws TransformerException
     */
    public static final void parse(File file, ContentHandler handler)
    throws IOException, TransformerException {
        final Transformer transformer = FACTORY.newTransformer();
        transformer.transform(new StreamSource(new FileReader(file)),
                new SAXResult(handler));
    }
    public static ContentHandler getSerializer(File file)
    throws IOException, TransformerException {
        final FileWriter writer = new FileWriter(file);
        final TransformerHandler transformerHandler = FACTORY.newTransformerHandler();
        final Transformer transformer = transformerHandler.getTransformer();
        final Properties format = new Properties();
        format.put(OutputKeys.METHOD, "xml");
        format.put(OutputKeys.OMIT_XML_DECLARATION, "no");
        format.put(OutputKeys.ENCODING, "UTF-8");
        format.put(OutputKeys.INDENT, "yes");
        transformer.setOutputProperties(format);
        transformerHandler.setResult(new StreamResult(writer));
        try {
            if ( needsNamespacesAsAttributes(format) ) {
                return new NamespaceAsAttributes(transformerHandler);
            }
        } catch (SAXException se) {
            throw new TransformerException("Unable to detect of namespace support for sax works properly.", se);
        }
        return transformerHandler;
    }
    /**
     * Checks if the used Trax implementation correctly handles namespaces set using
     * <code>startPrefixMapping()</code>, but wants them also as "xmlns:" attributes.
     * <p>
     * The check consists in sending SAX events representing a minimal namespaced document
     * with namespaces defined only with calls to <code>startPrefixMapping</code> (no
     * xmlns:xxx attributes) and check if they are present in the resulting text.
     */
    protected static boolean needsNamespacesAsAttributes(Properties format)
    throws TransformerException, SAXException {
        // Serialize a minimal document to check how namespaces are handled.
        final StringWriter writer = new StringWriter();
        final String uri = "namespaceuri";
        final String prefix = "nsp";
        final String check = "xmlns:" + prefix + "="" + uri + """;
        final TransformerHandler handler = FACTORY.newTransformerHandler();
        handler.getTransformer().setOutputProperties(format);
        handler.setResult(new StreamResult(writer));
        // Output a single element
        handler.startDocument();
        handler.startPrefixMapping(prefix, uri);
        handler.startElement(uri, "element", "element", new AttributesImpl());
        handler.endElement(uri, "element", "element");
        handler.endPrefixMapping(prefix);
        handler.endDocument();
        final String text = writer.toString();
        // Check if the namespace is there (replace " by " to be sure of what we search in)
        boolean needsIt = (text.replace(""", "\"").indexOf(check) == -1);
        return needsIt;
    }
    /**
     * A pipe that ensures that all namespace prefixes are also present as
     * "xmlns:" attributes. This used to circumvent Xalan"s serialization behaviour
     * which is to ignore namespaces if they"re not present as "xmlns:xxx" attributes.
     */
    public static class NamespaceAsAttributes implements ContentHandler {
        /** The wrapped content handler. */
        private final ContentHandler contentHandler;
        /**
         * The prefixes of startPrefixMapping() declarations for the coming element.
         */
        private List prefixList = new ArrayList();
        /**
         * The URIs of startPrefixMapping() declarations for the coming element.
         */
        private List uriList = new ArrayList();
        /**
         * Maps of URI<->prefix mappings. Used to work around a bug in the Xalan
         * serializer.
         */
        private Map uriToPrefixMap = new HashMap();
        private Map prefixToUriMap = new HashMap();
        /**
         * True if there has been some startPrefixMapping() for the coming element.
         */
        private boolean hasMappings = false;
        public NamespaceAsAttributes(ContentHandler ch) {
            this.contentHandler = ch;
        }
        public void startDocument() throws SAXException {
            // Cleanup
            this.uriToPrefixMap.clear();
            this.prefixToUriMap.clear();
            clearMappings();
            this.contentHandler.startDocument();
        }
        /**
         * Track mappings to be able to add <code>xmlns:</code> attributes
         * in <code>startElement()</code>.
         */
        public void startPrefixMapping(String prefix, String uri) throws SAXException {
            // Store the mappings to reconstitute xmlns:attributes
            // except prefixes starting with "xml": these are reserved
            // VG: (uri != null) fixes NPE in startElement
            if (uri != null && !prefix.startsWith("xml")) {
                this.hasMappings = true;
                this.prefixList.add(prefix);
                this.uriList.add(uri);
                // append the prefix colon now, in order to save concatenations later, but
                // only for non-empty prefixes.
                if (prefix.length() > 0) {
                    this.uriToPrefixMap.put(uri, prefix + ":");
                } else {
                    this.uriToPrefixMap.put(uri, prefix);
                }
                this.prefixToUriMap.put(prefix, uri);
            }
            this.contentHandler.startPrefixMapping(prefix, uri);
        }
        /**
         * Ensure all namespace declarations are present as <code>xmlns:</code> attributes
         * and add those needed before calling superclass. This is a workaround for a Xalan bug
         * (at least in version 2.0.1) : <code>org.apache.xalan.serialize.SerializerToXML</code>
         * ignores <code>start/endPrefixMapping()</code>.
         */
        public void startElement(String eltUri, String eltLocalName, String eltQName, Attributes attrs)
                throws SAXException {
            // try to restore the qName. The map already contains the colon
            if (null != eltUri && eltUri.length() != 0 && this.uriToPrefixMap.containsKey(eltUri)) {
                eltQName = this.uriToPrefixMap.get(eltUri) + eltLocalName;
            }
            if (this.hasMappings) {
                // Add xmlns* attributes where needed
                // New Attributes if we have to add some.
                AttributesImpl newAttrs = null;
                int mappingCount = this.prefixList.size();
                int attrCount = attrs.getLength();
                for (int mapping = 0; mapping < mappingCount; mapping++) {
                    // Build infos for this namespace
                    String uri = (String) this.uriList.get(mapping);
                    String prefix = (String) this.prefixList.get(mapping);
                    String qName = prefix.length() == 0 ? "xmlns" : ("xmlns:" + prefix);
                    // Search for the corresponding xmlns* attribute
                    boolean found = false;
                    for (int attr = 0; attr < attrCount; attr++) {
                        if (qName.equals(attrs.getQName(attr))) {
                            // Check if mapping and attribute URI match
                            if (!uri.equals(attrs.getValue(attr))) {
                                throw new SAXException("URI in prefix mapping and attribute do not match");
                            }
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        // Need to add this namespace
                        if (newAttrs == null) {
                            // Need to test if attrs is empty or we go into an infinite loop...
                            // Well know SAX bug which I spent 3 hours to remind of :-(
                            if (attrCount == 0) {
                                newAttrs = new AttributesImpl();
                            } else {
                                newAttrs = new AttributesImpl(attrs);
                            }
                        }
                        if (prefix.length() == 0) {
                            newAttrs.addAttribute(XML_NAMESPACE_URI, "xmlns", "xmlns", "CDATA", uri);
                        } else {
                            newAttrs.addAttribute(XML_NAMESPACE_URI, prefix, qName, "CDATA", uri);
                        }
                    }
                } // end for mapping
                // Cleanup for the next element
                clearMappings();
                // Start element with new attributes, if any
                this.contentHandler.startElement(eltUri, eltLocalName, eltQName, newAttrs == null ? attrs : newAttrs);
            } else {
                // Normal job
                this.contentHandler.startElement(eltUri, eltLocalName, eltQName, attrs);
            }
        }

        /**
         * Receive notification of the end of an element.
         * Try to restore the element qName.
         */
        public void endElement(String eltUri, String eltLocalName, String eltQName) throws SAXException {
            // try to restore the qName. The map already contains the colon
            if (null != eltUri && eltUri.length() != 0 && this.uriToPrefixMap.containsKey(eltUri)) {
                eltQName = this.uriToPrefixMap.get(eltUri) + eltLocalName;
            }
            this.contentHandler.endElement(eltUri, eltLocalName, eltQName);
        }
        /**
         * End the scope of a prefix-URI mapping:
         * remove entry from mapping tables.
         */
        public void endPrefixMapping(String prefix) throws SAXException {
            // remove mappings for xalan-bug-workaround.
            // Unfortunately, we"re not passed the uri, but the prefix here,
            // so we need to maintain maps in both directions.
            if (this.prefixToUriMap.containsKey(prefix)) {
                this.uriToPrefixMap.remove(this.prefixToUriMap.get(prefix));
                this.prefixToUriMap.remove(prefix);
            }
            if (hasMappings) {
                // most of the time, start/endPrefixMapping calls have an element event between them,
                // which will clear the hasMapping flag and so this code will only be executed in the
                // rather rare occasion when there are start/endPrefixMapping calls with no element
                // event in between. If we wouldn"t remove the items from the prefixList and uriList here,
                // the namespace would be incorrectly declared on the next element following the
                // endPrefixMapping call.
                int pos = prefixList.lastIndexOf(prefix);
                if (pos != -1) {
                    prefixList.remove(pos);
                    uriList.remove(pos);
                }
            }
            this.contentHandler.endPrefixMapping(prefix);
        }
        /**
         * @see org.xml.sax.ContentHandler#endDocument()
         */
        public void endDocument() throws SAXException {
            // Cleanup
            this.uriToPrefixMap.clear();
            this.prefixToUriMap.clear();
            clearMappings();
            this.contentHandler.endDocument();
        }
        private void clearMappings() {
            this.hasMappings = false;
            this.prefixList.clear();
            this.uriList.clear();
        }
        /**
         * @see org.xml.sax.ContentHandler#characters(char[], int, int)
         */
        public void characters(char[] ch, int start, int length) throws SAXException {
            contentHandler.characters(ch, start, length);
        }
        /**
         * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
         */
        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
            contentHandler.ignorableWhitespace(ch, start, length);
        }
        /**
         * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
         */
        public void processingInstruction(String target, String data) throws SAXException {
            contentHandler.processingInstruction(target, data);
        }
        /**
         * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
         */
        public void setDocumentLocator(Locator locator) {
            contentHandler.setDocumentLocator(locator);
        }
        /**
         * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
         */
        public void skippedEntity(String name) throws SAXException {
            contentHandler.skippedEntity(name);
        }
    }
    /**
     * Helper method to add an attribute.
     * This implementation adds a new attribute with the given name
     * and value. Before adding the value is checked for non-null.
     * @param ai    The attributes impl receiving the additional attribute.
     * @param name  The name of the attribute.
     * @param value The value of the attribute.
     */
    protected static void addAttribute(AttributesImpl ai, String name, Object value) {
        if ( value != null ) {
            ai.addAttribute("", name, name, "CDATA", value.toString());
        }
    }
    /**
     * Helper method writing out a string.
     * @param ch    The content handler.
     * @param text
     * @throws SAXException
     */
    protected static void text(ContentHandler ch, String text)
    throws SAXException {
        if ( text != null ) {
            final char[] c = text.toCharArray();
            ch.characters(c, 0, c.length);
        }
    }
    /**
     * Helper method to indent the xml elements.
     * Each level is indented with four spaces.
     * @param ch    The content handler.
     * @param level The level of indention.
     */
    protected static void indent(ContentHandler ch, int level)
    throws SAXException {
        for(int i=0;i<level;i++) {
            IOUtils.text(ch, "    ");
        }
    }
    /**
     * Helper method to create a new line.
     * @param ch    The content handler.
     * @throws SAXException
     */
    protected static void newline(ContentHandler ch)
    throws SAXException {
        IOUtils.text(ch, "\n");
    }
}





XML utility methods that only depend on the JDK

   
/*
 * StandardUtilities.java - Miscelaneous XML utility functions.
 * :tabSize=8:indentSize=8:noTabs=false:
 * :folding=explicit:collapseFolds=1:
 *
 * Copyright (C) 1999, 2006 Marcelo Vanzin, Slava Pestov
 * Portions copyright (C) 2000 Richard S. Hall
 * Portions copyright (C) 2001 Dirk Moebius
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//{{{ Imports
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
//}}}
/**
 * XML utility methods that only depend on the JDK.
 *
 * @author Marcelo Vanzin
 * @version $Id: XMLUtilities.java 13929 2008-10-25 14:23:41Z k_satoda $
 * @since 4.3pre6
 */
public class XMLUtilities
{
  //{{{ charsToEntities() method
  /**
   * Converts &lt;, &gt;, &amp; in the string to their HTML entity
   * equivalents.
   *
   * <p>If <code>xml11</code> is true, then character entities
   * are used to convert illegal XML characters (mainly ASCII
   * control characters).</p>
   *
   * @param str The string
   * @param xml11 Whether to allow XML 1.1 constructs.
   */
  public static String charsToEntities(String str, boolean xml11)
  {
    StringBuilder buf = new StringBuilder(str.length());
    for(int i = 0; i < str.length(); i++)
    {
      char ch = str.charAt(i);
      // control characters, excluding \t, \r and \n
      // See: http://www.w3.org/International/questions/qa-controls
      if (((0x00 <= ch && ch <= 0x1F) || (0x7F <= ch && ch <= 0x9F))
        && ch != "\r" && ch != "\n" && ch != "\t")
      {
        if (xml11 && ch != 0x00)
        {
          buf.append("&#").append((int)ch).append(";");
        }
        else
        {
          // The character is illegal.
          // But put a PI instead, to make it
          // recoverable in certain apps.
          buf.append("<?illegal-xml-character ")
            .append((int)ch)
            .append("?>");
        }
        continue;
      }
      switch(ch)
      {
      case "<":
        buf.append("&lt;");
        break;
      case ">":
        buf.append("&gt;");
        break;
      case "&":
        buf.append("&amp;");
        break;
      default:
        buf.append(ch);
        break;
      }
    }
    return buf.toString();
  } //}}}
  //{{{ parseXML() method
  /**
   * Convenience method for parsing an XML file. This method will
   * wrap the resource in an InputSource and set the source"s
   * systemId to "jedit.jar" (so the source should be able to
   * handle any external entities by itself).
   *
   * <p>SAX Errors are caught and are not propagated to the caller;
   * instead, an error message is printed to jEdit"s activity
   * log. So, if you need custom error handling, <b>do not use
   * this method</b>.
   *
   * <p>The given stream is closed before the method returns,
   * regardless whether there were errors or not.</p>
   *
   * @return true if any error occured during parsing, false if success.
   */
  public static boolean parseXML(InputStream in, DefaultHandler handler)
    throws IOException
  {
    try
    {
      XMLReader parser = XMLReaderFactory.createXMLReader();
      InputSource isrc = new InputSource(
        new BufferedInputStream(in));
      isrc.setSystemId("jedit.jar");
      parser.setContentHandler(handler);
      parser.setDTDHandler(handler);
      parser.setEntityResolver(handler);
      parser.setErrorHandler(handler);
      parser.parse(isrc);
    }
    catch(SAXParseException se)
    {
      int line = se.getLineNumber();
      return true;
    }
    catch(SAXException e)
    {
      return true;
    }
    finally
    {
      try
      {
        if(in != null)
          in.close();
      }
      catch(IOException io)
      {
      }
    }
    return false;
  } //}}}
  //{{{ resolveEntity() method
  /**
   * Tries to find the given systemId in the context of the given
   * class. If the given systemId ends with the given test string,
   * then try to load a resource using the Class"s
   * <code>getResourceAsStream()</code> method using the test string
   * as the resource.
   *
   * <p>This is used a lot internally while parsing XML files used
   * by jEdit, but anyone is free to use the method if it sounds
   * usable.</p>
   */
  public static InputSource findEntity(String systemId, String test, Class where)
  {
    if (systemId != null && systemId.endsWith(test))
    {
      try
      {
        return new InputSource(new BufferedInputStream(
          where.getResourceAsStream(test)));
      }
      catch (Exception e)
      {
      }
    }
    return null;
  } //}}}
  private XMLUtilities() { }
}