Java/XML/Writer

Материал из Java эксперт
Перейти к: навигация, поиск

Convenience methods for writing XML

   <source lang="java">
 

/*

* Copyright Aduna (http://www.aduna-software.ru/) (c) 1997-2006.
*
* Licensed under the Aduna BSD-style license.
*/

import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map.Entry; /**

* A utility class offering convenience methods for writing XML. This class
* takes care of character escaping, identation, etc. This class does not verify
* that the written data is legal XML. It is the callers responsibility to make
* sure that elements are properly nested, etc.
*
*

Example:

*

* To write the following XML: *

 * <?xml version="1.0" encoding="UTF-8"?>
 * <xml-doc>
 *  <foo a="1" b="2&amp;3"/>
 *  <bar>Hello World!</bar>
 * </xml-doc>
 *
* <p>
* One can use the following code:
*
 * XMLWriter xmlWriter = new XMLWriter(myWriter);
 * xmlWriter.setPrettyPrint(true);
 *
 * xmlWriter.startDocument();
 * xmlWriter.startTag("xml-doc");
 *
 * xmlWriter.setAttribute("a", 1);
 * xmlWriter.setAttribute("b", "2&3");
 * xmlWriter.simpleTag("foo");
 *
 * xmlWriter.textTag("bar", "Hello World!");
 *
 * xmlWriter.endTag("xml-doc");
 * xmlWriter.endDocument();
 * 
*/

public class XMLWriter {

 /*-----------*
  * Constants *
  *-----------*/
 /**
  * The (platform-dependent) line separator.
  */
 private static final String LINE_SEPARATOR = System.getProperty("line.separator");
 /*-----------*
  * Variables *
  *-----------*/
 /**
  * The writer to write the XML to.
  */
 private Writer _writer;
 /**
  * The required character encoding of the written data.
  */
 private String _charEncoding;
 /**
  * Flag indicating whether the output should be printed pretty, i.e. adding
  * newlines and indentation.
  */
 private boolean _prettyPrint = false;
 /**
  * The current indentation level, i.e. the number of tabs to indent a start
  * or end tag.
  */
 protected int _indentLevel = 0;
 /**
  * The string to use for indentation, e.g. a tab or a number of spaces.
  */
 private String _indentString = "\t";
 /**
  * A mapping from attribute names to values for the next start tag.
  */
 private HashMap<String, String> _attributes = new LinkedHashMap<String, String>();
 /*--------------*
  * Constructors *
  *--------------*/
 /**
  * Creates a new XMLWriter that will write its data to the supplied Writer.
  * Character encoding issues are left to the supplier of the Writer.
  *
  * @param writer The Writer to write the XML to.
  */
 public XMLWriter(Writer writer) {
   _writer = writer;
 }
 /**
  * Creates a new XMLWriter that will write its data to the supplied
  * OutputStream in the default UTF-8 character encoding.
  *
  * @param outputStream The OutputStream to write the XML to.
  */
 public XMLWriter(OutputStream outputStream) {
   try {
     _charEncoding = "UTF-8";
     _writer = new OutputStreamWriter(outputStream, _charEncoding);
   }
   catch (UnsupportedEncodingException e) {
     // UTF-8 must be supported by all compliant JVM"s,
     // this exception should never be thrown.
     throw new RuntimeException(
         "UTF-8 character encoding not supported on this platform");
   }
 }
 /**
  * Creates a new XMLWriter that will write its data to the supplied
  * OutputStream in specified character encoding.
  *
  * @param outputStream The OutputStream to write the XML to.
  */
 public XMLWriter(OutputStream outputStream, String charEncoding)
   throws UnsupportedEncodingException
 {
   _charEncoding = charEncoding;
   _writer = new OutputStreamWriter(outputStream, _charEncoding);
 }
 /*---------*
  * Methods *
  *---------*/
 /**
  * Enables or disables pretty-printing. If pretty-printing is enabled, the
  * XMLWriter will add newlines and indentation to the written data.
  * Pretty-printing is disabled by default.
  *
  * @param prettyPrint Flag indicating whether pretty-printing should be
  * enabled.
  */
 public void setPrettyPrint(boolean prettyPrint) {
   _prettyPrint = prettyPrint;
 }
 /**
  * Checks whether pretty-printing is enabled.
  *
  * @return true if pretty-printing is enabled, false
  * otherwise.
  */
 public boolean prettyPrintEnabled() {
   return _prettyPrint;
 }
 /**
  * Sets the string that should be used for indentation when pretty-printing
  * is enabled. The default indentation string is a tab character.
  *
  * @param indentString The indentation string, e.g. a tab or a number of
  * spaces.
  */
 public void setIndentString(String indentString) {
   _indentString = indentString;
 }
 /**
  * Gets the string used for indentation.
  *
  * @return the indentation string.
  */
 public String getIndentString() {
   return _indentString;
 }
 /**
  * Writes the XML header for the XML file.
  *
  * @throws IOException If an I/O error occurs.
  */
 public void startDocument()
   throws IOException
 {
   _write("<?xml version="1.0"");
   if (_charEncoding != null) {
     _write(" encoding="" + _charEncoding + """);
   }
   _writeLn("?>");
 }
 /**
  * Finishes writing and flushes the OutputStream or Writer that this
  * XMLWriter is writing to.
  */
 public void endDocument()
   throws IOException
 {
   _writer.flush();
   _writer = null;
 }
 /**
  * Sets an attribute for the next start tag.
  *
  * @param name The name of the attribute.
  * @param value The value of the attribute.
  */
 public void setAttribute(String name, String value) {
   _attributes.put(name, value);
 }
 /**
  * Sets an attribute for the next start element.
  *
  * @param name The name of the attribute.
  * @param value The value of the attribute. The integer value will be
  * transformed to a string using the method String.valueOf(int).
  * @see java.lang.String#valueOf(int)
  */
 public void setAttribute(String name, int value) {
   setAttribute(name, String.valueOf(value));
 }
 /**
  * Sets an attribute for the next start element.
  *
  * @param name The name of the attribute.
  * @param value The value of the attribute. The boolean value will be
  * transformed to a string using the method
  * String.valueOf(boolean).
  * @see java.lang.String#valueOf(boolean)
  */
 public void setAttribute(String name, boolean value) {
   setAttribute(name, String.valueOf(value));
 }
 /**
  * Writes a start tag containing the previously set attributes.
  *
  * @param elName The element name.
  * @see #setAttribute(java.lang.String,java.lang.String)
  */
 public void startTag(String elName)
   throws IOException
 {
   _writeIndent();
   _write("<" + elName);
   _writeAtts();
   _writeLn(">");
   _indentLevel++;
 }
 /**
  * Writes an end tag.
  *
  * @param elName The element name.
  */
 public void endTag(String elName)
   throws IOException
 {
   _indentLevel--;
   _writeIndent();
   _writeLn("</" + elName + ">");
 }
 /**
  * Writes an "empty" element, e.g. <foo/>. The tag will
  * contain any previously set attributes.
  *
  * @param elName The element name.
  * @see #setAttribute(java.lang.String,java.lang.String)
  */
 public void emptyElement(String elName)
   throws IOException
 {
   _writeIndent();
   _write("<" + elName);
   _writeAtts();
   _writeLn("/>");
 }
 /**
  * Writes a start and end tag with the supplied text between them. The start
  * tag will contain any previously set attributes.
  *
  * @param elName The element name.
  * @param text The text.
  * @see #setAttribute(java.lang.String,java.lang.String)
  */
 public void textElement(String elName, String text)
   throws IOException
 {
   _writeIndent();
   _write("<" + elName);
   _writeAtts();
   _write(">");
   text(text);
   _writeLn("</" + elName + ">");
 }
 /**
  * Writes a start and end tag with the supplied text between them, without
  * the usual escape rules. The start tag will contain any previously set
  * attributes.
  *
  * @param elName The element name.
  * @param text The text.
  * @see #setAttribute(java.lang.String,java.lang.String)
  */
 public void unescapedTextElement(String elName, String text)
   throws IOException
 {
   _writeIndent();
   _write("<" + elName);
   _writeAtts();
   _write(">");
   _write(text);
   _writeLn("</" + elName + ">");
 }
 /**
  * Writes a start and end tag with the supplied value between them. The
  * start tag will contain any previously set attributes.
  *
  * @param elName The element name.
  * @param value The value. The integer value will be transformed to a string
  * using the method String.valueOf(int).
  * @see java.lang.String#valueOf(int)
  */
 public void textElement(String elName, int value)
   throws IOException
 {
   textElement(elName, String.valueOf(value));
 }
 /**
  * Writes a start and end tag with the supplied boolean value between them.
  * The start tag will contain any previously set attributes.
  *
  * @param elName The element name.
  * @param value The boolean value. The integer value will be transformed to
  * a string using the method String.valueOf(boolean).
  * @see java.lang.String#valueOf(boolean)
  */
 public void textElement(String elName, boolean value)
   throws IOException
 {
   textElement(elName, String.valueOf(value));
 }
 /**
  * Writes a piece of text.
  *
  * @param text The text.
  */
 public void text(String text)
   throws IOException
 {
   _write(text);
 }
 
 /**
  * Writes a comment.
  *
  * @param comment The comment.
  */
 public void comment(String comment)
   throws IOException
 {
   _writeIndent();
   _writeLn("");
 }
 /**
  * Writes an empty line. A call to this method will be ignored when
  * pretty-printing is disabled.
  *
  * @see #setPrettyPrint
  */
 public void emptyLine()
   throws IOException
 {
   _writeLn("");
 }
 /**
  * Writes any set attributes and clears them afterwards.
  */
 private void _writeAtts()
   throws IOException
 {
   for (Entry<String,String> entry : _attributes.entrySet()) {
     String name = entry.getKey();
     String value = entry.getValue();
     _write(" " + name + "="");
     if (value != null) {
       _write(value);
     }
     _write(""");
   }
   
   _attributes.clear();
 }
 /**
  * Writes a string.
  */
 protected void _write(String s)
   throws IOException
 {
   _writer.write(s);
 }
 /**
  * Writes a string followed by a line-separator. The line-separator is not
  * written when pretty-printing is disabled.
  */
 protected void _writeLn(String s)
   throws IOException
 {
   _write(s);
   if (_prettyPrint) {
     _write(LINE_SEPARATOR);
   }
 }
 /**
  * Writes as much indentation strings as appropriate for the current
  * indentation level. A call to this method is ignored when pretty-printing
  * is disabled.
  */
 protected void _writeIndent()
   throws IOException
 {
   if (_prettyPrint) {
     for (int i = 0; i < _indentLevel; i++) {
       _write(_indentString);
     }
   }
 }

}


 </source>
   
  
 
  



DOM writer

   <source lang="java">

/*

* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
* 
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
* 
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
* 
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
* 
* Contributor(s):
* 
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don"t indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*

* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999-2003 The Apache Software Foundation.  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 acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* 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 APACHE SOFTWARE FOUNDATION 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 on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.apache.org.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; /**

* A sample DOM writer. This sample program illustrates how to
* traverse a DOM tree in order to print a document that is parsed.
*
* @author Andy Clark, IBM
*
* @version $Id: DOMWriter.java,v 1.2 2007/07/19 04:35:46 ofung Exp $
*/

public class DOMWriter {

   //
   // 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";
   /** 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";
   // 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 = "dom.wrappers.Xerces";
   /** Default namespaces support (true). */
   protected static final boolean DEFAULT_NAMESPACES = true;
   /** 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 canonical output (false). */
   protected static final boolean DEFAULT_CANONICAL = false;
   //
   // Data
   //
   /** Print writer. */
   protected PrintWriter fOut;
   /** Canonical output. */
   protected boolean fCanonical;
   
   /** Processing XML 1.1 document. */
   protected boolean fXML11;
   //
   // Constructors
   //
   /** Default constructor. */
   public DOMWriter() {
   } // <init>()
   public DOMWriter(boolean canonical) {
       fCanonical = canonical;
   } // <init>(boolean)
   
   public DOMWriter( OutputStream out, String encoding ) throws UnsupportedEncodingException {
       this();
       setOutput(out,encoding);
   }
   //
   // 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)
   /** Writes the specified node, recursively. */
   public void write(Node node) {
       // is there anything to do?
       if (node == null) {
           return;
       }
       short type = node.getNodeType();
       switch (type) {
           case Node.DOCUMENT_NODE: {
               Document document = (Document)node;
               fXML11 = "1.1".equals(getVersion(document));
               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();
                   write(document.getDoctype());
               }
               write(document.getDocumentElement());
               break;
           }
           case Node.DOCUMENT_TYPE_NODE: {
               DocumentType doctype = (DocumentType)node;
               fOut.print("<!DOCTYPE ");
               fOut.print(doctype.getName());
               String publicId = doctype.getPublicId();
               String systemId = doctype.getSystemId();
               if (publicId != null) {
                   fOut.print(" PUBLIC "");
                   fOut.print(publicId);
                   fOut.print("" "");
                   fOut.print(systemId);
                   fOut.print("\"");
               }
               else if (systemId != null) {
                   fOut.print(" SYSTEM "");
                   fOut.print(systemId);
                   fOut.print("\"");
               }
               String internalSubset = doctype.getInternalSubset();
               if (internalSubset != null) {
                   fOut.println(" [");
                   fOut.print(internalSubset);
                   fOut.print("]");
               }
               fOut.println(">");
               break;
           }
           case Node.ELEMENT_NODE: {
               fOut.print("<");
               fOut.print(node.getNodeName());
               Attr attrs[] = sortAttributes(node.getAttributes());
               for (int i = 0; i < attrs.length; i++) {
                   Attr attr = attrs[i];
                   fOut.print(" ");
                   fOut.print(attr.getNodeName());
                   fOut.print("=\"");
                   normalizeAndPrint(attr.getNodeValue(), true);
                   fOut.print(""");
               }
               fOut.print(">");
               fOut.flush();
               Node child = node.getFirstChild();
               while (child != null) {
                   write(child);
                   child = child.getNextSibling();
               }
               break;
           }
           case Node.ENTITY_REFERENCE_NODE: {
               if (fCanonical) {
                   Node child = node.getFirstChild();
                   while (child != null) {
                       write(child);
                       child = child.getNextSibling();
                   }
               }
               else {
                   fOut.print("&");
                   fOut.print(node.getNodeName());
                   fOut.print(";");
                   fOut.flush();
               }
               break;
           }
           case Node.CDATA_SECTION_NODE: {
               if (fCanonical) {
                   normalizeAndPrint(node.getNodeValue(), false);
               }
               else {
                   fOut.print("<![CDATA[");
                   fOut.print(node.getNodeValue());
                   fOut.print("]]>");
               }
               fOut.flush();
               break;
           }
           case Node.TEXT_NODE: {
               normalizeAndPrint(node.getNodeValue(), false);
               fOut.flush();
               break;
           }
           case Node.PROCESSING_INSTRUCTION_NODE: {
               fOut.print("<?");
               fOut.print(node.getNodeName());
               String data = node.getNodeValue();
               if (data != null && data.length() > 0) {
                   fOut.print(" ");
                   fOut.print(data);
               }
               fOut.print("?>");
               fOut.flush();
               break;
           }
           
           case Node.ruMENT_NODE: {
               if (!fCanonical) {
                   fOut.print("");
                   fOut.flush();
               }
           }
       }
       if (type == Node.ELEMENT_NODE) {
           fOut.print("</");
           fOut.print(node.getNodeName());
           fOut.print(">");
           fOut.flush();
       }
   } // write(Node)
   /** Returns a sorted list of attributes. */
   protected Attr[] sortAttributes(NamedNodeMap attrs) {
       int len = (attrs != null) ? attrs.getLength() : 0;
       Attr array[] = new Attr[len];
       for (int i = 0; i < len; i++) {
           array[i] = (Attr)attrs.item(i);
       }
       for (int i = 0; i < len - 1; i++) {
           String name = array[i].getNodeName();
           int index = i;
           for (int j = i + 1; j < len; j++) {
               String curName = array[j].getNodeName();
               if (curName.rupareTo(name) < 0) {
                   name = curName;
                   index = j;
               }
           }
           if (index != i) {
               Attr temp = array[i];
               array[i] = array[index];
               array[index] = temp;
           }
       }
       return array;
   } // sortAttributes(NamedNodeMap):Attr[]
   //
   // Protected methods
   //
   /** 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 print the given character. */
   protected void normalizeAndPrint(char c, boolean isAttValue) {
       switch (c) {
           case "<": {
               fOut.print("<");
               break;
           }
           case ">": {
               fOut.print(">");
               break;
           }
           case "&": {
               fOut.print("&");
               break;
           }
           case """: {
               // A """ that appears in character data 
               // does not need to be escaped.
               if (isAttValue) {
                   fOut.print(""");
               }
               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("
");
                   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)
   /** Extracts the XML version from the Document. */
   protected String getVersion(Document document) {
       if (document == null) {
           return null;
       }
       String version = null;
       Method getXMLVersion = null;
       try {
           getXMLVersion = document.getClass().getMethod("getXmlVersion", new Class[]{});
           // If Document class implements DOM L3, this method will exist.
           if (getXMLVersion != null) {
               version = (String) getXMLVersion.invoke(document, null);
           }
       } 
       catch (Exception e) { 
           // Either this locator object doesn"t have 
           // this method, or we"re on an old JDK.
       }
       return version;
   } // getVersion(Document)
   //
   // Private static methods
   //
   /** Prints the usage. */
   private static void printUsage() {
       System.err.println("usage: java dom.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("  -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("  -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("  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("  Canonical:  ");
       System.err.println(DEFAULT_CANONICAL ? "on" : "off");
   } // printUsage()

} // class Writer

 </source>
   
  
 
  



Makes writing XML much much easier

   <source lang="java">

/*

* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation.  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 acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org /)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
*    "Apache Commons" must not be used to endorse or promote products
*    derived from this software without prior written permission. For
*    written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    "Apache Turbine", nor may "Apache" appear in their name, without
*    prior written permission of the Apache Software Foundation.
*
* 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 APACHE SOFTWARE FOUNDATION 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 on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org />.
*/

import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.Stack;

/**

* Makes writing XML much much easier.
* Improved from
* 
* @author Last changed by: $Author: gommma $
* @version $Revision: 859 $ $Date: 2008-11-02 12:50:23 +0100 (dom, 02 nov 2008) $
* @since 1.0
*/

public class XmlWriter {

   /**
    * CDATA start tag: {@value}
    */
   public static final String CDATA_START = "<![CDATA[";
   /**
    * CDATA end tag: {@value}
    */
   public static final String CDATA_END = "]]>";
   /**
    * Default encoding value which is {@value}
    */
   public static final String DEFAULT_ENCODING = "UTF-8";
   
   /**
    * Logger for this class
    */
   private Writer out;      // underlying writer
   private String encoding; // the encoding to be written into the XML header/metatag
   private Stack stack = new Stack();        // of xml element names
   private StringBuffer attrs; // current attribute string
   private boolean empty;      // is the current node empty
   private boolean closed = true;     // is the current node closed...
   private boolean pretty = true;    // is pretty printing enabled?
   /**
    * was text the last thing output?
    */
   private boolean wroteText = false;
   /**
    * output this to indent one level when pretty printing
    */
   private String indent = "  ";
   /**
    * output this to end a line when pretty printing
    */
   private String newline = "\n";
   
   /**
    * Create an XmlWriter on top of an existing java.io.Writer.
    */
   public XmlWriter(Writer writer)
   {
       this(writer, null);
   }
   /**
    * Create an XmlWriter on top of an existing java.io.Writer.
    */
   public XmlWriter(Writer writer, String encoding)
   {
       setWriter(writer, encoding);
   }
   /**
    * Create an XmlWriter on top of an existing {@link java.io.OutputStream}.
    * @param outputStream
    * @param encoding The encoding to be used for writing to the given output
    * stream. Can be null. If it is null the 
    * {@link #DEFAULT_ENCODING} is used.
    * @throws UnsupportedEncodingException 
    * @since 2.4
    */
   public XmlWriter(OutputStream outputStream, String encoding) 
   throws UnsupportedEncodingException
   {
       if(encoding==null)
       {
           encoding = DEFAULT_ENCODING;            
       }
       OutputStreamWriter writer = new OutputStreamWriter(outputStream, encoding);
       setWriter(writer, encoding);
   }
   /**
    * Turn pretty printing on or off.
    * Pretty printing is enabled by default, but it can be turned off
    * to generate more compact XML.
    *
    * @param enable true to enable, false to disable pretty printing.
    */
   public void enablePrettyPrint(boolean enable)
   {
       this.pretty = enable;
   }
 /**
    * Specify the string to prepend to a line for each level of indent.
    * It is 2 spaces ("  ") by default. Some may prefer a single tab ("\t")
    * or a different number of spaces. Specifying an empty string will turn
    * off indentation when pretty printing.
    *
    * @param indent representing one level of indentation while pretty printing.
    */
   public void setIndent(String indent)
   {
       this.indent = indent;
   }
   /**
    * Specify the string used to terminate each line when pretty printing.
    * It is a single newline ("\n") by default. Users who need to read
    * generated XML documents in Windows editors like Notepad may wish to
    * set this to a carriage return/newline sequence ("\r\n"). Specifying
    * an empty string will turn off generation of line breaks when pretty
    * printing.
    *
    * @param newline representing the newline sequence when pretty printing.
    */
   public void setNewline(String newline)
   {
       this.newline = newline;
   }
   /**
    * A helper method. It writes out an element which contains only text.
    *
    * @param name String name of tag
    * @param text String of text to go inside the tag
    */
   public XmlWriter writeElementWithText(String name, String text) throws IOException
   {
       writeElement(name);
       writeText(text);
       return endElement();
   }
   /**
    * A helper method. It writes out empty entities.
    *
    * @param name String name of tag
    */
   public XmlWriter writeEmptyElement(String name) throws IOException
   {
       writeElement(name);
       return endElement();
   }
   /**
    * Begin to write out an element. Unlike the helper tags, this tag
    * will need to be ended with the endElement method.
    *
    * @param name String name of tag
    */
   public XmlWriter writeElement(String name) throws IOException
   {
       return openElement(name);
   }
   /**
    * Begin to output an element.
    *
    * @param name name of element.
    */
   private XmlWriter openElement(String name) throws IOException
   {
       boolean wasClosed = this.closed;
       closeOpeningTag();
       this.closed = false;
       if (this.pretty)
       {
           //   ! wasClosed separates adjacent opening tags by a newline.
           // this.wroteText makes sure an element embedded within the text of
           // its parent element begins on a new line, indented to the proper
           // level. This solves only part of the problem of pretty printing
           // entities which contain both text and child entities.
           if (!wasClosed || this.wroteText)
           {
               this.out.write(newline);
           }
           for (int i = 0; i < this.stack.size(); i++)
           {
               this.out.write(indent); // Indent opening tag to proper level
           }
       }
       this.out.write("<");
       this.out.write(name);
       stack.add(name);
       this.empty = true;
       this.wroteText = false;
       return this;
   }
   // close off the opening tag
   private void closeOpeningTag() throws IOException
   {
       if (!this.closed)
       {
           writeAttributes();
           this.closed = true;
           this.out.write(">");
       }
   }
   // write out all current attributes
   private void writeAttributes() throws IOException
   {
       if (this.attrs != null)
       {
           this.out.write(this.attrs.toString());
           this.attrs.setLength(0);
           this.empty = false;
       }
   }
   /**
    * Write an attribute out for the current element.
    * Any XML characters in the value are escaped.
    * Currently it does not actually throw the exception, but
    * the API is set that way for future changes.
    *
    * @param attr name of attribute.
    * @param value value of attribute.
    * @see #writeAttribute(String, String, boolean)
    */
   public XmlWriter writeAttribute(String attr, String value) throws IOException
   {
       return this.writeAttribute(attr, value, false);
   }
   /**
    * Write an attribute out for the current element.
    * Any XML characters in the value are escaped.
    * Currently it does not actually throw the exception, but
    * the API is set that way for future changes.
    *
    * @param attr name of attribute.
    * @param value value of attribute.
    * @param literally If the writer should be literally on the given value
    * which means that meta characters will also be preserved by escaping them. 
    * Mainly preserves newlines and tabs.
    */
   public XmlWriter writeAttribute(String attr, String value, boolean literally) throws IOException
   {
     if(this.wroteText==true) {
       throw new IllegalStateException("The text for the current element has already been written. Cannot add attributes afterwards.");
     }
       // maintain API
       if (false) throw new IOException();
       if (this.attrs == null)
       {
           this.attrs = new StringBuffer();
       }
       this.attrs.append(" ");
       this.attrs.append(attr);
       this.attrs.append("=\"");
       String val = escapeXml(value);
       if(literally){
         val = escapeMetaCharacters(val);
       }
       this.attrs.append(val);
       this.attrs.append("\"");
       return this;
   }
   /**
    * End the current element. This will throw an exception
    * if it is called when there is not a currently open
    * element.
    */
   public XmlWriter endElement() throws IOException
   {
       if (this.stack.empty())
       {
           throw new IOException("Called endElement too many times. ");
       }
       String name = (String)this.stack.pop();
       if (name != null)
       {
           if (this.empty)
           {
               writeAttributes();
               this.out.write("/>");
           }
           else
           {
               if (this.pretty && !this.wroteText)
               {
                   for (int i = 0; i < this.stack.size(); i++)
                   {
                       this.out.write(indent); // Indent closing tag to proper level
                   }
               }
               this.out.write("</");
               this.out.write(name);
               this.out.write(">");
           }
           if (this.pretty)
               this.out.write(newline); // Add a newline after the closing tag
           this.empty = false;
           this.closed = true;
           this.wroteText = false;
       }
       return this;
   }
   /**
    * Close this writer. It does not close the underlying
    * writer, but does throw an exception if there are
    * as yet unclosed tags.
    */
   public void close() throws IOException
   {
       this.out.flush();
       if (!this.stack.empty())
       {
           throw new IOException("Tags are not all closed. " +
                   "Possibly, " + this.stack.pop() + " is unclosed. ");
       }
   }
   /**
    * Output body text. Any XML characters are escaped.
    * @param text The text to be written
    * @return This writer
    * @throws IOException
    * @see #writeText(String, boolean)
    */
   public XmlWriter writeText(String text) throws IOException
   {
       return this.writeText(text, false);
   }
   /**
    * Output body text. Any XML characters are escaped.
    * @param text The text to be written
    * @param literally If the writer should be literally on the given value
    * which means that meta characters will also be preserved by escaping them. 
    * Mainly preserves newlines and tabs.
    * @return This writer
    * @throws IOException
    */
   public XmlWriter writeText(String text, boolean literally) throws IOException
   {
       closeOpeningTag();
       this.empty = false;
       this.wroteText = true;
       String val = escapeXml(text);
       if(literally){
         val = escapeMetaCharacters(val);
       }
       this.out.write(val);
       return this;
   }
   /**
    * Write out a chunk of CDATA. This helper method surrounds the
    * passed in data with the CDATA tag.
    *
    * @param cdata of CDATA text.
    */
   public XmlWriter writeCData(String cdata) throws IOException
   {
 
       closeOpeningTag();
       
       boolean hasAlreadyEnclosingCdata = cdata.startsWith(CDATA_START) && cdata.endsWith(CDATA_END);
       
       // There may already be CDATA sections inside the data.
       // But CDATA sections can"t be nested - can"t have ]]> inside a CDATA section. 
       // (See http://www.w3.org/TR/REC-xml/#NT-CDStart in the W3C specs)
       // The solutions is to replace any occurrence of "]]>" by "]]]]><![CDATA[>",
       // so that the top CDATA section is split into many valid CDATA sections (you
       // can look at the "]]]]>" as if it was an escape sequence for "]]>").
       if(!hasAlreadyEnclosingCdata) {
           cdata = cdata.replaceAll(CDATA_END, "]]]]><![CDATA[>");
       }
       
       this.empty = false;
       this.wroteText = true;
       if(!hasAlreadyEnclosingCdata)
           this.out.write(CDATA_START);
       this.out.write(cdata);
       if(!hasAlreadyEnclosingCdata)
           this.out.write(CDATA_END);
       return this;
   }
   /**
    * Write out a chunk of comment. This helper method surrounds the
    * passed in data with the XML comment tag.
    *
    * @param comment of text to comment.
    */
   public XmlWriter writeComment(String comment) throws IOException
   {
  
       writeChunk("");
       return this;
   }
   private void writeChunk(String data) throws IOException
   {
   
       closeOpeningTag();
       this.empty = false;
       if (this.pretty && !this.wroteText)
       {
           for (int i = 0; i < this.stack.size(); i++)
           {
               this.out.write(indent);
           }
       }
       this.out.write(data);
       if (this.pretty)
       {
           this.out.write(newline);
       }
   }
   // Two example methods. They should output the same XML:
   // <person name="fred" age="12"><phone>425343</phone><bob/></person>
   static public void main(String[] args) throws IOException
   {
   
       test1();
       test2();
   }
   static public void test1() throws IOException
   {
    
       Writer writer = new java.io.StringWriter();
       XmlWriter xmlwriter = new XmlWriter(writer);
       xmlwriter.writeElement("person").writeAttribute("name", "fred").writeAttribute("age", "12").writeElement("phone").writeText("4254343").endElement().writeElement("friends").writeElement("bob").endElement().writeElement("jim").endElement().endElement().endElement();
       xmlwriter.close();
       System.err.println(writer.toString());
   }
   static public void test2() throws IOException
   {
    
       Writer writer = new java.io.StringWriter();
       XmlWriter xmlwriter = new XmlWriter(writer);
       xmlwriter.writeComment("Example of XmlWriter running");
       xmlwriter.writeElement("person");
       xmlwriter.writeAttribute("name", "fred");
       xmlwriter.writeAttribute("age", "12");
       xmlwriter.writeElement("phone");
       xmlwriter.writeText("4254343");
       xmlwriter.endElement();
       xmlwriter.writeComment("Examples of empty tags");

// xmlwriter.setDefaultNamespace("test");

       xmlwriter.writeElement("friends");
       xmlwriter.writeEmptyElement("bob");
       xmlwriter.writeEmptyElement("jim");
       xmlwriter.endElement();
       xmlwriter.writeElementWithText("foo", "This is an example.");
       xmlwriter.endElement();
       xmlwriter.close();
       System.err.println(writer.toString());
   }
   ////////////////////////////////////////////////////////////////////////////
   // Added for DbUnit
   /**
    * Escapes some meta characters like \n, \r that should be preserved in the XML
    * so that a reader will not filter out those symbols.
    * @param str The string to be escaped
    * @return The escaped string
    * @since 2.3.0
    */
   private String escapeMetaCharacters(String str)
   {
   
       // 2. Do additional escapes. See http://www.w3.org/TR/2004/REC-xml-20040204/#AVNormalize
       str = replace(str, "\n", "
"); // linefeed (LF)
       str = replace(str, "\r", "&#xD;"); // carriage return (CR)
       return str;
   }
   
   private String escapeXml(String str)
   {
    
       str = replace(str, "&", "&");
       str = replace(str, "<", "<");
       str = replace(str, ">", ">");
       str = replace(str, "\"", """);
       str = replace(str, """, "'");
       str = replace(str, "\t", "	"); // tab
       return str;
   }
   private String replace(String value, String original, String replacement)
   {
 
       StringBuffer buffer = null;
       int startIndex = 0;
       int lastEndIndex = 0;
       for (; ;)
       {
           startIndex = value.indexOf(original, lastEndIndex);
           if (startIndex == -1)
           {
               if (buffer != null)
               {
                   buffer.append(value.substring(lastEndIndex));
               }
               break;
           }
           if (buffer == null)
           {
               buffer = new StringBuffer((int)(original.length() * 1.5));
           }
           buffer.append(value.substring(lastEndIndex, startIndex));
           buffer.append(replacement);
           lastEndIndex = startIndex + original.length();
       }
       return buffer == null ? value : buffer.toString();
   }
   private void setEncoding(String encoding)
   {
    
       if (encoding == null && out instanceof OutputStreamWriter)
           encoding = ((OutputStreamWriter)out).getEncoding();
       if (encoding != null)
       {
           encoding = encoding.toUpperCase();
           // Use official encoding names where we know them,
           // avoiding the Java-only names.  When using common
           // encodings where we can easily tell if characters
           // are out of range, we"ll escape out-of-range
           // characters using character refs for safety.
           // I _think_ these are all the main synonyms for these!
           if ("UTF8".equals(encoding))
           {
               encoding = "UTF-8";
           }
           else if ("US-ASCII".equals(encoding)
                   || "ASCII".equals(encoding))
           {

// dangerMask = (short)0xff80;

               encoding = "US-ASCII";
           }
           else if ("ISO-8859-1".equals(encoding)
                   || "8859_1".equals(encoding)
                   || "ISO8859_1".equals(encoding))
           {

// dangerMask = (short)0xff00;

               encoding = "ISO-8859-1";
           }
           else if ("UNICODE".equals(encoding)
                   || "UNICODE-BIG".equals(encoding)
                   || "UNICODE-LITTLE".equals(encoding))
           {
               encoding = "UTF-16";
               // TODO: UTF-16BE, UTF-16LE ... no BOM; what
               // release of JDK supports those Unicode names?
           }

// if (dangerMask != 0) // stringBuf = new StringBuffer();

       }
       this.encoding = encoding;
   }
   /**
    * Resets the handler to write a new text document.
    *
    * @param writer XML text is written to this writer.
    * @param encoding if non-null, and an XML declaration is written,
    *  this is the name that will be used for the character encoding.
    *
    * @exception IllegalStateException if the current
    *  document hasn"t yet ended (i.e. the output stream {@link #out} is not null)
    */
   final public void setWriter(Writer writer, String encoding)
   {
  
       if (this.out != null)
           throw new IllegalStateException(
                   "can"t change stream in mid course");
       this.out = writer;
       if (this.out != null)
           setEncoding(encoding);

// if (!(this.out instanceof BufferedWriter)) // this.out = new BufferedWriter(this.out);

   }
   public XmlWriter writeDeclaration() throws IOException
   {
    
       if (this.encoding != null)
       {
           this.out.write("<?xml version="1.0"");
           this.out.write(" encoding="" + this.encoding + """);
           this.out.write("?>");
           this.out.write(this.newline);
       }
       return this;
   }
   public XmlWriter writeDoctype(String systemId, String publicId) throws IOException
   {
    
       if (systemId != null || publicId != null)
       {
           this.out.write("<!DOCTYPE dataset");
           if (systemId != null)
           {
               this.out.write(" SYSTEM \"");
               this.out.write(systemId);
               this.out.write("\"");
           }
           if (publicId != null)
           {
               this.out.write(" PUBLIC \"");
               this.out.write(publicId);
               this.out.write("\"");
           }
           this.out.write(">");
           this.out.write(this.newline);
       }
       return this;
   }

}

 </source>
   
  
 
  



Use DOM L3 DOMBuilder, DOMBuilderFilter DOMWriter and other DOM L3 functionality to preparse, revalidate and safe document.

   <source lang="java">

/*

* 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 org.w3c.dom.DOMConfiguration; import org.w3c.dom.DOMError; import org.w3c.dom.DOMErrorHandler; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.bootstrap.DOMImplementationRegistry; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSOutput; import org.w3c.dom.ls.LSParser; import org.w3c.dom.ls.LSParserFilter; import org.w3c.dom.ls.LSSerializer; import org.w3c.dom.traversal.NodeFilter; /**

* This sample program illustrates how to use DOM L3 DOMBuilder,
* DOMBuilderFilter DOMWriter and other DOM L3 functionality to preparse,
* revalidate and safe document.
*/

public class DOM3 implements DOMErrorHandler, LSParserFilter {

 /** Default namespaces support (true). */
 protected static final boolean DEFAULT_NAMESPACES = true;
 /** Default validation support (false). */
 protected static final boolean DEFAULT_VALIDATION = false;
 /** Default Schema validation support (false). */
 protected static final boolean DEFAULT_SCHEMA_VALIDATION = false;
 static LSParser builder;
 public static void main(String[] argv) {
   if (argv.length == 0) {
     printUsage();
     System.exit(1);
   }
   try {
     // get DOM Implementation using DOM Registry
     System.setProperty(DOMImplementationRegistry.PROPERTY,
         "org.apache.xerces.dom.DOMXSImplementationSourceImpl");
     DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
     DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
     // create DOMBuilder
     builder = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
     DOMConfiguration config = builder.getDomConfig();
     // create Error Handler
     DOMErrorHandler errorHandler = new DOM3();
     // create filter
     LSParserFilter filter = new DOM3();
     builder.setFilter(filter);
     // set error handler
     config.setParameter("error-handler", errorHandler);
     // set validation feature
     // config.setParameter("validate", Boolean.FALSE);
     config.setParameter("validate", Boolean.TRUE);
     // set schema language
     config.setParameter("schema-type", "http://www.w3.org/2001/XMLSchema");
     // config.setParameter("psvi",Boolean.TRUE);
     // config.setParameter("schema-type","http://www.w3.org/TR/REC-xml");
     // set schema location
     config.setParameter("schema-location", "personal.xsd");
     // parse document
     System.out.println("Parsing " + argv[0] + "...");
     Document doc = builder.parseURI(argv[0]);
     // set error handler on the Document
     config = doc.getDomConfig();
     config.setParameter("error-handler", errorHandler);
     // set validation feature
     config.setParameter("validate", Boolean.TRUE);
     config.setParameter("schema-type", "http://www.w3.org/2001/XMLSchema");
     // config.setParameter("schema-type","http://www.w3.org/TR/REC-xml");
     config.setParameter("schema-location", "data/personal.xsd");
     // remove comments from the document
     config.setParameter("comments", Boolean.FALSE);
     System.out.println("Normalizing document... ");
     doc.normalizeDocument();
     // create DOMWriter
     LSSerializer domWriter = impl.createLSSerializer();
     System.out.println("Serializing document... ");
     config = domWriter.getDomConfig();
     config.setParameter("xml-declaration", Boolean.FALSE);
     // config.setParameter("validate",errorHandler);
     // serialize document to standard output
     // domWriter.writeNode(System.out, doc);
     LSOutput dOut = impl.createLSOutput();
     dOut.setByteStream(System.out);
     domWriter.write(doc, dOut);
   } catch (Exception ex) {
     ex.printStackTrace();
   }
 }
 private static void printUsage() {
   System.err.println("usage: java dom.DOM3 uri ...");
   System.err.println();
   System.err.println("NOTE: You can only validate DOM tree against XML Schemas.");
 } // printUsage()
 public boolean handleError(DOMError error) {
   short severity = error.getSeverity();
   if (severity == DOMError.SEVERITY_ERROR) {
     System.out.println("[dom3-error]: " + error.getMessage());
   }
   if (severity == DOMError.SEVERITY_WARNING) {
     System.out.println("[dom3-warning]: " + error.getMessage());
   }
   return true;
 }
 /**
  * @see org.w3c.dom.ls.LSParserFilter#acceptNode(Node)
  */
 public short acceptNode(Node enode) {
   return NodeFilter.FILTER_ACCEPT;
 }
 /**
  * @see org.w3c.dom.ls.LSParserFilter#getWhatToShow()
  */
 public int getWhatToShow() {
   return NodeFilter.SHOW_ELEMENT;
 }
 /**
  * @see org.w3c.dom.ls.LSParserFilter#startElement(Element)
  */
 public short startElement(Element elt) {
   return LSParserFilter.FILTER_ACCEPT;
 }

}

 </source>
   
  
 
  



Write DOM out

   <source lang="java">
 

/*

* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License.  When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
* Microsystems, Inc. All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*/

import java.io.IOException; import java.io.OutputStream; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; /**

* Utility class collecting library methods related to XML processing. Stolen
* from nbbuild/antsrc and openide/.../xml.
* 
* @author Petr Kuzel, Jesse Glick
*/

public final class XMLUtil {

 public static void write(Document doc, OutputStream out) throws IOException {
   // XXX note that this may fail to write out namespaces correctly if the
   // document
   // is created with namespaces and no explicit prefixes; however no code in
   // this package is likely to be doing so
   try {
     Transformer t = TransformerFactory.newInstance().newTransformer();
     DocumentType dt = doc.getDoctype();
     if (dt != null) {
       String pub = dt.getPublicId();
       if (pub != null) {
         t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, pub);
       }
       t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dt.getSystemId());
     }
     t.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); // NOI18N
     t.setOutputProperty(OutputKeys.INDENT, "yes"); // NOI18N
     t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); // NOI18N
     Source source = new DOMSource(doc);
     Result result = new StreamResult(out);
     t.transform(source, result);
   } catch (Exception e) {
     throw (IOException) new IOException(e.toString()).initCause(e);
   } catch (TransformerFactoryConfigurationError e) {
     throw (IOException) new IOException(e.toString()).initCause(e);
   }
 }

}


 </source>
   
  
 
  



write Xml DOM Node

   <source lang="java">
 

import java.io.OutputStream; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Node; /**

* 
* 
* @author Costin Manolache
*/

public class Main {

 public static void writeXml(Node n, OutputStream os) throws TransformerException {
   TransformerFactory tf = TransformerFactory.newInstance();
   // identity
   Transformer t = tf.newTransformer();
   t.setOutputProperty(OutputKeys.INDENT, "yes");
   t.transform(new DOMSource(n), new StreamResult(os));
 }

}


 </source>
   
  
 
  



Write Xml (Node n, OutputStream os)

   <source lang="java">

/**

* 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 javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Node; /**

* Few simple utils to read DOM. This is originally from the Jakarta Commons
* Modeler.
* 
* @author Costin Manolache
*/

public class Utils {

 public static void writeXml(Node n, OutputStream os) throws TransformerException {
   TransformerFactory tf = TransformerFactory.newInstance();
   // identity
   Transformer t = tf.newTransformer();
   t.setOutputProperty(OutputKeys.INDENT, "yes");
   t.transform(new DOMSource(n), new StreamResult(os));

} }

 </source>
   
  
 
  



Writing a DOM Document to an XML File

   <source lang="java">
    

import java.io.File; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; public class Main {

 public static void main(String[] argv) throws Exception {
   Document doc = null;
   String filename = "name.xml";
   Source source = new DOMSource(doc);
   File file = new File(filename);
   Result result = new StreamResult(file);
   Transformer xformer = TransformerFactory.newInstance().newTransformer();
   xformer.transform(source, result);
 }

}



 </source>
   
  
 
  



XML Document Writer

   <source lang="java">
   

/*

* 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.PrintWriter; import org.w3c.dom.CDATASection; import org.w3c.dom.rument; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; /**

* Output a DOM Level 1 Document object to a java.io.PrintWriter as a simple XML
* document. This class does not handle every type of DOM node, and it doesn"t
* deal with all the details of XML like DTDs, character encodings and preserved
* and ignored whitespace. However, it does output basic well-formed XML that
* can be parsed by a non-validating parser.
*/

public class XMLDocumentWriter {

 PrintWriter out; // the stream to send output to
 /** Initialize the output stream */
 public XMLDocumentWriter(PrintWriter out) {
   this.out = out;
 }
 /** Close the output stream. */
 public void close() {
   out.close();
 }
 /** Output a DOM Node (such as a Document) to the output stream */
 public void write(Node node) {
   write(node, "");
 }
 /**
  * Output the specified DOM Node object, printing it using the specified
  * indentation string
  */
 public void write(Node node, String indent) {
   // The output depends on the type of the node
   switch (node.getNodeType()) {
   case Node.DOCUMENT_NODE: { // If its a Document node
     Document doc = (Document) node;
     out.println(indent + "<?xml version="1.0"?>"); // Output header
     Node child = doc.getFirstChild(); // Get the first node
     while (child != null) { // Loop "till no more nodes
       write(child, indent); // Output node
       child = child.getNextSibling(); // Get next node
     }
     break;
   }
   case Node.DOCUMENT_TYPE_NODE: { // It is a <!DOCTYPE> tag
     DocumentType doctype = (DocumentType) node;
     // Note that the DOM Level 1 does not give us information about
     // the the public or system ids of the doctype, so we can"t output
     // a complete <!DOCTYPE> tag here. We can do better with Level 2.
     out.println("<!DOCTYPE " + doctype.getName() + ">");
     break;
   }
   case Node.ELEMENT_NODE: { // Most nodes are Elements
     Element elt = (Element) node;
     out.print(indent + "<" + elt.getTagName()); // Begin start tag
     NamedNodeMap attrs = elt.getAttributes(); // Get attributes
     for (int i = 0; i < attrs.getLength(); i++) { // Loop through them
       Node a = attrs.item(i);
       out.print(" " + a.getNodeName() + "="" + // Print attr. name
           fixup(a.getNodeValue()) + """); // Print attr. value
     }
     out.println(">"); // Finish start tag
     String newindent = indent + "    "; // Increase indent
     Node child = elt.getFirstChild(); // Get child
     while (child != null) { // Loop
       write(child, newindent); // Output child
       child = child.getNextSibling(); // Get next child
     }
     out.println(indent + "</" + // Output end tag
         elt.getTagName() + ">");
     break;
   }
   case Node.TEXT_NODE: { // Plain text node
     Text textNode = (Text) node;
     String text = textNode.getData().trim(); // Strip off space
     if ((text != null) && text.length() > 0) // If non-empty
       out.println(indent + fixup(text)); // print text
     break;
   }
   case Node.PROCESSING_INSTRUCTION_NODE: { // Handle PI nodes
     ProcessingInstruction pi = (ProcessingInstruction) node;
     out.println(indent + "<?" + pi.getTarget() + " " + pi.getData()
         + "?>");
     break;
   }
   case Node.ENTITY_REFERENCE_NODE: { // Handle entities
     out.println(indent + "&" + node.getNodeName() + ";");
     break;
   }
   case Node.CDATA_SECTION_NODE: { // Output CDATA sections
     CDATASection cdata = (CDATASection) node;
     // Careful! Don"t put a CDATA section in the program itself!
     out.println(indent + "<" + "![CDATA[" + cdata.getData() + "]]"
         + ">");
     break;
   }
   case Node.ruMENT_NODE: { // Comments
     Comment c = (Comment) node;
     out.println(indent + "");
     break;
   }
   default: // Hopefully, this won"t happen too much!
     System.err.println("Ignoring node: " + node.getClass().getName());
     break;
   }
 }
 // This method replaces reserved characters with entities.
 String fixup(String s) {
   StringBuffer sb = new StringBuffer();
   int len = s.length();
   for (int i = 0; i < len; i++) {
     char c = s.charAt(i);
     switch (c) {
     default:
       sb.append(c);
       break;
     case "<":
       sb.append("<");
       break;
     case ">":
       sb.append(">");
       break;
     case "&":
       sb.append("&");
       break;
     case """:
       sb.append(""");
       break;
     case "\"":
       sb.append("'");
       break;
     }
   }
   return sb.toString();
 }

}



 </source>
   
  
 
  



XML Writer

   <source lang="java">
  

/**

* Copyright (c) 2004-2006 Regents of the University of California.
* See "license-prefuse.txt" for licensing terms.
*/

import java.io.PrintWriter; import java.util.ArrayList; /**

* Utility class for writing XML files. This class provides convenience
* methods for creating XML documents, such as starting and ending
* tags, and adding content and comments. This class handles correct
* XML formatting and will properly escape text to ensure that the
* text remains valid XML.
* 
* <p>To use this class, create a new instance with the desired
* PrintWriter to write the XML to. Call the {@link #begin()} or
* {@link #begin(String, int)} method when ready to start outputting
* XML. Then use the provided methods to generate the XML file.
* Finally, call either the {@link #finish()} or {@link #finish(String)}
* methods to signal the completion of the file.

* 
* @author 
*/

public class XMLWriter {

   private PrintWriter m_out;
   private int m_bias = 0;
   private int m_tab;
   private ArrayList m_tagStack = new ArrayList();
   
   /**
    * Create a new XMLWriter.
    * @param out the print writer to write the XML to
    */
   public XMLWriter(PrintWriter out) {
       this(out, 2);
   }
   /**
    * Create a new XMLWriter.
    * @param out the print writer to write the XML to
    * @param tabLength the number of spaces to use for each
    *  level of indentation in the XML file
    */
   public XMLWriter(PrintWriter out, int tabLength) {
       m_out = out;
       m_tab = 2;
   }
   
   /**
    * Print unescaped text into the XML file. To print
    * escaped text, use the {@link #content(String)} method instead.
    * @param s the text to print. This String will not be escaped.
    */
   public void print(String s) {
       m_out.print(s);
   }
   /**
    * Print unescaped text into the XML file, followed by
    * a newline. To print escaped text, use the {@link #content(String)}
    * method instead.
    * @param s the text to print. This String will not be escaped.
    */
   public void println(String s) {
       m_out.print(s);
       m_out.print("\n");
   }
   
   /**
    * Print a newline into the XML file.
    */
   public void println() {
       m_out.print("\n");
   }
   
   /**
    * Begin the XML document. This must be called before any other
    * formatting methods. This method prints an XML header into
    * the top of the output stream.
    */
   public void begin() {
       m_out.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
       println();
   }
   
   /**
    * Begin the XML document. This must be called before any other
    * formatting methods. This method prints an XML header into
    * the top of the output stream, plus additional header text
    * provided by the client
    * @param header header text to insert into the document
    * @param bias the spacing bias to use for all subsequent indenting
    */
   public void begin(String header, int bias) {
       begin();
       m_out.print(header);
       m_bias = bias;
   }
   
   /**
    * Print a comment in the XML document. The comment will be printed
    * according to the current spacing and followed by a newline.
    * @param comment the comment text
    */
   public void comment(String comment) {
       spacing();
       m_out.print("");
       println();
   }
   
   /**
    * Internal method for printing a tag with attributes.
    * @param tag the tag name
    * @param names the names of the attributes
    * @param values the values of the attributes
    * @param nattr the number of attributes
    * @param close true to close the tag, false to leave it
    * open and adjust the spacing
    */
   protected void tag(String tag, String[] names, String[] values,
           int nattr, boolean close)
   {
       spacing();
       m_out.print("<");
       m_out.print(tag);
       for ( int i=0; i<nattr; ++i ) {
           m_out.print(" ");
           m_out.print(names[i]);
           m_out.print("=");
           m_out.print("\"");
           escapeString(values[i]);
           m_out.print("\"");
       }
       if ( close ) m_out.print("/");
       m_out.print(">");
       println();
       
       if ( !close ) {
           m_tagStack.add(tag);
       }
   }
   
   /**
    * Print a closed tag with attributes. The tag will be followed by a
    * newline.
    * @param tag the tag name
    * @param names the names of the attributes
    * @param values the values of the attributes
    * @param nattr the number of attributes
    */
   public void tag(String tag, String[] names, String[] values, int nattr)
   {
       tag(tag, names, values, nattr, true);
   }
   
   /**
    * Print a start tag with attributes. The tag will be followed by a
    * newline, and the indentation level will be increased.
    * @param tag the tag name
    * @param names the names of the attributes
    * @param values the values of the attributes
    * @param nattr the number of attributes
    */
   public void start(String tag, String[] names, String[] values, int nattr)
   {
       tag(tag, names, values, nattr, false);
   }
   
   /**
    * Internal method for printing a tag with a single attribute.
    * @param tag the tag name
    * @param name the name of the attribute
    * @param value the value of the attribute
    * @param close true to close the tag, false to leave it
    * open and adjust the spacing
    */
   protected void tag(String tag, String name, String value, boolean close) {
       spacing();
       m_out.print("<");
       m_out.print(tag);
       m_out.print(" ");
       m_out.print(name);
       m_out.print("=");
       m_out.print("\"");
       escapeString(value);
       m_out.print("\"");
       if ( close ) m_out.print("/");
       m_out.print(">");
       println();
       
       if ( !close ) {
           m_tagStack.add(tag);
       }
   }
   
   /**
    * Print a closed tag with one attribute. The tag will be followed by a
    * newline.
    * @param tag the tag name
    * @param name the name of the attribute
    * @param value the value of the attribute
    */
   public void tag(String tag, String name, String value)
   {
       tag(tag, name, value, true);
   }
   
   /**
    * Print a start tag with one attribute. The tag will be followed by a
    * newline, and the indentation level will be increased.
    * @param tag the tag name
    * @param name the name of the attribute
    * @param value the value of the attribute
    */
   public void start(String tag, String name, String value)
   {
       tag(tag, name, value, false);
   }
   
   /**
    * Internal method for printing a tag with attributes.
    * @param tag the tag name
    * @param names the names of the attributes
    * @param values the values of the attributes
    * @param nattr the number of attributes
    * @param close true to close the tag, false to leave it
    * open and adjust the spacing
    */
   protected void tag(String tag, ArrayList names, ArrayList values,
           int nattr, boolean close)
   {
       spacing();
       m_out.print("<");
       m_out.print(tag);
       for ( int i=0; i<nattr; ++i ) {
           m_out.print(" ");
           m_out.print((String)names.get(i));
           m_out.print("=");
           m_out.print("\"");
           escapeString((String)values.get(i));
           m_out.print("\"");
       }
       if ( close ) m_out.print("/");
       m_out.print(">");
       println();
       
       if ( !close ) {
           m_tagStack.add(tag);
       }
   }
   
   /**
    * Print a closed tag with attributes. The tag will be followed by a
    * newline.
    * @param tag the tag name
    * @param names the names of the attributes
    * @param values the values of the attributes
    * @param nattr the number of attributes
    */
   public void tag(String tag, ArrayList names, ArrayList values, int nattr)
   {
       tag(tag, names, values, nattr, true);
   }
   
   /**
    * Print a start tag with attributes. The tag will be followed by a
    * newline, and the indentation level will be increased.
    * @param tag the tag name
    * @param names the names of the attributes
    * @param values the values of the attributes
    * @param nattr the number of attributes
    */
   public void start(String tag, ArrayList names, ArrayList values, int nattr)
   {
       tag(tag, names, values, nattr, false);
   }
   
   /**
    * Print a start tag without attributes. The tag will be followed by a
    * newline, and the indentation level will be increased.
    * @param tag the tag name
    */
   public void start(String tag) {
       tag(tag, (String[])null, null, 0, false);
   }
   /**
    * Close the most recently opened tag. The tag will be followed by a
    * newline, and the indentation level will be decreased.
    */
   public void end() {
       String tag = (String)m_tagStack.remove(m_tagStack.size()-1);
       spacing();
       m_out.print("<");
       m_out.print("/");
       m_out.print(tag);
       m_out.print(">");
       println();
   }
   
   /**
    * Print a new content tag with a single attribute, consisting of an
    * open tag, content text, and a closing tag, all on one line.
    * @param tag the tag name
    * @param name the name of the attribute
    * @param value the value of the attribute, this text will be escaped
    * @param content the text content, this text will be escaped
    */
   public void contentTag(String tag, String name, String value, 
                          String content)
   {
       spacing();
       m_out.print("<"); m_out.print(tag); m_out.print(" ");
       m_out.print(name); m_out.print("=");
       m_out.print("\""); escapeString(value); m_out.print("\"");
       m_out.print(">");    
       escapeString(content);
       m_out.print("<"); m_out.print("/"); m_out.print(tag); m_out.print(">");
       println();
   }
   
   /**
    * Print a new content tag with no attributes, consisting of an
    * open tag, content text, and a closing tag, all on one line.
    * @param tag the tag name
    * @param content the text content, this text will be escaped
    */
   public void contentTag(String tag, String content) {
       spacing();
       m_out.print("<"); m_out.print(tag); m_out.print(">");
       escapeString(content);
       m_out.print("<"); m_out.print("/"); m_out.print(tag); m_out.print(">");
       println();
   }
   
   /**
    * Print content text.
    * @param content the content text, this text will be escaped
    */
   public void content(String content) {
       escapeString(content);
   }
   
   /**
    * Finish the XML document.
    */
   public void finish() {
       m_bias = 0;
       m_out.flush();
   }
   
   /**
    * Finish the XML document, printing the given footer text at the
    * end of the document.
    * @param footer the footer text, this will not be escaped
    */
   public void finish(String footer) {
       m_bias = 0;
       m_out.print(footer);
       m_out.flush();
   }
   
   /**
    * Print the current spacing (determined by the indentation level)
    * into the document. This method is used by many of the other
    * formatting methods, and so should only need to be called in
    * the case of custom text printing outside the mechanisms
    * provided by this class.
    */
   public void spacing() {
       int len = m_bias + m_tagStack.size() * m_tab;
       for ( int i=0; i<len; ++i )
           m_out.print(" ");
   }
   
   // ------------------------------------------------------------------------
   // Escape Text
   
   // unicode ranges and valid/invalid characters
   private static final char   LOWER_RANGE = 0x20;
   private static final char   UPPER_RANGE = 0x7f;
   private static final char[] VALID_CHARS = { 0x9, 0xA, 0xD };
   
   private static final char[] INVALID = { "<", ">", """, "\"", "&" };
   private static final String[] VALID = 
       { "<", ">", """, "'", "&" };
   
   /**
    * Escape a string such that it is safe to use in an XML document.
    * @param str the string to escape
    */
   protected void escapeString(String str) {
       if ( str == null ) {
           m_out.print("null");
           return;
       }
       
       int len = str.length();
       for (int i = 0; i < len; ++i) {
           char c = str.charAt(i);
           
           if ( (c < LOWER_RANGE     && c != VALID_CHARS[0] && 
                 c != VALID_CHARS[1] && c != VALID_CHARS[2]) 
                || (c > UPPER_RANGE) )
           {
               // character out of range, escape with character value
               m_out.print("&#");
               m_out.print(Integer.toString(c));
               m_out.print(";");
           } else {
               boolean valid = true;
               // check for invalid characters (e.g., "<", "&", etc)
               for (int j=INVALID.length-1; j >= 0; --j )
               {
                   if ( INVALID[j] == c) {
                       valid = false;
                       m_out.print(VALID[j]);
                       break;
                   }
               }
               // if character is valid, don"t escape
               if (valid) {
                   m_out.print(c);
               }
           }
       }
   }
   

} // end of class XMLWriter


 </source>
   
  
 
  



XMLWriter helper class

   <source lang="java">

/*

* 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.IOException; import java.io.Writer; /**

* XMLWriter helper class.
*
* @author 
*/

public class XMLWriter {

   // -------------------------------------------------------------- Constants
   /**
    * Opening tag.
    */
   public static final int OPENING = 0;
   /**
    * Closing tag.
    */
   public static final int CLOSING = 1;
   /**
    * Element with no content.
    */
   public static final int NO_CONTENT = 2;
   // ----------------------------------------------------- Instance Variables
   /**
    * Buffer.
    */
   protected StringBuffer buffer = new StringBuffer();
   /**
    * Writer.
    */
   protected Writer writer = null;
   // ----------------------------------------------------------- Constructors
   /**
    * Constructor.
    */
   public XMLWriter() {
   }
   /**
    * Constructor.
    */
   public XMLWriter(Writer writer) {
       this.writer = writer;
   }
   // --------------------------------------------------------- Public Methods
   /**
    * Retrieve generated XML.
    *
    * @return String containing the generated XML
    */
   public String toString() {
       return buffer.toString();
   }
   /**
    * Write property to the XML.
    *
    * @param namespace Namespace
    * @param namespaceInfo Namespace info
    * @param name Property name
    * @param value Property value
    */
   public void writeProperty(String namespace, String namespaceInfo,
                             String name, String value) {
       writeElement(namespace, namespaceInfo, name, OPENING);
       buffer.append(value);
       writeElement(namespace, namespaceInfo, name, CLOSING);
   }
   /**
    * Write property to the XML.
    *
    * @param namespace Namespace
    * @param name Property name
    * @param value Property value
    */
   public void writeProperty(String namespace, String name, String value) {
       writeElement(namespace, name, OPENING);
       buffer.append(value);
       writeElement(namespace, name, CLOSING);
   }
   /**
    * Write property to the XML.
    *
    * @param namespace Namespace
    * @param name Property name
    */
   public void writeProperty(String namespace, String name) {
       writeElement(namespace, name, NO_CONTENT);
   }
   /**
    * Write an element.
    *
    * @param name Element name
    * @param namespace Namespace abbreviation
    * @param type Element type
    */
   public void writeElement(String namespace, String name, int type) {
       writeElement(namespace, null, name, type);
   }
   /**
    * Write an element.
    *
    * @param namespace Namespace abbreviation
    * @param namespaceInfo Namespace info
    * @param name Element name
    * @param type Element type
    */
   public void writeElement(String namespace, String namespaceInfo,
                            String name, int type) {
       if ((namespace != null) && (namespace.length() > 0)) {
           switch (type) {
           case OPENING:
               if (namespaceInfo != null) {
                   buffer.append("<" + namespace + ":" + name + " xmlns:"
                                 + namespace + "=\""
                                 + namespaceInfo + "\">");
               } else {
                   buffer.append("<" + namespace + ":" + name + ">");
               }
               break;
           case CLOSING:
               buffer.append("</" + namespace + ":" + name + ">\n");
               break;
           case NO_CONTENT:
           default:
               if (namespaceInfo != null) {
                   buffer.append("<" + namespace + ":" + name + " xmlns:"
                                 + namespace + "=\""
                                 + namespaceInfo + "\"/>");
               } else {
                   buffer.append("<" + namespace + ":" + name + "/>");
               }
               break;
           }
       } else {
           switch (type) {
           case OPENING:
               buffer.append("<" + name + ">");
               break;
           case CLOSING:
               buffer.append("</" + name + ">\n");
               break;
           case NO_CONTENT:
           default:
               buffer.append("<" + name + "/>");
               break;
           }
       }
   }
   /**
    * Write text.
    *
    * @param text Text to append
    */
   public void writeText(String text) {
       buffer.append(text);
   }
   /**
    * Write data.
    *
    * @param data Data to append
    */
   public void writeData(String data) {
       buffer.append(data);
   }
   /**
    * Write XML Header.
    */
   public void writeXMLHeader() {
       buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
   }
   /**
    * Send data and reinitializes buffer.
    */
   public void sendData()
       throws IOException {
       if (writer != null) {
           writer.write(buffer.toString());
           buffer = new StringBuffer();
       }
   }

}

 </source>
   
  
 
  



XMLWriter.java - serialize an XML document

   <source lang="java">
  

// XMLWriter.java - serialize an XML document. // Written by David Megginson, david@megginson.ru // and placed by him into the public domain. // Extensively modified by John Cowan for TagSoup. // TagSoup is licensed under the Apache License, // Version 2.0. You may obtain a copy of this license at // http://www.apache.org/licenses/LICENSE-2.0 . You may also have // additional legal rights not granted by this license. // // TagSoup is distributed in the hope that it will be useful, but // unless required by applicable law or agreed to in writing, TagSoup // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS // OF ANY KIND, either express or implied; not even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

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.
*
*

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.

*
*

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

*
*
 * w.startElement("foo");
 * 
*
*

is equivalent to the regular SAX2 ContentHandler method

*
*
 * w.startElement("", "foo", "", new AttributesImpl());
 * 
*
*

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:

*
*
 * XMLWriter w = new XMLWriter();
 *
 * w.startDocument();
 * w.startElement("greeting");
 * w.characters("Hello, world!");
 * w.endElement("greeting");
 * w.endDocument();
 * 
*
*

The resulting document will look like this:

*
*
 * <?xml version="1.0" standalone="yes"?>
 *
 * <greeting>Hello, world!</greeting>
 * 
*
*

In fact, there is an even simpler convenience method, * dataElement, designed for writing elements that * contain only character data, so the code to generate the * document could be shortened to

*
*
 * XMLWriter w = new XMLWriter();
 *
 * w.startDocument();
 * w.dataElement("greeting", "Hello, world!");
 * w.endDocument();
 * 
*
*

Whitespace

*
*

According to the XML Recommendation, all 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

*
*
 * w.dataElement("item", "1");
 * w.dataElement("item", "2");
 * w.dataElement("item", "3");
 * 
*
*

you will end up with

*
*
 * <item>1</item><item>3</item><item>3</item>
 * 
*
*

You need to invoke one of the characters 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).

*
*
*

Namespace Support

*
*

The writer contains extensive support for XML Namespaces, so that * a client application does not have to keep track of prefixes and * supply xmlns 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:

*
*
 * w.startDocument();
 * w.emptyElement("http://www.foo.ru/ns/", "foo");
 * w.endDocument();
 * 
*
*

The resulting document will look like this:

*
*
 * <?xml version="1.0" standalone="yes"?>
 *
 * <_NS1:foo xmlns:_NS1="http://www.foo.ru/ns/"/>
 * 
*
*

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:

*
*
    *
  1. the qualified name
  2. *
  3. the {@link #setPrefix setPrefix} method.
  4. *
*
*

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).

*
*

Before writing a document, the client can also pre-map a prefix * to a Namespace URI with the setPrefix method:

*
*
 * w.setPrefix("http://www.foo.ru/ns/", "foo");
 * w.startDocument();
 * w.emptyElement("http://www.foo.ru/ns/", "foo");
 * w.endDocument();
 * 
*
*

The resulting document will look like this:

*
*
 * <?xml version="1.0" standalone="yes"?>
 *
 * <foo:foo xmlns:foo="http://www.foo.ru/ns/"/>
 * 
*
*

The default Namespace simply uses an empty string as the prefix:

*
*
 * w.setPrefix("http://www.foo.ru/ns/", "");
 * w.startDocument();
 * w.emptyElement("http://www.foo.ru/ns/", "foo");
 * w.endDocument();
 * 
*
*

The resulting document will look like this:

*
*
 * <?xml version="1.0" standalone="yes"?>
 *
 * <foo xmlns="http://www.foo.ru/ns/"/>
 * 
*
*

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:

*
*
 * <xml version="1.0" standalone="yes"?>
 *
 * <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
 *  <rdf:Description about="http://www.foo.ru/ids/books/12345">
 *   <dc:title xmlns:dc="http://www.purl.org/dc/">A Dark Night</dc:title>
 *   <dc:creator xmlns:dc="http://www.purl.org/dc/">Jane Smith</dc:title>
 *   <dc:date xmlns:dc="http://www.purl.org/dc/">2000-09-09</dc:title>
 *  </rdf:Description>
 * </rdf:RDF>
 * 
*
*

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:

*
*
 * w.forceNSDecl("http://www.purl.org/dc/");
 * 
*
*

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:

*
*
 * <xml version="1.0" standalone="yes"?>
 *
 * <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 *             xmlns:dc="http://www.purl.org/dc/">
 *  <rdf:Description about="http://www.foo.ru/ids/books/12345">
 *   <dc:title>A Dark Night</dc:title>
 *   <dc:creator>Jane Smith</dc:title>
 *   <dc:date>2000-09-09</dc:title>
 *  </rdf:Description>
 * </rdf:RDF>
 * 
*
*

This approach is also useful for declaring Namespace prefixes * that be used by qualified names appearing in attribute values or * character data.

*
* @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.
    *
*

Write to standard output.

    */
   public XMLWriter () 
   {
       init(null);
   }
   
   /**
    * Create a new XML writer.
    *
*

Write to the writer provided.

    *
    * @param writer The output destination, or null to use standard
    *        output.
    */
   public XMLWriter (Writer writer) 
   {
       init(writer);
   }
   
   /**
    * Create a new XML writer.
    *
*

Use the specified XML reader as the parent.

    *
    * @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.
    *
*

Use the specified XML reader as the parent, and write * to the specified writer.

    *
    * @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.
    *
*

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.

    *
*

This method is invoked automatically by the * {@link #startDocument startDocument} method before writing * a new document.

    *
*

Note: this method will not * clear the prefix or URI information in the writer or * the selected output writer.

    *
    * @see #flush
    */
   public void reset ()
   {
       elementLevel = 0;
       prefixCounter = 0;
       nsSupport.reset();
   }
   
   /**
    * Flush the output.
    *
*

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.

    *
*

This method is invoked automatically by the * {@link #endDocument endDocument} method after writing a * document.

    *
    * @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.
    *
*

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.

    *
    * @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.
    *
*

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.

    *
*

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.

    *
    * @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.
    *
*

This is a convenience method that invokes {@link * #setPrefix setPrefix} then {@link #forceNSDecl(java.lang.String) * forceNSDecl}.

    *
    * @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");
           if (version == null) {
               write(" version=\"1.0\"");
           } else {
               write(" version=\"");
               write(version);
               write("\"");
           }
           if (outputEncoding != null && outputEncoding != "") {
               write(" encoding=\"");
               write(outputEncoding);
               write("\"");
           }
           if (standalone == null) {
               write(" standalone=\"yes\"?>\n");
           } else {
               write(" standalone=\"");
               write(standalone);
               write("\"");
           }
       }
       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();
 if (forceDTD && !hasOutputDTD) startDTD(localName == null ? qName : localName, "", "");
       write("<");
       writeName(uri, localName, qName, true);
       writeAttributes(atts);
       if (elementLevel == 1) {
           forceNSDecls();
       }
       writeNSDecls();
       write(">");

// System.out.println("%%%% startElement [" + qName + "] htmlMode = " + htmlMode);

 if (htmlMode && (qName.equals("script") || qName.equals("style"))) {
               cdataElement = true;

// System.out.println("%%%% CDATA element");

               }
       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 (!(htmlMode &&
           (uri.equals("http://www.w3.org/1999/xhtml") ||
   uri.equals("")) &&
           (qName.equals("area") || qName.equals("base") ||
           qName.equals("basefont") || qName.equals("br") ||
           qName.equals("col") || qName.equals("frame") ||
           qName.equals("hr") || qName.equals("img") ||
           qName.equals("input") || qName.equals("isindex") ||
           qName.equals("link") || qName.equals("meta") ||
           qName.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.
    *
*

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.

    *
    * @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.
    *
*

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.

    *
    * @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.
    *
*

This method will supply an empty string for the qName. * It invokes {@link #endElement(String, String, String)} * directly.

    *
    * @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.
    *
*

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.

    *
    * @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.
    *
*

This method will supply an empty string for the qname * and an empty attribute list. It invokes * {@link #emptyElement(String, String, String, Attributes)} * directly.

    *
    * @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.
    *
*

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.

    *
    * @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.
    *
*

This is a convenience method to write a complete element * with character data content, including the start tag * and end tag.

    *
*

This method invokes * {@link #startElement(String, String, String, Attributes)}, * followed by * {@link #characters(String)}, followed by * {@link #endElement(String, String, String)}.

    *
    * @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.
    *
*

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.

    *
*

This method invokes * {@link #startElement(String, String, String, Attributes)}, * followed by * {@link #characters(String)}, followed by * {@link #endElement(String, String, String)}.

    *
    * @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.
    *
*

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.

    *
*

This method invokes * {@link #startElement(String, String, String, Attributes)}, * followed by * {@link #characters(String)}, followed by * {@link #endElement(String, String, String)}.

    *
    * @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.
    *
*

This is a convenience method that takes an XML * String, converts it to a character array, then invokes * {@link #characters(char[], int, int)}.

    *
    * @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);
           if (htmlMode &&
               booleanAttribute(atts.getLocalName(i), atts.getQName(i), atts.getValue(i))) break;
           write("=\"");
           writeEsc(ch, 0, ch.length, true);
           write(""");
       }
   }
   private String[] booleans = {"checked", "compact", "declare", "defer",
                                "disabled", "ismap", "multiple",
                                "nohref", "noresize", "noshade",
                                "nowrap", "readonly", "selected"};
   // Return true if the attribute is an HTML boolean from the above list.
   private boolean booleanAttribute (String localName, String qName, String value)
   {
       String name = localName;
       if (name == null) {
           int i = qName.indexOf(":");
           if (i != -1) name = qName.substring(i + 1, qName.length());
       }
       if (!name.equals(value)) return false;
       for (int j = 0; j < booleans.length; j++) {
           if (name.equals(booleans[j])) return true;
           }
       return false;
   }
   /**
    * 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("&");
               break;
           case "<":
               write("<");
               break;
           case ">":
               write(">");
               break;
           case "\"":
               if (isAttVal) {
                   write(""");
               } else {
                   write("\"");
               }
               break;
           default:
               if (!unicodeMode && ch[i] > "\u007f") {
                   write("&#");
                   write(Integer.toString(ch[i]));
                   write(";");
               } else {
                   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("");
   }
   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 {
       if (name == null) return;               // can"t cope
 if (hasOutputDTD) return;   // only one DTD
 hasOutputDTD = true;
       write("<!DOCTYPE ");
       write(name);
       if (systemid == null) systemid = "";
 if (overrideSystem != null) systemid = overrideSystem;
       char sysquote = (systemid.indexOf(""") != -1) ? "\"": """;
 if (overridePublic != null) publicid = overridePublic;
       if (!(publicid == null || "".equals(publicid))) {
               char pubquote = (publicid.indexOf(""") != -1) ? "\"": """;
               write(" PUBLIC ");
               write(pubquote);
               write(publicid);
               write(pubquote);
               write(" ");
               }
       else {
               write(" SYSTEM ");
               }
       write(sysquote);
       write(systemid);
       write(sysquote);
       write(">\n");
       }
   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);

// System.out.println("%%%% key = [" + key + "] value = [" + value +"]");

       if (key.equals(ENCODING)) {
           outputEncoding = value;
           unicodeMode = value.substring(0, 3).equalsIgnoreCase("utf");

// System.out.println("%%%% unicodeMode = " + unicodeMode);

 }
 else if (key.equals(METHOD)) {
   htmlMode = value.equals("html");
 }
 else if (key.equals(DOCTYPE_PUBLIC)) {
   overridePublic = value;
   forceDTD = true;
   }
 else if (key.equals(DOCTYPE_SYSTEM)) {
   overrideSystem = value;
   forceDTD = true;
   }
 else if (key.equals(VERSION)) {
   version = value;
   }
 else if (key.equals(STANDALONE)) {
   standalone = value;
   }

// System.out.println("%%%% htmlMode = " + htmlMode);

   }
   
   ////////////////////////////////////////////////////////////////////
   // 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";  // currently ignored
   public static final String MEDIA_TYPE = "media-type";  // currently ignored
   public static final String METHOD = "method";  // currently html or xml
   public static final String OMIT_XML_DECLARATION = "omit-xml-declaration";
   public static final String STANDALONE = "standalone";  // currently ignored
   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 unicodeMode = false;
   private String outputEncoding = "";
   private boolean htmlMode = false;
   private boolean forceDTD = false;
   private boolean hasOutputDTD = false;
   private String overridePublic = null;
   private String overrideSystem = null;
   private String version = null;
   private String standalone = null;
   private boolean cdataElement = false;
   

} // end of XMLWriter.java


 </source>