auto import from //depot/cupcake/@135843
diff --git a/xml/src/main/java/javax/xml/XMLConstants.java b/xml/src/main/java/javax/xml/XMLConstants.java
new file mode 100644
index 0000000..88fcdad
--- /dev/null
+++ b/xml/src/main/java/javax/xml/XMLConstants.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.xml;
+
+/**
+ * Defines several standard constants that are often used during XML processing.
+ *  
+ * @since Android 1.0
+ */
+public class XMLConstants {
+
+    /**
+     * The default namespace prefix. Defined to be the empty string. 
+     */
+    public static final String DEFAULT_NS_PREFIX = "";
+
+    /**
+     * The SAX feature name for secure processing. Turning on this feature
+     * might result in a parser rejecting XML documents that are considered
+     * "insecure" (having a potential for DOS attacks, for example). The
+     * Android XML parsing implementation currently ignores this feature.  
+     */
+    public static final String FEATURE_SECURE_PROCESSING = 
+        "http://javax.xml.XMLConstants/feature/secure-processing";
+
+    /**
+     * The namespace URI for the case that no namespace is being used at all.
+     * Defined to be the empty string.
+     */
+    public static final String NULL_NS_URI = "";
+
+    /**
+     * The official Relax-NG namespace URI.
+     */
+    public static final String RELAXNG_NS_URI = 
+        "http://relaxng.org/ns/structure/1.0";
+
+    /**
+     * The official XSchema instance namespace URI, as defined by W3C.
+     */
+    public static final String W3C_XML_SCHEMA_INSTANCE_NS_URI = 
+        "http://www.w3.org/2001/XMLSchema-instance";
+
+    /**
+     * The official XSchema namespace URI, as defined by W3C.
+     */
+    public static final String W3C_XML_SCHEMA_NS_URI = 
+        "http://www.w3.org/2001/XMLSchema";
+
+    /**
+     * The official XPath datatype namespace URI, as defined by W3C.
+     */
+    public static final String W3C_XPATH_DATATYPE_NS_URI = 
+        "http://www.w3.org/2003/11/xpath-datatypes";
+
+    /**
+     * The official XML namespace attribute, as defined by W3C.
+     */
+    public static final String XMLNS_ATTRIBUTE = "xmlns";
+
+    /**
+     * The official XML namespace attribute URI, as defined by W3C.
+     */
+    public static final String XMLNS_ATTRIBUTE_NS_URI = 
+        "http://www.w3.org/2000/xmlns/";
+
+    /**
+     * The official XML DTD namespace URI, as defined by W3C.
+     */
+    public static final String XML_DTD_NS_URI = "http://www.w3.org/TR/REC-xml";
+
+    /**
+     * The official XML namespace prefix, as defined by W3C. 
+     */
+    public static final String XML_NS_PREFIX = "xml";
+
+    /**
+     * The official XML namespace URI, as defined by W3C. 
+     */
+    public static final String XML_NS_URI = 
+        "http://www.w3.org/XML/1998/namespace";
+
+}
diff --git a/xml/src/main/java/javax/xml/package.html b/xml/src/main/java/javax/xml/package.html
new file mode 100644
index 0000000..5a4621d
--- /dev/null
+++ b/xml/src/main/java/javax/xml/package.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <p>
+      Provides a utility class with useful XML constants.
+    </p>
+    @since Android 1.0
+  </body>
+</html>
\ No newline at end of file
diff --git a/xml/src/main/java/javax/xml/parsers/DocumentBuilder.java b/xml/src/main/java/javax/xml/parsers/DocumentBuilder.java
new file mode 100644
index 0000000..6fd6550
--- /dev/null
+++ b/xml/src/main/java/javax/xml/parsers/DocumentBuilder.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.xml.parsers;
+
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Defines a bridge from XML sources (files, stream etc.) to DOM trees. Can be
+ * used for easily obtaining a {@link org.w3c.dom.Document} for the input. The
+ * class itself is abstract. The class {@link DocumentBuilderFactory} is able to
+ * provide instances (of concrete subclasses known to the system).
+ * 
+ * @since Android 1.0
+ */
+public abstract class DocumentBuilder {
+
+    /**
+     * Do-nothing constructor. Prevents instantiation. To be overridden by
+     * concrete subclasses.
+     * 
+     * @since Android 1.0
+     */
+    protected DocumentBuilder() {
+        // Does nothing.
+    }
+
+    /**
+     * Queries the DOM implementation this {@code DocumentBuilder} is working
+     * on.
+     * 
+     * @return the DOM implementation
+     * 
+     * @since Android 1.0
+     */
+    public abstract DOMImplementation getDOMImplementation();
+
+// TODO No XSchema support in Android 1.0. Maybe later.
+//    /**
+//     * Queries the XML schema used by the DocumentBuilder.
+//     * 
+//     * @return The XML schema
+//     * 
+//     * @throws UnsupportedOperationException when the underlying implementation
+//     *         doesn't support XML schemas.
+//     */
+//    public javax.xml.validation.Schema getSchema() throws
+//            UnsupportedOperationException {
+//        throw new UnsupportedOperationException();
+//    }
+     
+    /**
+     * Queries whether the {@code DocumentBuilder} has namespace support
+     * enabled.
+     * 
+     * @return {@code true} if namespaces are turned on, {@code false}
+     *         otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public abstract boolean isNamespaceAware();
+
+    /**
+     * Queries whether the {@code DocumentBuilder} has validation support
+     * enabled.
+     * 
+     * @return {@code true} if validation is turned on, {@code false} otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public abstract boolean isValidating();
+
+    /**
+     * Queries whether the {@code DocumentBuilder} has XInclude support enabled.
+     * 
+     * @return {@code true} if XInclude support is turned on, {@code false}
+     *         otherwise.
+     * 
+     * @throws UnsupportedOperationException if the underlying implementation
+     *         doesn't support XInclude.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isXIncludeAware() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Creates a new, empty document, serving as the starting point for a DOM
+     * tree.
+     * 
+     * @return the document.
+     * 
+     * @since Android 1.0
+     */
+    public abstract Document newDocument();
+
+    /**
+     * Parses a given XML file and builds a DOM tree from it.
+     * 
+     * @param file the file to be parsed.
+     * @return the document element that represents the root of the DOM tree.
+     * 
+     * @throws SAXException if the XML parsing fails.
+     * @throws IOException if an input/output error occurs.
+     * 
+     * @since Android 1.0
+     */
+    public Document parse(File file) throws SAXException, IOException {
+        if (file == null) {
+            throw new IllegalArgumentException();
+        }
+        
+        return parse(new BufferedInputStream(new FileInputStream(file), 8192));
+    }
+
+    /**
+     * Parses a given XML input stream and builds a DOM tree from it.
+     * 
+     * @param stream the stream to be parsed.
+     * @return the document element that represents the root of the DOM tree.
+     * 
+     * @throws SAXException if the XML parsing fails.
+     * @throws IOException if an input/output error occurs.
+     * 
+     * @since Android 1.0
+     */
+    public Document parse(InputStream stream) throws SAXException, IOException {
+        if (stream == null) {
+            throw new IllegalArgumentException();
+        }
+        
+        return parse(new InputSource(stream));
+    }
+
+    /**
+     * Parses a given XML input stream and builds a DOM tree from it.
+     * 
+     * @param stream the stream to be parsed.
+     * @param systemId the base for resolving relative URIs.
+     * @return the document element that represents the root of the DOM tree.
+     * 
+     * @throws SAXException if the XML parsing fails.
+     * @throws IOException if an input/output error occurs.
+     * 
+     * @since Android 1.0
+     */
+    public org.w3c.dom.Document parse(InputStream stream, String systemId)
+            throws SAXException, IOException {
+        if (stream == null) {
+            throw new IllegalArgumentException();
+        }
+        
+        InputSource source = new InputSource(stream);
+        source.setSystemId(systemId);
+        return parse(source);
+    }
+
+    /**
+     * Parses an XML input stream from a given URI and builds a DOM tree from
+     * it.
+     * 
+     * @param uri the URI to fetch the XML stream from.
+     * @return the document element that represents the root of the DOM tree.
+     * 
+     * @throws SAXException if the XML parsing fails.
+     * @throws IOException if an input/output error occurs.
+     * 
+     * @since Android 1.0
+     */
+    public org.w3c.dom.Document parse(String uri) throws SAXException,
+            IOException {
+        if (uri == null) {
+            throw new IllegalArgumentException();
+        }
+        
+        return parse(new InputSource(uri));
+    }
+
+    /**
+     * Parses an XML input source and builds a DOM tree from it.
+     * 
+     * @param source the input source to parse.
+     * @return the document element that represents the root of the DOM tree.
+     * 
+     * @throws SAXException if the XML parsing fails.
+     * @throws IOException if an input/output error occurs.
+     * 
+     * @since Android 1.0
+     */
+    public abstract org.w3c.dom.Document parse(InputSource source)
+            throws SAXException, IOException;
+
+    /**
+     * Resets the DocumentBuilder to the same state is was in after its
+     * creation.
+     * 
+     * @since Android 1.0
+     */
+    public void reset() {
+        // Do nothing.
+    }
+
+    /**
+     * Sets the {@link EntityResolver} used for resolving entities encountered
+     * during the parse process. Passing {@code null} results in the
+     * {@code DocumentBuilder}'s own {@code EntityResolver} being used.
+     * 
+     * @param resolver the {@code EntityResolver} to use, or null for the
+     *        built-in one.
+     * 
+     * @since Android 1.0
+     */
+    public abstract void setEntityResolver(EntityResolver resolver);
+
+    /**
+     * Sets the {@link ErrorHandler} used for dealing with errors encountered
+     * during the parse process. Passing {@code null} results in the
+     * {@code DocumentBuilder}'s own {@code ErrorHandler} being used.
+     * 
+     * @param handler the {@code ErrorHandler} to use, or {@code null} for the
+     *        built-in one.
+     * 
+     * @since Android 1.0
+     */
+    public abstract void setErrorHandler(ErrorHandler handler);
+
+}
diff --git a/xml/src/main/java/javax/xml/parsers/DocumentBuilderFactory.java b/xml/src/main/java/javax/xml/parsers/DocumentBuilderFactory.java
new file mode 100644
index 0000000..4e186c1
--- /dev/null
+++ b/xml/src/main/java/javax/xml/parsers/DocumentBuilderFactory.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.xml.parsers;
+
+import org.apache.harmony.xml.parsers.DocumentBuilderFactoryImpl;
+
+/**
+ * Provides a factory for {@link DocumentBuilder} instances. The class first
+ * needs to be instantiated using the {@link #newInstance()} method. The
+ * instance can be configured as desired. A call to
+ * {@link #newDocumentBuilder()} then provides a {@code DocumentBuilder}
+ * instance matching this configuration (if possible).
+ * 
+ * @since Android 1.0
+ */
+public abstract class DocumentBuilderFactory extends Object {
+
+    private boolean coalesce;
+
+    private boolean expandEntityReferences;
+
+    private boolean ignoreComments;
+
+    private boolean ignoreElementContentWhitespace;
+
+    private boolean namespaceAware;
+
+    private boolean validate;
+
+    /**
+     * Do-nothing constructor. To be overridden by concrete document builders.
+     * 
+     * @since Android 1.0
+     */
+    protected DocumentBuilderFactory() {
+        // Does nothing.
+    }
+
+    /**
+     * Queries an attribute from the underlying implementation.
+     * 
+     * @param name the name of the attribute.
+     * @return the value of the attribute.
+     * 
+     * @throws IllegalArgumentException if the argument is unknown to the
+     *         underlying implementation.
+     * 
+     * @since Android 1.0
+     */
+    public abstract Object getAttribute(String name)
+            throws IllegalArgumentException;
+
+    /**
+     * Queries a feature from the underlying implementation.
+     * 
+     * @param name The name of the feature. The default Android implementation
+     *             of {@link DocumentBuilder} supports only the following three
+     *             features:
+     *             
+     *             <dl>
+     *               <dt>{@code http://xml.org/sax/features/namespaces}</dt>
+     *               <dd>Queries the state of namespace-awareness.</dd>
+     *               
+     *               <dt>
+     *                 {@code http://xml.org/sax/features/namespace-prefixes}
+     *               </dt>
+     *               <dd>Queries the state of namespace prefix processing</dd>
+     *
+     *               <dt>
+     *                 {@code http://xml.org/sax/features/validation}
+     *               </dt>
+     *               <dd>Queries the state of validation.</dd>
+     *             </dl>
+     *             
+     *             Note that despite the ability to query the validation
+     *             feature, there is currently no validating parser available.
+     *             Also note that currently either namespaces or 
+     *             namespace prefixes can be enabled, but not both at the same 
+     *             time.
+     * 
+     * @return the status of the feature.
+     * 
+     * @throws IllegalArgumentException if the feature is unknown to
+     *         the underlying implementation.
+     * @throws ParserConfigurationException if the feature is
+     *         known, but not supported.
+     * 
+     * @since Android 1.0
+     */
+    public abstract boolean getFeature(String name)
+            throws ParserConfigurationException;
+
+// TODO No XSchema support in Android 1.0. Maybe later.
+//    /**
+//     * Queries the desired XML Schema object.
+//     * 
+//     * @return The XML Schema object, if it has been set by a call to setSchema,
+//     *         or null otherwise.
+//     */
+//    public javax.xml.validation.Schema getSchema() {
+//        return schema;
+//    }
+    
+    /**
+     * Queries whether the factory is configured to deliver parsers that convert
+     * CDATA nodes to text nodes and melt them with neighboring nodes. This is
+     * called "coalescing".
+     * 
+     * @return {@code true} if coalescing is desired, {@code false} otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isCoalescing() {
+        return coalesce;
+    }
+
+    /**
+     * Queries whether the factory is configured to deliver parsers that expand
+     * entity references.
+     * 
+     * @return {@code true} if entity expansion is desired, {@code false}
+     * otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isExpandEntityReferences() {
+        return expandEntityReferences;
+    }
+
+    /**
+     * Queries whether the factory is configured to deliver parsers that ignore
+     * comments.
+     * 
+     * @return {@code true} if comment ignorance is desired, {@code false}
+     * otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isIgnoringComments() {
+        return ignoreComments;
+    }
+
+    /**
+     * Queries whether the factory is configured to deliver parsers that ignore
+     * whitespace in elements.
+     * 
+     * @return {@code true} if whitespace ignorance is desired, {@code false}
+     * otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isIgnoringElementContentWhitespace() {
+        return ignoreElementContentWhitespace;
+    }
+
+    /**
+     * Queries whether the factory is configured to deliver parsers that are
+     * namespace-aware.
+     * 
+     * @return {@code true} if namespace-awareness is desired, {@code false}
+     * otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isNamespaceAware() {
+        return namespaceAware;
+    }
+
+    /**
+     * Queries whether the factory is configured to deliver parsers that are
+     * validating.
+     * 
+     * @return {@code true} if validating is desired, {@code false} otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isValidating() {
+        return validate;
+    }
+
+    /**
+     * Queries whether the factory is configured to deliver parsers that are
+     * XInclude-aware.
+     * 
+     * @return {@code true} if XInclude-awareness is desired, {@code false}
+     * otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isXIncludeAware() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Creates a new {@link DocumentBuilder} that matches the current
+     * configuration of the factory.
+     * 
+     * @return the DocumentBuilder.
+     * @throws ParserConfigurationException if no matching
+     *         {@code DocumentBuilder} could be found.
+     * 
+     * @since Android 1.0
+     */
+    public abstract DocumentBuilder newDocumentBuilder()
+            throws ParserConfigurationException;
+
+    /**
+     * Creates a new DocumentBuilderFactory that can be configured and then be
+     * used for creating DocumentBuilder objects. The method first checks the
+     * value of the {@code DocumentBuilderFactory} property.
+     * If this is non-{@code null}, it is assumed to be the name of a class
+     * that serves as the factory. The class is instantiated, and the instance
+     * is returned. If the property value is {@code null}, the system's default
+     * factory implementation is returned.
+     * 
+     * @return the DocumentBuilderFactory.
+     * @throws FactoryConfigurationError if no {@code DocumentBuilderFactory}
+     *         can be created.
+     * 
+     * @since Android 1.0
+     */
+    public static DocumentBuilderFactory newInstance()
+            throws FactoryConfigurationError {
+        // TODO Properties file and META-INF case missing here. See spec.
+        String factory = System
+                .getProperty("javax.xml.parsers.DocumentBuilderFactory");
+        if (factory != null) {
+            try {
+                return (DocumentBuilderFactory) Class.forName(factory)
+                        .newInstance();
+            } catch (Exception ex) {
+                // Ignore.
+            }
+        }
+
+        try {
+            return new DocumentBuilderFactoryImpl();
+        } catch (Exception ex) {
+            // Ignore.
+        }
+
+        throw new FactoryConfigurationError(
+                "Cannot create DocumentBuilderFactory");
+    }
+
+    /**
+     * Sets an attribute in the underlying implementation.
+     * 
+     * @param name the name of the attribute.
+     * @param value the value of the attribute.
+     * 
+     * @throws IllegalArgumentException if the argument is unknown to the
+     *         underlying implementation.
+     * 
+     * @since Android 1.0
+     */
+    public abstract void setAttribute(String name, Object value)
+            throws IllegalArgumentException;
+
+    /**
+     * Determines whether the factory is configured to deliver parsers that
+     * convert CDATA nodes to text nodes and melt them with neighboring nodes.
+     * This is called "coalescing".
+     * 
+     * @param value turns coalescing on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setCoalescing(boolean value) {
+        coalesce = value;
+    }
+
+    /**
+     * Determines whether the factory is configured to deliver parsers that
+     * expands entity references.
+     * 
+     * @param value turns entity reference expansion on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setExpandEntityReferences(boolean value) {
+        expandEntityReferences = value;
+    }
+
+    /**
+     * Sets a feature in the underlying implementation.
+     * 
+     * @param name the name of the feature. The default Android implementation
+     *             of {@link DocumentBuilder} supports only the following three
+     *             features:
+     *             
+     *             <dl>
+     *               <dt>{@code http://xml.org/sax/features/namespaces}</dt>
+     *               <dd>Sets the state of namespace-awareness.</dd>
+     *               
+     *               <dt>
+     *                 {@code http://xml.org/sax/features/namespace-prefixes}
+     *               </dt>
+     *               <dd>Sets the state of namespace prefix processing</dd>
+     *
+     *               <dt>{@code http://xml.org/sax/features/validation}</dt>
+     *               <dd>Sets the state of validation.</dd>
+     *             </dl>
+     *             
+     *             Note that despite the ability to set the validation
+     *             feature, there is currently no validating parser available.
+     *             Also note that currently either namespaces or
+     *             namespace prefixes can be enabled, but not both at the same
+     *             time.
+     * 
+     * @param value the value of the feature.
+     * 
+     * @throws ParserConfigurationException if the feature is unknown to the
+     *         underlying implementation.
+     * 
+     * @since Android 1.0
+     */
+    public abstract void setFeature(String name, boolean value)
+            throws ParserConfigurationException;
+
+    /**
+     * Determines whether the factory is configured to deliver parsers that
+     * ignore comments.
+     * 
+     * @param value turns comment ignorance on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setIgnoringComments(boolean value) {
+        ignoreComments = value;
+    }
+
+    /**
+     * Determines whether the factory is configured to deliver parsers that
+     * ignores element whitespace.
+     * 
+     * @param value turns element whitespace ignorance on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setIgnoringElementContentWhitespace(boolean value) {
+        ignoreElementContentWhitespace = value;
+    }
+
+    /**
+     * Determines whether the factory is configured to deliver parsers that are
+     * namespace-aware.
+     * 
+     * @param value turns namespace-awareness on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setNamespaceAware(boolean value) {
+        namespaceAware = value;
+    }
+
+// TODO No XSchema support in Android 1.0. Maybe later.
+//    /**
+//     * Sets the desired XML Schema object.
+//     * 
+//     * @param schema The XML Schema object.
+//     */
+//    public void setSchema(Schema schema) {
+//        this.schema = schema;
+//    }
+    
+    /**
+     * Determines whether the factory is configured to deliver parsers that are
+     * validating.
+     * 
+     * @param value turns validation on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setValidating(boolean value) {
+        validate = value;
+    }
+
+    /**
+     * Determines whether the factory is configured to deliver parsers that are
+     * XInclude-aware.
+     * 
+     * @param value turns XInclude-awareness on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setXIncludeAware(boolean value) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/xml/src/main/java/javax/xml/parsers/FactoryConfigurationError.java b/xml/src/main/java/javax/xml/parsers/FactoryConfigurationError.java
new file mode 100644
index 0000000..f5e0c03
--- /dev/null
+++ b/xml/src/main/java/javax/xml/parsers/FactoryConfigurationError.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.xml.parsers;
+
+/**
+ * Represents an error that occurred during the configuration of parser factory.
+ * 
+ * @since Android 1.0
+ */
+public class FactoryConfigurationError extends Error {
+
+    /**
+     * The nested exception that caused this exception. Note that the nested
+     * exception will be stored in a special attribute, and can be queried using
+     * the {@link #getException()} method. It does not use the facility the
+     * {@link Exception} class provides for storing nested exceptions, since the
+     * XML API predates that facility.
+     */
+    private Exception cause;
+    
+    /**
+     * Creates a new {@code FactoryConfigurationError} with no error message and
+     * no cause.
+     * 
+     * @since Android 1.0
+     */
+    public FactoryConfigurationError() {
+        super();
+    }
+
+    /**
+     * Creates a new {@code FactoryConfigurationError} with no error message and
+     * a given cause.
+     * 
+     * @param cause the cause of the error. Note that the nested exception will
+     *        be stored in a special attribute, and can be queried using the
+     *        {@link #getException()} method. It does not use the facility the
+     *        Exception class provides for storing nested exceptions, since the
+     *        XML API predates that facility.
+     * 
+     * @since Android 1.0
+     */
+    public FactoryConfigurationError(Exception cause) {
+        super();
+        this.cause = cause;
+    }
+
+    /**
+     * Creates a new {@code FactoryConfigurationError} with a given error
+     * message and cause.
+     * 
+     * @param cause the cause of the error. Note that the nested exception will
+     *        be stored in a special attribute, and can be queried using the
+     *        {@link #getException()} method. It does not use the facility the
+     *        {@link Exception} class provides for storing nested exceptions,
+     *        since the XML API predates that facility.
+     * @param message The error message.
+     * 
+     * @since Android 1.0
+     */
+    public FactoryConfigurationError(Exception cause, String message) {
+        super(message);
+        this.cause = cause;
+    }
+
+    /**
+     * Creates a new {@code FactoryConfigurationError} with a given error
+     * message and no cause.
+     * 
+     * @param message the error message.
+     * 
+     * @since Android 1.0
+     */
+    public FactoryConfigurationError(String message) {
+        super(message);
+    }
+
+    /**
+     * Returns the cause of the error, in case there is one.
+     * 
+     * @return the exception that caused the error, or {@code null} if none is
+     *         set.
+     * 
+     * @since Android 1.0
+     */
+    public Exception getException() {
+        return cause;
+    }
+
+    /**
+     * Returns the message of the error, in case there is one.
+     * 
+     * @return the message. If an explicit error message has been assigned to
+     *         the exception, this one is returned. If not, and there is an
+     *         underlying exception (the cause), then the result of invoking
+     *         {@link #toString()} on that object is returned. Otherwise, {@code
+     *         null} is returned.
+     * 
+     * @since Android 1.0
+     */
+    public String getMessage() {
+        String message = super.getMessage();
+
+        if (message != null) {
+            return message;
+        } else if (cause != null) {
+            return cause.toString();
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/xml/src/main/java/javax/xml/parsers/ParserConfigurationException.java b/xml/src/main/java/javax/xml/parsers/ParserConfigurationException.java
new file mode 100644
index 0000000..49875d6
--- /dev/null
+++ b/xml/src/main/java/javax/xml/parsers/ParserConfigurationException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.xml.parsers;
+
+/**
+ * Represents an exception that occurred during the configuration of parser.
+ * 
+ * @since Android 1.0
+ */
+public class ParserConfigurationException extends Exception {
+
+    /**
+     * Creates a new {@code ParserConfigurationException} with no error message.
+     * 
+     * @since Android 1.0
+     */
+    public ParserConfigurationException() {
+        super();
+    }
+
+    /**
+     * Creates a new {@code ParserConfigurationException} with a given error
+     * message.
+     * 
+     * @param msg the error message.
+     * 
+     * @since Android 1.0
+     */
+    public ParserConfigurationException(String msg) {
+        super(msg);
+    }
+
+}
diff --git a/xml/src/main/java/javax/xml/parsers/SAXParser.java b/xml/src/main/java/javax/xml/parsers/SAXParser.java
new file mode 100644
index 0000000..73cc0eb
--- /dev/null
+++ b/xml/src/main/java/javax/xml/parsers/SAXParser.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.xml.parsers;
+
+import org.xml.sax.HandlerBase;
+import org.xml.sax.InputSource;
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Provides a wrapper around a SAX {@link XMLReader}. This abstract
+ * class only defines the interface, whereas the {@link SAXParserFactory} class
+ * is used to obtain instances of concrete subclasses.
+ * 
+ * @since Android 1.0
+ */
+public abstract class SAXParser extends java.lang.Object {
+
+    /**
+     * Do-nothing constructor. Prevents instantiation. To be overridden by
+     * concrete subclasses.
+     * 
+     * @since Android 1.0
+     */
+    protected SAXParser() {
+        // Does nothing.
+    }
+
+    /**
+     * Queries the underlying SAX {@link Parser} object.
+     * 
+     * @return the SAX {@code Parser}.
+     * 
+     * @throws SAXException if a problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public abstract Parser getParser()
+            throws SAXException;
+
+    /**
+     * Queries a property of the underlying SAX {@link XMLReader}.
+     * 
+     * @param name the name of the property.
+     * @return the value of the property.
+     * 
+     * @throws SAXNotRecognizedException if the property is not known to the
+     *         underlying SAX {@code XMLReader}.
+     * @throws SAXNotSupportedException if the property is known, but not
+     *         supported by the underlying SAX {@code XMLReader}.
+     * 
+     * @since Android 1.0
+     */
+    public abstract Object getProperty(String name)
+            throws SAXNotRecognizedException, SAXNotSupportedException;
+
+// TODO No XSchema support in Android 1.0. Maybe later.
+//    /**
+//     * Queries the XML Schema used by the underlying XMLReader.
+//     * 
+//     * @return The XML Schema.
+//     */
+//    public Schema getSchema() {
+//        return schema;
+//    }
+    
+    /**
+     * Queries the underlying SAX XMLReader object.
+     * 
+     * @return the SAX XMLREader.
+     * 
+     * @throws SAXException if a problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public abstract XMLReader getXMLReader() throws SAXException;
+
+    /**
+     * Reflects whether this {@code SAXParser} is namespace-aware.
+     * 
+     * @return {@code true} if the {@code SAXParser} is namespace-aware, or
+     * {@code false} otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public abstract boolean isNamespaceAware();
+
+    /**
+     * Reflects whether this {@code SAXParser} is validating.
+     * 
+     * @return {@code true} if the {@code SAXParser} is validating, or {@code
+     * false} otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public abstract boolean isValidating();
+
+    /**
+     * Reflects whether this {@code SAXParser} is XInclude-aware.
+     * 
+     * @return {@code true} if the {@code SAXParser} is XInclude-aware, or
+     *         {@code false} otherwise.
+     * 
+     * @throws UnsupportedOperationException if the underlying implementation
+     *         doesn't know about XInclude at all (backwards compatibility).
+     * 
+     * @since Android 1.0
+     */
+    public boolean isXIncludeAware() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Parses the given XML file using the given SAX event handler.
+     * 
+     * @param file the file containing the XML document.
+     * @param handler the SAX handler.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(File file, HandlerBase handler) throws SAXException,
+            IOException {
+        if (file == null) {
+            throw new IllegalArgumentException("file must not be null");
+        }
+        if (file.isDirectory()) {
+            throw new IllegalArgumentException("file must not be a directory");
+        }
+        InputSource source = new InputSource("file:" + file.getAbsolutePath());
+        parse(source, handler);
+    }
+
+    /**
+     * Parses the given XML file using the given SAX event handler.
+     * 
+     * @param file the file containing the XML document.
+     * @param handler the SAX handler.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(File file, DefaultHandler handler) throws SAXException,
+            IOException {
+        if (file == null) {
+            throw new IllegalArgumentException("file must not be null");
+        }
+        if (file.isDirectory()) {
+            throw new IllegalArgumentException("file must not be a directory");
+        }
+        InputSource source = new InputSource("file:" + file.getAbsolutePath());
+        parse(source, handler);
+    }
+
+    /**
+     * Parses the given XML InputStream using the given SAX event handler.
+     * 
+     * @param stream the InputStream containing the XML document.
+     * @param handler the SAX handler.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(InputStream stream, HandlerBase handler)
+            throws SAXException, IOException {
+        if (stream == null) {
+            throw new IllegalArgumentException("stream must not be null");
+        }
+        parse(new InputSource(stream), handler);
+    }
+
+    /**
+     * Parses the given XML InputStream using the given SAX event handler and
+     * system ID.
+     * 
+     * @param stream the InputStream containing the XML document.
+     * @param handler the SAX handler.
+     * @param systemId the system ID.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(InputStream stream, HandlerBase handler, String systemId)
+            throws SAXException, IOException {
+        if (stream == null) {
+            throw new IllegalArgumentException("stream must not be null");
+        }
+        InputSource source = new InputSource(stream);
+        if (systemId != null) {
+            source.setSystemId(systemId);
+        }
+        parse(source, handler);
+    }
+
+    /**
+     * Parses the given XML InputStream using the given SAX event handler.
+     * 
+     * @param stream the InputStream containing the XML document.
+     * @param handler the SAX handler.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(InputStream stream, DefaultHandler handler)
+            throws SAXException, IOException {
+        parse(new InputSource(stream), handler);
+    }
+
+    /**
+     * Parses the given XML InputStream using the given SAX event handler and
+     * system ID.
+     * 
+     * @param stream the InputStream containing the XML document.
+     * @param handler the SAX handler.
+     * @param systemId the system ID.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(InputStream stream, DefaultHandler handler,
+            String systemId) throws SAXException, IOException {
+        if (stream  == null) {
+            throw new IllegalArgumentException("stream must not be null");
+        }
+        InputSource source = new InputSource(stream);
+        if (systemId != null) {
+            source.setSystemId(systemId);
+        }
+        parse(source, handler);
+    }
+
+    /**
+     * Parses the contents of the given URI using the given SAX event handler.
+     * 
+     * @param uri the URI pointing to the XML document.
+     * @param handler the SAX handler.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(String uri, HandlerBase handler) throws SAXException,
+            IOException {
+        if (uri == null) {
+            throw new IllegalArgumentException("uri must not be null");
+        }
+        parse(new InputSource(uri), handler);
+    }
+
+    /**
+     * Parses the contents of the given URI using the given SAX event handler.
+     * 
+     * @param uri the URI pointing to the XML document.
+     * @param handler the SAX handler.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(String uri, DefaultHandler handler) throws SAXException,
+            IOException {
+        if (uri == null) {
+            throw new IllegalArgumentException("uri must not be null");
+        }
+        parse(new InputSource(uri), handler);
+    }
+
+    /**
+     * Parses the given SAX {@link InputSource} using the given SAX event
+     * handler.
+     * 
+     * @param source the SAX {@code InputSource} containing the XML document.
+     * @param handler the SAX handler.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(InputSource source, HandlerBase handler)
+            throws SAXException, IOException {
+        Parser parser = getParser();
+        if (source == null) {
+            throw new IllegalArgumentException("source must not be null");
+        }
+
+        if (handler != null) {
+            parser.setDocumentHandler(handler);
+            parser.setDTDHandler(handler);
+            parser.setEntityResolver(handler);
+            parser.setErrorHandler(handler);
+        }
+
+        parser.parse(source);
+    }
+
+    /**
+     * Parses the given SAX {@link InputSource} using the given SAX event
+     * handler.
+     * 
+     * @param source the SAX {@code InputSource} containing the XML document.
+     * @param handler the SAX handler.
+     * 
+     * @throws SAXException if a problem occurs during SAX parsing.
+     * @throws IOException if a general IO problem occurs.
+     * 
+     * @since Android 1.0
+     */
+    public void parse(InputSource source, DefaultHandler handler)
+            throws SAXException, IOException {
+        if (source == null) {
+            throw new IllegalArgumentException("source must not be null");
+        }
+        XMLReader reader = getXMLReader();
+
+        if (handler != null) {
+            reader.setContentHandler(handler);
+            reader.setDTDHandler(handler);
+            reader.setEntityResolver(handler);
+            reader.setErrorHandler(handler);
+        }
+
+        reader.parse(source);
+    }
+
+    /**
+     * Resets the {@code SAXParser} to the same state is was in after its
+     * creation.
+     * 
+     * @since Android 1.0
+     */
+    public void reset() {
+        // Do nothing.
+    }
+
+    /**
+     * Sets a property of the underlying SAX {@link XMLReader}.
+     * 
+     * @param name the name of the property.
+     * @param value the value of the property.
+     * 
+     * @throws SAXNotRecognizedException if the property is not known to the
+     *         underlying SAX {@code XMLReader}.
+     * @throws SAXNotSupportedException if the property is known, but not
+     *         supported by the underlying SAX {@code XMLReader}.
+     * 
+     * @since Android 1.0
+     */
+    public abstract void setProperty(String name, Object value)
+            throws SAXNotRecognizedException, SAXNotSupportedException;
+
+}
diff --git a/xml/src/main/java/javax/xml/parsers/SAXParserFactory.java b/xml/src/main/java/javax/xml/parsers/SAXParserFactory.java
new file mode 100644
index 0000000..ebf0531
--- /dev/null
+++ b/xml/src/main/java/javax/xml/parsers/SAXParserFactory.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.xml.parsers;
+
+import org.apache.harmony.xml.parsers.SAXParserFactoryImpl;
+
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXException;
+
+/**
+ * Provides a factory for {@link SAXParser} instances. The class first needs to
+ * be instantiated using the {@link #newInstance()} method. The instance can be
+ * configured as desired. A call to its {@link #newSAXParser()} then provides a
+ * {@code SAXParser} instance matching this configuration, if possible.
+ * 
+ * @since Android 1.0
+ */
+public abstract class SAXParserFactory {
+
+    private boolean namespaceAware;
+
+    private boolean validating;
+
+    private boolean xincludeAware;
+
+    /**
+     * Do-nothing constructor. Prevents instantiation. To be overridden by
+     * concrete subclasses.
+     * 
+     * @since Android 1.0
+     */
+    protected SAXParserFactory() {
+        // Does nothing.
+    }
+
+    /**
+     * Queries a feature from the underlying implementation.
+     * 
+     * @param name The name of the feature. The default Android implementation
+     *             of {@link SAXParser} supports only the following three
+     *             features:
+     *             
+     *             <dl>
+     *               <dt>{@code http://xml.org/sax/features/namespaces}</dt>
+     *               <dd>Queries the state of namespace-awareness.</dd>
+     *               
+     *               <dt>
+     *                 {@code http://xml.org/sax/features/namespace-prefixes}
+     *               </dt>
+     *               <dd>Queries the state of namespace prefix processing</dd>
+     *
+     *               <dt>{@code http://xml.org/sax/features/validation}</dt>
+     *               <dd>Queries the state of validation.</dd>
+     *             </dl>
+     *             
+     *             Note that despite the ability to query the validation
+     *             feature, there is currently no validating parser available.
+     *             Also note that currently either namespaces or 
+     *             namespace prefixes can be enabled, but not both at the same 
+     *             time.
+     *             
+     * @return the status of the feature.
+     * 
+     * @throws ParserConfigurationException if no {@code SAXParser} matching the
+     *         given criteria is available.
+     * @throws SAXNotRecognizedException if the given feature is not known to
+     *         the underlying implementation.
+     * @throws SAXNotSupportedException if the given features is known, but not
+     *         supported by the underlying implementation.
+     *         
+     * @since Android 1.0
+     */
+    public abstract boolean getFeature(String name)
+            throws ParserConfigurationException, SAXNotRecognizedException,
+            SAXNotSupportedException;
+
+// TODO No XSchema support in Android 1.0. Maybe later.
+//    /**
+//     * Queries the desired XML Schema object.
+//     * 
+//     * @return The XML Schema object, if it has been set by a call to setSchema,
+//     *         or null otherwise.
+//     */
+//    public javax.xml.validation.Schema getSchema() {
+//        return schema;
+//    }
+    
+    /**
+     * Queries whether the factory is configured to deliver parsers that are
+     * namespace-aware.
+     * 
+     * @return {@code true} if namespace-awareness is desired, {@code false}
+     *         otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isNamespaceAware() {
+        return namespaceAware;
+    }
+
+    /**
+     * Queries whether the factory is configured to deliver parsers that are
+     * validating.
+     * 
+     * @return {@code true} if validating is desired, {@code false} otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isValidating() {
+        return validating;
+    }
+
+    /**
+     * Queries whether the factory is configured to deliver parsers that are
+     * XInclude-aware.
+     * 
+     * @return {@code true} if XInclude-awareness is desired, {@code false}
+     *         otherwise.
+     * 
+     * @since Android 1.0
+     */
+    public boolean isXIncludeAware() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Creates a new {@code SAXParserFactory} that can be configured and then be
+     * used for creating {@link SAXParser} objects. The method first checks the
+     * value of the {@code SAXParserFactory} property. If this
+     * is non-{@code null}, it is assumed to be the name of a class that serves
+     * as the factory. The class is instantiated, and the instance is returned.
+     * If the property value is {@code null}, the system's default factory
+     * implementation is returned. 
+     * 
+     * @return the {@code SAXParserFactory}.
+     * 
+     * @throws FactoryConfigurationError if no {@code SAXParserFactory} can be
+     *         created.
+     *         
+     * @since Android 1.0
+     */
+    public static SAXParserFactory newInstance()
+            throws FactoryConfigurationError {
+        // TODO Properties file and META-INF case missing here. See spec.
+        String factory = System
+                .getProperty("javax.xml.parsers.SAXParserFactory");
+        if (factory != null) {
+            try {
+                return (SAXParserFactory) Class.forName(factory).newInstance();
+            } catch (Exception ex) {
+                throw new FactoryConfigurationError(factory);
+            }
+        }
+
+        try {
+            return new SAXParserFactoryImpl();
+        } catch (Exception ex) {
+            // Ignore.
+        }
+
+        throw new FactoryConfigurationError("Cannot create SAXParserFactory");
+    }
+
+    /**
+     * Creates a new {@link SAXParser} that matches the current configuration of
+     * the factory.
+     * 
+     * @return the {@code SAXParser}.
+     * 
+     * @throws ParserConfigurationException if no matching {@code SAXParser}
+     *         could be found.
+     * @throws SAXException if creating the {@code SAXParser} failed due to some
+     *         other reason.
+     * 
+     * @since Android 1.0
+     */
+    public abstract SAXParser newSAXParser()
+            throws ParserConfigurationException, SAXException;
+
+    /**
+     * Sets a feature in the underlying implementation.
+     * 
+     * @param name the name of the feature. The default Android implementation
+     *             of {@link SAXParser} supports only the following three
+     *             features:
+     *             
+     *             <dl>
+     *               <dt>{@code http://xml.org/sax/features/namespaces}</dt>
+     *               <dd>Sets the state of namespace-awareness.</dd>
+     *
+     *               <dt>
+     *                 {@code http://xml.org/sax/features/namespace-prefixes}
+     *               </dt>
+     *               <dd>Sets the state of namespace prefix processing</dd>
+     *
+     *               <dt>{@code http://xml.org/sax/features/validation}</dt>
+     *               <dd>Sets the state of validation.</dd>
+     *             </dl>
+     *             
+     *             Note that despite the ability to query the validation
+     *             feature, there is currently no validating parser available.
+     *             Also note that currently either namespaces or 
+     *             namespace prefixes can be enabled, but not both at the same 
+     *             time.
+     *             
+     * @param value the status of the feature.
+     * 
+     * @throws ParserConfigurationException if no {@code SAXParser} matching
+     *         the given criteria is available.
+     * @throws SAXNotRecognizedException if the given feature is not known to
+     *         the underlying implementation.
+     * @throws SAXNotSupportedException if the given features is known, but not
+     *         supported by the underlying implementation.
+     *         
+     * @since Android 1.0
+     */
+    public abstract void setFeature(String name, boolean value)
+            throws ParserConfigurationException, SAXNotRecognizedException,
+            SAXNotSupportedException;
+
+    /**
+     * Determines whether the factory is configured to deliver parsers that are
+     * namespace-aware.
+     * 
+     * @param value turns namespace-awareness on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setNamespaceAware(boolean value) {
+        namespaceAware = value;
+    }
+
+// TODO No XSchema support in Android 1.0. Maybe later.
+//    /**
+//     * Sets the desired XML Schema object.
+//     * 
+//     * @param schema The XML Schema object.
+//     */
+//    public void setSchema(Schema schema) {
+//       this.schema = schema;
+//    }
+
+    /**
+     * Determines whether the factory is configured to deliver parsers that are
+     * validating.
+     * 
+     * @param value turns validation on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setValidating(boolean value) {
+        validating = value;
+    }
+
+    /**
+     * Determines whether the factory is configured to deliver parsers that are
+     * XInclude-aware.
+     * 
+     * @param value turns XInclude-awareness on or off.
+     * 
+     * @since Android 1.0
+     */
+    public void setXIncludeAware(boolean value) {
+        throw new UnsupportedOperationException();
+    }
+
+}
+
diff --git a/xml/src/main/java/javax/xml/parsers/package.html b/xml/src/main/java/javax/xml/parsers/package.html
new file mode 100644
index 0000000..7e0921d
--- /dev/null
+++ b/xml/src/main/java/javax/xml/parsers/package.html
@@ -0,0 +1,24 @@
+<html>
+  <body>
+    <p>
+      Provides facilities for parsing XML documents and building Document Object
+      Model (DOM) trees from them. The
+      {@link javax.xml.parsers.SAXParserFactory} class serves as an entry point
+      to event-based XML parsing. The
+      {@link javax.xml.parsers.DocumentBuilderFactory} class is an entry point
+      for dealing with DOM trees. Both factories are usually configured
+      before their factory methods are invoked. They then try to create a
+      {@link javax.xml.parsers.SAXParser} or a
+      {@link javax.xml.parsers.DocumentBuilder} (respectively) suiting the
+      application's needs. If none can be found, an Exception is thrown. 
+    </p>
+    <p>
+      Note that in order to cater for resource-constrained environments,
+      Android's XML packages currently only provide DOM Level 2 Core support
+      and a non-validating parser. This means that (a) the interface for the
+      various DOM classes might differ from other implementations and (b)
+      requesting a validating parser will always fail.
+    </p>
+    @since Android 1.0
+  </body>
+</html>
\ No newline at end of file
diff --git a/xml/src/main/java/org/apache/harmony/xml/ExpatAttributes.java b/xml/src/main/java/org/apache/harmony/xml/ExpatAttributes.java
new file mode 100644
index 0000000..ed6cb11
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/ExpatAttributes.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml;
+
+import org.xml.sax.Attributes;
+
+/**
+ * Wraps native attribute array.
+ */
+abstract class ExpatAttributes implements Attributes {
+
+    /**
+     * Since we don't do validation, pretty much everything is CDATA type.
+     */
+    private static final String CDATA = "CDATA";
+
+    /**
+     * Gets the number of attributes.
+     */
+    public abstract int getLength();
+
+    /**
+     * Gets the pointer to the parser. We need this so we can get to the
+     * interned string pool.
+     */
+    abstract int getParserPointer();
+
+    /**
+     * Gets the pointer to the underlying attribute array. Can be 0 if the
+     * length is 0.
+     */
+    public abstract int getPointer();
+
+    public String getURI(int index) {
+        if (index < 0 || index >= getLength()) {
+            return null;
+        }
+        return getURI(getParserPointer(), getPointer(), index);
+    }
+
+    public String getLocalName(int index) {
+        return (index < 0 || index >= getLength())
+                ? null
+                : getLocalName(getParserPointer(), getPointer(), index);
+    }
+
+    public String getQName(int index) {
+        return (index < 0 || index >= getLength())
+                ? null
+                : getQName(getParserPointer(), getPointer(), index);
+    }
+
+    public String getType(int index) {
+        return (index < 0 || index >= getLength()) ? null : CDATA;
+    }
+
+    public String getValue(int index) {
+        return (index < 0 || index >= getLength())
+                ? null
+                : getValue(getPointer(), index);
+    }
+
+    public int getIndex(String uri, String localName) {
+        if (uri == null) {
+            throw new NullPointerException("uri");
+        }
+        if (localName == null) {
+            throw new NullPointerException("local name");
+        }
+        int pointer = getPointer();
+        if (pointer == 0) {
+            return -1;
+        }
+        return getIndex(pointer, uri, localName);
+    }
+
+    public int getIndex(String qName) {
+        if (qName == null) {
+            throw new NullPointerException("uri");
+        }
+        int pointer = getPointer();
+        if (pointer == 0) {
+            return -1;
+        }
+        return getIndex(pointer, qName);
+    }
+
+    public String getType(String uri, String localName) {
+        if (uri == null) {
+            throw new NullPointerException("uri");
+        }
+        if (localName == null) {
+            throw new NullPointerException("local name");
+        }
+        return getIndex(uri, localName) == -1 ? null : CDATA;
+    }
+
+    public String getType(String qName) {
+        return getIndex(qName) == -1 ? null : CDATA;
+    }
+
+    public String getValue(String uri, String localName) {
+        if (uri == null) {
+            throw new NullPointerException("uri");
+        }
+        if (localName == null) {
+            throw new NullPointerException("local name");
+        }
+        int pointer = getPointer();
+        if (pointer == 0) {
+            return null;
+        }
+        return getValue(pointer, uri, localName);
+    }
+
+    public String getValue(String qName) {
+        if (qName == null) {
+            throw new NullPointerException("qName");
+        }
+        int pointer = getPointer();
+        if (pointer == 0) {
+            return null;
+        }
+        return getValue(pointer, qName);
+    }
+
+    static native String getURI(int pointer, int attributePointer, int index);
+    static native String getLocalName(int pointer, int attributePointer,
+            int index);
+    static native String getQName(int pointer, int attributePointer,
+            int index);
+    static native String getValue(int attributePointer, int index);
+    static native int getIndex(int attributePointer, String uri,
+            String localName);
+    static native int getIndex(int attributePointer, String qName);
+    static native String getValue(int attributePointer,
+            String uri, String localName);
+    static native String getValue(int attributePointer, String qName);
+    static native void freeAttributes(int pointer);
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/ExpatException.java b/xml/src/main/java/org/apache/harmony/xml/ExpatException.java
new file mode 100644
index 0000000..da3db9d
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/ExpatException.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml;
+
+/**
+ * Used internally to propogate Expat errors. We convert these exceptions into
+ * SAXParseExceptions before propogating them to the client.
+ */
+class ExpatException extends Exception {
+
+    public ExpatException(String message) {
+        super(message);
+    }
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/ExpatParser.java b/xml/src/main/java/org/apache/harmony/xml/ExpatParser.java
new file mode 100644
index 0000000..60d74b8
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/ExpatParser.java
@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.ext.LexicalHandler;
+
+import java.io.Reader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URLConnection;
+import java.net.URL;
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+/**
+ * Adapts SAX API to the Expat native XML parser. Not intended for reuse
+ * across documents.
+ *
+ * @see org.apache.harmony.xml.ExpatPullParser
+ * @see org.apache.harmony.xml.ExpatReader
+ */
+class ExpatParser {
+
+    private static final int BUFFER_SIZE = 8096; // in bytes
+
+    /** Pointer to XML_Parser instance. */
+    private int pointer;
+
+    private boolean inStartElement = false;
+    private int attributeCount = -1;
+    private int attributePointer = 0;
+
+    private final Locator locator = new ExpatLocator();
+
+    private final ExpatReader xmlReader;
+
+    private final String publicId;
+    private final String systemId;
+
+    private final String encoding;
+
+    private final ExpatAttributes attributes = new CurrentAttributes();
+
+    private static final String OUTSIDE_START_ELEMENT
+            = "Attributes can only be used within the scope of startElement().";
+
+    /** We default to UTF-8 when the user doesn't specify an encoding. */
+    private static final String DEFAULT_ENCODING = "UTF-8";
+
+    /** Encoding used for Java chars, used to parse Readers and Strings */
+    /*package*/ static final String CHARACTER_ENCODING = "UTF-16";
+
+    /** Timeout for HTTP connections (in ms) */
+    private static final int TIMEOUT = 20 * 1000;
+
+    /**
+     * Constructs a new parser with the specified encoding.
+     */
+    /*package*/ ExpatParser(String encoding, ExpatReader xmlReader,
+            boolean processNamespaces, String publicId, String systemId) {
+        this.publicId = publicId;
+        this.systemId = systemId;
+
+        this.xmlReader = xmlReader;
+
+        /*
+         * TODO: Let Expat try to guess the encoding instead of defaulting.
+         * Unfortunately, I don't know how to tell which encoding Expat picked,
+         * so I won't know how to encode "<externalEntity>" below. The solution
+         * I think is to fix Expat to not require the "<externalEntity>"
+         * workaround.
+         */
+        this.encoding = encoding == null ? DEFAULT_ENCODING : encoding;
+        this.pointer = initialize(
+            this.encoding,
+            processNamespaces
+        );
+    }
+
+    /**
+     * Used by {@link EntityParser}.
+     */
+    private ExpatParser(String encoding, ExpatReader xmlReader, int pointer,
+            String publicId, String systemId) {
+        this.encoding = encoding;
+        this.xmlReader = xmlReader;
+        this.pointer = pointer;
+        this.systemId = systemId;
+        this.publicId = publicId;
+    }
+
+    /**
+     * Initializes native resources.
+     *
+     * @return the pointer to the native parser
+     */
+    private native int initialize(String encoding, boolean namespacesEnabled);
+
+    /**
+     * Called at the start of an element.
+     *
+     * @param uri namespace URI of element or "" if namespace processing is
+     *  disabled
+     * @param localName local name of element or "" if namespace processing is
+     *  disabled
+     * @param qName qualified name or "" if namespace processing is enabled
+     * @param attributePointer pointer to native attribute char*--we keep
+     *  a separate pointer so we can detach it from the parser instance
+     * @param attributeCount number of attributes
+     */
+    /*package*/ void startElement(String uri, String localName, String qName,
+            int attributePointer, int attributeCount) throws SAXException {
+        ContentHandler contentHandler = xmlReader.contentHandler;
+        if (contentHandler == null) {
+            return;
+        }
+
+        try {
+            inStartElement = true;
+            this.attributePointer = attributePointer;
+            this.attributeCount = attributeCount;
+
+            contentHandler.startElement(
+                    uri, localName, qName, this.attributes);
+        }
+        finally {
+            inStartElement = false;
+            this.attributeCount = -1;
+            this.attributePointer = 0;
+        }
+    }
+
+    /*package*/ void endElement(String uri, String localName, String qName)
+            throws SAXException {
+        ContentHandler contentHandler = xmlReader.contentHandler;
+        if (contentHandler != null) {
+            contentHandler.endElement(uri, localName, qName);
+        }
+    }
+
+    /*package*/ void text(char[] text, int length) throws SAXException {
+        ContentHandler contentHandler = xmlReader.contentHandler;
+        if (contentHandler != null) {
+            contentHandler.characters(text, 0, length);
+        }
+    }
+
+    /*package*/ void comment(char[] text, int length) throws SAXException {
+        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
+        if (lexicalHandler != null) {
+            lexicalHandler.comment(text, 0, length);
+        }
+    }
+
+    /*package*/ void startCdata() throws SAXException {
+        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
+        if (lexicalHandler != null) {
+            lexicalHandler.startCDATA();
+        }
+    }
+
+    /*package*/ void endCdata() throws SAXException {
+        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
+        if (lexicalHandler != null) {
+            lexicalHandler.endCDATA();
+        }
+    }
+
+    /*package*/ void startNamespace(String prefix, String uri)
+            throws SAXException {
+        ContentHandler contentHandler = xmlReader.contentHandler;
+        if (contentHandler != null) {
+            contentHandler.startPrefixMapping(prefix, uri);
+        }
+    }
+
+    /*package*/ void endNamespace(String prefix) throws SAXException {
+        ContentHandler contentHandler = xmlReader.contentHandler;
+        if (contentHandler != null) {
+            contentHandler.endPrefixMapping(prefix);
+        }
+    }
+
+    /*package*/ void startDtd(String name, String publicId, String systemId)
+            throws SAXException {
+        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
+        if (lexicalHandler != null) {
+            lexicalHandler.startDTD(name, publicId, systemId);
+        }
+    }
+
+    /*package*/ void endDtd() throws SAXException {
+        LexicalHandler lexicalHandler = xmlReader.lexicalHandler;
+        if (lexicalHandler != null) {
+            lexicalHandler.endDTD();
+        }
+    }
+
+    /*package*/ void processingInstruction(String target, String data)
+            throws SAXException {
+        ContentHandler contentHandler = xmlReader.contentHandler;
+        if (contentHandler != null) {
+            contentHandler.processingInstruction(target, data);
+        }        
+    }
+
+    /**
+     * Handles an external entity.
+     *
+     * @param context to be passed back to Expat when we parse the entity
+     * @param publicId the publicId of the entity
+     * @param systemId the systemId of the entity
+     */
+    /*package*/ void handleExternalEntity(String context, String publicId,
+            String systemId) throws SAXException, IOException {
+        EntityResolver entityResolver = xmlReader.entityResolver;
+        if (entityResolver == null) {
+            return;
+        }
+
+        /*
+         * The spec. is terribly under-specified here. It says that if the
+         * systemId is a URL, we should try to resolve it, but it doesn't
+         * specify how to tell whether or not the systemId is a URL let alone
+         * how to resolve it.
+         *
+         * Other implementations do various insane things. We try to keep it
+         * simple: if the systemId parses as a URI and it's relative, we try to
+         * resolve it against the parent document's systemId. If anything goes
+         * wrong, we go with the original systemId. If crazybob had designed
+         * the API, he would have left all resolving to the EntityResolver.
+         */
+        if (this.systemId != null) {
+            try {
+                URI systemUri = new URI(systemId);
+                if (!systemUri.isAbsolute() && !systemUri.isOpaque()) {
+                    // It could be relative (or it may not be a URI at all!)
+                    URI baseUri = new URI(this.systemId);
+                    systemUri = baseUri.resolve(systemUri);
+
+                    // Replace systemId w/ resolved URI
+                    systemId = systemUri.toString();
+                }
+            } catch (Exception e) {
+                Logger.getLogger(ExpatParser.class.getName()).log(Level.INFO,
+                        "Could not resolve '" + systemId + "' relative to"
+                        + " '" + this.systemId + "' at " + locator, e);
+            }
+        }
+
+        InputSource inputSource = entityResolver.resolveEntity(
+                publicId, systemId);
+        if (inputSource == null) {
+            /*
+             * The spec. actually says that we should try to treat systemId
+             * as a URL and download and parse its contents here, but an
+             * entity resolver can easily accomplish the same by returning
+             * new InputSource(systemId).
+             *
+             * Downloading external entities by default would result in several
+             * unwanted DTD downloads, not to mention pose a security risk
+             * when parsing untrusted XML (http://tinyurl.com/56ggrk),
+             * so we just do nothing instead. This also enables the user to
+             * opt out of entity parsing when using
+             * {@link org.xml.sax.helpers.DefaultHandler}, something that
+             * wouldn't be possible otherwise.
+             */
+            return;
+        }
+
+        String encoding = pickEncoding(inputSource);
+        int pointer = createEntityParser(this.pointer, context, encoding);
+        try {
+            EntityParser entityParser = new EntityParser(encoding, xmlReader,
+                    pointer, inputSource.getPublicId(),
+                    inputSource.getSystemId());
+
+            parseExternalEntity(entityParser, inputSource);
+        } finally {
+            releaseParser(pointer);
+        }
+    }
+
+    /**
+     * Picks an encoding for an external entity. Defaults to UTF-8.
+     */
+    private String pickEncoding(InputSource inputSource) {
+        Reader reader = inputSource.getCharacterStream();
+        if (reader != null) {
+            return CHARACTER_ENCODING;
+        }
+
+        String encoding = inputSource.getEncoding();
+        return encoding == null ? DEFAULT_ENCODING : encoding;
+    }
+
+    /**
+     * Parses the the external entity provided by the input source.
+     */
+    private void parseExternalEntity(ExpatParser entityParser,
+            InputSource inputSource) throws IOException, SAXException {
+        /*
+         * Expat complains if the external entity isn't wrapped with a root
+         * element so we add one and ignore it later on during parsing.
+         */
+        
+        // Try the character stream.
+        Reader reader = inputSource.getCharacterStream();
+        if (reader != null) {
+            try {
+                entityParser.append("<externalEntity>");
+                entityParser.parseFragment(reader);
+                entityParser.append("</externalEntity>");
+            } finally {
+                // TODO: Don't eat original exception when close() throws.
+                reader.close();
+            }
+            return;
+        }
+
+        // Try the byte stream.
+        InputStream in = inputSource.getByteStream();
+        if (in != null) {
+            try {
+                entityParser.append("<externalEntity>"
+                        .getBytes(entityParser.encoding));
+                entityParser.parseFragment(in);
+                entityParser.append("</externalEntity>"
+                        .getBytes(entityParser.encoding));
+            } finally {
+                // TODO: Don't eat original exception when close() throws.
+                in.close();
+            }
+            return;
+        }
+
+        // Make sure we use the user-provided systemId.
+        String systemId = inputSource.getSystemId();
+        if (systemId == null) {
+            // TODO: We could just try our systemId here.
+            throw new ParseException("No input specified.", locator);
+        }
+
+        // Try the system id.
+        in = openUrl(systemId);
+        try {
+            entityParser.append("<externalEntity>"
+                    .getBytes(entityParser.encoding));
+            entityParser.parseFragment(in);
+            entityParser.append("</externalEntity>"
+                    .getBytes(entityParser.encoding));
+        } finally {
+            in.close();
+        }
+    }
+
+    /**
+     * Creates a native entity parser.
+     *
+     * @param parentPointer pointer to parent Expat parser
+     * @param context passed to {@link #handleExternalEntity}
+     * @param encoding
+     * @return pointer to native parser
+     */
+    private static native int createEntityParser(int parentPointer,
+            String context, String encoding);
+
+    /**
+     * Appends part of an XML document. This parser will parse the given XML to
+     * the extent possible and dispatch to the appropriate methods.
+     *
+     * @param xml a whole or partial snippet of XML
+     * @throws SAXException if an error occurs during parsing
+     */
+    /*package*/ void append(String xml) throws SAXException {
+        try {
+            append(this.pointer, xml, false);
+        } catch (ExpatException e) {
+            throw new ParseException(e.getMessage(), this.locator);
+        }
+    }
+
+    private native void append(int pointer, String xml, boolean isFinal)
+            throws SAXException, ExpatException;
+
+    /**
+     * Appends part of an XML document. This parser will parse the given XML to
+     * the extent possible and dispatch to the appropriate methods.
+     *
+     * @param xml a whole or partial snippet of XML
+     * @param offset into the char[]
+     * @param length of characters to use
+     * @throws SAXException if an error occurs during parsing
+     */
+    /*package*/ void append(char[] xml, int offset, int length)
+            throws SAXException {
+        try {
+            append(this.pointer, xml, offset, length);
+        } catch (ExpatException e) {
+            throw new ParseException(e.getMessage(), this.locator);
+        }
+    }
+
+    private native void append(int pointer, char[] xml, int offset,
+            int length) throws SAXException, ExpatException;
+
+    /**
+     * Appends part of an XML document. This parser will parse the given XML to
+     * the extent possible and dispatch to the appropriate methods.
+     *
+     * @param xml a whole or partial snippet of XML
+     * @throws SAXException if an error occurs during parsing
+     */
+    /*package*/ void append(byte[] xml) throws SAXException {
+        append(xml, 0, xml.length);
+    }
+
+    /**
+     * Appends part of an XML document. This parser will parse the given XML to
+     * the extent possible and dispatch to the appropriate methods.
+     *
+     * @param xml a whole or partial snippet of XML
+     * @param offset into the byte[]
+     * @param length of bytes to use
+     * @throws SAXException if an error occurs during parsing
+     */
+    /*package*/ void append(byte[] xml, int offset, int length)
+            throws SAXException {
+        try {
+            append(this.pointer, xml, offset, length);
+        } catch (ExpatException e) {
+            throw new ParseException(e.getMessage(), this.locator);
+        }
+    }
+
+    private native void append(int pointer, byte[] xml, int offset,
+            int length) throws SAXException, ExpatException;
+
+    /**
+     * Parses an XML document from the given input stream.
+     */
+    /*package*/ void parseDocument(InputStream in) throws IOException,
+            SAXException {
+        startDocument();
+        parseFragment(in);
+        finish();
+        endDocument();
+    }
+
+    /**
+     * Parses an XML Document from the given reader.
+     */
+    /*package*/ void parseDocument(Reader in) throws IOException, SAXException {
+        startDocument();
+        parseFragment(in);
+        finish();
+        endDocument();
+    }
+
+    /**
+     * Parses XML from the given Reader.
+     */
+    private void parseFragment(Reader in) throws IOException, SAXException {
+        char[] buffer = new char[BUFFER_SIZE / 2];
+        int length;
+        while ((length = in.read(buffer)) != -1) {
+            try {
+                append(this.pointer, buffer, 0, length);
+            } catch (ExpatException e) {
+                throw new ParseException(e.getMessage(), locator);
+            }
+        }
+    }
+
+    /**
+     * Parses XML from the given input stream.
+     */
+    private void parseFragment(InputStream in)
+            throws IOException, SAXException {
+        byte[] buffer = new byte[BUFFER_SIZE];
+        int length;
+        while ((length = in.read(buffer)) != -1) {
+            try {
+                append(this.pointer, buffer, 0, length);
+            } catch (ExpatException e) {
+                throw new ParseException(e.getMessage(), this.locator);
+            }
+        }
+    }
+
+    private void startDocument() throws SAXException {
+        ContentHandler contentHandler = xmlReader.contentHandler;
+        if (contentHandler != null) {
+            contentHandler.setDocumentLocator(this.locator);
+            contentHandler.startDocument();
+        }
+    }
+
+    private void endDocument() throws SAXException {
+        ContentHandler contentHandler;
+        contentHandler = xmlReader.contentHandler;
+        if (contentHandler != null) {
+            contentHandler.endDocument();
+        }
+    }
+
+    /**
+     * Indicate that we're finished parsing.
+     *
+     * @throws SAXException if the xml is incomplete
+     */
+    /*package*/ void finish() throws SAXException {
+        try {
+            append(this.pointer, "", true);
+        } catch (ExpatException e) {
+            throw new ParseException(e.getMessage(), this.locator);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("FinalizeDoesntCallSuperFinalize")
+    protected synchronized void finalize() throws Throwable {
+        if (this.pointer != 0) {
+            release(this.pointer);
+            this.pointer = 0;
+        }
+    }
+
+    /**
+     * Releases all native objects.
+     */
+    private native void release(int pointer);
+
+    /**
+     * Releases native parser only.
+     */
+    private static native void releaseParser(int pointer);
+
+    /**
+     * Initialize static resources.
+     */
+    private static native void staticInitialize(String emptyString);
+
+    static {
+        staticInitialize("");
+    }
+
+    /**
+     * Gets the current line number within the XML file.
+     */
+    private int line() {
+        return line(this.pointer);
+    }
+
+    private static native int line(int pointer);
+
+    /**
+     * Gets the current column number within the XML file.
+     */
+    private int column() {
+        return column(this.pointer);
+    }
+
+    private static native int column(int pointer);
+
+    /**
+     * Clones the current attributes so they can be used outside of
+     * startElement().
+     */
+    /*package*/ Attributes cloneAttributes() {
+        if (!inStartElement) {
+            throw new IllegalStateException(OUTSIDE_START_ELEMENT);
+        }
+
+        if (attributeCount == 0) {
+            return ClonedAttributes.EMPTY;
+        }
+
+        int clonePointer
+                = cloneAttributes(this.attributePointer, this.attributeCount);
+        return new ClonedAttributes(pointer, clonePointer, attributeCount);
+    }
+
+    private static native int cloneAttributes(int pointer, int attributeCount);
+
+    /**
+     * Used for cloned attributes.
+     */
+    private static class ClonedAttributes extends ExpatAttributes {
+
+        private static final Attributes EMPTY = new ClonedAttributes(0, 0, 0);
+
+        private final int parserPointer;
+        private int pointer;
+        private final int length;
+
+        /**
+         * Constructs a Java wrapper for native attributes.
+         *
+         * @param parserPointer pointer to the parse, can be 0 if length is 0.
+         * @param pointer pointer to the attributes array, can be 0 if the
+         *  length is 0.
+         * @param length number of attributes
+         */
+        private ClonedAttributes(int parserPointer, int pointer, int length) {
+            this.parserPointer = parserPointer;
+            this.pointer = pointer;
+            this.length = length;
+        }
+
+        @Override
+        public int getParserPointer() {
+            return this.parserPointer;
+        }
+
+        @Override
+        public int getPointer() {
+            return pointer;
+        }
+
+        @Override
+        public int getLength() {
+            return length;
+        }
+
+        @Override
+        @SuppressWarnings("FinalizeDoesntCallSuperFinalize")
+        protected synchronized void finalize() throws Throwable {
+            if (pointer != 0) {
+                freeAttributes(pointer);
+                pointer = 0;
+            }
+        }
+    }
+
+    private class ExpatLocator implements Locator {
+
+        public String getPublicId() {
+            return publicId;
+        }
+
+        public String getSystemId() {
+            return systemId;
+        }
+
+        public int getLineNumber() {
+            return line();
+        }
+
+        public int getColumnNumber() {
+            return column();
+        }
+
+        @Override
+        public String toString() {
+            return "Locator[publicId: " + publicId + ", systemId: " + systemId
+                + ", line: " + getLineNumber()
+                + ", column: " + getColumnNumber() + "]";
+        }
+    }
+
+    /**
+     * Attributes that are only valid during startElement().
+     */
+    private class CurrentAttributes extends ExpatAttributes {
+
+        @Override
+        public int getParserPointer() {
+            return pointer;
+        }
+
+        @Override
+        public int getPointer() {
+            if (!inStartElement) {
+                throw new IllegalStateException(OUTSIDE_START_ELEMENT);
+            }
+            return attributePointer;
+        }
+
+        @Override
+        public int getLength() {
+            if (!inStartElement) {
+                throw new IllegalStateException(OUTSIDE_START_ELEMENT);
+            }
+            return attributeCount;
+        }
+    }
+
+    /**
+     * Includes line and column in the message.
+     */
+    private static class ParseException extends SAXParseException {
+
+        private ParseException(String message, Locator locator) {
+            super(makeMessage(message, locator), locator);
+        }
+
+        private static String makeMessage(String message, Locator locator) {
+            return makeMessage(message, locator.getLineNumber(),
+                    locator.getColumnNumber());
+        }
+
+        private static String makeMessage(
+                String message, int line, int column) {
+            return "At line " + line + ", column "
+                    + column + ": " + message;
+        }
+    }
+    
+    /**
+     * Opens an InputStream for the given URL.
+     */
+    /*package*/ static InputStream openUrl(String url) throws IOException {
+        try {
+            URLConnection urlConnection = new URL(url).openConnection();
+            urlConnection.setConnectTimeout(TIMEOUT);
+            urlConnection.setReadTimeout(TIMEOUT);
+            urlConnection.setDoInput(true);
+            urlConnection.setDoOutput(false);
+            return urlConnection.getInputStream();
+        } catch (Exception e) {
+            IOException ioe = new IOException("Couldn't open " + url);
+            ioe.initCause(e);
+            throw ioe;
+        }
+    }
+
+    /**
+     * Parses an external entity.
+     */
+    private static class EntityParser extends ExpatParser {
+
+        private int depth = 0; 
+
+        private EntityParser(String encoding, ExpatReader xmlReader,
+                int pointer, String publicId, String systemId) {
+            super(encoding, xmlReader, pointer, publicId, systemId);
+        }
+
+        @Override
+        void startElement(String uri, String localName, String qName,
+                int attributePointer, int attributeCount) throws SAXException {
+            /*
+             * Skip topmost element generated by our workaround in
+             * {@link #handleExternalEntity}.
+             */
+            if (depth++ > 0) {
+                super.startElement(uri, localName, qName, attributePointer,
+                        attributeCount);
+            }
+        }
+        
+        @Override
+        void endElement(String uri, String localName, String qName)
+                throws SAXException {
+            if (--depth > 0) {
+                super.endElement(uri, localName, qName);
+            }
+        }
+
+        @Override
+        @SuppressWarnings("FinalizeDoesntCallSuperFinalize")
+        protected synchronized void finalize() throws Throwable {
+            /*
+             * Don't release our native resources. We do so explicitly in
+             * {@link #handleExternalEntity} and we don't want to release the
+             * parsing context--our parent is using it.
+             */
+        }
+    }
+}
+
diff --git a/xml/src/main/java/org/apache/harmony/xml/ExpatPullParser.java b/xml/src/main/java/org/apache/harmony/xml/ExpatPullParser.java
new file mode 100644
index 0000000..4759718
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/ExpatPullParser.java
@@ -0,0 +1,964 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ * Fast, partial XmlPullParser implementation based upon Expat. Does not
+ * support validation or {@code DOCTYPE} processing.
+ */
+public class ExpatPullParser implements XmlPullParser {
+    /**
+     * This feature is identified by http://xmlpull.org/v1/doc/features.html#relaxed
+     * If this feature is supported that means that XmlPull parser will be
+     * lenient when checking XML well formedness.
+     * NOTE: use it only if XML input is not well-formed and in general usage
+     * if this feature is discouraged
+     * NOTE: as there is no definition of what is relaxed XML parsing
+     * therefore what parser will do completely depends on implementation used
+     */
+    public static final String FEATURE_RELAXED =
+            "http://xmlpull.org/v1/doc/features.html#relaxed";
+
+    private static final int BUFFER_SIZE = 8096;
+
+    private static final String NOT_A_START_TAG = "This is not a start tag.";
+
+    private Document document;
+    private boolean processNamespaces = false;
+    private boolean relaxed = false;
+
+    public void setFeature(String name, boolean state)
+            throws XmlPullParserException {
+        if (name == null) {
+            // Required by API.          
+            throw new IllegalArgumentException("Null feature name");
+        }
+
+        if (name.equals(FEATURE_PROCESS_NAMESPACES)) {
+            processNamespaces = state;
+            return;
+        }
+
+        if (name.equals(FEATURE_RELAXED)) {
+            relaxed = true;
+            return;
+        }
+
+        // You're free to turn these features off because we don't support them.
+        if (!state && (name.equals(FEATURE_REPORT_NAMESPACE_ATTRIBUTES)
+                || name.equals(FEATURE_PROCESS_DOCDECL)
+                || name.equals(FEATURE_VALIDATION))) {
+            return;
+        }
+
+        throw new XmlPullParserException("Unsupported feature: " + name);
+    }
+
+    public boolean getFeature(String name) {
+        if (name == null) {
+            // Required by API.
+            throw new IllegalArgumentException("Null feature name");
+        }
+
+        // We always support namespaces, but no other features.
+        return name.equals(FEATURE_PROCESS_NAMESPACES) && processNamespaces;
+    }
+
+    /**
+     * Returns true if this parser processes namespaces.
+     *
+     * @see #setNamespaceProcessingEnabled(boolean)
+     */
+    public boolean isNamespaceProcessingEnabled() {
+        return processNamespaces;
+    }
+
+    /**
+     * Enables or disables namespace processing. Set to false by default.
+     *
+     * @see #isNamespaceProcessingEnabled()
+     */
+    public void setNamespaceProcessingEnabled(boolean processNamespaces) {
+        this.processNamespaces = processNamespaces;
+    }
+
+    public void setProperty(String name, Object value)
+            throws XmlPullParserException {
+        if (name == null) {
+            // Required by API.
+            throw new IllegalArgumentException("Null feature name");
+        }
+
+        // We don't support any properties.
+        throw new XmlPullParserException("Properties aren't supported.");
+    }
+
+    public Object getProperty(String name) {
+        return null;
+    }
+
+    public void setInput(Reader in) throws XmlPullParserException {
+        this.document = new CharDocument(in, processNamespaces);
+    }
+
+    public void setInput(InputStream in, String encodingName)
+            throws XmlPullParserException {
+        this.document = new ByteDocument(in, encodingName, processNamespaces);
+    }
+
+    public String getInputEncoding() {
+        return this.document.getEncoding();
+    }
+
+    /**
+     * Not supported.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    public void defineEntityReplacementText(String entityName,
+            String replacementText) throws XmlPullParserException {
+        throw new UnsupportedOperationException();
+    }
+
+    public int getNamespaceCount(int depth) throws XmlPullParserException {
+        return document.currentEvent.namespaceStack.countAt(depth);
+    }
+
+    public String getNamespacePrefix(int pos) throws XmlPullParserException {
+        String prefix = document.currentEvent.namespaceStack.prefixAt(pos);
+        @SuppressWarnings("StringEquality")
+        boolean hasPrefix = prefix != "";
+        return hasPrefix ? prefix : null;
+    }
+
+    public String getNamespaceUri(int pos) throws XmlPullParserException {
+        return document.currentEvent.namespaceStack.uriAt(pos);
+    }
+
+    public String getNamespace(String prefix) {
+        // In XmlPullParser API, null == default namespace.
+        if (prefix == null) {
+            // Internally, we use empty string instead of null.
+            prefix = "";
+        }
+
+        return document.currentEvent.namespaceStack.uriFor(prefix);
+    }
+
+    public int getDepth() {
+        return this.document.getDepth();
+    }
+
+    public String getPositionDescription() {
+        return "line " + getLineNumber() + ", column " + getColumnNumber();
+    }
+
+    /**
+     * Not supported.
+     *
+     * @return {@literal -1} always
+     */
+    public int getLineNumber() {
+        // We would have to record the line number in each event.
+        return -1;
+    }
+
+    /**
+     * Not supported.
+     *
+     * @return {@literal -1} always
+     */
+    public int getColumnNumber() {
+        // We would have to record the column number in each event.
+        return -1;
+    }
+
+    public boolean isWhitespace() throws XmlPullParserException {
+        if (getEventType() != TEXT) {
+            throw new XmlPullParserException("Not on text.");
+        }
+
+        String text = getText();
+
+        if (text.length() == 0) {
+            return true;
+        }
+
+        int length = text.length();
+        for (int i = 0; i < length; i++) {
+            if (!Character.isWhitespace(text.charAt(i))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public String getText() {
+        final StringBuilder builder = this.document.currentEvent.getText();
+        return builder == null ? null : builder.toString();
+    }
+
+    public char[] getTextCharacters(int[] holderForStartAndLength) {
+        final StringBuilder builder = this.document.currentEvent.getText();
+
+        final int length = builder.length();
+        char[] characters = new char[length];
+        builder.getChars(0, length, characters, 0);
+
+        holderForStartAndLength[0] = 0;
+        holderForStartAndLength[1] = length;
+
+        return characters;
+    }
+
+    public String getNamespace() {
+        return this.document.currentEvent.getNamespace();
+    }
+
+    public String getName() {
+        return this.document.currentEvent.getName();
+    }
+
+    /**
+     * Not supported.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    public String getPrefix() {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean isEmptyElementTag() throws XmlPullParserException {
+        return this.document.isCurrentElementEmpty();
+    }
+
+    public int getAttributeCount() {
+        return this.document.currentEvent.getAttributeCount();
+    }
+
+    public String getAttributeNamespace(int index) {
+        return this.document.currentEvent.getAttributeNamespace(index);
+    }
+
+    public String getAttributeName(int index) {
+        return this.document.currentEvent.getAttributeName(index);
+    }
+
+    /**
+     * Not supported.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    public String getAttributePrefix(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getAttributeType(int index) {
+        return "CDATA";
+    }
+
+    public boolean isAttributeDefault(int index) {
+        return false;
+    }
+
+    public String getAttributeValue(int index) {
+        return this.document.currentEvent.getAttributeValue(index);
+    }
+
+    public String getAttributeValue(String namespace, String name) {
+        return this.document.currentEvent.getAttributeValue(namespace, name);
+    }
+
+    public int getEventType() throws XmlPullParserException {
+        return this.document.currentEvent.getType();
+    }
+
+    public int next() throws XmlPullParserException, IOException {
+        return this.document.dequeue();
+    }
+
+    /**
+     * Not supported.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    public int nextToken() throws XmlPullParserException, IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    public void require(int type, String namespace, String name)
+            throws XmlPullParserException, IOException {
+        if (type != getEventType()
+                || (namespace != null && !namespace.equals(getNamespace()))
+                || (name != null && !name.equals(getName()))) {
+            throw new XmlPullParserException("expected "
+                    + TYPES[type] + getPositionDescription());
+        }
+    }
+
+    public String nextText() throws XmlPullParserException, IOException {
+        if (this.document.currentEvent.getType() != START_TAG)
+            throw new XmlPullParserException("Not on start tag.");
+
+        int next = this.document.dequeue();
+        switch (next) {
+            case TEXT: return getText();
+            case END_TAG: return "";
+            default: throw new XmlPullParserException(
+                "Unexpected event type: " + TYPES[next]);
+        }
+    }
+
+    public int nextTag() throws XmlPullParserException, IOException {
+        int eventType = next();
+        if (eventType == TEXT && isWhitespace()) {
+            eventType = next();
+        }
+        if (eventType != START_TAG && eventType != END_TAG) {
+            throw new XmlPullParserException(
+                "Expected start or end tag", this, null);
+        }
+        return eventType;
+    }
+
+    /**
+     * Immutable namespace stack. Pushing a new namespace on to the stack
+     * only results in one object allocation. Most operations are O(N) where
+     * N is the stack size. Accessing recently pushed namespaces, like those
+     * for the current element, is significantly faster.
+     */
+    static class NamespaceStack {
+
+        /** An empty stack. */
+        static final NamespaceStack EMPTY = new NamespaceStack();
+
+        private final NamespaceStack parent;
+        private final String prefix;
+        private final String uri;
+        private final int index;
+        private final int depth;
+
+        /**
+         * Constructs an actual namespace stack node. Internally, the nodes
+         * and the stack are one in the same making for a very efficient
+         * implementation. The user just sees an immutable stack and the
+         * builder.
+         */
+        private NamespaceStack(NamespaceStack parent, String prefix,
+                String uri, int depth) {
+            this.parent = parent;
+            this.prefix = prefix;
+            this.uri = uri;
+            this.index = parent.index + 1;
+            this.depth = depth;
+        }
+
+        /**
+         * Constructs a dummy node which only serves to point to the bottom
+         * of the stack. Using an actual node instead of null simplifies the
+         * code.
+         */
+        private NamespaceStack() {
+            this.parent = null;
+            this.prefix = null;
+            this.uri = null;
+
+            // This node has an index of -1 since the actual first node in the
+            // stack has index 0.
+            this.index = -1;
+            
+            // The actual first node will have a depth of 1.
+            this.depth = 0;
+        }
+
+        String uriFor(String prefix) {
+            for (NamespaceStack node = this; node.index >= 0;
+                    node = node.parent) {
+                if (node.prefix.equals(prefix)) {
+                    return node.uri;
+                }
+            }
+
+            // Not found.
+            return null;
+        }
+
+        /**
+         * Gets the prefix at the given index in the stack.
+         */
+        String prefixAt(int index) {
+            return nodeAt(index).prefix;
+        }
+
+        /**
+         * Gets the URI at the given index in the stack.
+         */
+        String uriAt(int index) {
+            return nodeAt(index).uri;
+        }
+
+        private NamespaceStack nodeAt(int index) {
+            if (index > this.index) {
+                throw new IndexOutOfBoundsException("Index > size.");
+            }
+            if (index < 0) {
+                throw new IndexOutOfBoundsException("Index < 0.");
+            }
+
+            NamespaceStack node = this;
+            while (index != node.index) {
+                node = node.parent;
+            }
+            return node;
+        }
+
+        /**
+         * Gets the size of the stack at the given element depth.
+         */
+        int countAt(int depth) {
+            if (depth > this.depth) {
+                throw new IndexOutOfBoundsException("Depth > maximum.");
+            }
+            if (depth < 0) {
+                throw new IndexOutOfBoundsException("Depth < 0.");
+            }
+
+            NamespaceStack node = this;
+            while (depth < node.depth) {
+                node = node.parent;
+            }
+            return node.index + 1;         
+        }
+
+        /** Builds a NamespaceStack. */
+        static class Builder {
+
+            NamespaceStack top = EMPTY;
+
+            /**
+             * Pushes a namespace onto the stack.
+             *
+             * @param depth of the element upon which the namespace was
+             *  declared
+             */
+            void push(String prefix, String uri, int depth) {
+                top = new NamespaceStack(top, prefix, uri, depth);
+            }
+
+            /**
+             * Pops all namespaces from the given element depth.
+             */
+            void pop(int depth) {
+                // Remove all nodes at the specified depth.
+                while (top != null && top.depth == depth) {
+                    top = top.parent;
+                }
+            }
+
+            /** Returns the current stack. */
+            NamespaceStack build() {
+                return top;
+            }
+        }
+    }
+
+    /**
+     * Base class for events. Implements event chaining and defines event API
+     * along with common implementations which can be overridden.
+     */
+    static abstract class Event {
+
+        /** Element depth at the time of this event. */
+        final int depth;
+
+        /** The namespace stack at the time of this event. */
+        final NamespaceStack namespaceStack;
+
+        /** Next event in the queue. */ 
+        Event next = null;
+
+        Event(int depth, NamespaceStack namespaceStack) {
+            this.depth = depth;
+            this.namespaceStack = namespaceStack;
+        }
+
+        void setNext(Event next) {
+            this.next = next;
+        }
+
+        Event getNext() {
+            return next;
+        }
+
+        StringBuilder getText() {
+            return null;
+        }
+
+        String getNamespace() {
+            return null;
+        }
+
+        String getName() {
+            return null;
+        }
+
+        int getAttributeCount() {
+            return -1;
+        }
+
+        String getAttributeNamespace(int index) {
+            throw new IndexOutOfBoundsException(NOT_A_START_TAG);
+        }
+
+        String getAttributeName(int index) {
+            throw new IndexOutOfBoundsException(NOT_A_START_TAG);
+        }
+
+        String getAttributeValue(int index) {
+            throw new IndexOutOfBoundsException(NOT_A_START_TAG);
+        }
+
+        abstract int getType();
+
+        String getAttributeValue(String namespace, String name) {
+            throw new IndexOutOfBoundsException(NOT_A_START_TAG);
+        }
+
+        public int getDepth() {
+            return this.depth;
+        }
+    }
+
+    static class StartDocumentEvent extends Event {
+
+        public StartDocumentEvent() {
+            super(0, NamespaceStack.EMPTY);
+        }
+
+        @Override
+        int getType() {
+            return START_DOCUMENT;
+        }
+    }
+
+    static class StartTagEvent extends Event {
+
+        final String name;
+        final String namespace;
+        final Attributes attributes;
+        final boolean processNamespaces;
+
+        StartTagEvent(String namespace,
+                String name,
+                ExpatParser expatParser,
+                int depth,
+                NamespaceStack namespaceStack,
+                boolean processNamespaces) {
+            super(depth, namespaceStack);
+            this.namespace = namespace;
+            this.name = name;
+            this.attributes = expatParser.cloneAttributes();
+            this.processNamespaces = processNamespaces;
+        }
+
+        @Override
+        String getNamespace() {
+            return namespace;
+        }
+
+        @Override
+        String getName() {
+            return name;
+        }
+
+        @Override
+        int getAttributeCount() {
+            return attributes.getLength();
+        }
+
+        @Override
+        String getAttributeNamespace(int index) {
+            return attributes.getURI(index);
+        }
+
+        @Override
+        String getAttributeName(int index) {
+            return processNamespaces ? attributes.getLocalName(index)
+                    : attributes.getQName(index);
+        }
+
+        @Override
+        String getAttributeValue(int index) {
+            return attributes.getValue(index);
+        }
+
+        @Override
+        String getAttributeValue(String namespace, String name) {
+            if (namespace == null) {
+                namespace = "";
+            }
+
+            return attributes.getValue(namespace, name);
+        }
+
+        @Override
+        int getType() {
+            return START_TAG;
+        }
+    }
+
+    static class EndTagEvent extends Event {
+
+        final String namespace;
+        final String localName;
+
+        EndTagEvent(String namespace, String localName, int depth,
+                NamespaceStack namespaceStack) {
+            super(depth, namespaceStack);
+            this.namespace = namespace;
+            this.localName = localName;
+        }
+
+        @Override
+        String getName() {
+            return this.localName;
+        }
+
+        @Override
+        String getNamespace() {
+            return this.namespace;
+        }
+
+        @Override
+        int getType() {
+            return END_TAG;
+        }
+    }
+
+    static class TextEvent extends Event {
+
+        final StringBuilder builder;
+
+        public TextEvent(int initialCapacity, int depth,
+                NamespaceStack namespaceStack) {
+            super(depth, namespaceStack);
+            this.builder = new StringBuilder(initialCapacity);
+        }
+
+        @Override
+        int getType() {
+            return TEXT;
+        }
+
+        @Override
+        StringBuilder getText() {
+            return this.builder;
+        }
+
+        void append(char[] text, int start, int length) {
+            builder.append(text, start, length);
+        }
+    }
+
+    static class EndDocumentEvent extends Event {
+
+        EndDocumentEvent() {
+            super(0, NamespaceStack.EMPTY);
+        }
+
+        @Override
+        Event getNext() {
+            throw new IllegalStateException("End of document.");
+        }
+
+        @Override
+        void setNext(Event next) {
+            throw new IllegalStateException("End of document.");
+        }
+
+        @Override
+        int getType() {
+            return END_DOCUMENT;
+        }
+    }
+
+    /**
+     * Encapsulates the parsing context of the current document.
+     */
+    abstract class Document {
+
+        final String encoding;
+        final ExpatParser parser;
+        final boolean processNamespaces;
+
+        TextEvent textEvent = null;
+        boolean finished = false;
+
+        Document(String encoding, boolean processNamespaces) {
+            this.encoding = encoding;
+            this.processNamespaces = processNamespaces;
+
+            ExpatReader xmlReader = new ExpatReader();
+            xmlReader.setContentHandler(new SaxHandler());
+
+            this.parser = new ExpatParser(
+                    encoding, xmlReader, processNamespaces, null, null);
+        }
+
+        /** Namespace stack builder. */
+        NamespaceStack.Builder namespaceStackBuilder
+                = new NamespaceStack.Builder();
+        
+        Event currentEvent = new StartDocumentEvent();
+        Event last = currentEvent;
+
+        /**
+         * Sends some more XML to the parser.
+         */
+        void pump() throws IOException, XmlPullParserException {
+            if (this.finished) {
+                return;
+            }
+
+            int length = buffer();
+
+            // End of document.
+            if (length == -1) {
+                this.finished = true;
+                if (!relaxed) {
+                    try {
+                        parser.finish();
+                    } catch (SAXException e) {
+                        throw new XmlPullParserException(
+                            "Premature end of document.", ExpatPullParser.this, e);
+                    }
+                }
+                add(new EndDocumentEvent());
+                return;
+            }
+
+            if (length == 0) {
+                return;
+            }
+
+            flush(parser, length);
+        }
+
+        /**
+         * Reads data into the buffer.
+         *
+         * @return the length of data buffered or {@code -1} if we've reached
+         *  the end of the data.
+         */
+        abstract int buffer() throws IOException;
+
+        /**
+         * Sends buffered data to the parser.
+         *
+         * @param parser the parser to flush to
+         * @param length of data buffered
+         */
+        abstract void flush(ExpatParser parser, int length)
+                throws XmlPullParserException;
+
+        /**
+         * Adds an event.
+         */
+        void add(Event event) {
+            // Flush pre-exising text event if necessary.
+            if (textEvent != null) {
+                last.setNext(textEvent);
+                last = textEvent;
+                textEvent = null;
+            }
+
+            last.setNext(event);
+            last = event;
+        }
+
+        /**
+         * Moves to the next event in the queue.
+         *
+         * @return type of next event
+         */
+        int dequeue() throws XmlPullParserException, IOException {
+            Event next;
+
+            while ((next = currentEvent.getNext()) == null) {
+                pump();
+            }
+
+            currentEvent.next = null;
+            currentEvent = next;
+
+            return currentEvent.getType();
+        }
+
+        String getEncoding() {
+            return this.encoding;
+        }
+
+        int getDepth() {
+            return currentEvent.getDepth();
+        }
+
+        /**
+         * Returns true if we're on a start element and the next event is
+         * its corresponding end element.
+         *
+         * @throws XmlPullParserException if we aren't on a start element
+         */
+        boolean isCurrentElementEmpty() throws XmlPullParserException {
+            if (currentEvent.getType() != START_TAG) {
+                throw new XmlPullParserException(NOT_A_START_TAG);
+            }
+
+            Event next;
+
+            try {
+                while ((next = currentEvent.getNext()) == null) {
+                    pump();
+                }
+            } catch (IOException ex) {
+                throw new XmlPullParserException(ex.toString());
+            }
+
+            return next.getType() == END_TAG;
+        }
+
+        private class SaxHandler implements ContentHandler {
+
+            int depth = 0;
+
+            public void startPrefixMapping(String prefix, String uri)
+                    throws SAXException {
+                // Depth + 1--we aren't actually in the element yet.
+                namespaceStackBuilder.push(prefix, uri, depth + 1);
+            }
+
+            public void startElement(String uri, String localName, String qName,
+                    Attributes attributes) {
+                String name = processNamespaces ? localName : qName;
+
+                add(new StartTagEvent(uri, name, parser, ++this.depth,
+                        namespaceStackBuilder.build(), processNamespaces));
+            }
+
+            public void endElement(String uri, String localName, String qName) {
+                String name = processNamespaces ? localName : qName;
+
+                int depth = this.depth--;
+                add(new EndTagEvent(uri, name, depth,
+                        namespaceStackBuilder.build()));
+                namespaceStackBuilder.pop(depth);
+            }
+
+            public void characters(char ch[], int start, int length) {
+                // Ignore empty strings.
+                if (length == 0) {
+                    return;
+                }
+
+                // Start a new text event if necessary.
+                if (textEvent == null) {
+                    textEvent = new TextEvent(length, this.depth,
+                            namespaceStackBuilder.build());
+                }
+
+                // Append to an existing text event.
+                textEvent.append(ch, start, length);
+            }
+
+            public void setDocumentLocator(Locator locator) {}
+            public void startDocument() throws SAXException {}
+            public void endDocument() throws SAXException {}
+            public void endPrefixMapping(String prefix) throws SAXException {}
+            public void ignorableWhitespace(char ch[], int start, int length)
+                    throws SAXException {}
+            public void processingInstruction(String target, String data)
+                    throws SAXException {}
+            public void skippedEntity(String name) throws SAXException {}
+        }
+    }
+
+    class CharDocument extends Document {
+
+        final char[] buffer = new char[BUFFER_SIZE / 2];
+        final Reader in;
+
+        CharDocument(Reader in, boolean processNamespaces) {
+            super("UTF-16", processNamespaces);
+            this.in = in;
+        }
+
+        @Override
+        int buffer() throws IOException {
+            return in.read(buffer);
+        }
+
+        @Override
+        void flush(ExpatParser parser, int length)
+                throws XmlPullParserException {
+            try {
+                parser.append(buffer, 0, length);
+            } catch (SAXException e) {
+                throw new XmlPullParserException(
+                        "Error parsing document.", ExpatPullParser.this, e);
+            }
+        }
+    }
+
+    class ByteDocument extends Document {
+
+        final byte[] buffer = new byte[BUFFER_SIZE];
+        final InputStream in;
+
+        ByteDocument(InputStream in, String encoding,
+                boolean processNamespaces) {
+            super(encoding, processNamespaces);
+            this.in = in;
+        }
+
+        @Override
+        int buffer() throws IOException {
+            return in.read(buffer);
+        }
+
+        @Override
+        void flush(ExpatParser parser, int length)
+                throws XmlPullParserException {
+            try {
+                parser.append(buffer, 0, length);
+            } catch (SAXException e) {
+                throw new XmlPullParserException(
+                        "Error parsing document.", ExpatPullParser.this, e);
+            }
+        }
+    }
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/ExpatReader.java b/xml/src/main/java/org/apache/harmony/xml/ExpatReader.java
new file mode 100644
index 0000000..a6a83a0
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/ExpatReader.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.LexicalHandler;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.InputStream;
+import java.util.logging.Logger;
+
+/**
+ * SAX wrapper around Expat. Interns strings. Does not support validation.
+ * Does not support {@link DTDHandler}.
+ */
+public class ExpatReader implements XMLReader {
+
+    private static final Logger logger
+            = Logger.getLogger(ExpatReader.class.getName());
+
+    /*
+     * ExpatParser accesses these fields directly during parsing. The user
+     * should be able to safely change them during parsing.
+     */
+    /*package*/ ContentHandler contentHandler;
+    /*package*/ EntityResolver entityResolver;
+    /*package*/ ErrorHandler errorHandler;
+    /*package*/ LexicalHandler lexicalHandler;
+
+    private boolean processNamespaces = true;
+    private boolean processNamespacePrefixes = false;
+
+    private static final String LEXICAL_HANDLER_PROPERTY
+            = "http://xml.org/sax/properties/lexical-handler";
+
+    private static class Feature {
+
+        private static final String BASE_URI = "http://xml.org/sax/features/";
+
+        private static final String VALIDATION = BASE_URI + "validation";
+        private static final String NAMESPACES = BASE_URI + "namespaces";
+        private static final String NAMESPACE_PREFIXES
+                = BASE_URI + "namespace-prefixes";
+        private static final String STRING_INTERNING
+                = BASE_URI + "string-interning";
+    }
+
+    public boolean getFeature(String name)
+            throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name");
+        }
+
+        if (name.equals(Feature.VALIDATION)) {
+            return false;
+        }
+
+        if (name.equals(Feature.NAMESPACES)) {
+            return processNamespaces;
+        }
+
+        if (name.equals(Feature.NAMESPACE_PREFIXES)) {
+            return processNamespacePrefixes;
+        }
+
+        if (name.equals(Feature.STRING_INTERNING)) {
+            return true;
+        }
+
+        throw new SAXNotRecognizedException(name);
+    }
+
+    public void setFeature(String name, boolean value)
+            throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name");
+        }
+
+        if (name.equals(Feature.VALIDATION)) {
+            if (value) {
+                throw new SAXNotSupportedException("Cannot enable " + name);
+            } else {
+                // Default.
+                return;
+            }
+        }
+
+        if (name.equals(Feature.NAMESPACES)) {
+            processNamespaces = value;
+            return;
+        }
+
+        if (name.equals(Feature.NAMESPACE_PREFIXES)) {
+            processNamespacePrefixes = value;
+            return;
+        }
+
+        if (name.equals(Feature.STRING_INTERNING)) {
+            if (value) {
+                // Default.
+                return;
+            } else {
+                throw new SAXNotSupportedException("Cannot disable " + name);
+            }
+        }
+
+        throw new SAXNotRecognizedException(name);
+    }
+
+    public Object getProperty(String name)
+            throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name");
+        }
+
+        if (name.equals(LEXICAL_HANDLER_PROPERTY)) {
+            return lexicalHandler;
+        }
+
+        throw new SAXNotRecognizedException(name);
+    }
+
+    public void setProperty(String name, Object value)
+            throws SAXNotRecognizedException, SAXNotSupportedException {
+        if (name == null) {
+            throw new NullPointerException("name");
+        }
+
+        if (name.equals(LEXICAL_HANDLER_PROPERTY)) {
+            // The object must implement LexicalHandler
+            if (value instanceof LexicalHandler) {
+                this.lexicalHandler = (LexicalHandler) value;
+                return;
+            }
+            throw new SAXNotSupportedException("value doesn't implement " +
+                    "org.xml.sax.ext.LexicalHandler");
+        }
+
+        throw new SAXNotRecognizedException(name);
+    }
+
+    public void setEntityResolver(EntityResolver resolver) {
+        this.entityResolver = resolver;
+    }
+
+    public EntityResolver getEntityResolver() {
+        return entityResolver;
+    }
+
+    /**
+     * Not implemented.
+     */
+    public void setDTDHandler(DTDHandler ignored) {
+        logger.warning("DTD handlers aren't supported.");
+    }
+
+    /**
+     * Always returns null.
+     */
+    public DTDHandler getDTDHandler() {
+        return null;
+    }
+
+    public void setContentHandler(ContentHandler handler) {
+        this.contentHandler = handler;
+    }
+
+    public ContentHandler getContentHandler() {
+        return this.contentHandler;
+    }
+
+    public void setErrorHandler(ErrorHandler handler) {
+        this.errorHandler = handler;
+    }
+
+    public ErrorHandler getErrorHandler() {
+        return errorHandler;
+    }
+
+    /**
+     * Returns the current lexical handler.
+     *
+     * @return the current lexical handler, or null if none has been registered
+     * @see #setLexicalHandler
+     */
+    public LexicalHandler getLexicalHandler() {
+        return lexicalHandler;
+    }
+
+    /**
+     * Registers a lexical event handler. Supports neither
+     * {@link LexicalHandler#startEntity(String)} nor
+     * {@link LexicalHandler#endEntity(String)}.
+     *
+     * <p>If the application does not register a lexical handler, all
+     * lexical events reported by the SAX parser will be silently
+     * ignored.</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param lexicalHandler listens for lexical events
+     * @see #getLexicalHandler()
+     */
+    public void setLexicalHandler(LexicalHandler lexicalHandler) {
+        this.lexicalHandler = lexicalHandler;
+    }
+
+    /**
+     * Returns true if this SAX parser processes namespaces.
+     *
+     * @see #setNamespaceProcessingEnabled(boolean)
+     */
+    public boolean isNamespaceProcessingEnabled() {
+        return processNamespaces;
+    }
+
+    /**
+     * Enables or disables namespace processing. Set to true by default. If you
+     * enable namespace processing, the parser will invoke
+     * {@link ContentHandler#startPrefixMapping(String, String)} and
+     * {@link ContentHandler#endPrefixMapping(String)}, and it will filter
+     * out namespace declarations from element attributes.
+     *
+     * @see #isNamespaceProcessingEnabled()
+     */
+    public void setNamespaceProcessingEnabled(boolean processNamespaces) {
+        this.processNamespaces = processNamespaces;
+    }
+
+    public void parse(InputSource input) throws IOException, SAXException {
+        if (processNamespacePrefixes == processNamespaces) {
+            /*
+             * Expat has XML_SetReturnNSTriplet, but that still doesn't
+             * include xmlns attributes like this feature requires. We may
+             * have to implement namespace processing ourselves if we want
+             * this (not too difficult). We obviously "support" namespace
+             * prefixes if namespaces are disabled.
+             */
+            throw new SAXNotSupportedException("The 'namespace-prefix' " +
+                    "feature is not supported while the 'namespaces' " +
+                    "feature is enabled.");
+        }
+
+        // Try the character stream.
+        Reader reader = input.getCharacterStream();
+        if (reader != null) {
+            try {
+                parse(reader, input.getPublicId(), input.getSystemId());
+            } finally {
+                // TODO: Don't eat original exception when close() throws.
+                reader.close();
+            }
+            return;
+        }
+
+        // Try the byte stream.
+        InputStream in = input.getByteStream();
+        String encoding = input.getEncoding();
+        if (in != null) {
+            try {
+                parse(in, encoding, input.getPublicId(), input.getSystemId());
+            } finally {
+                // TODO: Don't eat original exception when close() throws.
+                in.close();
+            }
+            return;
+        }
+
+        String systemId = input.getSystemId();
+        if (systemId == null) {
+            throw new SAXException("No input specified.");
+        }
+
+        // Try the system id.
+        in = ExpatParser.openUrl(systemId);
+        try {
+            parse(in, encoding, input.getPublicId(), systemId);
+        } finally {
+            in.close();
+        }
+    }
+
+    private void parse(Reader in, String publicId, String systemId)
+            throws IOException, SAXException {
+        ExpatParser parser = new ExpatParser(
+                ExpatParser.CHARACTER_ENCODING,
+                this,
+                processNamespaces,
+                publicId,
+                systemId
+        );
+        parser.parseDocument(in);
+    }
+
+    private void parse(InputStream in, String encoding, String publicId,
+            String systemId) throws IOException, SAXException {
+        ExpatParser parser = new ExpatParser(
+                encoding,
+                this,
+                processNamespaces,
+                publicId,
+                systemId
+        );
+        parser.parseDocument(in);
+    }
+
+    public void parse(String systemId) throws IOException, SAXException {
+        parse(new InputSource(systemId));
+    }
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
new file mode 100644
index 0000000..a39e0c4
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class AttrImpl extends NodeImpl implements Attr {
+
+    // Maintained by ElementImpl.
+    ElementImpl ownerElement;
+
+    private boolean namespaceAware;
+    
+    private String namespaceURI;
+
+    private String localName;
+
+    private String prefix;
+    
+    private String value;
+
+    AttrImpl(DocumentImpl document, String namespaceURI, String qualifiedName) {
+        super(document);
+
+        namespaceAware = true;
+        this.namespaceURI = namespaceURI;
+
+        if (qualifiedName == null || "".equals(qualifiedName)) {
+            throw new DOMException(DOMException.NAMESPACE_ERR, qualifiedName);
+        }
+        
+        int prefixSeparator = qualifiedName.lastIndexOf(":");
+        if (prefixSeparator != -1) {
+            setPrefix(qualifiedName.substring(0, prefixSeparator));
+            qualifiedName = qualifiedName.substring(prefixSeparator + 1);
+        }
+
+        localName = qualifiedName;
+        
+        if ("".equals(localName)) {
+            throw new DOMException(DOMException.NAMESPACE_ERR, localName);
+        }
+        
+        if ("xmlns".equals(localName) && !"http://www.w3.org/2000/xmlns/".equals(namespaceURI)) {
+            throw new DOMException(DOMException.NAMESPACE_ERR, localName);
+        }
+            
+        if (!document.isXMLIdentifier(localName)) {
+            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, localName);
+        }
+            
+        value = "";
+    }
+
+    AttrImpl(DocumentImpl document, String name) {
+        super(document);
+
+        this.namespaceAware = false;
+        
+        int prefixSeparator = name.lastIndexOf(":");
+        if (prefixSeparator != -1) {
+            String prefix = name.substring(0, prefixSeparator);
+            String localName = name.substring(prefixSeparator + 1);
+            
+            if (!document.isXMLIdentifier(prefix) || !document.isXMLIdentifier(localName)) {
+                throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
+            }
+        } else {
+            if (!document.isXMLIdentifier(name)) {
+                throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
+            }
+        }
+        
+        this.localName = name;
+    }
+    
+    @Override
+    public String getLocalName() {
+        return namespaceAware ? localName : null;
+    }
+
+    public String getName() {
+        return (prefix != null ? prefix + ":" : "") + localName;
+    }
+
+    @Override
+    public String getNamespaceURI() {
+        return namespaceURI;
+    }
+
+    @Override
+    public String getNodeName() {
+        return getName();
+    }
+
+    public short getNodeType() {
+        return Node.ATTRIBUTE_NODE;
+    }
+
+    @Override
+    public String getNodeValue() {
+        return getValue();
+    }
+
+    public Element getOwnerElement() {
+        return ownerElement;
+    }
+
+    @Override
+    public String getPrefix() {
+        return prefix;
+    }
+
+    public boolean getSpecified() {
+        return value != null;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public void setNodeValue(String value) throws DOMException {
+        setValue(value);
+    }
+    
+    @Override
+    public void setPrefix(String prefix) {
+        if (!namespaceAware) {
+            throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
+        }
+        
+        if (prefix != null) {
+            if (namespaceURI == null || !document.isXMLIdentifier(prefix) || "xmlns".equals(prefix)) {
+                throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
+            }
+
+            if ("xml".equals(prefix) && !"http://www.w3.org/XML/1998/namespace".equals(namespaceURI)) {
+                throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
+            }
+        }
+
+        this.prefix = prefix;
+    }
+    
+    public void setValue(String value) throws DOMException {
+        this.value = value;
+    }
+    
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/CDATASectionImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/CDATASectionImpl.java
new file mode 100644
index 0000000..f54e5f4
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/CDATASectionImpl.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class CDATASectionImpl extends TextImpl implements CDATASection {
+
+    CDATASectionImpl(DocumentImpl document, String data) {
+        super(document, data);
+    }
+
+    @Override
+    public String getNodeName() {
+        return "#cdata-section";
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.CDATA_SECTION_NODE;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/CharacterDataImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/CharacterDataImpl.java
new file mode 100644
index 0000000..010cb22
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/CharacterDataImpl.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.CharacterData;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public abstract class CharacterDataImpl extends LeafNodeImpl implements
+        CharacterData {
+
+    private StringBuffer buffer;
+
+    CharacterDataImpl(DocumentImpl document, String data) {
+        super(document);
+        setData(data);
+    }
+
+    public void appendData(String arg) throws DOMException {
+        buffer.append(arg);
+    }
+
+    public void deleteData(int offset, int count) throws DOMException {
+        buffer.delete(offset, offset + count);
+    }
+
+    public String getData() throws DOMException {
+        return buffer.toString();
+    }
+
+    public int getLength() {
+        return buffer.length();
+    }
+
+    @Override
+    public String getNodeValue() {
+        return getData();
+    }
+
+    public void insertData(int offset, String arg) throws DOMException {
+        try {
+            buffer.insert(offset, arg);
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            throw new DOMException(DOMException.INDEX_SIZE_ERR, null);
+        }
+    }
+
+    public void replaceData(int offset, int count, String arg)
+            throws DOMException {
+        try {
+            buffer.replace(offset, offset + count, arg);
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            throw new DOMException(DOMException.INDEX_SIZE_ERR, null);
+        }
+    }
+
+    public void setData(String data) throws DOMException {
+        buffer = new StringBuffer(data);
+    }
+
+    public String substringData(int offset, int count) throws DOMException {
+        try {
+            return buffer.substring(offset, offset + count);
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            throw new DOMException(DOMException.INDEX_SIZE_ERR, null);
+        }
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/CommentImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/CommentImpl.java
new file mode 100644
index 0000000..6c1f446
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/CommentImpl.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class CommentImpl extends CharacterDataImpl implements Comment {
+
+    CommentImpl(DocumentImpl document, String data) {
+        super(document, data);
+    }
+
+    @Override
+    public String getNodeName() {
+        return "#comment";
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.COMMENT_NODE;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java
new file mode 100644
index 0000000..4e13d19
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class DOMImplementationImpl implements DOMImplementation {
+
+    // Singleton instance.
+    private static DOMImplementationImpl instance;
+
+    DOMImplementationImpl() {
+    }
+
+    public Document createDocument(String namespaceURI, String qualifiedName,
+            DocumentType doctype) throws DOMException {
+        return new DocumentImpl(this, namespaceURI, qualifiedName, doctype);
+    }
+
+    public DocumentType createDocumentType(String qualifiedName,
+            String publicId, String systemId) throws DOMException {
+        return new DocumentTypeImpl(this, qualifiedName, publicId, systemId);
+    }
+
+    public boolean hasFeature(String feature, String version) {
+        // We claim to support DOM Core Level 1 & 2, nothing else.
+
+        if ("Core".equalsIgnoreCase(feature) || "XML".equalsIgnoreCase(feature)) {
+            if (version == null || "".equals(version) || "1.0".equals(version) || "2.0".equals(version)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Requests the singleton instance of the class. Creates it first, if
+     * necessary.
+     * 
+     * @return The singleton Android DOMImplementationImpl instance.
+     */
+    public static DOMImplementationImpl getInstance() {
+        if (instance == null) {
+            instance = new DOMImplementationImpl();
+        }
+
+        return instance;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentFragmentImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentFragmentImpl.java
new file mode 100644
index 0000000..88e6175
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentFragmentImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class DocumentFragmentImpl extends InnerNodeImpl implements
+        DocumentFragment {
+
+    DocumentFragmentImpl(DocumentImpl document) {
+        super(document);
+    }
+
+    @Override
+    public String getNodeName() {
+        return "#document-fragment";
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.DOCUMENT_FRAGMENT_NODE;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
new file mode 100644
index 0000000..fbb1cac
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.CharacterData;
+import org.w3c.dom.Comment;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class DocumentImpl extends InnerNodeImpl implements Document {
+
+    private DOMImplementation domImplementation;
+
+    DocumentImpl(DOMImplementationImpl impl, String namespaceURI,
+            String qualifiedName, DocumentType doctype) {
+        super(null);
+
+        this.domImplementation = impl;
+        // this.document = this;
+        
+        if (doctype != null) {
+            appendChild(doctype);
+        }
+
+        if (qualifiedName != null) {
+            appendChild(createElementNS(namespaceURI, qualifiedName));
+        }
+    }
+
+    private static boolean isXMLIdentifierStart(char c) {
+        return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_');
+    }
+
+    private static boolean isXMLIdentifierPart(char c) {
+        return isXMLIdentifierStart(c) || (c >= '0' && c <= '9') || (c == '-') || (c == '.');
+    }
+
+    static boolean isXMLIdentifier(String s) {
+        if (s.length() == 0) {
+            return false;
+        }
+        
+        if (!isXMLIdentifierStart(s.charAt(0))) {
+            return false;
+        }
+        
+        for (int i = 1; i < s.length(); i++) {
+            if (!isXMLIdentifierPart(s.charAt(i))) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Clones a node and (if requested) its children. The source node(s) may
+     * have been created by a different DocumentImpl or even DOM implementation.
+     * 
+     * @param node The node to clone.
+     * @param deep If true, a deep copy is created (including all child nodes).
+     * 
+     * @return The new node.
+     */
+    Node cloneNode(Node node, boolean deep) throws DOMException {
+        Node target;
+        
+        switch (node.getNodeType()) {
+            case Node.ATTRIBUTE_NODE: {
+                Attr source = (Attr)node;
+                target = createAttributeNS(source.getNamespaceURI(), source.getLocalName());
+                target.setPrefix(source.getPrefix());
+                target.setNodeValue(source.getNodeValue());
+                break;
+            }
+            case Node.CDATA_SECTION_NODE: {
+                CharacterData source = (CharacterData)node;
+                target = createCDATASection(source.getData());
+                break;
+            }
+            case Node.COMMENT_NODE: {
+                Comment source = (Comment)node;
+                target = createComment(source.getData());
+                break;
+            }
+            case Node.DOCUMENT_FRAGMENT_NODE: {
+                // Source is irrelevant in this case.
+                target = createDocumentFragment();
+                break;
+            }
+            case Node.DOCUMENT_NODE: {
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a Document node");
+            }
+            case Node.DOCUMENT_TYPE_NODE: {
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a DocumentType node");
+            }
+            case Node.ELEMENT_NODE: {
+                Element source = (Element)node;
+                target = createElementNS(source.getNamespaceURI(), source.getLocalName());
+                target.setPrefix(source.getPrefix());
+
+                NamedNodeMap map = source.getAttributes();
+                for (int i = 0; i < map.getLength(); i++) {
+                    Attr attr = (Attr)map.item(i);
+                    ((Element)target).setAttributeNodeNS((Attr)cloneNode(attr, deep));
+                }
+                break;
+            }
+            case Node.ENTITY_NODE: {
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone an Entity node");
+            }
+            case Node.ENTITY_REFERENCE_NODE: {
+                EntityReference source = (EntityReference)node;
+                target = createEntityReference(source.getNodeName());
+                break;
+            }
+            case Node.NOTATION_NODE: {
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a Notation node");
+            }
+            case Node.PROCESSING_INSTRUCTION_NODE: {
+                ProcessingInstruction source = (ProcessingInstruction)node;
+                target = createProcessingInstruction(source.getTarget(), source.getData());
+                break;
+            }
+            case Node.TEXT_NODE: {
+                Text source = (Text)node;
+                target = createTextNode(source.getData());
+                break;
+            }
+            default: {
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone unknown node type " + node.getNodeType() + " (" + node.getClass().getSimpleName() + ")");
+            }
+        }
+
+        if (deep) {
+            NodeList list = node.getChildNodes();
+            for (int i = 0; i < list.getLength(); i++) {
+                Node child = cloneNode(list.item(i), deep);
+                target.appendChild(child);
+            }
+        }
+        
+        return target;
+    }
+    
+    public AttrImpl createAttribute(String name) throws DOMException {
+        return new AttrImpl(this, name);
+    }
+
+    public Attr createAttributeNS(String namespaceURI, String qualifiedName)
+            throws DOMException {
+        return new AttrImpl(this, namespaceURI, qualifiedName);
+    }
+
+    public CDATASection createCDATASection(String data) throws DOMException {
+        return new CDATASectionImpl(this, data);
+    }
+
+    public Comment createComment(String data) {
+        return new CommentImpl(this, data);
+    }
+
+    public DocumentFragment createDocumentFragment() {
+        return new DocumentFragmentImpl(this);
+    }
+
+    public Element createElement(String tagName) throws DOMException {
+        return new ElementImpl(this, tagName);
+    }
+
+    public Element createElementNS(String namespaceURI, String qualifiedName)
+            throws DOMException {
+        return new ElementImpl(this, namespaceURI, qualifiedName);
+    }
+
+    public EntityReference createEntityReference(String name)
+            throws DOMException {
+        return new EntityReferenceImpl(this, name);
+    }
+
+    public ProcessingInstruction createProcessingInstruction(String target,
+            String data) throws DOMException {
+        return new ProcessingInstructionImpl(this, target, data);
+    }
+
+    public Text createTextNode(String data) {
+        return new TextImpl(this, data);
+    }
+
+    public DocumentType getDoctype() {
+        for (int i = 0; i < children.size(); i++) {
+            if (children.get(i) instanceof DocumentType) {
+                return (DocumentType) children.get(i);
+            }
+        }
+
+        return null;
+    }
+
+    public Element getDocumentElement() {
+        for (int i = 0; i < children.size(); i++) {
+            if (children.get(i) instanceof Element) {
+                return (Element) children.get(i);
+            }
+        }
+
+        return null;
+    }
+
+    public Element getElementById(String elementId) {
+        ElementImpl root = (ElementImpl) getDocumentElement();
+
+        return (root == null ? null : root.getElementById(elementId));
+    }
+
+    public NodeList getElementsByTagName(String tagname) {
+        ElementImpl root = (ElementImpl) getDocumentElement();
+
+        return (root == null ? new NodeListImpl()
+                : root.getElementsByTagName(tagname));
+    }
+
+    public NodeList getElementsByTagNameNS(String namespaceURI, String localName) {
+        ElementImpl root = (ElementImpl) getDocumentElement();
+
+        return (root == null ? new NodeListImpl() : root.getElementsByTagNameNS(
+                namespaceURI, localName));
+    }
+
+    public DOMImplementation getImplementation() {
+        return domImplementation;
+    }
+
+    @Override
+    public String getNodeName() {
+        return "#document";
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.DOCUMENT_NODE;
+    }
+
+    public Node importNode(Node importedNode, boolean deep) throws DOMException {
+        return cloneNode(importedNode, deep);
+    }
+
+    @Override
+    public Node insertChildAt(Node newChild, int index) throws DOMException {
+        // Make sure we have at most one root element and one DTD element.
+        if (newChild instanceof Element && getDocumentElement() != null) {
+            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
+                    "Only one root element allowed");
+        } else if (newChild instanceof DocumentType && getDoctype() != null) {
+            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
+                    "Only one DOCTYPE element allowed");
+        }
+
+        return super.insertChildAt(newChild, index);
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentTypeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentTypeImpl.java
new file mode 100644
index 0000000..df40d4b
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentTypeImpl.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class DocumentTypeImpl extends LeafNodeImpl implements DocumentType {
+
+    private String qualifiedName;
+
+    private String publicId;
+
+    private String systemId;
+
+    DocumentTypeImpl(DOMImplementationImpl impl, String qualifiedName,
+            String publicId, String systemId) {
+        super(null);
+
+        if (qualifiedName == null || "".equals(qualifiedName)) {
+            throw new DOMException(DOMException.NAMESPACE_ERR, qualifiedName);
+        }
+        
+        int prefixSeparator = qualifiedName.lastIndexOf(":");
+        if (prefixSeparator != -1) {
+            String prefix = qualifiedName.substring(0, prefixSeparator);
+            String localName = qualifiedName.substring(prefixSeparator + 1);
+            
+            if (!DocumentImpl.isXMLIdentifier(prefix)) {
+                throw new DOMException(DOMException.NAMESPACE_ERR, qualifiedName);
+            }
+
+            if (!DocumentImpl.isXMLIdentifier(localName)) {
+                throw new DOMException(DOMException.INVALID_CHARACTER_ERR, qualifiedName);
+            }
+        } else {
+            if (!DocumentImpl.isXMLIdentifier(qualifiedName)) {
+                throw new DOMException(DOMException.INVALID_CHARACTER_ERR, qualifiedName);
+            }
+        }
+        
+        this.qualifiedName = qualifiedName;
+        this.publicId = publicId;
+        this.systemId = systemId;
+    }
+
+    @Override
+    public String getNodeName() {
+        return qualifiedName;
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.DOCUMENT_TYPE_NODE;
+    }
+
+    public NamedNodeMap getEntities() {
+        // TODO Dummy. Implement this later, if at all (we're DOM level 2 only).
+        return null;
+    }
+
+    public String getInternalSubset() {
+        // TODO Dummy. Implement this later, if at all (we're DOM level 2 only).
+        return null;
+    }
+
+    public String getName() {
+        return qualifiedName;
+    }
+
+    public NamedNodeMap getNotations() {
+        // TODO Dummy. Implement this later, if at all (we're DOM level 2 only).
+        return null;
+    }
+
+    public String getPublicId() {
+        return publicId;
+    }
+
+    public String getSystemId() {
+        return systemId;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
new file mode 100644
index 0000000..3b44ff3
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class ElementImpl extends InnerNodeImpl implements Element {
+
+    private boolean namespaceAware;
+    
+    private String namespaceURI;
+
+    private String prefix;
+    
+    private String localName;
+
+    private List<AttrImpl> attributes = new ArrayList<AttrImpl>();
+
+    ElementImpl(DocumentImpl document, String namespaceURI, String qualifiedName) {
+        super(document);
+
+        this.namespaceAware = true;
+        this.namespaceURI = namespaceURI;
+
+        if (qualifiedName == null || "".equals(qualifiedName)) {
+            throw new DOMException(DOMException.NAMESPACE_ERR, qualifiedName);
+        }
+        
+        int p = qualifiedName.lastIndexOf(":");
+        if (p != -1) {
+            setPrefix(qualifiedName.substring(0, p));
+            qualifiedName = qualifiedName.substring(p + 1);
+        }
+        
+        if (!document.isXMLIdentifier(qualifiedName)) {
+            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, qualifiedName);
+        }
+            
+        this.localName = qualifiedName;
+    }
+
+    ElementImpl(DocumentImpl document, String name) {
+        super(document);
+
+        this.namespaceAware = false;
+        
+        int p = name.lastIndexOf(":");
+        if (p != -1) {
+            String prefix = name.substring(0, p);
+            String localName = name.substring(p + 1);
+            
+            if (!document.isXMLIdentifier(prefix) || !document.isXMLIdentifier(localName)) {
+                throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
+            }
+        } else {
+            if (!document.isXMLIdentifier(name)) {
+                throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
+            }
+        }
+        
+        this.localName = name;
+    }
+
+    private int indexOfAttribute(String name) {
+        for (int i = 0; i < attributes.size(); i++) {
+            AttrImpl attr = attributes.get(i);
+            if (attr.matchesName(name, false)) {
+                return i;
+            }
+        }
+        
+        return -1;
+    }
+    
+    private int indexOfAttributeNS(String namespaceURI, String localName) {
+        for (int i = 0; i < attributes.size(); i++) {
+            AttrImpl attr = attributes.get(i);
+            if (attr.matchesNameNS(namespaceURI, localName, false)) {
+                return i;
+            }
+        }
+        
+        return -1;
+    }
+    
+    public String getAttribute(String name) {
+        Attr attr = getAttributeNode(name);
+
+        if (attr == null) {
+            return "";
+        }
+
+        return attr.getValue();
+    }
+
+    public String getAttributeNS(String namespaceURI, String localName) {
+        Attr attr = getAttributeNodeNS(namespaceURI, localName);
+
+        if (attr == null) {
+            return "";
+        }
+
+        return attr.getValue();
+    }
+
+    public Attr getAttributeNode(String name) {
+        int i = indexOfAttribute(name);
+        
+        if (i == -1) {
+            return null;
+        }
+        
+        return attributes.get(i);
+    }
+
+    public Attr getAttributeNodeNS(String namespaceURI, String localName) {
+        int i = indexOfAttributeNS(namespaceURI, localName);
+        
+        if (i == -1) {
+            return null;
+        }
+        
+        return attributes.get(i);
+    }
+
+    @Override
+    public NamedNodeMap getAttributes() {
+        return new ElementAttrNamedNodeMapImpl();
+    }
+    
+    Element getElementById(String name) {
+        if (name.equals(getAttribute("id"))) {
+            return this;
+        }
+
+        for (NodeImpl node : children) {
+            if (node.getNodeType() == Node.ELEMENT_NODE) {
+                Element element = ((ElementImpl) node).getElementById(name);
+                if (element != null) {
+                    return element;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public NodeList getElementsByTagName(String name) {
+        NodeListImpl list = new NodeListImpl();
+        getElementsByTagName(list, name);
+        return list;
+    }
+
+    void getElementsByTagName(NodeListImpl list, String name) {
+        if (matchesName(name, true)) {
+            list.add(this);
+        }
+
+        for (NodeImpl node : children) {
+            if (node.getNodeType() == Node.ELEMENT_NODE) {
+                ((ElementImpl) node).getElementsByTagName(list, name);
+            }
+        }
+    }
+
+    public NodeList getElementsByTagNameNS(String namespaceURI, String localName) {
+        NodeListImpl list = new NodeListImpl();
+        getElementsByTagNameNS(list, namespaceURI, localName);
+        return list;
+    }
+
+    void getElementsByTagNameNS(NodeListImpl list, String namespaceURI,
+            String localName) {
+        if (matchesNameNS(namespaceURI, localName, true)) {
+            list.add(this);
+        }
+        
+        for (NodeImpl node : children) {
+            if (node.getNodeType() == Node.ELEMENT_NODE) {
+                ((ElementImpl) node).getElementsByTagNameNS(list, namespaceURI,
+                        localName);
+            }
+        }
+    }
+
+    @Override
+    public String getLocalName() {
+        return namespaceAware ? localName : null;
+    }
+
+    @Override
+    public String getNamespaceURI() {
+        return namespaceURI;
+    }
+
+    @Override
+    public String getNodeName() {
+        return getTagName();
+    }
+
+    public short getNodeType() {
+        return Node.ELEMENT_NODE;
+    }
+
+    @Override
+    public String getPrefix() {
+        return prefix;
+    }
+
+    public String getTagName() {
+        return (prefix != null ? prefix + ":" : "") + localName;
+    }
+
+    public boolean hasAttribute(String name) {
+        return indexOfAttribute(name) != -1;
+    }
+
+    public boolean hasAttributeNS(String namespaceURI, String localName) {
+        return indexOfAttributeNS(namespaceURI, localName) != -1;
+    }
+
+    @Override
+    public boolean hasAttributes() {
+        return !attributes.isEmpty();
+    }
+
+    public void removeAttribute(String name) throws DOMException {
+        int i = indexOfAttribute(name);
+        
+        if (i != -1) {
+            attributes.remove(i);
+        }
+    }
+
+    public void removeAttributeNS(String namespaceURI, String localName)
+            throws DOMException {
+        int i = indexOfAttributeNS(namespaceURI, localName);
+        
+        if (i != -1) {
+            attributes.remove(i);
+        }
+    }
+
+    public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
+        AttrImpl oldAttrImpl = (AttrImpl) oldAttr;
+
+        if (oldAttrImpl.getOwnerElement() != this) {
+            throw new DOMException(DOMException.NOT_FOUND_ERR, null);
+        }
+
+        attributes.remove(oldAttr);
+        oldAttrImpl.ownerElement = null;
+
+        return oldAttrImpl;
+    }
+
+    public void setAttribute(String name, String value) throws DOMException {
+        Attr attr = getAttributeNode(name);
+
+        if (attr == null) {
+            attr = document.createAttribute(name);
+            setAttributeNode(attr);
+        }
+
+        attr.setValue(value);
+    }
+
+    public void setAttributeNS(String namespaceURI, String qualifiedName,
+            String value) throws DOMException {
+        Attr attr = getAttributeNodeNS(namespaceURI, qualifiedName);
+
+        if (attr == null) {
+            attr = document.createAttributeNS(namespaceURI, qualifiedName);
+            setAttributeNodeNS(attr);
+        }
+
+        attr.setValue(value);
+    }
+
+    public Attr setAttributeNode(Attr newAttr) throws DOMException {
+        AttrImpl newAttrImpl = (AttrImpl) newAttr;
+        
+        if (newAttrImpl.document != this.getOwnerDocument()) {
+            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
+        }
+
+        if (newAttrImpl.getOwnerElement() != null) {
+            throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, null);
+        }
+
+        AttrImpl oldAttrImpl = null;
+        
+        int i = indexOfAttribute(newAttr.getName());
+        if (i != -1) {
+            oldAttrImpl = attributes.get(i);
+            attributes.remove(i);
+        }
+        
+        attributes.add(newAttrImpl);
+        newAttrImpl.ownerElement = this;
+
+        return oldAttrImpl;
+    }
+
+    public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
+        AttrImpl newAttrImpl = (AttrImpl) newAttr;
+
+        if (newAttrImpl.document != this.getOwnerDocument()) {
+            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
+        }
+
+        if (newAttrImpl.getOwnerElement() != null) {
+            throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, null);
+        }
+
+        AttrImpl oldAttrImpl = null;
+        
+        int i = indexOfAttributeNS(newAttr.getNamespaceURI(), newAttr.getLocalName());
+        if (i != -1) {
+            oldAttrImpl = attributes.get(i);
+            attributes.remove(i);
+        }
+        
+        attributes.add(newAttrImpl);
+        newAttrImpl.ownerElement = this;
+
+        return oldAttrImpl;
+    }
+
+    @Override
+    public void setPrefix(String prefix) {
+        if (!namespaceAware) {
+            throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
+        }
+        
+        if (prefix != null) {
+            if (namespaceURI == null || !document.isXMLIdentifier(prefix)) {
+                throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
+            }
+            
+            if ("xml".equals(prefix) && !"http://www.w3.org/XML/1998/namespace".equals(namespaceURI)) {
+                throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
+            }
+        }
+        
+        this.prefix = prefix;
+    }
+    
+    public class ElementAttrNamedNodeMapImpl implements NamedNodeMap {
+
+        public int getLength() {
+            return ElementImpl.this.attributes.size();
+        }
+
+        private int indexOfItem(String name) {
+            return ElementImpl.this.indexOfAttribute(name);
+        }
+        
+        private int indexOfItemNS(String namespaceURI, String localName) {
+            return ElementImpl.this.indexOfAttributeNS(namespaceURI, localName);
+        }
+
+        public Node getNamedItem(String name) {
+            return ElementImpl.this.getAttributeNode(name);
+        }
+
+        public Node getNamedItemNS(String namespaceURI, String localName) {
+            return ElementImpl.this.getAttributeNodeNS(namespaceURI, localName);
+        }
+
+        public Node item(int index) {
+            return ElementImpl.this.attributes.get(index);
+        }
+
+        public Node removeNamedItem(String name) throws DOMException {
+            int i = indexOfItem(name);
+            
+            if (i == -1) {
+                throw new DOMException(DOMException.NOT_FOUND_ERR, null);
+            }
+
+            return ElementImpl.this.attributes.remove(i);
+        }
+
+        public Node removeNamedItemNS(String namespaceURI, String localName)
+                throws DOMException {
+            int i = indexOfItemNS(namespaceURI, localName);
+            
+            if (i == -1) {
+                throw new DOMException(DOMException.NOT_FOUND_ERR, null);
+            }
+
+            return ElementImpl.this.attributes.remove(i);
+        }
+
+        public Node setNamedItem(Node arg) throws DOMException {
+            if (!(arg instanceof Attr)) {
+                throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+            }
+
+            return ElementImpl.this.setAttributeNode((Attr)arg);
+        }
+
+        public Node setNamedItemNS(Node arg) throws DOMException {
+            if (!(arg instanceof Attr)) {
+                throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+            }
+            
+            return ElementImpl.this.setAttributeNodeNS((Attr)arg);
+        }
+    }
+    
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/EntityImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/EntityImpl.java
new file mode 100644
index 0000000..463e863
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/EntityImpl.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Entity;
+import org.w3c.dom.Node;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class EntityImpl extends NodeImpl implements Entity {
+
+    private String notationName;
+
+    private String publicID;
+
+    private String systemID;
+
+    EntityImpl(DocumentImpl document, String notationName, String publicID,
+            String systemID) {
+        super(document);
+        this.notationName = notationName;
+        this.publicID = publicID;
+        this.systemID = systemID;
+    }
+
+    @Override
+    public String getNodeName() {
+        return getNotationName();
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.ENTITY_NODE;
+    }
+
+    public String getNotationName() {
+        return notationName;
+    }
+
+    public String getPublicId() {
+        return publicID;
+    }
+
+    public String getSystemId() {
+        return systemID;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/EntityReferenceImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/EntityReferenceImpl.java
new file mode 100644
index 0000000..f612a15
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/EntityReferenceImpl.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.Node;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class EntityReferenceImpl extends LeafNodeImpl implements EntityReference {
+
+    private String name;
+
+    EntityReferenceImpl(DocumentImpl document, String name) {
+        super(document);
+        this.name = name;
+    }
+
+    @Override
+    public String getNodeName() {
+        return name;
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.ENTITY_REFERENCE_NODE;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java
new file mode 100644
index 0000000..f71d289
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ * <p>
+ * This class represents a Node that has a parent Node as well as (potentially)
+ * a number of children.
+ */
+public abstract class InnerNodeImpl extends LeafNodeImpl {
+
+    // Maintained by LeafNodeImpl and ElementImpl.
+    List<LeafNodeImpl> children = new ArrayList<LeafNodeImpl>();
+
+    public InnerNodeImpl(DocumentImpl document) {
+        super(document);
+    }
+
+    public Node appendChild(Node newChild) throws DOMException {
+        return insertChildAt(newChild, children.size());
+    }
+
+    public NodeList getChildNodes() {
+        NodeListImpl list = new NodeListImpl();
+
+        for (NodeImpl node : children) {
+            list.add(node);
+        }
+
+        return list;
+    }
+
+    public Node getFirstChild() {
+        return (!children.isEmpty() ? children.get(0) : null);
+    }
+
+    public Node getLastChild() {
+        return (!children.isEmpty() ? children.get(children.size() - 1) : null);
+    }
+
+    public Node getNextSibling() {
+        if (parent == null || index >= parent.children.size()) {
+            return null;
+        }
+
+        return parent.children.get(index + 1);
+    }
+
+    public boolean hasChildNodes() {
+        return children.size() != 0;
+    }
+
+    public Node insertBefore(Node newChild, Node refChild) throws DOMException {
+        LeafNodeImpl refChildImpl = (LeafNodeImpl) refChild;
+
+        if (refChildImpl.document != document) {
+            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
+        }
+
+        if (refChildImpl.parent != this) {
+            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+        }
+
+        return insertChildAt(newChild, refChildImpl.index);
+    }
+
+    /**
+     * Inserts a new child node into this node at a given position. If the new
+     * node is already child of another node, it is first removed from there.
+     * This method is the generalization of the appendChild() and insertBefore()
+     * methods.
+     * 
+     * @param newChild The new child node to add.
+     * @param index The index at which to insert the new child node.
+     * 
+     * @return The node added.
+     * 
+     * @throws DOMException If the attempted operation violates the XML/DOM
+     *         well-formedness rules.
+     */
+    public Node insertChildAt(Node newChild, int index) throws DOMException {
+        LeafNodeImpl newChildImpl = (LeafNodeImpl) newChild;
+
+        if (document != null && newChildImpl.document != null && newChildImpl.document != document) {
+            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
+        }
+
+        if (newChildImpl.isParentOf(this)) {
+            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+        }
+
+        if (newChildImpl.parent != null) {
+            int oldIndex = newChildImpl.index;
+            newChildImpl.parent.children.remove(oldIndex);
+            newChildImpl.parent.refreshIndices(oldIndex);
+        }
+
+        children.add(index, newChildImpl);
+        newChildImpl.parent = this;
+        refreshIndices(index);
+
+        return newChild;
+    }
+
+    public boolean isParentOf(Node node) {
+        LeafNodeImpl nodeImpl = (LeafNodeImpl) node;
+
+        while (nodeImpl != null) {
+            if (nodeImpl == this) {
+                return true;
+            }
+
+            nodeImpl = nodeImpl.parent;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void normalize() {
+        Node nextNode = null;
+        
+        for (int i = children.size() - 1; i >= 0; i--) {
+            Node thisNode = children.get(i);
+
+            thisNode.normalize();
+            
+            if (thisNode.getNodeType() == Node.TEXT_NODE) {
+                if (nextNode != null && nextNode.getNodeType() == Node.TEXT_NODE) {
+                    ((Text)thisNode).setData(thisNode.getNodeValue() + nextNode.getNodeValue());
+                    removeChild(nextNode);
+                }
+                
+                if ("".equals(thisNode.getNodeValue())) {
+                    removeChild(thisNode);
+                    nextNode = null;
+                } else {
+                    nextNode = thisNode;
+                }
+            }
+        }
+    }
+
+    private void refreshIndices(int fromIndex) {
+        for (int i = fromIndex; i < children.size(); i++) {
+            children.get(i).index = i;
+        }
+    }
+
+    public Node removeChild(Node oldChild) throws DOMException {
+        LeafNodeImpl oldChildImpl = (LeafNodeImpl) oldChild;
+
+        if (oldChildImpl.document != document) {
+            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
+        }
+
+        if (oldChildImpl.parent != this) {
+            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+        }
+
+        int index = oldChildImpl.index;
+        children.remove(index);
+        oldChildImpl.parent = null;
+        refreshIndices(index);
+
+        return oldChild;
+    }
+
+    public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
+        LeafNodeImpl oldChildImpl = (LeafNodeImpl) oldChild;
+        LeafNodeImpl newChildImpl = (LeafNodeImpl) newChild;
+
+        if (oldChildImpl.document != document
+                || newChildImpl.document != document) {
+            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
+        }
+
+        if (oldChildImpl.parent != this || newChildImpl.isParentOf(this)) {
+            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+        }
+
+        int index = oldChildImpl.index;
+        children.set(index, newChildImpl);
+        oldChildImpl.parent = null;
+        newChildImpl.parent = this;
+        refreshIndices(index);
+
+        return oldChildImpl;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/LeafNodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/LeafNodeImpl.java
new file mode 100644
index 0000000..5f9698e
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/LeafNodeImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ * <p>
+ * This class represents a Node that has a parent Node, but no children.
+ */
+public abstract class LeafNodeImpl extends NodeImpl {
+
+    // Maintained by InnerNodeImpl.
+    InnerNodeImpl parent;
+
+    // Maintained by InnerNodeImpl.
+    int index;
+
+    LeafNodeImpl(DocumentImpl document) {
+        super(document);
+    }
+
+    public Node getNextSibling() {
+        if (parent == null || index + 1 >= parent.children.size()) {
+            return null;
+        }
+
+        return parent.children.get(index + 1);
+    }
+
+    public Node getParentNode() {
+        return parent;
+    }
+
+    public Node getPreviousSibling() {
+        if (parent == null || index == 0) {
+            return null;
+        }
+
+        return parent.children.get(index - 1);
+    }
+
+    boolean isParentOf(Node node) {
+        return false;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/NamedNodeMapImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/NamedNodeMapImpl.java
new file mode 100644
index 0000000..0952d83
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/NamedNodeMapImpl.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class NamedNodeMapImpl implements NamedNodeMap {
+
+    private Class<?> type;
+    
+    private List<NodeImpl> list;
+
+    NamedNodeMapImpl(Class<?> type) {
+        list = new ArrayList<NodeImpl>();
+        this.type = type;
+    }
+
+    NamedNodeMapImpl(List<NodeImpl> list, Class<?> type) {
+        this.list = list;
+        this.type = type;
+    }
+
+    public int getLength() {
+        return list.size();
+    }
+
+    private int indexOfItem(String name) {
+        for (int i = 0; i < list.size(); i++) {
+            NodeImpl node = list.get(i);
+            if (node.matchesName(name, false)) {
+                return i;
+            }
+        }
+        
+        return -1;
+    }
+    
+    private int indexOfItemNS(String namespaceURI, String localName) {
+        for (int i = 0; i < list.size(); i++) {
+            NodeImpl node = list.get(i);
+            if (node.matchesNameNS(namespaceURI, localName, false)) {
+                return i;
+            }
+        }
+        
+        return -1;
+    }
+
+    public Node getNamedItem(String name) {
+        int i = indexOfItem(name);
+        
+        return (i == -1 ? null : item(i));
+    }
+
+    public Node getNamedItemNS(String namespaceURI, String localName) {
+        int i = indexOfItemNS(namespaceURI, localName);
+        
+        return (i == -1 ? null : item(i));
+    }
+
+    public Node item(int index) {
+        return list.get(index);
+    }
+
+    public Node removeNamedItem(String name) throws DOMException {
+        int i = indexOfItem(name);
+        
+        if (i == -1) {
+            throw new DOMException(DOMException.NOT_FOUND_ERR, null);
+        }
+
+        return list.remove(i);
+    }
+
+    public Node removeNamedItemNS(String namespaceURI, String localName)
+            throws DOMException {
+        int i = indexOfItemNS(namespaceURI, localName);
+        
+        if (i == -1) {
+            throw new DOMException(DOMException.NOT_FOUND_ERR, null);
+        }
+
+        return list.remove(i);
+    }
+
+    public Node setNamedItem(Node arg) throws DOMException {
+        // Ensure we only accept nodes of the correct type.
+        if (!type.isAssignableFrom(arg.getClass())) {
+            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+        }
+        
+        // All nodes in the map must belong to the same document.
+        if (list.size() != 0) {
+            Document document = list.get(0).getOwnerDocument();
+
+            if (document != null && arg.getOwnerDocument() != document) {
+                throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+            }
+        }
+
+// TODO Theoretically we should ensure that the nodes don't have a parent.
+//        if (newAttrImpl.getOwnerElement() != null) {
+//            throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, null);
+//        }
+
+        int i = indexOfItem(arg.getNodeName());
+        
+        if (i != -1) {
+            list.remove(i);
+        }
+        
+        list.add((NodeImpl)arg);
+        return arg;
+    }
+
+    public Node setNamedItemNS(Node arg) throws DOMException {
+        // Ensure we only accept nodes of the correct type.
+        if (!type.isAssignableFrom(arg.getClass())) {
+            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+        }
+        
+        // All nodes in the map must belong to the same document.
+        if (list.size() != 0) {
+            Document document = list.get(0).getOwnerDocument();
+
+            if (document != null && arg.getOwnerDocument() != document) {
+                throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+            }
+        }
+
+// TODO Theoretically we should ensure that the nodes don't have a parent.
+//        if (newAttrImpl.getOwnerElement() != null) {
+//            throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, null);
+//        }
+
+        int i = indexOfItemNS(arg.getNamespaceURI(), arg.getLocalName());
+        
+        if (i != -1) {
+            list.remove(i);
+        }
+        
+        list.add((NodeImpl)arg);
+        return arg;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
new file mode 100644
index 0000000..ca6fb8f
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ * <p>
+ * This class represents a Node that has neither a parent nor children.
+ */
+public abstract class NodeImpl implements Node {
+
+    private static final NodeList EMPTY_LIST = new NodeListImpl();
+    
+    // Maintained by InnerNodeImpl and ElementImpl.
+    DocumentImpl document;
+
+    NodeImpl(DocumentImpl document) {
+        this.document = document;
+    }
+
+    public Node appendChild(Node newChild) throws DOMException {
+        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+    }
+
+    public Node cloneNode(boolean deep) {
+        return document.cloneNode(this, deep);
+    }
+
+    public NamedNodeMap getAttributes() {
+        return null;
+    }
+
+    public NodeList getChildNodes() {
+        return EMPTY_LIST;
+    }
+
+    public Node getFirstChild() {
+        return null;
+    }
+
+    public Node getLastChild() {
+        return null;
+    }
+
+    public String getLocalName() {
+        return null;
+    }
+
+    public String getNamespaceURI() {
+        return null;
+    }
+
+    public Node getNextSibling() {
+        return null;
+    }
+
+    public String getNodeName() {
+        return null;
+    }
+
+    public abstract short getNodeType();
+
+    public String getNodeValue() throws DOMException {
+        return null;
+    }
+
+    public Document getOwnerDocument() {
+        return document;
+    }
+
+    public Node getParentNode() {
+        return null;
+    }
+
+    public String getPrefix() {
+        return null;
+    }
+
+    public Node getPreviousSibling() {
+        return null;
+    }
+
+    public boolean hasAttributes() {
+        return false;
+    }
+
+    public boolean hasChildNodes() {
+        return false;
+    }
+
+    public Node insertBefore(Node newChild, Node refChild) throws DOMException {
+        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+    }
+
+    public boolean isSupported(String feature, String version) {
+        return DOMImplementationImpl.getInstance().hasFeature(feature, version);
+    }
+
+    public void normalize() {
+    }
+
+    public Node removeChild(Node oldChild) throws DOMException {
+        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+    }
+
+    public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
+        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
+    }
+
+    public void setNodeValue(String nodeValue) throws DOMException {
+    }
+
+    public void setPrefix(String prefix) throws DOMException {
+    }
+
+    /**
+     * Checks whether a required string matches an actual string. This utility
+     * method is used for comparing namespaces and such. It takes into account
+     * null arguments and the "*" special case.
+     * 
+     * @param required The required string.
+     * @param actual The actual string.
+     * @return True if and only if the actual string matches the required one.
+     */
+    private static boolean matchesName(String required, String actual, boolean wildcard) {
+        if (wildcard && "*".equals(required)) {
+            return true;
+        }
+        
+        if (required == null) {
+            return (actual == null);
+        }
+        
+        return required.equals(actual);
+    }
+
+    /**
+     * Checks whether this node's name matches a required name. It takes into
+     * account null arguments and the "*" special case.
+     * 
+     * @param name The required name.
+     * @param wildcard TODO
+     * @return True if and only if the actual name matches the required one.
+     */
+    public boolean matchesName(String name, boolean wildcard) {
+        return matchesName(name, getNodeName(), wildcard);
+    }
+
+    /**
+     * Checks whether this node's namespace and local name match a required
+     * pair of namespace and local name. It takes into account null arguments
+     * and the "*" special case.
+     *
+     * @param namespaceURI The required namespace.
+     * @param localName The required local name.
+     * @param wildcard TODO
+     * @return True if and only if the actual namespace and local name match
+     *         the required pair of namespace and local name.
+     */
+    public boolean matchesNameNS(String namespaceURI, String localName, boolean wildcard) {
+        return matchesName(namespaceURI, getNamespaceURI(), wildcard) && matchesName(localName, getLocalName(), wildcard);
+    }
+    
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/NodeListImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/NodeListImpl.java
new file mode 100644
index 0000000..caa56af
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/NodeListImpl.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class NodeListImpl implements NodeList {
+
+    private List<NodeImpl> children;
+
+    NodeListImpl() {
+        children = new ArrayList<NodeImpl>();
+    }
+
+    NodeListImpl(List<NodeImpl> list) {
+        children = list;
+    }
+
+    void add(NodeImpl node) {
+        children.add(node);
+    }
+
+    public int getLength() {
+        return children.size();
+    }
+
+    public Node item(int index) {
+        if (index >= children.size()) {
+            return null;
+        } else {
+            return children.get(index);
+        }
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/NotationImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/NotationImpl.java
new file mode 100644
index 0000000..4d91d75
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/NotationImpl.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Notation;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class NotationImpl extends LeafNodeImpl implements Notation {
+
+    private String notationName;
+
+    private String publicID;
+
+    private String systemID;
+
+    NotationImpl(DocumentImpl document, String notationName, String publicID,
+            String systemID) {
+        super(document);
+    }
+
+    @Override
+    public String getNodeName() {
+        return notationName;
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.NOTATION_NODE;
+    }
+
+    public String getPublicId() {
+        return publicID;
+    }
+
+    public String getSystemId() {
+        return systemID;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/ProcessingInstructionImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/ProcessingInstructionImpl.java
new file mode 100644
index 0000000..c3610d5
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/ProcessingInstructionImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class ProcessingInstructionImpl extends LeafNodeImpl implements
+        ProcessingInstruction {
+
+    private String target;
+
+    private String data;
+
+    ProcessingInstructionImpl(DocumentImpl document, String target, String data) {
+        super(document);
+        this.target = target;
+        this.data = data;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    @Override
+    public String getNodeName() {
+        return target;
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.PROCESSING_INSTRUCTION_NODE;
+    }
+
+    @Override
+    public String getNodeValue() {
+        return data;
+    }
+
+    public String getTarget() {
+        return target;
+    }
+
+    public void setData(String data) throws DOMException {
+        this.data = data;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java
new file mode 100644
index 0000000..3553546
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/TextImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.dom;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+/**
+ * Provides a straightforward implementation of the corresponding W3C DOM
+ * interface. The class is used internally only, thus only notable members that
+ * are not in the original interface are documented (the W3C docs are quite
+ * extensive). Hope that's ok.
+ * <p>
+ * Some of the fields may have package visibility, so other classes belonging to
+ * the DOM implementation can easily access them while maintaining the DOM tree
+ * structure.
+ */
+public class TextImpl extends CharacterDataImpl implements Text {
+
+    TextImpl(DocumentImpl document, String data) {
+        super(document, data);
+    }
+
+    @Override
+    public String getNodeName() {
+        return "#text";
+    }
+
+    @Override
+    public short getNodeType() {
+        return Node.TEXT_NODE;
+    }
+
+    @Override
+    public String getNodeValue() {
+        return getData();
+    }
+
+    public Text splitText(int offset) throws DOMException {
+        Text newText = getOwnerDocument().createTextNode(
+                substringData(offset, getLength() - offset));
+        deleteData(0, offset);
+
+        Node refNode = getNextSibling();
+        if (refNode == null) {
+            getParentNode().appendChild(newText);
+        } else {
+            getParentNode().insertBefore(newText, refNode);
+        }
+
+        return this;
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderFactoryImpl.java b/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderFactoryImpl.java
new file mode 100644
index 0000000..4b8eef3
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderFactoryImpl.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.parsers;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+/**
+ * Provides a straightforward DocumentBuilderFactory implementation based on
+ * XMLPull/KXML. The class is used internally only, thus only notable members
+ * that are not already in the abstract superclass are documented. Hope that's
+ * ok.
+ */
+public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory {
+
+    private static final String NAMESPACES =
+            "http://xml.org/sax/features/namespaces";
+
+    private static final String VALIDATION =
+            "http://xml.org/sax/features/validation";
+    
+    @Override
+    public Object getAttribute(String name) throws IllegalArgumentException {
+        throw new IllegalArgumentException(name);
+    }
+
+    @Override
+    public boolean getFeature(String name) throws ParserConfigurationException {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        
+        if (NAMESPACES.equals(name)) {
+            return isNamespaceAware();
+        } else if (VALIDATION.equals(name)) {
+            return isValidating();
+        } else {
+            throw new ParserConfigurationException(name);
+        }
+    }
+
+    @Override
+    public DocumentBuilder newDocumentBuilder()
+            throws ParserConfigurationException {
+        if (isValidating()) {
+            throw new ParserConfigurationException(
+                    "No validating DocumentBuilder implementation available");
+        }
+        
+        /**
+         * TODO If Android is going to support a different DocumentBuilder
+         * implementations, this should be wired here. If we wanted to
+         * allow different implementations, these could be distinguished by
+         * a special feature (like http://www.org.apache.harmony.com/xml/expat)
+         * or by throwing the full SPI monty at it.  
+         */
+        DocumentBuilderImpl builder = new DocumentBuilderImpl();
+        
+        builder.setIgnoreComments(isIgnoringComments());
+        builder.setIgnoreElementContentWhitespace(
+                isIgnoringElementContentWhitespace());
+        builder.setNamespaceAware(isNamespaceAware());
+
+        // TODO What about expandEntityReferences?
+        
+        return builder;
+    }
+    
+    @Override
+    public void setAttribute(String name, Object value)
+            throws IllegalArgumentException {
+        throw new IllegalArgumentException(name);
+    }
+
+    @Override
+    public void setFeature(String name, boolean value)
+            throws ParserConfigurationException {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+
+        if (NAMESPACES.equals(name)) {
+            setNamespaceAware(value);
+        } else if (VALIDATION.equals(name)) {
+            setValidating(value);
+        } else {
+            throw new ParserConfigurationException(name);
+        }
+    }
+
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java b/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
new file mode 100644
index 0000000..f831c8b
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.parsers;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import javax.xml.parsers.DocumentBuilder;
+
+import org.kxml2.io.KXmlParser;
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.LocatorImpl;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import org.apache.harmony.xml.dom.DOMImplementationImpl;
+
+/**
+ * Provides a straightforward DocumentBuilder implementation based on
+ * XMLPull/KXML. The class is used internally only, thus only notable members
+ * that are not already in the abstract superclass are documented. Hope that's
+ * ok.
+ */
+class DocumentBuilderImpl extends DocumentBuilder {
+
+    private static DOMImplementation dom = DOMImplementationImpl.getInstance();
+
+    private EntityResolver entityResolver;
+
+    private ErrorHandler errorHandler;
+
+    private boolean ignoreComments;
+
+    private boolean ignoreElementContentWhitespace;
+
+    private boolean namespaceAware;
+
+    DocumentBuilderImpl() {
+        // Do nothing.
+    }
+
+    @Override
+    public DOMImplementation getDOMImplementation() {
+        return dom;
+    }
+
+    /**
+     * Reflects whether this DocumentBuilder is configured to ignore comments.
+     * 
+     * @return True if and only if comments are ignored.
+     */
+    public boolean isIgnoringComments() {
+        return ignoreComments;
+    }
+
+    /**
+     * Reflects whether this DocumentBuilder is configured to ignore element
+     * content whitespace.
+     * 
+     * @return True if and only if whitespace element content is ignored.
+     */
+    public boolean isIgnoringElementContentWhitespace() {
+        return ignoreElementContentWhitespace;
+    }
+
+    @Override
+    public boolean isNamespaceAware() {
+        return namespaceAware;
+    }
+
+    @Override
+    public boolean isValidating() {
+        return false;
+    }
+
+    @Override
+    public Document newDocument() {
+        return dom.createDocument(null, null, null);
+    }
+
+    @Override
+    public Document parse(InputSource source) throws SAXException, IOException {
+        if (source == null) {
+            throw new IllegalArgumentException();
+        }
+        
+        Document document = newDocument();
+
+        try {
+            XmlPullParser parser = new KXmlParser();
+
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,
+                    namespaceAware);
+            
+            if (source.getByteStream() != null) {
+                parser.setInput(source.getByteStream(), source.getEncoding());
+            } else if (source.getCharacterStream() != null) {
+                parser.setInput(source.getCharacterStream());
+            } else {
+                // TODO Accept other sources as well?
+                throw new SAXParseException(
+                        "InputSource needs either stream or reader", null);
+            }
+
+            if(parser.nextToken() == XmlPullParser.END_DOCUMENT) {
+                throw new SAXParseException(
+                        "Unexpected end of document", null);
+            }
+
+            parse(parser, document, document, XmlPullParser.END_DOCUMENT);
+
+            parser.require(XmlPullParser.END_DOCUMENT, null, null);
+        } catch (XmlPullParserException ex) {
+            if(ex.getDetail() instanceof IOException) {
+                throw (IOException)ex.getDetail();
+            }
+            if(ex.getDetail() instanceof RuntimeException) {
+                throw (RuntimeException)ex.getDetail();
+            }
+            
+            LocatorImpl locator = new LocatorImpl();
+
+            locator.setPublicId(source.getPublicId());
+            locator.setSystemId(source.getSystemId());
+            locator.setLineNumber(ex.getLineNumber());
+            locator.setColumnNumber(ex.getColumnNumber());
+
+            SAXParseException newEx = new SAXParseException(ex.getMessage(),
+                    locator);
+
+            if (errorHandler != null) {
+                errorHandler.error(newEx);
+            }
+
+            throw newEx;
+        }
+
+        return document;
+    }
+
+    /**
+     * Implements the whole parsing of the XML document. The XML pull parser is
+     * actually more of a tokenizer, and we are doing a classical recursive
+     * descent parsing (the method invokes itself for XML elements). Our
+     * approach to parsing does accept some illegal documents (more than one
+     * root element, for example). The assumption is that the DOM implementation
+     * throws the proper exceptions in these cases.
+     * 
+     * @param parser The XML pull parser we're reading from.
+     * @param document The document we're building.
+     * @param node The node we're currently on (initially the document itself).
+     * @param endToken The token that will end this recursive call. Either
+     *        XmlPullParser.END_DOCUMENT or XmlPullParser.END_TAG.
+     * 
+     * @throws XmlPullParserException If a parsing error occurs.
+     * @throws IOException If a general IO error occurs.
+     */
+    private void parse(XmlPullParser parser, Document document, Node node,
+            int endToken) throws XmlPullParserException, IOException {
+
+        int token = parser.getEventType();
+
+        /*
+         * The main parsing loop. The precondition is that we are already on the
+         * token to be processed. This holds for each iteration of the loop, so
+         * the inner statements have to ensure that (in particular the recursive
+         * call).
+         */
+        while (token != endToken && token != XmlPullParser.END_DOCUMENT) {
+            if (token == XmlPullParser.PROCESSING_INSTRUCTION) {
+                /*
+                 * Found a processing instructions. We need to split the token
+                 * text at the first whitespace character.
+                 */
+                String text = parser.getText();
+
+                int dot = text.indexOf(' ');
+
+                String target = (dot != -1 ? text.substring(0, dot) : text);
+                String data = (dot != -1 ? text.substring(dot + 1) : "");
+
+                node.appendChild(document.createProcessingInstruction(target,
+                        data));
+            } else if (token == XmlPullParser.DOCDECL) {
+                /*
+                 * Found a document type declaration. Unfortunately KXML doesn't
+                 * have the necessary details. Do we parse it ourselves, or do
+                 * we silently ignore it, since it isn't mandatory in DOM 2
+                 * anyway?
+                 */
+                StringTokenizer tokenizer = new StringTokenizer(parser.getText());
+                if (tokenizer.hasMoreTokens()) {
+                    String name = tokenizer.nextToken();
+                    String pubid = null;
+                    String sysid = null;
+                    
+                    if (tokenizer.hasMoreTokens()) {
+                        String text = tokenizer.nextToken();
+                        
+                        if ("SYSTEM".equals(text)) {
+                            if (tokenizer.hasMoreTokens()) {
+                                sysid = tokenizer.nextToken();
+                            }
+                        } else if ("PUBLIC".equals(text)) {
+                            if (tokenizer.hasMoreTokens()) {
+                                pubid = tokenizer.nextToken();
+                            }
+                            if (tokenizer.hasMoreTokens()) {
+                                sysid = tokenizer.nextToken();
+                            }
+                        }
+                    }
+                    
+                    if (pubid != null && pubid.length() >= 2 && pubid.startsWith("\"") && pubid.endsWith("\"")) {
+                        pubid = pubid.substring(1, pubid.length() - 1);
+                    }
+                    
+                    if (sysid != null && sysid.length() >= 2 && sysid.startsWith("\"") && sysid.endsWith("\"")) {
+                        sysid = sysid.substring(1, sysid.length() - 1);
+                    }
+                    
+                    document.appendChild(dom.createDocumentType(name, pubid, sysid));
+                }
+                
+            } else if (token == XmlPullParser.COMMENT) {
+                /*
+                 * Found a comment. We simply take the token text, but we only
+                 * create a node if the client wants to see comments at all.
+                 */
+                if (!ignoreComments) {
+                    node.appendChild(document.createComment(parser.getText()));
+                }
+            } else if (token == XmlPullParser.IGNORABLE_WHITESPACE) {
+                /*
+                 * Found some ignorable whitespace. We simply take the token
+                 * text, but we only create a node if the client wants to see
+                 * whitespace at all.
+                 */
+                if (!ignoreElementContentWhitespace) {
+                    node.appendChild(document.createTextNode(parser.getText()));
+                }
+            } else if (token == XmlPullParser.TEXT) {
+                /*
+                 * Found a piece of text. That's the easiest case. We simply
+                 * take it and create a corresponding node.
+                 */
+                node.appendChild(document.createTextNode(parser.getText()));
+            } else if (token == XmlPullParser.CDSECT) {
+                /*
+                 * Found a CDATA section. That's also trivial. We simply
+                 * take it and create a corresponding node.
+                 */
+                node.appendChild(document.createCDATASection(parser.getText()));
+            } else if (token == XmlPullParser.ENTITY_REF) {
+                /*
+                 * Found an entity reference. If an entity resolver is
+                 * installed, we replace it by text (if possible). Otherwise we
+                 * add an entity reference node.
+                 */
+                String entity = parser.getName();
+
+                if (entityResolver != null) {
+                    // TODO Implement this...
+                }
+
+                String replacement = resolveStandardEntity(entity);
+                if (replacement != null) {
+                    node.appendChild(document.createTextNode(replacement));
+                } else {
+                    node.appendChild(document.createEntityReference(entity));
+                }
+            } else if (token == XmlPullParser.START_TAG) {
+                /*
+                 * Found an element start tag. We create an element node with
+                 * the proper info and attributes. We then invoke parse()
+                 * recursively to handle the next level of nesting. When we
+                 * return from this call, we check that we are on the proper
+                 * element end tag. The whole handling differs somewhat
+                 * depending on whether the parser is namespace-aware or not.
+                 */
+                if (namespaceAware) {
+                    // Collect info for element node
+                    String namespace = parser.getNamespace();
+                    String name = parser.getName();
+                    String prefix = parser.getPrefix();
+
+                    if ("".equals(namespace)) {
+                        namespace = null;
+                    }
+                    
+                    // Create element node and wire it correctly
+                    Element element = document.createElementNS(namespace, name);
+                    element.setPrefix(prefix);
+                    node.appendChild(element);
+
+                    for (int i = 0; i < parser.getAttributeCount(); i++) {
+                        // Collect info for a single attribute node
+                        String attrNamespace = parser.getAttributeNamespace(i);
+                        String attrPrefix = parser.getAttributePrefix(i);
+                        String attrName = parser.getAttributeName(i);
+                        String attrValue = parser.getAttributeValue(i);
+
+                        if ("".equals(attrNamespace)) {
+                            attrNamespace = null;
+                        }
+                        
+                        // Create attribute node and wire it correctly
+                        Attr attr = document.createAttributeNS(attrNamespace, attrName);
+                        attr.setPrefix(attrPrefix);
+                        attr.setValue(attrValue);
+                        element.setAttributeNodeNS(attr);
+                    }
+                    
+                    // Recursive descent
+                    token = parser.nextToken();
+                    parse(parser, document, element, XmlPullParser.END_TAG);
+
+                    // Expect the element's end tag here
+                    parser.require(XmlPullParser.END_TAG, namespace, name);
+                    
+                } else {
+                    // Collect info for element node
+                    String name = parser.getName();
+
+                    // Create element node and wire it correctly
+                    Element element = document.createElement(name);
+                    node.appendChild(element);
+
+                    for (int i = 0; i < parser.getAttributeCount(); i++) {
+                        // Collect info for a single attribute node
+                        String attrName = parser.getAttributeName(i);
+                        String attrValue = parser.getAttributeValue(i);
+
+                        // Create attribute node and wire it correctly
+                        Attr attr = document.createAttribute(attrName);
+                        attr.setValue(attrValue);
+                        element.setAttributeNode(attr);
+                    }
+
+                    // Recursive descent
+                    token = parser.nextToken();
+                    parse(parser, document, element, XmlPullParser.END_TAG);
+
+                    // Expect the element's end tag here
+                    parser.require(XmlPullParser.END_TAG, "", name);
+                }
+            }
+
+            token = parser.nextToken();
+        }
+    }
+
+    @Override
+    public void setEntityResolver(EntityResolver resolver) {
+        entityResolver = resolver;
+    }
+
+    @Override
+    public void setErrorHandler(ErrorHandler handler) {
+        errorHandler = handler;
+    }
+
+    /**
+     * Controls whether this DocumentBuilder ignores comments.
+     * 
+     * @param value Turns comment ignorance on or off.
+     */
+    public void setIgnoreComments(boolean value) {
+        ignoreComments = value;
+    }
+
+    /**
+     * Controls whether this DocumentBuilder ignores element content whitespace.
+     * 
+     * @param value Turns element whitespace content ignorance on or off.
+     */
+    public void setIgnoreElementContentWhitespace(boolean value) {
+        ignoreElementContentWhitespace = value;
+    }
+
+    /**
+     * Controls whether this DocumentBuilder is namespace-aware.
+     * 
+     * @param value Turns namespace awareness on or off.
+     */
+    public void setNamespaceAware(boolean value) {
+        namespaceAware = value;
+    }
+
+    /**
+     * Resolves one of the five standard XML entities.
+     * 
+     * @param entity The name of the entity to resolve, not including
+     *               the ampersand or the semicolon.
+     * 
+     * @return The proper replacement, or null, if the entity is unknown.
+     */
+    private String resolveStandardEntity(String entity) {
+        if ("lt".equals(entity)) {
+            return "<";
+        } else if ("gt".equals(entity)) {
+            return ">";
+        } else if ("amp".equals(entity)) {
+            return "&";
+        } else if ("apos".equals(entity)) {
+            return "'";
+        } else if ("quot".equals(entity)) {
+            return "\"";
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/parsers/SAXParserFactoryImpl.java b/xml/src/main/java/org/apache/harmony/xml/parsers/SAXParserFactoryImpl.java
new file mode 100644
index 0000000..6846216
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/parsers/SAXParserFactoryImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.parsers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.SAXNotRecognizedException;
+
+/**
+ * Provides a straightforward SAXParserFactory implementation based on
+ * Expat. The class is used internally only, thus only notable members
+ * that are not already in the abstract superclass are documented.
+ */
+public class SAXParserFactoryImpl extends SAXParserFactory {
+
+    private static final String NAMESPACES
+            = "http://xml.org/sax/features/namespaces";
+    
+    private static final String VALIDATION
+            = "http://xml.org/sax/features/validation";
+    
+    private Map<String, Boolean> features = new HashMap<String, Boolean>();
+
+    @Override
+    public boolean getFeature(String name) throws SAXNotRecognizedException {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        
+        if (!name.startsWith("http://xml.org/sax/features/")) {
+            throw new SAXNotRecognizedException(name);
+        }
+        
+        return Boolean.TRUE.equals(features.get(name));
+    }
+
+    @Override
+    public boolean isNamespaceAware() {
+        try {
+            return getFeature(NAMESPACES);
+        } catch (SAXNotRecognizedException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+
+    @Override
+    public boolean isValidating() {
+        try {
+            return getFeature(VALIDATION);
+        } catch (SAXNotRecognizedException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+
+    @Override
+    public SAXParser newSAXParser() throws ParserConfigurationException {
+        if (isValidating()) {
+            throw new ParserConfigurationException(
+                    "No validating SAXParser implementation available");
+        }
+        
+        try {
+            return new SAXParserImpl(features);
+        } catch (Exception ex) {
+            throw new ParserConfigurationException(ex.toString());
+        }
+    }
+
+    @Override
+    public void setFeature(String name, boolean value) throws SAXNotRecognizedException {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        
+        if (!name.startsWith("http://xml.org/sax/features/")) {
+            throw new SAXNotRecognizedException(name);
+        }
+        
+        if (value) {
+            features.put(name, Boolean.TRUE);
+        } else {
+            // This is needed to disable features that are enabled by default.
+            features.put(name, Boolean.FALSE);
+        }
+    }
+
+    @Override
+    public void setNamespaceAware(boolean value) {
+        try {
+            setFeature(NAMESPACES, value);
+        } catch (SAXNotRecognizedException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+
+    @Override
+    public void setValidating(boolean value) {
+        try {
+            setFeature(VALIDATION, value);
+        } catch (SAXNotRecognizedException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+}
diff --git a/xml/src/main/java/org/apache/harmony/xml/parsers/SAXParserImpl.java b/xml/src/main/java/org/apache/harmony/xml/parsers/SAXParserImpl.java
new file mode 100644
index 0000000..b3af61f
--- /dev/null
+++ b/xml/src/main/java/org/apache/harmony/xml/parsers/SAXParserImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xml.parsers;
+
+import org.apache.harmony.xml.ExpatReader;
+
+import java.util.Map;
+
+import javax.xml.parsers.SAXParser;
+
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderAdapter;
+
+/**
+ * Provides a straightforward SAXParser implementation based on ExpatReader.
+ * The class is used internally only, thus only notable members that are not
+ * already in the abstract superclass are documented. Hope that's ok.
+ */
+class SAXParserImpl extends SAXParser {
+
+    private XMLReader reader;
+
+    private Parser parser;
+
+    SAXParserImpl(Map<String, Boolean> features)
+            throws SAXNotRecognizedException, SAXNotSupportedException {
+        reader = new ExpatReader();
+
+        for (Map.Entry<String,Boolean> entry : features.entrySet()) {
+            reader.setFeature(entry.getKey(), entry.getValue());
+        }
+    }
+
+    @Override
+    public Parser getParser() {
+        if (parser == null) {
+            parser = new XMLReaderAdapter(reader);
+        }
+
+        return parser;
+    }
+
+    @Override
+    public Object getProperty(String name) throws SAXNotRecognizedException,
+            SAXNotSupportedException {
+        return reader.getProperty(name);
+    }
+
+    @Override
+    public XMLReader getXMLReader() {
+        return reader;
+    }
+
+    @Override
+    public boolean isNamespaceAware() {
+        try {
+            return reader.getFeature("http://xml.org/sax/features/namespaces");
+        } catch (SAXException ex) {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean isValidating() {
+        return false;
+    }
+
+    @Override
+    public void setProperty(String name, Object value)
+            throws SAXNotRecognizedException, SAXNotSupportedException {
+        reader.setProperty(name, value);
+    }
+}
diff --git a/xml/src/main/java/org/kxml2/io/KXmlParser.java b/xml/src/main/java/org/kxml2/io/KXmlParser.java
new file mode 100644
index 0000000..0727bc7
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/io/KXmlParser.java
@@ -0,0 +1,1440 @@
+/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The  above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE. */
+
+// Contributors: Paul Hackenberger (unterminated entity handling in relaxed mode)
+
+package org.kxml2.io;
+
+import java.io.*;
+import java.util.*;
+
+import org.xmlpull.v1.*;
+
+/** A simple, pull based XML parser. This classe replaces the kXML 1
+    XmlParser class and the corresponding event classes. */
+
+public class KXmlParser implements XmlPullParser {
+
+    private Object location;
+    static final private String UNEXPECTED_EOF = "Unexpected EOF";
+    static final private String ILLEGAL_TYPE = "Wrong event type";
+    static final private int LEGACY = 999;
+    static final private int XML_DECL = 998;
+
+    // general
+
+    private String version;
+    private Boolean standalone;
+
+    private boolean processNsp;
+    private boolean relaxed;
+    private Hashtable entityMap;
+    private int depth;
+    private String[] elementStack = new String[16];
+    private String[] nspStack = new String[8];
+    private int[] nspCounts = new int[4];
+
+    // source
+
+    private Reader reader;
+    private String encoding;
+    private char[] srcBuf;
+
+    private int srcPos;
+    private int srcCount;
+
+    private int line;
+    private int column;
+
+    // txtbuffer
+
+    private char[] txtBuf = new char[128];
+    private int txtPos;
+
+    // Event-related
+
+    private int type;
+    //private String text;
+    private boolean isWhitespace;
+    private String namespace;
+    private String prefix;
+    private String name;
+
+    private boolean degenerated;
+    private int attributeCount;
+    private String[] attributes = new String[16];
+    private int stackMismatch = 0;
+    private String error;
+
+    /** 
+     * A separate peek buffer seems simpler than managing
+     * wrap around in the first level read buffer */
+
+    private int[] peek = new int[2];
+    private int peekCount;
+    private boolean wasCR;
+
+    private boolean unresolved;
+    private boolean token;
+
+    public KXmlParser() {
+        // BEGIN android-changed
+        // We don't have a Runtime class at this time.
+        // srcBuf =
+        //         new char[Runtime.getRuntime().freeMemory() >= 1048576 ? 8192 : 128];
+        srcBuf = new char[8192];
+        // END android-changed
+    }
+
+    private final boolean isProp(String n1, boolean prop, String n2) {
+        if (!n1.startsWith("http://xmlpull.org/v1/doc/"))
+            return false;
+        if (prop)
+            return n1.substring(42).equals(n2);
+        else
+            return n1.substring(40).equals(n2);
+    }
+
+    private final boolean adjustNsp() throws XmlPullParserException {
+
+        boolean any = false;
+
+        for (int i = 0; i < attributeCount << 2; i += 4) {
+            // * 4 - 4; i >= 0; i -= 4) {
+
+            String attrName = attributes[i + 2];
+            int cut = attrName.indexOf(':');
+            String prefix;
+
+            if (cut != -1) {
+                prefix = attrName.substring(0, cut);
+                attrName = attrName.substring(cut + 1);
+            }
+            else if (attrName.equals("xmlns")) {
+                prefix = attrName;
+                attrName = null;
+            }
+            else
+                continue;
+
+            if (!prefix.equals("xmlns")) {
+                any = true;
+            }
+            else {
+                int j = (nspCounts[depth]++) << 1;
+
+                nspStack = ensureCapacity(nspStack, j + 2);
+                nspStack[j] = attrName;
+                nspStack[j + 1] = attributes[i + 3];
+
+                if (attrName != null && attributes[i + 3].equals(""))
+                    error("illegal empty namespace");
+
+                //  prefixMap = new PrefixMap (prefixMap, attrName, attr.getValue ());
+
+                //System.out.println (prefixMap);
+
+                System.arraycopy(
+                    attributes,
+                    i + 4,
+                    attributes,
+                    i,
+                    ((--attributeCount) << 2) - i);
+
+                i -= 4;
+            }
+        }
+
+        if (any) {
+            for (int i = (attributeCount << 2) - 4; i >= 0; i -= 4) {
+
+                String attrName = attributes[i + 2];
+                int cut = attrName.indexOf(':');
+
+                if (cut == 0 && !relaxed)
+                    throw new RuntimeException(
+                        "illegal attribute name: " + attrName + " at " + this);
+
+                else if (cut != -1) {
+                    String attrPrefix = attrName.substring(0, cut);
+
+                    attrName = attrName.substring(cut + 1);
+
+                    String attrNs = getNamespace(attrPrefix);
+
+                    if (attrNs == null && !relaxed)
+                        throw new RuntimeException(
+                            "Undefined Prefix: " + attrPrefix + " in " + this);
+
+                    attributes[i] = attrNs;
+                    attributes[i + 1] = attrPrefix;
+                    attributes[i + 2] = attrName;
+
+                    /*
+                                        if (!relaxed) {
+                                            for (int j = (attributeCount << 2) - 4; j > i; j -= 4)
+                                                if (attrName.equals(attributes[j + 2])
+                                                    && attrNs.equals(attributes[j]))
+                                                    exception(
+                                                        "Duplicate Attribute: {"
+                                                            + attrNs
+                                                            + "}"
+                                                            + attrName);
+                                        }
+                        */
+                }
+            }
+        }
+
+        int cut = name.indexOf(':');
+
+        if (cut == 0)
+            error("illegal tag name: " + name);
+
+        if (cut != -1) {
+            prefix = name.substring(0, cut);
+            name = name.substring(cut + 1);
+        }
+
+        this.namespace = getNamespace(prefix);
+
+        if (this.namespace == null) {
+            if (prefix != null)
+                error("undefined prefix: " + prefix);
+            this.namespace = NO_NAMESPACE;
+        }
+
+        return any;
+    }
+
+    private final String[] ensureCapacity(String[] arr, int required) {
+        if (arr.length >= required)
+            return arr;
+        String[] bigger = new String[required + 16];
+        System.arraycopy(arr, 0, bigger, 0, arr.length);
+        return bigger;
+    }
+
+    private final void error(String desc) throws XmlPullParserException {
+        if (relaxed) {
+            if (error == null)
+                error = "ERR: " + desc;
+        }
+        else
+            exception(desc);
+    }
+
+    private final void exception(String desc) throws XmlPullParserException {
+        throw new XmlPullParserException(
+            desc.length() < 100 ? desc : desc.substring(0, 100) + "\n",
+            this,
+            null);
+    }
+
+    /** 
+     * common base for next and nextToken. Clears the state, except from 
+     * txtPos and whitespace. Does not set the type variable */
+
+    private final void nextImpl() throws IOException, XmlPullParserException {
+
+        if (reader == null)
+            exception("No Input specified");
+
+        if (type == END_TAG)
+            depth--;
+
+        while (true) {
+            attributeCount = -1;
+
+            // degenerated needs to be handled before error because of possible
+            // processor expectations(!)
+
+            if (degenerated) {
+                degenerated = false;
+                type = END_TAG;
+                return;
+            }
+
+
+            if (error != null) {
+                for (int i = 0; i < error.length(); i++)
+                    push(error.charAt(i));
+                //                text = error;
+                error = null;
+                type = COMMENT;
+                return;
+            }
+
+
+            if (relaxed
+                && (stackMismatch > 0 || (peek(0) == -1 && depth > 0))) {
+                int sp = (depth - 1) << 2;
+                type = END_TAG;
+                namespace = elementStack[sp];
+                prefix = elementStack[sp + 1];
+                name = elementStack[sp + 2];
+                if (stackMismatch != 1)
+                    error = "missing end tag /" + name + " inserted";
+                if (stackMismatch > 0)
+                    stackMismatch--;
+                return;
+            }
+
+            prefix = null;
+            name = null;
+            namespace = null;
+            //            text = null;
+
+            type = peekType();
+
+            switch (type) {
+
+                case ENTITY_REF :
+                    pushEntity();
+                    return;
+
+                case START_TAG :
+                    parseStartTag(false);
+                    return;
+
+                case END_TAG :
+                    parseEndTag();
+                    return;
+
+                case END_DOCUMENT :
+                    return;
+
+                case TEXT :
+                    pushText('<', !token);
+                    if (depth == 0) {
+                        if (isWhitespace)
+                            type = IGNORABLE_WHITESPACE;
+                        // make exception switchable for instances.chg... !!!!
+                        //    else 
+                        //    exception ("text '"+getText ()+"' not allowed outside root element");
+                    }
+                    return;
+
+                default :
+                    type = parseLegacy(token);
+                    if (type != XML_DECL)
+                        return;
+            }
+        }
+    }
+
+    private final int parseLegacy(boolean push)
+        throws IOException, XmlPullParserException {
+
+        String req = "";
+        int term;
+        int result;
+        int prev = 0;
+
+        read(); // <
+        int c = read();
+
+        if (c == '?') {
+            if ((peek(0) == 'x' || peek(0) == 'X')
+                && (peek(1) == 'm' || peek(1) == 'M')) {
+
+                if (push) {
+                    push(peek(0));
+                    push(peek(1));
+                }
+                read();
+                read();
+
+                if ((peek(0) == 'l' || peek(0) == 'L') && peek(1) <= ' ') {
+
+                    if (line != 1 || column > 4)
+                        error("PI must not start with xml");
+
+                    parseStartTag(true);
+
+                    if (attributeCount < 1 || !"version".equals(attributes[2]))
+                        error("version expected");
+
+                    version = attributes[3];
+
+                    int pos = 1;
+
+                    if (pos < attributeCount
+                        && "encoding".equals(attributes[2 + 4])) {
+                        encoding = attributes[3 + 4];
+                        pos++;
+                    }
+
+                    if (pos < attributeCount
+                        && "standalone".equals(attributes[4 * pos + 2])) {
+                        String st = attributes[3 + 4 * pos];
+                        if ("yes".equals(st))
+                            standalone = new Boolean(true);
+                        else if ("no".equals(st))
+                            standalone = new Boolean(false);
+                        else
+                            error("illegal standalone value: " + st);
+                        pos++;
+                    }
+
+                    if (pos != attributeCount)
+                        error("illegal xmldecl");
+
+                    isWhitespace = true;
+                    txtPos = 0;
+
+                    return XML_DECL;
+                }
+            }
+
+            /*            int c0 = read ();
+                        int c1 = read ();
+                        int */
+
+            term = '?';
+            result = PROCESSING_INSTRUCTION;
+        }
+        else if (c == '!') {
+            if (peek(0) == '-') {
+                result = COMMENT;
+                req = "--";
+                term = '-';
+            }
+            else if (peek(0) == '[') {
+                result = CDSECT;
+                req = "[CDATA[";
+                term = ']';
+                push = true;
+            }
+            else {
+                result = DOCDECL;
+                req = "DOCTYPE";
+                term = -1;
+            }
+        }
+        else {
+            error("illegal: <" + c);
+            return COMMENT;
+        }
+
+        for (int i = 0; i < req.length(); i++)
+            read(req.charAt(i));
+
+        if (result == DOCDECL)
+            parseDoctype(push);
+        else {
+            while (true) {
+                c = read();
+                if (c == -1){
+                    error(UNEXPECTED_EOF);
+                    return COMMENT;
+                }
+
+                if (push)
+                    push(c);
+
+                if ((term == '?' || c == term)
+                    && peek(0) == term
+                    && peek(1) == '>')
+                    break;
+
+                prev = c;
+            }
+
+            if (term == '-' && prev == '-')
+                error("illegal comment delimiter: --->");
+
+            read();
+            read();
+
+            if (push && term != '?')
+                txtPos--;
+
+        }
+        return result;
+    }
+
+    /** precondition: &lt! consumed */
+
+    private final void parseDoctype(boolean push)
+        throws IOException, XmlPullParserException {
+
+        int nesting = 1;
+        boolean quoted = false;
+
+        // read();
+
+        while (true) {
+            int i = read();
+            switch (i) {
+
+                case -1 :
+                    error(UNEXPECTED_EOF);
+                    return;
+
+                case '\'' :
+                    quoted = !quoted;
+                    break;
+
+                case '<' :
+                    if (!quoted)
+                        nesting++;
+                    break;
+
+                case '>' :
+                    if (!quoted) {
+                        if ((--nesting) == 0)
+                            return;
+                    }
+                    break;
+            }
+            if (push)
+                push(i);
+        }
+    }
+
+    /* precondition: &lt;/ consumed */
+
+    private final void parseEndTag()
+        throws IOException, XmlPullParserException {
+
+        read(); // '<'
+        read(); // '/'
+        name = readName();
+        skip();
+        read('>');
+
+        int sp = (depth - 1) << 2;
+
+        if (depth == 0) {
+            error("element stack empty");
+            type = COMMENT;
+            return;
+        }
+
+        if (!name.equals(elementStack[sp + 3])) {
+            error("expected: /" + elementStack[sp + 3] + " read: " + name);
+
+            // become case insensitive in relaxed mode
+
+            int probe = sp;
+            while (probe >= 0 && !name.toLowerCase().equals(elementStack[probe + 3].toLowerCase())) {
+                stackMismatch++;
+                probe -= 4;
+            }
+
+            if (probe < 0) {
+                stackMismatch = 0;
+                //            text = "unexpected end tag ignored";
+                type = COMMENT;
+                return;
+            }
+        }
+
+        namespace = elementStack[sp];
+        prefix = elementStack[sp + 1];
+        name = elementStack[sp + 2];
+    }
+
+    private final int peekType() throws IOException {
+        switch (peek(0)) {
+            case -1 :
+                return END_DOCUMENT;
+            case '&' :
+                return ENTITY_REF;
+            case '<' :
+                switch (peek(1)) {
+                    case '/' :
+                        return END_TAG;
+                    case '?' :
+                    case '!' :
+                        return LEGACY;
+                    default :
+                        return START_TAG;
+                }
+            default :
+                return TEXT;
+        }
+    }
+
+    private final String get(int pos) {
+        return new String(txtBuf, pos, txtPos - pos);
+    }
+
+    /*
+    private final String pop (int pos) {
+    String result = new String (txtBuf, pos, txtPos - pos);
+    txtPos = pos;
+    return result;
+    }
+    */
+
+    private final void push(int c) {
+
+        isWhitespace &= c <= ' ';
+
+        if (txtPos == txtBuf.length) {
+            char[] bigger = new char[txtPos * 4 / 3 + 4];
+            System.arraycopy(txtBuf, 0, bigger, 0, txtPos);
+            txtBuf = bigger;
+        }
+
+        txtBuf[txtPos++] = (char) c;
+    }
+
+    /** Sets name and attributes */
+
+    private final void parseStartTag(boolean xmldecl)
+        throws IOException, XmlPullParserException {
+
+        if (!xmldecl)
+            read();
+        name = readName();
+        attributeCount = 0;
+
+        while (true) {
+            skip();
+
+            int c = peek(0);
+
+            if (xmldecl) {
+                if (c == '?') {
+                    read();
+                    read('>');
+                    return;
+                }
+            }
+            else {
+                if (c == '/') {
+                    degenerated = true;
+                    read();
+                    skip();
+                    read('>');
+                    break;
+                }
+
+                if (c == '>' && !xmldecl) {
+                    read();
+                    break;
+                }
+            }
+
+            if (c == -1) {
+                error(UNEXPECTED_EOF);
+                //type = COMMENT;
+                return;
+            }
+
+            String attrName = readName();
+
+            if (attrName.length() == 0) {
+                error("attr name expected");
+               //type = COMMENT;
+                break;
+            }
+
+            int i = (attributeCount++) << 2;
+
+            attributes = ensureCapacity(attributes, i + 4);
+
+            attributes[i++] = "";
+            attributes[i++] = null;
+            attributes[i++] = attrName;
+
+            skip();
+
+            if (peek(0) != '=') {
+                error("Attr.value missing f. "+attrName);
+                attributes[i] = "1";
+            }
+            else {
+                read('=');
+                skip();
+                int delimiter = peek(0);
+
+                if (delimiter != '\'' && delimiter != '"') {
+                    error("attr value delimiter missing!");
+                    delimiter = ' ';
+                }
+                else 
+                    read();
+                
+                int p = txtPos;
+                pushText(delimiter, true);
+
+                attributes[i] = get(p);
+                txtPos = p;
+
+                if (delimiter != ' ')
+                    read(); // skip endquote
+            }
+        }
+
+        int sp = depth++ << 2;
+
+        elementStack = ensureCapacity(elementStack, sp + 4);
+        elementStack[sp + 3] = name;
+
+        if (depth >= nspCounts.length) {
+            int[] bigger = new int[depth + 4];
+            System.arraycopy(nspCounts, 0, bigger, 0, nspCounts.length);
+            nspCounts = bigger;
+        }
+
+        nspCounts[depth] = nspCounts[depth - 1];
+
+        /*
+                if(!relaxed){
+                for (int i = attributeCount - 1; i > 0; i--) {
+                    for (int j = 0; j < i; j++) {
+                        if (getAttributeName(i).equals(getAttributeName(j)))
+                            exception("Duplicate Attribute: " + getAttributeName(i));
+                    }
+                }
+                }
+        */
+        if (processNsp)
+            adjustNsp();
+        else
+            namespace = "";
+
+        elementStack[sp] = namespace;
+        elementStack[sp + 1] = prefix;
+        elementStack[sp + 2] = name;
+    }
+
+    /** 
+     * result: isWhitespace; if the setName parameter is set,
+     * the name of the entity is stored in "name" */
+
+    private final void pushEntity()
+        throws IOException, XmlPullParserException {
+
+        push(read()); // &
+        
+        
+        int pos = txtPos;
+
+        while (true) {
+            int c = read();
+            if (c == ';')
+                break;
+            if (c < 128
+                && (c < '0' || c > '9')
+                && (c < 'a' || c > 'z')
+                && (c < 'A' || c > 'Z')
+                && c != '_'
+                && c != '-'
+                && c != '#') {
+                if(!relaxed){
+                    error("unterminated entity ref");
+                }
+                //; ends with:"+(char)c);           
+                if (c != -1)
+                    push(c);
+                return;
+            }
+
+            push(c);
+        }
+
+        String code = get(pos);
+        txtPos = pos - 1;
+        if (token && type == ENTITY_REF){
+            name = code;
+        }
+
+        if (code.charAt(0) == '#') {
+            int c =
+                (code.charAt(1) == 'x'
+                    ? Integer.parseInt(code.substring(2), 16)
+                    : Integer.parseInt(code.substring(1)));
+            push(c);
+            return;
+        }
+
+        String result = (String) entityMap.get(code);
+
+        unresolved = result == null;
+
+        if (unresolved) {
+            if (!token)
+                error("unresolved: &" + code + ";");
+        }
+        else {
+            for (int i = 0; i < result.length(); i++)
+                push(result.charAt(i));
+        }
+    }
+
+    /** types:
+    '<': parse to any token (for nextToken ())
+    '"': parse to quote
+    ' ': parse to whitespace or '>'
+    */
+
+    private final void pushText(int delimiter, boolean resolveEntities)
+        throws IOException, XmlPullParserException {
+
+        int next = peek(0);
+        int cbrCount = 0;
+
+        while (next != -1 && next != delimiter) { // covers eof, '<', '"'
+
+            if (delimiter == ' ')
+                if (next <= ' ' || next == '>')
+                    break;
+
+            if (next == '&') {
+                if (!resolveEntities)
+                    break;
+
+                pushEntity();
+            }
+            else if (next == '\n' && type == START_TAG) {
+                read();
+                push(' ');
+            }
+            else
+                push(read());
+
+            if (next == '>' && cbrCount >= 2 && delimiter != ']')
+                error("Illegal: ]]>");
+
+            if (next == ']')
+                cbrCount++;
+            else
+                cbrCount = 0;
+
+            next = peek(0);
+        }
+    }
+
+    private final void read(char c)
+        throws IOException, XmlPullParserException {
+        int a = read();
+        if (a != c)
+            error("expected: '" + c + "' actual: '" + ((char) a) + "'");
+    }
+
+    private final int read() throws IOException {
+        int result;
+
+        if (peekCount == 0)
+            result = peek(0);
+        else {
+            result = peek[0];
+            peek[0] = peek[1];
+        }
+        //        else {
+        //            result = peek[0]; 
+        //            System.arraycopy (peek, 1, peek, 0, peekCount-1);
+        //        }
+        peekCount--;
+
+        column++;
+
+        if (result == '\n') {
+
+            line++;
+            column = 1;
+        }
+
+        return result;
+    }
+
+    /** Does never read more than needed */
+
+    private final int peek(int pos) throws IOException {
+
+        while (pos >= peekCount) {
+
+            int nw;
+
+            if (srcBuf.length <= 1)
+                nw = reader.read();
+            else if (srcPos < srcCount)
+                nw = srcBuf[srcPos++];
+            else {
+                srcCount = reader.read(srcBuf, 0, srcBuf.length);
+                if (srcCount <= 0)
+                    nw = -1;
+                else
+                    nw = srcBuf[0];
+
+                srcPos = 1;
+            }
+
+            if (nw == '\r') {
+                wasCR = true;
+                peek[peekCount++] = '\n';
+            }
+            else {
+                if (nw == '\n') {
+                    if (!wasCR)
+                        peek[peekCount++] = '\n';
+                }
+                else
+                    peek[peekCount++] = nw;
+
+                wasCR = false;
+            }
+        }
+
+        return peek[pos];
+    }
+
+    private final String readName()
+        throws IOException, XmlPullParserException {
+
+        int pos = txtPos;
+        int c = peek(0);
+        if ((c < 'a' || c > 'z')
+            && (c < 'A' || c > 'Z')
+            && c != '_'
+            && c != ':'
+            && c < 0x0c0
+            && !relaxed)
+            error("name expected");
+
+        do {
+            push(read());
+            c = peek(0);
+        }
+        while ((c >= 'a' && c <= 'z')
+            || (c >= 'A' && c <= 'Z')
+            || (c >= '0' && c <= '9')
+            || c == '_'
+            || c == '-'
+            || c == ':'
+            || c == '.'
+            || c >= 0x0b7);
+
+        String result = get(pos);
+        txtPos = pos;
+        return result;
+    }
+
+    private final void skip() throws IOException {
+
+        while (true) {
+            int c = peek(0);
+            if (c > ' ' || c == -1)
+                break;
+            read();
+        }
+    }
+
+    //  public part starts here...
+
+    public void setInput(Reader reader) throws XmlPullParserException {
+        this.reader = reader;
+
+        line = 1;
+        column = 0;
+        type = START_DOCUMENT;
+        name = null;
+        namespace = null;
+        degenerated = false;
+        attributeCount = -1;
+        encoding = null;
+        version = null;
+        standalone = null;
+
+        if (reader == null)
+            return;
+
+        srcPos = 0;
+        srcCount = 0;
+        peekCount = 0;
+        depth = 0;
+
+        entityMap = new Hashtable();
+        entityMap.put("amp", "&");
+        entityMap.put("apos", "'");
+        entityMap.put("gt", ">");
+        entityMap.put("lt", "<");
+        entityMap.put("quot", "\"");
+    }
+
+    public void setInput(InputStream is, String _enc)
+        throws XmlPullParserException {
+
+        srcPos = 0;
+        srcCount = 0;
+        String enc = _enc;
+
+        if (is == null)
+            throw new IllegalArgumentException();
+
+        try {
+
+            if (enc == null) {
+                // read four bytes 
+
+                int chk = 0;
+
+                while (srcCount < 4) {
+                    int i = is.read();
+                    if (i == -1)
+                        break;
+                    chk = (chk << 8) | i;
+                    srcBuf[srcCount++] = (char) i;
+                }
+
+                if (srcCount == 4) {
+                    switch (chk) {
+                        case 0x00000FEFF :
+                            enc = "UTF-32BE";
+                            srcCount = 0;
+                            break;
+
+                        case 0x0FFFE0000 :
+                            enc = "UTF-32LE";
+                            srcCount = 0;
+                            break;
+
+                        case 0x03c :
+                            enc = "UTF-32BE";
+                            srcBuf[0] = '<';
+                            srcCount = 1;
+                            break;
+
+                        case 0x03c000000 :
+                            enc = "UTF-32LE";
+                            srcBuf[0] = '<';
+                            srcCount = 1;
+                            break;
+
+                        case 0x0003c003f :
+                            enc = "UTF-16BE";
+                            srcBuf[0] = '<';
+                            srcBuf[1] = '?';
+                            srcCount = 2;
+                            break;
+
+                        case 0x03c003f00 :
+                            enc = "UTF-16LE";
+                            srcBuf[0] = '<';
+                            srcBuf[1] = '?';
+                            srcCount = 2;
+                            break;
+
+                        case 0x03c3f786d :
+                            while (true) {
+                                int i = is.read();
+                                if (i == -1)
+                                    break;
+                                srcBuf[srcCount++] = (char) i;
+                                if (i == '>') {
+                                    String s = new String(srcBuf, 0, srcCount);
+                                    int i0 = s.indexOf("encoding");
+                                    if (i0 != -1) {
+                                        while (s.charAt(i0) != '"'
+                                            && s.charAt(i0) != '\'')
+                                            i0++;
+                                        char deli = s.charAt(i0++);
+                                        int i1 = s.indexOf(deli, i0);
+                                        enc = s.substring(i0, i1);
+                                    }
+                                    break;
+                                }
+                            }
+
+                        default :
+                            if ((chk & 0x0ffff0000) == 0x0FEFF0000) {
+                                enc = "UTF-16BE";
+                                srcBuf[0] =
+                                    (char) ((srcBuf[2] << 8) | srcBuf[3]);
+                                srcCount = 1;
+                            }
+                            else if ((chk & 0x0ffff0000) == 0x0fffe0000) {
+                                enc = "UTF-16LE";
+                                srcBuf[0] =
+                                    (char) ((srcBuf[3] << 8) | srcBuf[2]);
+                                srcCount = 1;
+                            }
+                            else if ((chk & 0x0ffffff00) == 0x0EFBBBF00) {
+                                enc = "UTF-8";
+                                srcBuf[0] = srcBuf[3];
+                                srcCount = 1;
+                            }
+                    }
+                }
+            }
+
+            if (enc == null)
+                enc = "UTF-8";
+
+            int sc = srcCount;
+            setInput(new InputStreamReader(is, enc));
+            encoding = _enc;
+            srcCount = sc;
+        }
+        catch (Exception e) {
+            throw new XmlPullParserException(
+                "Invalid stream or encoding: " + e.toString(),
+                this,
+                e);
+        }
+    }
+
+    public boolean getFeature(String feature) {
+        if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature))
+            return processNsp;
+        else if (isProp(feature, false, "relaxed"))
+            return relaxed;
+        else
+            return false;
+    }
+
+    public String getInputEncoding() {
+        return encoding;
+    }
+
+    public void defineEntityReplacementText(String entity, String value)
+        throws XmlPullParserException {
+        if (entityMap == null)
+            throw new RuntimeException("entity replacement text must be defined after setInput!");
+        entityMap.put(entity, value);
+    }
+
+    public Object getProperty(String property) {
+        if (isProp(property, true, "xmldecl-version"))
+            return version;
+        if (isProp(property, true, "xmldecl-standalone"))
+            return standalone;
+        if (isProp(property, true, "location"))            
+            return location != null ? location : reader.toString();
+        return null;
+    }
+
+    public int getNamespaceCount(int depth) {
+        if (depth > this.depth)
+            throw new IndexOutOfBoundsException();
+        return nspCounts[depth];
+    }
+
+    public String getNamespacePrefix(int pos) {
+        return nspStack[pos << 1];
+    }
+
+    public String getNamespaceUri(int pos) {
+        return nspStack[(pos << 1) + 1];
+    }
+
+    public String getNamespace(String prefix) {
+
+        if ("xml".equals(prefix))
+            return "http://www.w3.org/XML/1998/namespace";
+        if ("xmlns".equals(prefix))
+            return "http://www.w3.org/2000/xmlns/";
+
+        for (int i = (getNamespaceCount(depth) << 1) - 2; i >= 0; i -= 2) {
+            if (prefix == null) {
+                if (nspStack[i] == null)
+                    return nspStack[i + 1];
+            }
+            else if (prefix.equals(nspStack[i]))
+                return nspStack[i + 1];
+        }
+        return null;
+    }
+
+    public int getDepth() {
+        return depth;
+    }
+
+    public String getPositionDescription() {
+
+        StringBuffer buf =
+            new StringBuffer(type < TYPES.length ? TYPES[type] : "unknown");
+        buf.append(' ');
+
+        if (type == START_TAG || type == END_TAG) {
+            if (degenerated)
+                buf.append("(empty) ");
+            buf.append('<');
+            if (type == END_TAG)
+                buf.append('/');
+
+            if (prefix != null)
+                buf.append("{" + namespace + "}" + prefix + ":");
+            buf.append(name);
+
+            int cnt = attributeCount << 2;
+            for (int i = 0; i < cnt; i += 4) {
+                buf.append(' ');
+                if (attributes[i + 1] != null)
+                    buf.append(
+                        "{" + attributes[i] + "}" + attributes[i + 1] + ":");
+                buf.append(attributes[i + 2] + "='" + attributes[i + 3] + "'");
+            }
+
+            buf.append('>');
+        }
+        else if (type == IGNORABLE_WHITESPACE);
+        else if (type != TEXT)
+            buf.append(getText());
+        else if (isWhitespace)
+            buf.append("(whitespace)");
+        else {
+            String text = getText();
+            if (text.length() > 16)
+                text = text.substring(0, 16) + "...";
+            buf.append(text);
+        }
+
+        buf.append("@"+line + ":" + column);
+        if(location != null){
+            buf.append(" in ");
+            buf.append(location);
+        }
+        else if(reader != null){
+            buf.append(" in ");
+            buf.append(reader.toString());
+        }
+        return buf.toString();
+    }
+
+    public int getLineNumber() {
+        return line;
+    }
+
+    public int getColumnNumber() {
+        return column;
+    }
+
+    public boolean isWhitespace() throws XmlPullParserException {
+        if (type != TEXT && type != IGNORABLE_WHITESPACE && type != CDSECT)
+            exception(ILLEGAL_TYPE);
+        return isWhitespace;
+    }
+
+    public String getText() {
+        return type < TEXT
+            || (type == ENTITY_REF && unresolved) ? null : get(0);
+    }
+
+    public char[] getTextCharacters(int[] poslen) {
+        if (type >= TEXT) {
+            if (type == ENTITY_REF) {
+                poslen[0] = 0;
+                poslen[1] = name.length();
+                return name.toCharArray();
+            }
+            poslen[0] = 0;
+            poslen[1] = txtPos;
+            return txtBuf;
+        }
+
+        poslen[0] = -1;
+        poslen[1] = -1;
+        return null;
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getPrefix() {
+        return prefix;
+    }
+
+    public boolean isEmptyElementTag() throws XmlPullParserException {
+        if (type != START_TAG)
+            exception(ILLEGAL_TYPE);
+        return degenerated;
+    }
+
+    public int getAttributeCount() {
+        return attributeCount;
+    }
+
+    public String getAttributeType(int index) {
+        return "CDATA";
+    }
+
+    public boolean isAttributeDefault(int index) {
+        return false;
+    }
+
+    public String getAttributeNamespace(int index) {
+        if (index >= attributeCount)
+            throw new IndexOutOfBoundsException();
+        return attributes[index << 2];
+    }
+
+    public String getAttributeName(int index) {
+        if (index >= attributeCount)
+            throw new IndexOutOfBoundsException();
+        return attributes[(index << 2) + 2];
+    }
+
+    public String getAttributePrefix(int index) {
+        if (index >= attributeCount)
+            throw new IndexOutOfBoundsException();
+        return attributes[(index << 2) + 1];
+    }
+
+    public String getAttributeValue(int index) {
+        if (index >= attributeCount)
+            throw new IndexOutOfBoundsException();
+        return attributes[(index << 2) + 3];
+    }
+
+    public String getAttributeValue(String namespace, String name) {
+
+        for (int i = (attributeCount << 2) - 4; i >= 0; i -= 4) {
+            if (attributes[i + 2].equals(name)
+                && (namespace == null || attributes[i].equals(namespace)))
+                return attributes[i + 3];
+        }
+
+        return null;
+    }
+
+    public int getEventType() throws XmlPullParserException {
+        return type;
+    }
+
+    public int next() throws XmlPullParserException, IOException {
+
+        txtPos = 0;
+        isWhitespace = true;
+        int minType = 9999;
+        token = false;
+
+        do {
+            nextImpl();
+            if (type < minType)
+                minType = type;
+            //        if (curr <= TEXT) type = curr; 
+        }
+        while (minType > ENTITY_REF // ignorable
+            || (minType >= TEXT && peekType() >= TEXT));
+
+        type = minType;
+        if (type > TEXT)
+            type = TEXT;
+
+        return type;
+    }
+
+    public int nextToken() throws XmlPullParserException, IOException {
+
+        isWhitespace = true;
+        txtPos = 0;
+
+        token = true;
+        nextImpl();
+        return type;
+    }
+
+    //
+    // utility methods to make XML parsing easier ...
+
+    public int nextTag() throws XmlPullParserException, IOException {
+
+        next();
+        if (type == TEXT && isWhitespace)
+            next();
+
+        if (type != END_TAG && type != START_TAG)
+            exception("unexpected type");
+
+        return type;
+    }
+
+    public void require(int type, String namespace, String name)
+        throws XmlPullParserException, IOException {
+
+        if (type != this.type
+            || (namespace != null && !namespace.equals(getNamespace()))
+            || (name != null && !name.equals(getName())))
+            exception(
+                "expected: " + TYPES[type] + " {" + namespace + "}" + name);
+    }
+
+    public String nextText() throws XmlPullParserException, IOException {
+        if (type != START_TAG)
+            exception("precondition: START_TAG");
+
+        next();
+
+        String result;
+
+        if (type == TEXT) {
+            result = getText();
+            next();
+        }
+        else
+            result = "";
+
+        if (type != END_TAG)
+            exception("END_TAG expected");
+
+        return result;
+    }
+
+    public void setFeature(String feature, boolean value)
+        throws XmlPullParserException {
+        if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature))
+            processNsp = value;
+        else if (isProp(feature, false, "relaxed"))
+            relaxed = value;
+        else
+            exception("unsupported feature: " + feature);
+    }
+
+    public void setProperty(String property, Object value)
+        throws XmlPullParserException {
+        if(isProp(property, true, "location"))
+            location = value;
+        else
+            throw new XmlPullParserException("unsupported property: " + property);
+    }
+
+    /**
+      * Skip sub tree that is currently porser positioned on.
+      * <br>NOTE: parser must be on START_TAG and when funtion returns
+      * parser will be positioned on corresponding END_TAG. 
+      */
+
+    //    Implementation copied from Alek's mail... 
+
+    public void skipSubTree() throws XmlPullParserException, IOException {
+        require(START_TAG, null, null);
+        int level = 1;
+        while (level > 0) {
+            int eventType = next();
+            if (eventType == END_TAG) {
+                --level;
+            }
+            else if (eventType == START_TAG) {
+                ++level;
+            }
+        }
+    }
+}
diff --git a/xml/src/main/java/org/kxml2/io/KXmlSerializer.java b/xml/src/main/java/org/kxml2/io/KXmlSerializer.java
new file mode 100644
index 0000000..d63ed04
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/io/KXmlSerializer.java
@@ -0,0 +1,562 @@
+/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The  above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE. */
+ 
+
+package org.kxml2.io;
+
+import java.io.*;
+import org.xmlpull.v1.*;
+
+public class KXmlSerializer implements XmlSerializer {
+
+    //    static final String UNDEFINED = ":";
+
+    // BEGIN android-added
+    /** size (in characters) for the write buffer */
+    private static final int WRITE_BUFFER_SIZE = 500;
+    // END android-added   
+
+    // BEGIN android-changed
+    // (Guarantee that the writer is always buffered.)
+    private BufferedWriter writer;
+    // END android-changed
+
+    private boolean pending;
+    private int auto;
+    private int depth;
+
+    private String[] elementStack = new String[12];
+    //nsp/prefix/name
+    private int[] nspCounts = new int[4];
+    private String[] nspStack = new String[8];
+    //prefix/nsp; both empty are ""
+    private boolean[] indent = new boolean[4];
+    private boolean unicode;
+    private String encoding;
+
+    private final void check(boolean close) throws IOException {
+        if (!pending)
+            return;
+
+        depth++;
+        pending = false;
+
+        if (indent.length <= depth) {
+            boolean[] hlp = new boolean[depth + 4];
+            System.arraycopy(indent, 0, hlp, 0, depth);
+            indent = hlp;
+        }
+        indent[depth] = indent[depth - 1];
+
+        for (int i = nspCounts[depth - 1];
+            i < nspCounts[depth];
+            i++) {
+            writer.write(' ');
+            writer.write("xmlns");
+            if (!"".equals(nspStack[i * 2])) {
+                writer.write(':');
+                writer.write(nspStack[i * 2]);
+            }
+            else if ("".equals(getNamespace()) && !"".equals(nspStack[i * 2 + 1]))
+                throw new IllegalStateException("Cannot set default namespace for elements in no namespace");
+            writer.write("=\"");
+            writeEscaped(nspStack[i * 2 + 1], '"');
+            writer.write('"');
+        }
+
+        if (nspCounts.length <= depth + 1) {
+            int[] hlp = new int[depth + 8];
+            System.arraycopy(nspCounts, 0, hlp, 0, depth + 1);
+            nspCounts = hlp;
+        }
+
+        nspCounts[depth + 1] = nspCounts[depth];
+        //   nspCounts[depth + 2] = nspCounts[depth];
+
+        writer.write(close ? " />" : ">");
+    }
+
+    private final void writeEscaped(String s, int quot)
+        throws IOException {
+
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            switch (c) {
+                case '\n':
+                case '\r':
+                case '\t':
+                    if(quot == -1) 
+                        writer.write(c);
+                    else 
+                        writer.write("&#"+((int) c)+';');
+                    break;
+                case '&' :
+                    writer.write("&amp;");
+                    break;
+                case '>' :
+                    writer.write("&gt;");
+                    break;
+                case '<' :
+                    writer.write("&lt;");
+                    break;
+                case '"' :
+                case '\'' :
+                    if (c == quot) {
+                        writer.write(
+                            c == '"' ? "&quot;" : "&apos;");
+                        break;
+                    }
+                default :
+                    //if(c < ' ')
+                    //    throw new IllegalArgumentException("Illegal control code:"+((int) c));
+
+                    if (c >= ' ' && c !='@' && (c < 127 || unicode))
+                        writer.write(c);
+                    else
+                        writer.write("&#" + ((int) c) + ";");
+
+            }
+        }
+    }
+
+    /*
+        private final void writeIndent() throws IOException {
+            writer.write("\r\n");
+            for (int i = 0; i < depth; i++)
+                writer.write(' ');
+        }*/
+
+    public void docdecl(String dd) throws IOException {
+        writer.write("<!DOCTYPE");
+        writer.write(dd);
+        writer.write(">");
+    }
+
+    public void endDocument() throws IOException {
+        while (depth > 0) {
+            endTag(
+                elementStack[depth * 3 - 3],
+                elementStack[depth * 3 - 1]);
+        }
+        flush();
+    }
+
+    public void entityRef(String name) throws IOException {
+        check(false);
+        writer.write('&');
+        writer.write(name);
+        writer.write(';');
+    }
+
+    public boolean getFeature(String name) {
+        //return false;
+        return (
+            "http://xmlpull.org/v1/doc/features.html#indent-output"
+                .equals(
+                name))
+            ? indent[depth]
+            : false;
+    }
+
+    public String getPrefix(String namespace, boolean create) {
+        try {
+            return getPrefix(namespace, false, create);
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e.toString());
+        }
+    }
+
+    private final String getPrefix(
+        String namespace,
+        boolean includeDefault,
+        boolean create)
+        throws IOException {
+
+        for (int i = nspCounts[depth + 1] * 2 - 2;
+            i >= 0;
+            i -= 2) {
+            if (nspStack[i + 1].equals(namespace)
+                && (includeDefault || !nspStack[i].equals(""))) {
+                String cand = nspStack[i];
+                for (int j = i + 2;
+                    j < nspCounts[depth + 1] * 2;
+                    j++) {
+                    if (nspStack[j].equals(cand)) {
+                        cand = null;
+                        break;
+                    }
+                }
+                if (cand != null)
+                    return cand;
+            }
+        }
+
+        if (!create)
+            return null;
+
+        String prefix;
+
+        if ("".equals(namespace))
+            prefix = "";
+        else {
+            do {
+                prefix = "n" + (auto++);
+                for (int i = nspCounts[depth + 1] * 2 - 2;
+                    i >= 0;
+                    i -= 2) {
+                    if (prefix.equals(nspStack[i])) {
+                        prefix = null;
+                        break;
+                    }
+                }
+            }
+            while (prefix == null);
+        }
+
+        boolean p = pending;
+        pending = false;
+        setPrefix(prefix, namespace);
+        pending = p;
+        return prefix;
+    }
+
+    public Object getProperty(String name) {
+        throw new RuntimeException("Unsupported property");
+    }
+
+    public void ignorableWhitespace(String s)
+        throws IOException {
+        text(s);
+    }
+
+    public void setFeature(String name, boolean value) {
+        if ("http://xmlpull.org/v1/doc/features.html#indent-output"
+            .equals(name)) {
+            indent[depth] = value;
+        }
+        else
+            throw new RuntimeException("Unsupported Feature");
+    }
+
+    public void setProperty(String name, Object value) {
+        throw new RuntimeException(
+            "Unsupported Property:" + value);
+    }
+
+    public void setPrefix(String prefix, String namespace)
+        throws IOException {
+
+        check(false);
+        if (prefix == null)
+            prefix = "";
+        if (namespace == null)
+            namespace = "";
+
+        String defined = getPrefix(namespace, true, false);
+
+        // boil out if already defined
+
+        if (prefix.equals(defined))
+            return;
+
+        int pos = (nspCounts[depth + 1]++) << 1;
+
+        if (nspStack.length < pos + 1) {
+            String[] hlp = new String[nspStack.length + 16];
+            System.arraycopy(nspStack, 0, hlp, 0, pos);
+            nspStack = hlp;
+        }
+
+        nspStack[pos++] = prefix;
+        nspStack[pos] = namespace;
+    }
+
+    public void setOutput(Writer writer) {
+        // BEGIN android-changed
+        // Guarantee that the writer is always buffered.
+        if (writer instanceof BufferedWriter) {
+            this.writer = (BufferedWriter) writer;
+        } else {
+            this.writer = new BufferedWriter(writer, WRITE_BUFFER_SIZE);
+        }
+        // END android-changed
+
+        // elementStack = new String[12]; //nsp/prefix/name
+        //nspCounts = new int[4];
+        //nspStack = new String[8]; //prefix/nsp
+        //indent = new boolean[4];
+
+        nspCounts[0] = 2;
+        nspCounts[1] = 2;
+        nspStack[0] = "";
+        nspStack[1] = "";
+        nspStack[2] = "xml";
+        nspStack[3] = "http://www.w3.org/XML/1998/namespace";
+        pending = false;
+        auto = 0;
+        depth = 0;
+
+        unicode = false;
+    }
+
+    public void setOutput(OutputStream os, String encoding)
+        throws IOException {
+        if (os == null)
+            throw new IllegalArgumentException();
+        setOutput(
+            encoding == null
+                ? new OutputStreamWriter(os)
+                : new OutputStreamWriter(os, encoding));
+        this.encoding = encoding;
+        if (encoding != null
+            && encoding.toLowerCase().startsWith("utf"))
+            unicode = true;
+    }
+
+    public void startDocument(
+        String encoding,
+        Boolean standalone)
+        throws IOException {
+        writer.write("<?xml version='1.0' ");
+
+        if (encoding != null) {
+            this.encoding = encoding;
+            if (encoding.toLowerCase().startsWith("utf"))
+                unicode = true;
+        }
+
+        if (this.encoding != null) {
+            writer.write("encoding='");
+            writer.write(this.encoding);
+            writer.write("' ");
+        }
+
+        if (standalone != null) {
+            writer.write("standalone='");
+            writer.write(
+                standalone.booleanValue() ? "yes" : "no");
+            writer.write("' ");
+        }
+        writer.write("?>");
+    }
+
+    public XmlSerializer startTag(String namespace, String name)
+        throws IOException {
+        check(false);
+
+        //        if (namespace == null)
+        //            namespace = "";
+
+        if (indent[depth]) {
+            writer.write("\r\n");
+            for (int i = 0; i < depth; i++)
+                writer.write("  ");
+        }
+
+        int esp = depth * 3;
+
+        if (elementStack.length < esp + 3) {
+            String[] hlp = new String[elementStack.length + 12];
+            System.arraycopy(elementStack, 0, hlp, 0, esp);
+            elementStack = hlp;
+        }
+
+        String prefix =
+            namespace == null
+                ? ""
+                : getPrefix(namespace, true, true);
+
+        if ("".equals(namespace)) {
+            for (int i = nspCounts[depth];
+                i < nspCounts[depth + 1];
+                i++) {
+                if ("".equals(nspStack[i * 2]) && !"".equals(nspStack[i * 2 + 1])) {
+                    throw new IllegalStateException("Cannot set default namespace for elements in no namespace");
+                }
+            }
+        }
+
+        elementStack[esp++] = namespace;
+        elementStack[esp++] = prefix;
+        elementStack[esp] = name;
+
+        writer.write('<');
+        if (!"".equals(prefix)) {
+            writer.write(prefix);
+            writer.write(':');
+        }
+
+        writer.write(name);
+
+        pending = true;
+
+        return this;
+    }
+
+    public XmlSerializer attribute(
+        String namespace,
+        String name,
+        String value)
+        throws IOException {
+        if (!pending)
+            throw new IllegalStateException("illegal position for attribute");
+
+        //        int cnt = nspCounts[depth];
+
+        if (namespace == null)
+            namespace = "";
+
+        //        depth--;
+        //        pending = false;
+
+        String prefix =
+            "".equals(namespace)
+                ? ""
+                : getPrefix(namespace, false, true);
+
+        //        pending = true;
+        //        depth++;
+
+        /*        if (cnt != nspCounts[depth]) {
+                    writer.write(' ');
+                    writer.write("xmlns");
+                    if (nspStack[cnt * 2] != null) {
+                        writer.write(':');
+                        writer.write(nspStack[cnt * 2]);
+                    }
+                    writer.write("=\"");
+                    writeEscaped(nspStack[cnt * 2 + 1], '"');
+                    writer.write('"');
+                }
+                */
+
+        writer.write(' ');
+        if (!"".equals(prefix)) {
+            writer.write(prefix);
+            writer.write(':');
+        }
+        writer.write(name);
+        writer.write('=');
+        char q = value.indexOf('"') == -1 ? '"' : '\'';
+        writer.write(q);
+        writeEscaped(value, q);
+        writer.write(q);
+
+        return this;
+    }
+
+    public void flush() throws IOException {
+        check(false);
+        writer.flush();
+    }
+    /*
+        public void close() throws IOException {
+            check();
+            writer.close();
+        }
+    */
+    public XmlSerializer endTag(String namespace, String name)
+        throws IOException {
+
+        if (!pending)
+            depth--;
+        //        if (namespace == null)
+        //          namespace = "";
+
+        if ((namespace == null
+            && elementStack[depth * 3] != null)
+            || (namespace != null
+                && !namespace.equals(elementStack[depth * 3]))
+            || !elementStack[depth * 3 + 2].equals(name))
+            throw new IllegalArgumentException("</{"+namespace+"}"+name+"> does not match start");
+
+        if (pending) {
+            check(true);
+            depth--;
+        }
+        else {
+            if (indent[depth + 1]) {
+                writer.write("\r\n");
+                for (int i = 0; i < depth; i++)
+                    writer.write("  ");
+            }
+
+            writer.write("</");
+            String prefix = elementStack[depth * 3 + 1];
+            if (!"".equals(prefix)) {
+                writer.write(prefix);
+                writer.write(':');
+            }
+            writer.write(name);
+            writer.write('>');
+        }
+
+        nspCounts[depth + 1] = nspCounts[depth];
+        return this;
+    }
+
+    public String getNamespace() {
+        return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 3];
+    }
+
+    public String getName() {
+        return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 1];
+    }
+
+    public int getDepth() {
+        return pending ? depth + 1 : depth;
+    }
+
+    public XmlSerializer text(String text) throws IOException {
+        check(false);
+        indent[depth] = false;
+        writeEscaped(text, -1);
+        return this;
+    }
+
+    public XmlSerializer text(char[] text, int start, int len)
+        throws IOException {
+        text(new String(text, start, len));
+        return this;
+    }
+
+    public void cdsect(String data) throws IOException {
+        check(false);
+        writer.write("<![CDATA[");
+        writer.write(data);
+        writer.write("]]>");
+    }
+
+    public void comment(String comment) throws IOException {
+        check(false);
+        writer.write("<!--");
+        writer.write(comment);
+        writer.write("-->");
+    }
+
+    public void processingInstruction(String pi)
+        throws IOException {
+        check(false);
+        writer.write("<?");
+        writer.write(pi);
+        writer.write("?>");
+    }
+}
diff --git a/xml/src/main/java/org/kxml2/kdom/Document.java b/xml/src/main/java/org/kxml2/kdom/Document.java
new file mode 100644
index 0000000..859334c
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/kdom/Document.java
@@ -0,0 +1,129 @@
+/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The  above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE. */
+ 
+
+package org.kxml2.kdom;
+
+import java.io.*;
+
+import org.xmlpull.v1.*;
+/** The document consists of some legacy events and a single root
+    element. This class basically adds some consistency checks to
+    Node. */
+
+public class Document extends Node {
+
+    protected int rootIndex = -1;
+    String encoding;
+    Boolean standalone;
+
+    /** returns "#document" */
+
+    public String getEncoding () {
+        return encoding;
+    }
+    
+    public void setEncoding(String enc) {
+        this.encoding = enc;
+    }
+    
+    public void setStandalone (Boolean standalone) {
+        this.standalone = standalone;
+    }
+    
+    public Boolean getStandalone() {
+        return standalone;
+    }
+
+
+    public String getName() {
+        return "#document";
+    }
+
+    /** Adds a child at the given index position. Throws
+    an exception when a second root element is added */
+
+    public void addChild(int index, int type, Object child) {
+        if (type == ELEMENT) {
+         //   if (rootIndex != -1)
+           //     throw new RuntimeException("Only one document root element allowed");
+
+            rootIndex = index;
+        }
+        else if (rootIndex >= index)
+            rootIndex++;
+
+        super.addChild(index, type, child);
+    }
+
+    /** reads the document and checks if the last event
+    is END_DOCUMENT. If not, an exception is thrown.
+    The end event is consumed. For parsing partial
+        XML structures, consider using Node.parse (). */
+
+    public void parse(XmlPullParser parser)
+        throws IOException, XmlPullParserException {
+
+        parser.require(XmlPullParser.START_DOCUMENT, null, null);
+        parser.nextToken ();            
+
+        encoding = parser.getInputEncoding();
+        standalone = (Boolean)parser.getProperty ("http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone");
+        
+        super.parse(parser);
+
+        if (parser.getEventType() != XmlPullParser.END_DOCUMENT)
+            throw new RuntimeException("Document end expected!");
+
+    }
+
+    public void removeChild(int index) {
+        if (index == rootIndex)
+            rootIndex = -1;
+        else if (index < rootIndex)
+            rootIndex--;
+
+        super.removeChild(index);
+    }
+
+    /** returns the root element of this document. */
+
+    public Element getRootElement() {
+        if (rootIndex == -1)
+            throw new RuntimeException("Document has no root element!");
+
+        return (Element) getChild(rootIndex);
+    }
+    
+    
+    /** Writes this node to the given XmlWriter. For node and document,
+        this method is identical to writeChildren, except that the
+        stream is flushed automatically. */
+
+    public void write(XmlSerializer writer)
+        throws IOException {
+        
+        writer.startDocument(encoding, standalone);
+        writeChildren(writer);
+        writer.endDocument();
+    }
+    
+    
+}
\ No newline at end of file
diff --git a/xml/src/main/java/org/kxml2/kdom/Element.java b/xml/src/main/java/org/kxml2/kdom/Element.java
new file mode 100644
index 0000000..6a5777b
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/kdom/Element.java
@@ -0,0 +1,335 @@
+/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The  above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE. */
+
+package org.kxml2.kdom;
+
+import java.io.*;
+import java.util.*;
+
+import org.xmlpull.v1.*;
+
+/** 
+ * In order to create an element, please use the createElement method
+ * instead of invoking the constructor directly. The right place to
+ * add user defined initialization code is the init method. */
+
+public class Element extends Node {
+
+    protected String namespace;
+    protected String name;
+    protected Vector attributes;
+    protected Node parent;
+    protected Vector prefixes;
+
+    public Element() {
+    }
+
+    /** 
+     * called when all properties are set, but before children
+     * are parsed. Please do not use setParent for initialization
+     * code any longer. */
+
+    public void init() {
+    }
+
+
+
+
+    /** 
+     * removes all children and attributes */
+
+    public void clear() {
+        attributes = null;
+        children = null;
+    }
+
+    /** 
+     * Forwards creation request to parent if any, otherwise
+     * calls super.createElement. */
+
+    public Element createElement(
+        String namespace,
+        String name) { 
+
+        return (this.parent == null)
+            ? super.createElement(namespace, name)
+            : this.parent.createElement(namespace, name);
+    }
+
+    /** 
+     * Returns the number of attributes of this element. */
+
+    public int getAttributeCount() {
+        return attributes == null ? 0 : attributes.size();
+    }
+
+    public String getAttributeNamespace (int index) {
+        return ((String []) attributes.elementAt (index)) [0];
+    }
+
+/*    public String getAttributePrefix (int index) {
+        return ((String []) attributes.elementAt (index)) [1];
+    }*/
+
+    public String getAttributeName (int index) {
+        return ((String []) attributes.elementAt (index)) [1];
+    }
+    
+
+    public String getAttributeValue (int index) {
+        return ((String []) attributes.elementAt (index)) [2];
+    }
+    
+    
+    public String getAttributeValue (String namespace, String name) {
+        for (int i = 0; i < getAttributeCount (); i++) {
+            if (name.equals (getAttributeName (i)) 
+                && (namespace == null || namespace.equals (getAttributeNamespace(i)))) {
+                return getAttributeValue (i);
+            }
+        }                        
+        return null;            
+    }
+
+    /** 
+     * Returns the root node, determined by ascending to the 
+     * all parents un of the root element. */
+
+    public Node getRoot() {
+
+        Element current = this;
+        
+        while (current.parent != null) {
+            if (!(current.parent instanceof Element)) return current.parent;
+            current = (Element) current.parent;
+        }
+        
+        return current;
+    }
+
+    /** 
+     * returns the (local) name of the element */
+
+    public String getName() {
+        return name;
+    }
+
+    /** 
+     * returns the namespace of the element */
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+
+    /** 
+     * returns the namespace for the given prefix */
+    
+    public String getNamespaceUri (String prefix) {
+        int cnt = getNamespaceCount ();
+        for (int i = 0; i < cnt; i++) {
+            if (prefix == getNamespacePrefix (i) ||
+                (prefix != null && prefix.equals (getNamespacePrefix (i))))
+                return getNamespaceUri (i);    
+        }
+        return parent instanceof Element ? ((Element) parent).getNamespaceUri (prefix) : null;
+    }
+
+
+    /** 
+     * returns the number of declared namespaces, NOT including
+     * parent elements */
+
+    public int getNamespaceCount () {
+        return (prefixes == null ? 0 : prefixes.size ());
+    }
+
+
+    public String getNamespacePrefix (int i) {
+        return ((String []) prefixes.elementAt (i)) [0];
+    }
+
+    public String getNamespaceUri (int i) {
+        return ((String []) prefixes.elementAt (i)) [1];
+    }
+
+
+    /** 
+     * Returns the parent node of this element */
+
+    public Node getParent() {
+        return parent;
+    }
+
+    /* 
+     * Returns the parent element if available, null otherwise 
+
+    public Element getParentElement() {
+        return (parent instanceof Element)
+            ? ((Element) parent)
+            : null;
+    }
+*/
+
+    /** 
+     * Builds the child elements from the given Parser. By overwriting 
+     * parse, an element can take complete control over parsing its 
+     * subtree. */
+
+    public void parse(XmlPullParser parser)
+        throws IOException, XmlPullParserException {
+
+        for (int i = parser.getNamespaceCount (parser.getDepth () - 1);
+            i < parser.getNamespaceCount (parser.getDepth ()); i++) {
+            setPrefix (parser.getNamespacePrefix (i), parser.getNamespaceUri(i));
+        }
+        
+        
+        for (int i = 0; i < parser.getAttributeCount (); i++) 
+            setAttribute (parser.getAttributeNamespace (i),
+//                          parser.getAttributePrefix (i),
+                          parser.getAttributeName (i),
+                          parser.getAttributeValue (i));
+
+
+        //        if (prefixMap == null) throw new RuntimeException ("!!");
+
+        init();
+
+
+        if (parser.isEmptyElementTag()) 
+            parser.nextToken ();
+        else {
+            parser.nextToken ();
+            super.parse(parser);
+
+            if (getChildCount() == 0)
+                addChild(IGNORABLE_WHITESPACE, "");
+        }
+        
+        parser.require(
+            XmlPullParser.END_TAG,
+            getNamespace(),
+            getName());
+            
+        parser.nextToken ();
+    }
+
+
+    /** 
+     * Sets the given attribute; a value of null removes the attribute */
+
+    public void setAttribute (String namespace, String name, String value) {
+        if (attributes == null) 
+            attributes = new Vector ();
+
+        if (namespace == null) 
+            namespace = "";
+        
+        for (int i = attributes.size()-1; i >=0; i--){
+            String[] attribut = (String[]) attributes.elementAt(i);
+            if (attribut[0].equals(namespace) &&
+                attribut[1].equals(name)){
+                    
+                if (value == null) {
+                    attributes.removeElementAt(i);
+                }
+                else {
+                    attribut[2] = value;
+                }
+                return; 
+            }
+        }
+
+        attributes.addElement 
+            (new String [] {namespace, name, value});
+    }
+
+
+    /** 
+     * Sets the given prefix; a namespace value of null removess the 
+     * prefix */
+
+    public void setPrefix (String prefix, String namespace) {
+        if (prefixes == null) prefixes = new Vector ();
+        prefixes.addElement (new String [] {prefix, namespace});        
+    }
+
+
+    /** 
+     * sets the name of the element */
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /** 
+     * sets the namespace of the element. Please note: For no
+     * namespace, please use Xml.NO_NAMESPACE, null is not a legal
+     * value. Currently, null is converted to Xml.NO_NAMESPACE, but
+     * future versions may throw an exception. */
+
+    public void setNamespace(String namespace) {
+        if (namespace == null) 
+            throw new NullPointerException ("Use \"\" for empty namespace");
+        this.namespace = namespace;
+    }
+
+    /** 
+     * Sets the Parent of this element. Automatically called from the
+     * add method.  Please use with care, you can simply
+     * create inconsitencies in the document tree structure using
+     * this method!  */
+
+    protected void setParent(Node parent) {
+        this.parent = parent;
+    }
+
+
+    /** 
+     * Writes this element and all children to the given XmlWriter. */
+
+    public void write(XmlSerializer writer)
+        throws IOException {
+
+        if (prefixes != null) {
+            for (int i = 0; i < prefixes.size(); i++) {
+                writer.setPrefix (getNamespacePrefix (i), getNamespaceUri (i));
+            }
+        }
+
+        writer.startTag(
+            getNamespace(),
+            getName());
+
+        int len = getAttributeCount();
+
+        for (int i = 0; i < len; i++) {
+            writer.attribute(
+                getAttributeNamespace(i),
+                getAttributeName(i),
+                getAttributeValue(i));
+        }
+
+        writeChildren(writer);
+
+        writer.endTag(getNamespace (), getName ());
+    }
+}
diff --git a/xml/src/main/java/org/kxml2/kdom/Node.java b/xml/src/main/java/org/kxml2/kdom/Node.java
new file mode 100644
index 0000000..a3cc78d
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/kdom/Node.java
@@ -0,0 +1,366 @@
+/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The  above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE. */
+
+package org.kxml2.kdom;
+
+import java.util.*;
+import java.io.*;
+import org.xmlpull.v1.*;
+/** A common base class for Document and Element, also used for
+    storing XML fragments. */
+
+public class Node { //implements XmlIO{
+
+    public static final int DOCUMENT = 0;
+    public static final int ELEMENT = 2;
+    public static final int TEXT = 4;
+    public static final int CDSECT = 5;
+    public static final int ENTITY_REF = 6;
+    public static final int IGNORABLE_WHITESPACE = 7;
+    public static final int PROCESSING_INSTRUCTION = 8;
+    public static final int COMMENT = 9;
+    public static final int DOCDECL = 10;
+
+    protected Vector children;
+    protected StringBuffer types;
+
+    /** inserts the given child object of the given type at the
+    given index. */
+
+    public void addChild(int index, int type, Object child) {
+
+        if (child == null)
+            throw new NullPointerException();
+
+        if (children == null) {
+            children = new Vector();
+            types = new StringBuffer();
+        }
+
+        if (type == ELEMENT) {
+            if (!(child instanceof Element))
+                throw new RuntimeException("Element obj expected)");
+
+            ((Element) child).setParent(this);
+        }
+        else if (!(child instanceof String))
+            throw new RuntimeException("String expected");
+
+        children.insertElementAt(child, index);
+        types.insert(index, (char) type);
+    }
+
+    /** convenience method for addChild (getChildCount (), child) */
+
+    public void addChild(int type, Object child) {
+        addChild(getChildCount(), type, child);
+    }
+
+    /** Builds a default element with the given properties. Elements
+    should always be created using this method instead of the
+    constructor in order to enable construction of specialized
+    subclasses by deriving custom Document classes. Please note:
+    For no namespace, please use Xml.NO_NAMESPACE, null is not a
+    legal value. Currently, null is converted to Xml.NO_NAMESPACE,
+    but future versions may throw an exception. */
+
+    public Element createElement(String namespace, String name) {
+
+        Element e = new Element();
+        e.namespace = namespace == null ? "" : namespace;
+        e.name = name;
+        return e;
+    }
+
+    /** Returns the child object at the given index.  For child
+        elements, an Element object is returned. For all other child
+        types, a String is returned. */
+
+    public Object getChild(int index) {
+        return children.elementAt(index);
+    }
+
+    /** Returns the number of child objects */
+
+    public int getChildCount() {
+        return children == null ? 0 : children.size();
+    }
+
+    /** returns the element at the given index. If the node at the
+    given index is a text node, null is returned */
+
+    public Element getElement(int index) {
+        Object child = getChild(index);
+        return (child instanceof Element) ? (Element) child : null;
+    }
+
+    /** Returns the element with the given namespace and name. If the
+        element is not found, or more than one matching elements are
+        found, an exception is thrown. */
+
+    public Element getElement(String namespace, String name) {
+
+        int i = indexOf(namespace, name, 0);
+        int j = indexOf(namespace, name, i + 1);
+
+        if (i == -1 || j != -1)
+            throw new RuntimeException(
+                "Element {"
+                    + namespace
+                    + "}"
+                    + name
+                    + (i == -1 ? " not found in " : " more than once in ")
+                    + this);
+
+        return getElement(i);
+    }
+
+    /* returns "#document-fragment". For elements, the element name is returned 
+    
+    public String getName() {
+        return "#document-fragment";
+    }
+    
+    /** Returns the namespace of the current element. For Node
+        and Document, Xml.NO_NAMESPACE is returned. 
+    
+    public String getNamespace() {
+        return "";
+    }
+    
+    public int getNamespaceCount () {
+        return 0;
+    }
+    
+    /** returns the text content if the element has text-only
+    content. Throws an exception for mixed content
+    
+    public String getText() {
+    
+        StringBuffer buf = new StringBuffer();
+        int len = getChildCount();
+    
+        for (int i = 0; i < len; i++) {
+            if (isText(i))
+                buf.append(getText(i));
+            else if (getType(i) == ELEMENT)
+                throw new RuntimeException("not text-only content!");
+        }
+    
+        return buf.toString();
+    }
+    */
+
+    /** Returns the text node with the given index or null if the node
+        with the given index is not a text node. */
+
+    public String getText(int index) {
+        return (isText(index)) ? (String) getChild(index) : null;
+    }
+
+    /** Returns the type of the child at the given index. Possible 
+    types are ELEMENT, TEXT, COMMENT, and PROCESSING_INSTRUCTION */
+
+    public int getType(int index) {
+        return types.charAt(index);
+    }
+
+    /** Convenience method for indexOf (getNamespace (), name,
+        startIndex). 
+    
+    public int indexOf(String name, int startIndex) {
+        return indexOf(getNamespace(), name, startIndex);
+    }
+    */
+
+    /** Performs search for an element with the given namespace and
+    name, starting at the given start index. A null namespace
+    matches any namespace, please use Xml.NO_NAMESPACE for no
+    namespace).  returns -1 if no matching element was found. */
+
+    public int indexOf(String namespace, String name, int startIndex) {
+
+        int len = getChildCount();
+
+        for (int i = startIndex; i < len; i++) {
+
+            Element child = getElement(i);
+
+            if (child != null
+                && name.equals(child.getName())
+                && (namespace == null || namespace.equals(child.getNamespace())))
+                return i;
+        }
+        return -1;
+    }
+
+    public boolean isText(int i) {
+        int t = getType(i);
+        return t == TEXT || t == IGNORABLE_WHITESPACE || t == CDSECT;
+    }
+
+    /** Recursively builds the child elements from the given parser
+    until an end tag or end document is found. 
+        The end tag is not consumed. */
+
+    public void parse(XmlPullParser parser)
+        throws IOException, XmlPullParserException {
+
+        boolean leave = false;
+
+        do {
+            int type = parser.getEventType();
+            
+   //         System.out.println(parser.getPositionDescription());
+            
+            switch (type) {
+
+                case XmlPullParser.START_TAG :
+                    {
+                        Element child =
+                            createElement(
+                                parser.getNamespace(),
+                                parser.getName());
+                        //    child.setAttributes (event.getAttributes ());
+                        addChild(ELEMENT, child);
+
+                        // order is important here since 
+                        // setparent may perform some init code!
+
+                        child.parse(parser);
+                        break;
+                    }
+
+                case XmlPullParser.END_DOCUMENT :
+                case XmlPullParser.END_TAG :
+                    leave = true;
+                    break;
+
+                default :
+                    if (parser.getText() != null)
+                        addChild(
+                            type == XmlPullParser.ENTITY_REF ? TEXT : type,
+                            parser.getText());
+                    else if (
+                        type == XmlPullParser.ENTITY_REF
+                            && parser.getName() != null) {
+                        addChild(ENTITY_REF, parser.getName());
+                    }
+                    parser.nextToken();
+            }
+        }
+        while (!leave);
+    }
+
+    /** Removes the child object at the given index */
+
+    public void removeChild(int idx) {
+        children.removeElementAt(idx);
+
+        /***  Modification by HHS - start ***/
+        //      types.deleteCharAt (index);
+        /***/
+        int n = types.length() - 1;
+
+        for (int i = idx; i < n; i++)
+            types.setCharAt(i, types.charAt(i + 1));
+
+        types.setLength(n);
+
+        /***  Modification by HHS - end   ***/
+    }
+
+    /* returns a valid XML representation of this Element including
+        attributes and children. 
+    public String toString() {
+        try {
+            ByteArrayOutputStream bos =
+                new ByteArrayOutputStream();
+            XmlWriter xw =
+                new XmlWriter(new OutputStreamWriter(bos));
+            write(xw);
+            xw.close();
+            return new String(bos.toByteArray());
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e.toString());
+        }
+    }
+    */
+
+    /** Writes this node to the given XmlWriter. For node and document,
+        this method is identical to writeChildren, except that the
+        stream is flushed automatically. */
+
+    public void write(XmlSerializer writer) throws IOException {
+        writeChildren(writer);
+        writer.flush();
+    }
+
+    /** Writes the children of this node to the given XmlWriter. */
+
+    public void writeChildren(XmlSerializer writer) throws IOException {
+        if (children == null)
+            return;
+
+        int len = children.size();
+
+        for (int i = 0; i < len; i++) {
+            int type = getType(i);
+            Object child = children.elementAt(i);
+            switch (type) {
+                case ELEMENT :
+                     ((Element) child).write(writer);
+                    break;
+
+                case TEXT :
+                    writer.text((String) child);
+                    break;
+
+                case IGNORABLE_WHITESPACE :
+                    writer.ignorableWhitespace((String) child);
+                    break;
+
+                case CDSECT :
+                    writer.cdsect((String) child);
+                    break;
+
+                case COMMENT :
+                    writer.comment((String) child);
+                    break;
+
+                case ENTITY_REF :
+                    writer.entityRef((String) child);
+                    break;
+
+                case PROCESSING_INSTRUCTION :
+                    writer.processingInstruction((String) child);
+                    break;
+
+                case DOCDECL :
+                    writer.docdecl((String) child);
+                    break;
+
+                default :
+                    throw new RuntimeException("Illegal type: " + type);
+            }
+        }
+    }
+}
diff --git a/xml/src/main/java/org/kxml2/wap/Wbxml.java b/xml/src/main/java/org/kxml2/wap/Wbxml.java
new file mode 100644
index 0000000..5b0c2d3
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/wap/Wbxml.java
@@ -0,0 +1,49 @@
+/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The  above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE. */
+
+package org.kxml2.wap;
+
+
+/** contains the WBXML constants  */
+
+
+public interface Wbxml {
+
+    static public final int SWITCH_PAGE = 0;
+    static public final int END = 1;
+    static public final int ENTITY = 2;
+    static public final int STR_I = 3;
+    static public final int LITERAL = 4;
+    static public final int EXT_I_0 = 0x40;
+    static public final int EXT_I_1 = 0x41;
+    static public final int EXT_I_2 = 0x42;
+    static public final int PI = 0x43;
+    static public final int LITERAL_C = 0x44;
+    static public final int EXT_T_0 = 0x80;
+    static public final int EXT_T_1 = 0x81;
+    static public final int EXT_T_2 = 0x82;
+    static public final int STR_T = 0x83;
+    static public final int LITERAL_A = 0x084;
+    static public final int EXT_0 = 0x0c0;
+    static public final int EXT_1 = 0x0c1;
+    static public final int EXT_2 = 0x0c2;
+    static public final int OPAQUE = 0x0c3; 
+    static public final int LITERAL_AC = 0x0c4;
+}
diff --git a/xml/src/main/java/org/kxml2/wap/WbxmlParser.java b/xml/src/main/java/org/kxml2/wap/WbxmlParser.java
new file mode 100644
index 0000000..617e1d4
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/wap/WbxmlParser.java
@@ -0,0 +1,1075 @@
+/* Copyright (c) 2002,2003,2004 Stefan Haustein, Oberhausen, Rhld., Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The  above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE. */
+
+// Contributors: Bjorn Aadland, Chris Bartley, Nicola Fankhauser,
+//               Victor Havin,  Christian Kurzke, Bogdan Onoiu,
+//                Elias Ross, Jain Sanjay, David Santoro.
+
+package org.kxml2.wap;
+
+import java.io.*;
+import java.util.Vector;
+import java.util.Hashtable;
+
+import org.xmlpull.v1.*;
+
+
+public class WbxmlParser implements XmlPullParser {
+
+    static final String HEX_DIGITS = "0123456789abcdef";
+    
+    /** Parser event type for Wbxml-specific events. The Wbxml event code can be 
+     * accessed with getWapCode() */
+    
+    public static final int WAP_EXTENSION = 64;
+    
+    static final private String UNEXPECTED_EOF =
+    "Unexpected EOF";
+    static final private String ILLEGAL_TYPE =
+    "Wrong event type";
+    
+    private InputStream in;
+    
+    private int TAG_TABLE = 0;
+    private int ATTR_START_TABLE = 1;
+    private int ATTR_VALUE_TABLE = 2;
+    
+    private String[] attrStartTable;
+    private String[] attrValueTable;
+    private String[] tagTable;
+    private byte[] stringTable;
+    private Hashtable cacheStringTable = null;
+    private boolean processNsp;
+    
+    private int depth;
+    private String[] elementStack = new String[16];
+    private String[] nspStack = new String[8];
+    private int[] nspCounts = new int[4];
+    
+    private int attributeCount;
+    private String[] attributes = new String[16];
+    private int nextId = -2;
+    
+    private Vector tables = new Vector();
+    
+    private int version;
+    private int publicIdentifierId;
+    
+    //    StartTag current;
+    //    ParseEvent next;
+    
+    private String prefix;
+    private String namespace;
+    private String name;
+    private String text;
+
+    private Object wapExtensionData;
+    private int wapCode;
+    
+    private int type;
+    
+    private boolean degenerated;
+    private boolean isWhitespace;
+    private String encoding;
+    
+    public boolean getFeature(String feature) {
+        if (XmlPullParser
+        .FEATURE_PROCESS_NAMESPACES
+        .equals(feature))
+            return processNsp;
+        else
+            return false;
+    }
+    
+    public String getInputEncoding() {
+        return encoding;
+    }
+    
+    public void defineEntityReplacementText(
+    String entity,
+    String value)
+    throws XmlPullParserException {
+        
+        // just ignore, has no effect
+    }
+    
+    public Object getProperty(String property) {
+        return null;
+    }
+    
+    public int getNamespaceCount(int depth) {
+        if (depth > this.depth)
+            throw new IndexOutOfBoundsException();
+        return nspCounts[depth];
+    }
+    
+    public String getNamespacePrefix(int pos) {
+        return nspStack[pos << 1];
+    }
+    
+    public String getNamespaceUri(int pos) {
+        return nspStack[(pos << 1) + 1];
+    }
+    
+    public String getNamespace(String prefix) {
+        
+        if ("xml".equals(prefix))
+            return "http://www.w3.org/XML/1998/namespace";
+        if ("xmlns".equals(prefix))
+            return "http://www.w3.org/2000/xmlns/";
+        
+        for (int i = (getNamespaceCount(depth) << 1) - 2;
+        i >= 0;
+        i -= 2) {
+            if (prefix == null) {
+                if (nspStack[i] == null)
+                    return nspStack[i + 1];
+            }
+            else if (prefix.equals(nspStack[i]))
+                return nspStack[i + 1];
+        }
+        return null;
+    }
+    
+    public int getDepth() {
+        return depth;
+    }
+    
+    public String getPositionDescription() {
+        
+        StringBuffer buf =
+        new StringBuffer(
+        type < TYPES.length ? TYPES[type] : "unknown");
+        buf.append(' ');
+        
+        if (type == START_TAG || type == END_TAG) {
+            if (degenerated)
+                buf.append("(empty) ");
+            buf.append('<');
+            if (type == END_TAG)
+                buf.append('/');
+            
+            if (prefix != null)
+                buf.append("{" + namespace + "}" + prefix + ":");
+            buf.append(name);
+            
+            int cnt = attributeCount << 2;
+            for (int i = 0; i < cnt; i += 4) {
+                buf.append(' ');
+                if (attributes[i + 1] != null)
+                    buf.append(
+                    "{"
+                    + attributes[i]
+                    + "}"
+                    + attributes[i
+                    + 1]
+                    + ":");
+                buf.append(
+                attributes[i
+                + 2]
+                + "='"
+                + attributes[i
+                + 3]
+                + "'");
+            }
+            
+            buf.append('>');
+        }
+        else if (type == IGNORABLE_WHITESPACE);
+        else if (type != TEXT)
+            buf.append(getText());
+        else if (isWhitespace)
+            buf.append("(whitespace)");
+        else {
+            String text = getText();
+            if (text.length() > 16)
+                text = text.substring(0, 16) + "...";
+            buf.append(text);
+        }
+        
+        return buf.toString();
+    }
+    
+    public int getLineNumber() {
+        return -1;
+    }
+    
+    public int getColumnNumber() {
+        return -1;
+    }
+    
+    public boolean isWhitespace()
+    throws XmlPullParserException {
+        if (type != TEXT
+        && type != IGNORABLE_WHITESPACE
+        && type != CDSECT)
+            exception(ILLEGAL_TYPE);
+        return isWhitespace;
+    }
+    
+    public String getText() {
+        return text;
+    }
+    
+    public char[] getTextCharacters(int[] poslen) {
+        if (type >= TEXT) {
+            poslen[0] = 0;
+            poslen[1] = text.length();
+            char[] buf = new char[text.length()];
+            text.getChars(0, text.length(), buf, 0);
+            return buf;
+        }
+        
+        poslen[0] = -1;
+        poslen[1] = -1;
+        return null;
+    }
+    
+    public String getNamespace() {
+        return namespace;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    public String getPrefix() {
+        return prefix;
+    }
+    
+    public boolean isEmptyElementTag()
+    throws XmlPullParserException {
+        if (type != START_TAG)
+            exception(ILLEGAL_TYPE);
+        return degenerated;
+    }
+    
+    public int getAttributeCount() {
+        return attributeCount;
+    }
+    
+    public String getAttributeType(int index) {
+        return "CDATA";
+    }
+    
+    public boolean isAttributeDefault(int index) {
+        return false;
+    }
+    
+    public String getAttributeNamespace(int index) {
+        if (index >= attributeCount)
+            throw new IndexOutOfBoundsException();
+        return attributes[index << 2];
+    }
+    
+    public String getAttributeName(int index) {
+        if (index >= attributeCount)
+            throw new IndexOutOfBoundsException();
+        return attributes[(index << 2) + 2];
+    }
+    
+    public String getAttributePrefix(int index) {
+        if (index >= attributeCount)
+            throw new IndexOutOfBoundsException();
+        return attributes[(index << 2) + 1];
+    }
+    
+    public String getAttributeValue(int index) {
+        if (index >= attributeCount)
+            throw new IndexOutOfBoundsException();
+        return attributes[(index << 2) + 3];
+    }
+    
+    public String getAttributeValue(
+    String namespace,
+    String name) {
+        
+        for (int i = (attributeCount << 2) - 4;
+        i >= 0;
+        i -= 4) {
+            if (attributes[i + 2].equals(name)
+            && (namespace == null
+            || attributes[i].equals(namespace)))
+                return attributes[i + 3];
+        }
+        
+        return null;
+    }
+    
+    public int getEventType() throws XmlPullParserException {
+        return type;
+    }
+    
+    
+    // TODO: Reuse resolveWapExtension here? Raw Wap extensions would still be accessible
+    // via nextToken();  ....?
+    
+    public int next() throws XmlPullParserException, IOException {
+        
+        isWhitespace = true;
+        int minType = 9999;
+        
+        while (true) {
+            
+            String save = text;
+            
+            nextImpl();
+            
+            if (type < minType)
+                minType = type;
+            
+            if (minType > CDSECT) continue; // no "real" event so far
+            
+            if (minType >= TEXT) {  // text, see if accumulate
+                
+                if (save != null) text = text == null ? save : save + text;
+                
+                switch(peekId()) {
+                    case Wbxml.ENTITY:
+                    case Wbxml.STR_I:
+                    case Wbxml.STR_T:
+                    case Wbxml.LITERAL:
+                    case Wbxml.LITERAL_C:
+                    case Wbxml.LITERAL_A:
+                    case Wbxml.LITERAL_AC: continue;
+                }
+            }
+            
+            break;
+        }
+        
+        type = minType;
+        
+        if (type > TEXT)
+            type = TEXT;
+        
+        return type;
+    }
+    
+    
+    public int nextToken() throws XmlPullParserException, IOException {
+        
+        isWhitespace = true;
+        nextImpl();
+        return type;
+    }
+    
+    
+    
+    public int nextTag() throws XmlPullParserException, IOException {
+        
+        next();
+        if (type == TEXT && isWhitespace)
+            next();
+        
+        if (type != END_TAG && type != START_TAG)
+            exception("unexpected type");
+        
+        return type;
+    }
+    
+    
+    public String nextText() throws XmlPullParserException, IOException {
+        if (type != START_TAG)
+            exception("precondition: START_TAG");
+        
+        next();
+        
+        String result;
+        
+        if (type == TEXT) {
+            result = getText();
+            next();
+        }
+        else
+            result = "";
+        
+        if (type != END_TAG)
+            exception("END_TAG expected");
+        
+        return result;
+    }
+    
+    
+    public void require(int type, String namespace, String name)
+    throws XmlPullParserException, IOException {
+        
+        if (type != this.type
+        || (namespace != null && !namespace.equals(getNamespace()))
+        || (name != null && !name.equals(getName())))
+            exception(
+            "expected: " + (type == WAP_EXTENSION ? "WAP Ext." : (TYPES[type] + " {" + namespace + "}" + name)));
+    }
+    
+    
+    public void setInput(Reader reader) throws XmlPullParserException {
+        exception("InputStream required");
+    }
+    
+    public void setInput(InputStream in, String enc)
+    throws XmlPullParserException {
+        
+        this.in = in;
+        
+        try {
+            version = readByte();
+            publicIdentifierId = readInt();
+            
+            if (publicIdentifierId == 0)
+                readInt();
+            
+            int charset = readInt(); // skip charset
+            
+            if (null == enc){
+                switch (charset){
+                    case   4: encoding = "ISO-8859-1"; break;
+                    case 106: encoding = "UTF-8";      break;
+                    // add more if you need them
+                    // http://www.iana.org/assignments/character-sets
+                    // case MIBenum: encoding = Name  break;
+                    default:  throw new UnsupportedEncodingException(""+charset);
+                } 
+            }else{
+                encoding = enc;
+            }
+
+            int strTabSize = readInt();
+            stringTable = new byte[strTabSize];
+            
+            int ok = 0;
+            while(ok < strTabSize){
+                int cnt = in.read(stringTable, ok, strTabSize - ok);
+                if(cnt <= 0) break;
+                ok += cnt;
+            }
+            
+            selectPage(0, true);
+            selectPage(0, false);
+        }
+        catch (IOException e) {
+            exception("Illegal input format");
+        }
+    }
+    
+    public void setFeature(String feature, boolean value)
+    throws XmlPullParserException {
+        if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature))
+            processNsp = value;
+        else
+            exception("unsupported feature: " + feature);
+    }
+    
+    public void setProperty(String property, Object value)
+    throws XmlPullParserException {
+        throw new XmlPullParserException("unsupported property: " + property);
+    }
+    
+    // ---------------------- private / internal methods
+    
+    private final boolean adjustNsp()
+    throws XmlPullParserException {
+        
+        boolean any = false;
+        
+        for (int i = 0; i < attributeCount << 2; i += 4) {
+            // * 4 - 4; i >= 0; i -= 4) {
+            
+            String attrName = attributes[i + 2];
+            int cut = attrName.indexOf(':');
+            String prefix;
+            
+            if (cut != -1) {
+                prefix = attrName.substring(0, cut);
+                attrName = attrName.substring(cut + 1);
+            }
+            else if (attrName.equals("xmlns")) {
+                prefix = attrName;
+                attrName = null;
+            }
+            else
+                continue;
+            
+            if (!prefix.equals("xmlns")) {
+                any = true;
+            }
+            else {
+                int j = (nspCounts[depth]++) << 1;
+                
+                nspStack = ensureCapacity(nspStack, j + 2);
+                nspStack[j] = attrName;
+                nspStack[j + 1] = attributes[i + 3];
+                
+                if (attrName != null
+                && attributes[i + 3].equals(""))
+                    exception("illegal empty namespace");
+                
+                //  prefixMap = new PrefixMap (prefixMap, attrName, attr.getValue ());
+                
+                //System.out.println (prefixMap);
+                
+                System.arraycopy(
+                attributes,
+                i + 4,
+                attributes,
+                i,
+                ((--attributeCount) << 2) - i);
+                
+                i -= 4;
+            }
+        }
+        
+        if (any) {
+            for (int i = (attributeCount << 2) - 4;
+            i >= 0;
+            i -= 4) {
+                
+                String attrName = attributes[i + 2];
+                int cut = attrName.indexOf(':');
+                
+                if (cut == 0)
+                    throw new RuntimeException(
+                    "illegal attribute name: "
+                    + attrName
+                    + " at "
+                    + this);
+                
+                else if (cut != -1) {
+                    String attrPrefix =
+                    attrName.substring(0, cut);
+                    
+                    attrName = attrName.substring(cut + 1);
+                    
+                    String attrNs = getNamespace(attrPrefix);
+                    
+                    if (attrNs == null)
+                        throw new RuntimeException(
+                        "Undefined Prefix: "
+                        + attrPrefix
+                        + " in "
+                        + this);
+                    
+                    attributes[i] = attrNs;
+                    attributes[i + 1] = attrPrefix;
+                    attributes[i + 2] = attrName;
+                    
+                    for (int j = (attributeCount << 2) - 4;
+                    j > i;
+                    j -= 4)
+                        if (attrName.equals(attributes[j + 2])
+                        && attrNs.equals(attributes[j]))
+                            exception(
+                            "Duplicate Attribute: {"
+                            + attrNs
+                            + "}"
+                            + attrName);
+                }
+            }
+        }
+        
+        int cut = name.indexOf(':');
+        
+        if (cut == 0)
+            exception("illegal tag name: " + name);
+        else if (cut != -1) {
+            prefix = name.substring(0, cut);
+            name = name.substring(cut + 1);
+        }
+        
+        this.namespace = getNamespace(prefix);
+        
+        if (this.namespace == null) {
+            if (prefix != null)
+                exception("undefined prefix: " + prefix);
+            this.namespace = NO_NAMESPACE;
+        }
+        
+        return any;
+    }
+    
+    private final void setTable(int page, int type, String[] table) {
+        if(stringTable != null){
+            throw new RuntimeException("setXxxTable must be called before setInput!");
+        }
+        while(tables.size() < 3*page +3){
+            tables.addElement(null);
+        }
+        tables.setElementAt(table, page*3+type);
+    }
+    
+    
+    
+    
+    
+    private final void exception(String desc)
+    throws XmlPullParserException {
+        throw new XmlPullParserException(desc, this, null);
+    }
+    
+    
+    private void selectPage(int nr, boolean tags) throws XmlPullParserException{
+        if(tables.size() == 0 && nr == 0) return;
+        
+        if(nr*3 > tables.size())
+            exception("Code Page "+nr+" undefined!");
+        
+        if(tags)
+            tagTable = (String[]) tables.elementAt(nr * 3 + TAG_TABLE);
+        else {
+            attrStartTable = (String[]) tables.elementAt(nr * 3 + ATTR_START_TABLE);
+            attrValueTable = (String[]) tables.elementAt(nr * 3 + ATTR_VALUE_TABLE);
+        }
+    }
+    
+    private final void nextImpl()
+    throws IOException, XmlPullParserException {
+        
+        String s;
+        
+        if (type == END_TAG) {
+            depth--;
+        }
+        
+        if (degenerated) {
+            type = XmlPullParser.END_TAG;
+            degenerated = false;
+            return;
+        }
+        
+        text = null;
+        prefix = null;
+        name = null;
+        
+        int id = peekId ();
+        while(id == Wbxml.SWITCH_PAGE){
+            nextId = -2;
+            selectPage(readByte(), true);
+            id = peekId();
+        }
+        nextId = -2;
+        
+        switch (id) {
+            case -1 :
+                type = XmlPullParser.END_DOCUMENT;
+                break;
+                
+            case Wbxml.END : 
+            {
+                int sp = (depth - 1) << 2;
+                
+                type = END_TAG;
+                namespace = elementStack[sp];
+                prefix = elementStack[sp + 1];
+                name = elementStack[sp + 2];
+            }
+            break;
+            
+            case Wbxml.ENTITY : 
+            {
+                type = ENTITY_REF;
+                char c = (char) readInt();
+                text = "" + c;
+                name = "#" + ((int) c);
+            }
+            
+            break;
+            
+            case Wbxml.STR_I :
+                type = TEXT;
+                text = readStrI();
+                break;
+                
+            case Wbxml.EXT_I_0 :
+            case Wbxml.EXT_I_1 :
+            case Wbxml.EXT_I_2 :
+            case Wbxml.EXT_T_0 :
+            case Wbxml.EXT_T_1 :
+            case Wbxml.EXT_T_2 :
+            case Wbxml.EXT_0 :
+            case Wbxml.EXT_1 :
+            case Wbxml.EXT_2 :
+            case Wbxml.OPAQUE :
+                
+                type = WAP_EXTENSION;
+                wapCode = id;
+                wapExtensionData = parseWapExtension(id);
+                break;
+                
+            case Wbxml.PI :
+                throw new RuntimeException("PI curr. not supp.");
+                // readPI;
+                // break;
+                
+            case Wbxml.STR_T : 
+            {
+                type = TEXT;
+                text = readStrT();
+            }
+            break;
+            
+            default :
+                parseElement(id);
+        }
+        //        }
+        //      while (next == null);
+        
+        //        return next;
+    }
+    
+    /** Overwrite this method to intercept all wap events */
+    
+    public Object parseWapExtension(int id)  throws IOException, XmlPullParserException {
+        
+        switch (id) {
+            case Wbxml.EXT_I_0 :
+            case Wbxml.EXT_I_1 :
+            case Wbxml.EXT_I_2 :
+                return readStrI();
+                
+            case Wbxml.EXT_T_0 :
+            case Wbxml.EXT_T_1 :
+            case Wbxml.EXT_T_2 :
+                return new Integer(readInt());
+                
+            case Wbxml.EXT_0 :
+            case Wbxml.EXT_1 :
+            case Wbxml.EXT_2 :
+                return null;
+                
+            case Wbxml.OPAQUE : 
+            {
+                int count = readInt();
+                byte[] buf = new byte[count];
+                
+                while(count > 0){
+                    count -= in.read(buf, buf.length-count, count);
+                }
+                
+                return buf;
+            } // case OPAQUE
+    
+            
+            default:
+                exception("illegal id: "+id);
+                return null; // dead code
+        } // SWITCH
+    }
+    
+    public void readAttr() throws IOException, XmlPullParserException {
+        
+        int id = readByte();
+        int i = 0;
+        
+        while (id != 1) {
+            
+            while(id == Wbxml.SWITCH_PAGE){
+                selectPage(readByte(), false);
+                id = readByte();
+            }
+            
+            String name = resolveId(attrStartTable, id);
+            StringBuffer value;
+            
+            int cut = name.indexOf('=');
+            
+            if (cut == -1)
+                value = new StringBuffer();
+            else {
+                value =
+                new StringBuffer(name.substring(cut + 1));
+                name = name.substring(0, cut);
+            }
+            
+            id = readByte();
+            while (id > 128
+            || id == Wbxml.SWITCH_PAGE
+            || id == Wbxml.ENTITY
+            || id == Wbxml.STR_I
+            || id == Wbxml.STR_T
+            || (id >= Wbxml.EXT_I_0 && id <= Wbxml.EXT_I_2)
+            || (id >= Wbxml.EXT_T_0 && id <= Wbxml.EXT_T_2)) {
+                
+                switch (id) {
+                    case Wbxml.SWITCH_PAGE :
+                        selectPage(readByte(), false);
+                        break;
+                        
+                    case Wbxml.ENTITY :
+                        value.append((char) readInt());
+                        break;
+                        
+                    case Wbxml.STR_I :
+                        value.append(readStrI());
+                        break;
+                        
+                    case Wbxml.EXT_I_0 :
+                    case Wbxml.EXT_I_1 :
+                    case Wbxml.EXT_I_2 :
+                    case Wbxml.EXT_T_0 :
+                    case Wbxml.EXT_T_1 :
+                    case Wbxml.EXT_T_2 :
+                    case Wbxml.EXT_0 :
+                    case Wbxml.EXT_1 :
+                    case Wbxml.EXT_2 :
+                    case Wbxml.OPAQUE :
+                        value.append(resolveWapExtension(id, parseWapExtension(id)));
+                        break;
+                        
+                    case Wbxml.STR_T :
+                        value.append(readStrT());
+                        break;
+                        
+                    default :
+                        value.append(
+                        resolveId(attrValueTable, id));
+                }
+                
+                id = readByte();
+            }
+            
+            attributes = ensureCapacity(attributes, i + 4);
+            
+            attributes[i++] = "";
+            attributes[i++] = null;
+            attributes[i++] = name;
+            attributes[i++] = value.toString();
+            
+            attributeCount++;
+        }
+    }
+    
+    private int peekId () throws IOException {
+        if (nextId == -2) {
+            nextId = in.read ();
+        }
+        return nextId;
+    }
+    
+    /** overwrite for own WAP extension handling in attributes and high level parsing 
+     * (above nextToken() level) */
+    
+    protected String resolveWapExtension(int id, Object data){
+        
+        if(data instanceof byte[]){
+            StringBuffer sb = new StringBuffer();
+            byte[] b = (byte[]) data;
+            
+            for (int i = 0; i < b.length; i++) {
+                sb.append(HEX_DIGITS.charAt((b[i] >> 4) & 0x0f));
+                sb.append(HEX_DIGITS.charAt(b[i] & 0x0f));
+            }
+            return sb.toString();
+        }
+
+        return "$("+data+")";
+    }
+    
+    String resolveId(String[] tab, int id) throws IOException {
+        int idx = (id & 0x07f) - 5;
+        if (idx == -1){
+            wapCode = -1;
+            return readStrT();
+        }
+        if (idx < 0
+        || tab == null
+        || idx >= tab.length
+        || tab[idx] == null)
+            throw new IOException("id " + id + " undef.");
+        
+        wapCode = idx+5;
+        
+        return tab[idx];
+    }
+    
+    void parseElement(int id)
+    throws IOException, XmlPullParserException {
+        
+        type = START_TAG;
+        name = resolveId(tagTable, id & 0x03f);
+        
+        attributeCount = 0;
+        if ((id & 128) != 0) {
+            readAttr();
+        }
+        
+        degenerated = (id & 64) == 0;
+        
+        int sp = depth++ << 2;
+        
+        // transfer to element stack
+        
+        elementStack = ensureCapacity(elementStack, sp + 4);
+        elementStack[sp + 3] = name;
+        
+        if (depth >= nspCounts.length) {
+            int[] bigger = new int[depth + 4];
+            System.arraycopy(nspCounts, 0, bigger, 0, nspCounts.length);
+            nspCounts = bigger;
+        }
+        
+        nspCounts[depth] = nspCounts[depth - 1];
+        
+        for (int i = attributeCount - 1; i > 0; i--) {
+            for (int j = 0; j < i; j++) {
+                if (getAttributeName(i)
+                .equals(getAttributeName(j)))
+                    exception(
+                    "Duplicate Attribute: "
+                    + getAttributeName(i));
+            }
+        }
+        
+        if (processNsp)
+            adjustNsp();
+        else
+            namespace = "";
+        
+        elementStack[sp] = namespace;
+        elementStack[sp + 1] = prefix;
+        elementStack[sp + 2] = name;
+        
+    }
+    
+    private final String[] ensureCapacity(
+    String[] arr,
+    int required) {
+        if (arr.length >= required)
+            return arr;
+        String[] bigger = new String[required + 16];
+        System.arraycopy(arr, 0, bigger, 0, arr.length);
+        return bigger;
+    }
+    
+    int readByte() throws IOException {
+        int i = in.read();
+        if (i == -1)
+            throw new IOException("Unexpected EOF");
+        return i;
+    }
+    
+    int readInt() throws IOException {
+        int result = 0;
+        int i;
+        
+        do {
+            i = readByte();
+            result = (result << 7) | (i & 0x7f);
+        }
+        while ((i & 0x80) != 0);
+        
+        return result;
+    }
+    
+    String readStrI() throws IOException {
+        ByteArrayOutputStream buf = new ByteArrayOutputStream();
+        boolean wsp = true;
+        while (true){
+            int i = in.read();
+            if (i == 0){
+                break;
+            }
+            if (i == -1){
+                throw new IOException(UNEXPECTED_EOF);
+            }
+            if (i > 32){
+                wsp = false;
+            }
+            buf.write(i);
+        }
+        isWhitespace = wsp;
+        String result = new String(buf.toByteArray(), encoding);
+        buf.close();
+        return result;
+    }
+    
+    String readStrT() throws IOException {
+        int pos = readInt();
+        // As the main reason of stringTable is compression we build a cache of Strings
+        // stringTable is supposed to help create Strings from parts which means some cache hit rate
+        // This will help to minimize the Strings created when invoking readStrT() repeatedly
+        if (cacheStringTable == null){
+            //Lazy init if device is not using StringTable but inline 0x03 strings
+            cacheStringTable = new Hashtable();
+        }
+        String forReturn = (String) cacheStringTable.get(new Integer(pos));
+        if (forReturn == null){
+
+            int end = pos;
+            while(end < stringTable.length && stringTable[end] != '\0'){
+                end++;
+            }
+            forReturn = new String(stringTable, pos, end-pos, encoding);
+            cacheStringTable.put(new Integer(pos), forReturn);
+        }
+        return forReturn;
+    }
+    
+    /**
+     * Sets the tag table for a given page.
+     * The first string in the array defines tag 5, the second tag 6 etc.
+     */
+    
+    public void setTagTable(int page, String[] table) {
+        setTable(page, TAG_TABLE, table);
+        
+        //        this.tagTable = tagTable;
+        //      if (page != 0)
+        //        throw new RuntimeException("code pages curr. not supp.");
+    }
+    
+    /** Sets the attribute start Table for a given page.
+     *  The first string in the array defines attribute
+     *  5, the second attribute 6 etc. Please use the
+     *  character '=' (without quote!) as delimiter
+     *  between the attribute name and the (start of the) value
+     */
+    
+    public void setAttrStartTable(
+    int page,
+    String[] table) {
+        
+        setTable(page, ATTR_START_TABLE, table);
+    }
+    
+    /** Sets the attribute value Table for a given page.
+     *  The first string in the array defines attribute value 0x85,
+     *  the second attribute value 0x86 etc.
+     */
+    
+    public void setAttrValueTable(
+    int page,
+    String[] table) {
+        
+        setTable(page, ATTR_VALUE_TABLE, table);
+    }
+    
+    /** Returns the token ID for start tags or the event type for wap proprietary events
+     * such as OPAQUE.
+     */
+    
+    public int getWapCode(){
+        return wapCode;
+    }
+    
+    public Object getWapExtensionData(){
+        return wapExtensionData;
+    }
+    
+    
+}
diff --git a/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java b/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java
new file mode 100644
index 0000000..8c1b598
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/wap/WbxmlSerializer.java
@@ -0,0 +1,512 @@
+/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The  above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE. */
+
+//Contributors: Jonathan Cox, Bogdan Onoiu, Jerry Tian
+
+package org.kxml2.wap;
+
+import java.io.*;
+import java.util.*;
+
+import org.xmlpull.v1.*;
+
+// TODO: make some of the "direct" WBXML token writing methods public??
+
+/**
+ * A class for writing WBXML.
+ *
+ */
+
+
+
+public class WbxmlSerializer implements XmlSerializer {
+    
+    
+    Hashtable stringTable = new Hashtable();
+    
+    OutputStream out;
+    
+    ByteArrayOutputStream buf = new ByteArrayOutputStream();
+    ByteArrayOutputStream stringTableBuf = new ByteArrayOutputStream();
+    
+    String pending;
+    int depth;
+    String name;
+    String namespace;
+    Vector attributes = new Vector();
+    
+    Hashtable attrStartTable = new Hashtable();
+    Hashtable attrValueTable = new Hashtable();
+    Hashtable tagTable = new Hashtable();
+    
+    private int attrPage;
+    private int tagPage;
+    
+    private String encoding;
+    
+    
+    public XmlSerializer attribute(String namespace, String name, String value) {
+        attributes.addElement(name);
+        attributes.addElement(value);
+        return this;
+    }
+    
+    
+    public void cdsect (String cdsect) throws IOException{
+        text (cdsect);
+    }
+    
+    
+    
+    /* silently ignore comment */
+    
+    public void comment (String comment) {
+    }
+    
+    
+    public void docdecl (String docdecl) {
+        throw new RuntimeException ("Cannot write docdecl for WBXML");
+    }
+    
+    
+    public void entityRef (String er) {
+        throw new RuntimeException ("EntityReference not supported for WBXML");
+    }
+    
+    public int getDepth() {
+        return depth;
+    }
+    
+    
+    public boolean getFeature (String name) {
+        return false;
+    }
+    
+    public String getNamespace() {
+        throw new RuntimeException("NYI");
+    }
+    
+    public String getName() {
+        throw new RuntimeException("NYI");
+    }
+    
+    public String getPrefix(String nsp, boolean create) {
+        throw new RuntimeException ("NYI");
+    }
+    
+    
+    public Object getProperty (String name) {
+        return null;
+    }
+    
+    public void ignorableWhitespace (String sp) {
+    }
+    
+    
+    public void endDocument() throws IOException {
+        writeInt(out, stringTableBuf.size());
+        
+        // write StringTable
+        
+        out.write(stringTableBuf.toByteArray());
+        
+        // write buf
+        
+        out.write(buf.toByteArray());
+        
+        // ready!
+        
+        out.flush();
+    }
+    
+    
+    /** ATTENTION: flush cannot work since Wbxml documents require
+      buffering. Thus, this call does nothing. */
+    
+    public void flush() {
+    }
+    
+    
+    public void checkPending(boolean degenerated) throws IOException {
+        if (pending == null)
+            return;
+        
+        int len = attributes.size();
+        
+        int[] idx = (int[]) tagTable.get(pending);
+        
+        // if no entry in known table, then add as literal
+        if (idx == null) {
+            buf.write(
+            len == 0
+            ? (degenerated ? Wbxml.LITERAL : Wbxml.LITERAL_C)
+            : (degenerated ? Wbxml.LITERAL_A : Wbxml.LITERAL_AC));
+            
+            writeStrT(pending, false);
+        }
+        else {
+            if(idx[0] != tagPage){
+                tagPage=idx[0];
+                buf.write(Wbxml.SWITCH_PAGE);
+                buf.write(tagPage);
+            }
+            
+            buf.write(
+            len == 0
+            ? (degenerated ? idx[1] : idx[1] | 64)
+            : (degenerated
+            ? idx[1] | 128
+            : idx[1] | 192));
+           
+        }
+        
+        for (int i = 0; i < len;) {
+            idx = (int[]) attrStartTable.get(attributes.elementAt(i));
+            
+            if (idx == null) {
+                buf.write(Wbxml.LITERAL);
+                writeStrT((String) attributes.elementAt(i), false);
+            }
+            else {
+                if(idx[0] != attrPage){
+                        attrPage = idx[0];
+                    buf.write(0);
+                    buf.write(attrPage);
+                }
+                buf.write(idx[1]);
+            }
+            idx = (int[]) attrValueTable.get(attributes.elementAt(++i));
+            if (idx == null) {
+                writeStr((String) attributes.elementAt(i));
+            }
+            else {
+                if(idx[0] != attrPage){
+                        attrPage = idx[0];
+                    buf.write(0);
+                    buf.write(attrPage);                    
+                }
+                buf.write(idx[1]);
+            }
+            ++i;
+        }
+        
+        if (len > 0)
+            buf.write(Wbxml.END);
+        
+        pending = null;
+        attributes.removeAllElements();
+    }
+    
+    
+    public void processingInstruction(String pi) {
+        throw new RuntimeException ("PI NYI");
+    }
+    
+    
+    public void setFeature(String name, boolean value) {
+        throw new IllegalArgumentException ("unknown feature "+name);
+    }
+    
+    
+    
+    public void setOutput (Writer writer) {
+        throw new RuntimeException ("Wbxml requires an OutputStream!");
+    }
+    
+    public void setOutput (OutputStream out, String encoding) throws IOException {
+        
+        this.encoding = encoding == null ? "UTF-8" : encoding;
+        this.out = out;
+        
+        buf = new ByteArrayOutputStream();
+        stringTableBuf = new ByteArrayOutputStream();
+        
+        // ok, write header
+    }
+    
+    
+    public void setPrefix(String prefix, String nsp) {
+        throw new RuntimeException("NYI");
+    }
+    
+    public void setProperty(String property, Object value) {
+        throw new IllegalArgumentException ("unknown property "+property);
+    }
+    
+    
+    public void startDocument(String s, Boolean b) throws IOException{
+        out.write(0x03); // version 1.3
+        // http://www.openmobilealliance.org/tech/omna/omna-wbxml-public-docid.htm
+        out.write(0x01); // unknown or missing public identifier
+
+        // default encoding is UTF-8
+        
+        if(s != null){
+            encoding = s;
+        }
+        
+        if (encoding.toUpperCase().equals("UTF-8")){
+            out.write(106);
+        }else if (encoding.toUpperCase().equals("ISO-8859-1")){
+            out.write(0x04);
+        }else{
+            throw new UnsupportedEncodingException(s);
+        }
+    }
+    
+    
+    public XmlSerializer startTag(String namespace, String name) throws IOException {
+        
+        if (namespace != null && !"".equals(namespace))
+            throw new RuntimeException ("NSP NYI");
+        
+        //current = new State(current, prefixMap, name);
+        
+        checkPending(false);
+        pending = name;
+        depth++;
+        
+        return this;
+    }
+    
+    public XmlSerializer text(char[] chars, int start, int len) throws IOException {
+
+        checkPending(false);
+        
+        writeStr(new String(chars, start, len));
+        
+        return this;
+    }
+    
+    public XmlSerializer text(String text) throws IOException {
+        
+        checkPending(false);
+        
+        writeStr(text);
+    
+        return this;
+    }
+    
+
+    /** Used in text() and attribute() to write text */
+    
+    private void writeStr(String text) throws IOException{
+        int p0 = 0;
+        int lastCut = 0;
+        int len = text.length();
+        
+        while(p0 < len){
+            while(p0 < len && text.charAt(p0) < 'A' ){ // skip interpunctation
+                p0++;
+            }
+            int p1 = p0;
+            while(p1 < len && text.charAt(p1) >= 'A'){
+                p1++;
+            }
+            
+            if(p1 - p0 > 10) {
+
+                if(p0 > lastCut && text.charAt(p0-1) == ' ' 
+                    && stringTable.get(text.substring(p0, p1)) == null){
+                    
+                       buf.write(Wbxml.STR_T);
+                       writeStrT(text.substring(lastCut, p1), false);
+                }
+                else {
+
+                    if(p0 > lastCut && text.charAt(p0-1) == ' '){
+                        p0--;
+                    }
+
+                    if(p0 > lastCut){
+                        buf.write(Wbxml.STR_T);
+                        writeStrT(text.substring(lastCut, p0), false);
+                    }
+                    buf.write(Wbxml.STR_T);
+                    writeStrT(text.substring(p0, p1), true);
+                }
+                lastCut = p1;
+            }
+            p0 = p1;
+        }
+
+        if(lastCut < len){
+            buf.write(Wbxml.STR_T);
+            writeStrT(text.substring(lastCut, len), false);
+        }
+    }
+    
+    
+
+    public XmlSerializer endTag(String namespace, String name) throws IOException {
+        
+        //        current = current.prev;
+        
+        if (pending != null)
+            checkPending(true);
+        else
+            buf.write(Wbxml.END);
+        
+        depth--;
+        
+        return this;
+    }
+    
+    /** 
+     * @throws IOException */
+    
+    public void writeWapExtension(int type, Object data) throws IOException {
+        checkPending(false);
+        buf.write(type);
+        switch(type){
+        case Wbxml.EXT_0:
+        case Wbxml.EXT_1:
+        case Wbxml.EXT_2:
+            break;
+        
+        case Wbxml.OPAQUE:
+            byte[] bytes = (byte[]) data;
+            writeInt(buf, bytes.length);
+            buf.write(bytes);
+            break;
+            
+        case Wbxml.EXT_I_0:
+        case Wbxml.EXT_I_1:
+        case Wbxml.EXT_I_2:
+            writeStrI(buf, (String) data);
+            break;
+
+        case Wbxml.EXT_T_0:
+        case Wbxml.EXT_T_1:
+        case Wbxml.EXT_T_2:
+            writeStrT((String) data, false);
+            break;
+            
+        default: 
+            throw new IllegalArgumentException();
+        }
+    }
+    
+    // ------------- internal methods --------------------------
+    
+    static void writeInt(OutputStream out, int i) throws IOException {
+        byte[] buf = new byte[5];
+        int idx = 0;
+        
+        do {
+            buf[idx++] = (byte) (i & 0x7f);
+            i = i >> 7;
+        }
+        while (i != 0);
+        
+        while (idx > 1) {
+            out.write(buf[--idx] | 0x80);
+        }
+        out.write(buf[0]);
+    }
+    
+    void writeStrI(OutputStream out, String s) throws IOException {
+        byte[] data = s.getBytes(encoding);
+        out.write(data);
+        out.write(0);
+    }
+    
+    private final void writeStrT(String s, boolean mayPrependSpace) throws IOException {
+        
+        Integer idx = (Integer) stringTable.get(s);
+        
+        if (idx != null) {
+            writeInt(buf, idx.intValue());
+        }
+        else{
+            int i = stringTableBuf.size();
+            if(s.charAt(0) >= '0' && mayPrependSpace){
+                s = ' ' + s;
+                writeInt(buf, i+1);
+            }
+            else{
+                writeInt(buf, i);
+            }
+            
+               stringTable.put(s, new Integer(i));
+               if(s.charAt(0) == ' '){
+                   stringTable.put(s.substring(1), new Integer(i+1));
+               }
+               int j = s.lastIndexOf(' ');
+               if(j > 1){
+                   stringTable.put(s.substring(j), new Integer(i+j));
+                   stringTable.put(s.substring(j+1), new Integer(i+j+1));
+               }
+                
+            writeStrI(stringTableBuf, s);
+            stringTableBuf.flush();
+        }
+        
+    }
+    
+    /**
+     * Sets the tag table for a given page.
+     * The first string in the array defines tag 5, the second tag 6 etc.
+     */
+    
+    public void setTagTable(int page, String[] tagTable) {
+        // TODO: clear entries in tagTable?
+        
+        for (int i = 0; i < tagTable.length; i++) {
+            if (tagTable[i] != null) {
+                Object idx = new int[]{page, i+5};
+                this.tagTable.put(tagTable[i], idx);
+            }
+        }
+    }
+    
+    /**
+     * Sets the attribute start Table for a given page.
+     * The first string in the array defines attribute
+     * 5, the second attribute 6 etc.
+     *  Please use the
+     *  character '=' (without quote!) as delimiter
+     *  between the attribute name and the (start of the) value
+     */
+    public void setAttrStartTable(int page, String[] attrStartTable) {
+        
+        for (int i = 0; i < attrStartTable.length; i++) {
+            if (attrStartTable[i] != null) {
+                Object idx = new int[] {page, i + 5};
+                this.attrStartTable.put(attrStartTable[i], idx);
+            }
+        }
+    }
+    
+    /**
+     * Sets the attribute value Table for a given page.
+     * The first string in the array defines attribute value 0x85,
+     * the second attribute value 0x86 etc.
+     */
+    public void setAttrValueTable(int page, String[] attrValueTable) {
+        // clear entries in this.table!
+        for (int i = 0; i < attrValueTable.length; i++) {
+            if (attrValueTable[i] != null) {
+                Object idx = new int[]{page, i + 0x085};
+                this.attrValueTable.put(attrValueTable[i], idx);
+            }
+        }
+    }
+}
diff --git a/xml/src/main/java/org/kxml2/wap/syncml/SyncML.java b/xml/src/main/java/org/kxml2/wap/syncml/SyncML.java
new file mode 100644
index 0000000..5ea8496
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/wap/syncml/SyncML.java
@@ -0,0 +1,192 @@
+package org.kxml2.wap.syncml;
+
+import org.kxml2.wap.*;
+
+public abstract class SyncML {
+    
+    
+    // SyncML-Common (-//SYNCML//DTD SyncML 1.2//EN and -//SYNCML//DTD MetInf 1.2//EN) support
+    
+    public static WbxmlParser createParser() {
+        WbxmlParser p = new WbxmlParser();
+        p.setTagTable(0, TAG_TABLE_0);
+        p.setTagTable(1, TAG_TABLE_1);
+        return p;
+    }
+
+    public static WbxmlSerializer createSerializer() {
+        WbxmlSerializer s = new WbxmlSerializer();
+        s.setTagTable(0, TAG_TABLE_0);
+        s.setTagTable(1, TAG_TABLE_1);
+        return s;
+    }
+    
+    
+    // SyncML-Common + DMDDF (-//OMA//DTD-DM-DDF 1.2//EN) support
+    
+    public static WbxmlParser createDMParser() {
+        WbxmlParser p = createParser();
+        p.setTagTable(2, TAG_TABLE_2_DM);
+        return p;
+    }
+
+    public static WbxmlSerializer createDMSerializer() {
+        WbxmlSerializer s = createSerializer();
+        s.setTagTable(2, TAG_TABLE_2_DM);
+        return s;
+    }
+
+    // Tables
+    
+    public static final String [] TAG_TABLE_0 = {
+        
+         //  -//SYNCML//DTD SyncML 1.2//EN
+        
+         "Add",            // 0x05 
+         "Alert",          // 0x06 
+         "Archive",        // 0x07 
+         "Atomic",         // 0x08 
+         "Chal",           // 0x09 
+         "Cmd",            // 0x0a 
+         "CmdID",          // 0x0b 
+         "CmdRef",         // 0x0c 
+         "Copy",           // 0x0d 
+         "Cred",           // 0x0e 
+         "Data",           // 0x0f 
+         "Delete",         // 0x10 
+         "Exec",           // 0x11 
+         "Final",          // 0x12 
+         "Get",            // 0x13 
+         "Item",           // 0x14 
+         "Lang",           // 0x15 
+         "LocName",        // 0x16 
+         "LocURI",         // 0x17 
+         "Map",            // 0x18 
+         "MapItem",        // 0x19 
+         "Meta",           // 0x1a 
+         "MsgID",          // 0x1b 
+         "MsgRef",         // 0x1c 
+         "NoResp",         // 0x1d 
+         "NoResults",      // 0x1e 
+         "Put",            // 0x1f 
+         "Replace",        // 0x20 
+         "RespURI",        // 0x21 
+         "Results",        // 0x22 
+         "Search",         // 0x23 
+         "Sequence",       // 0x24 
+         "SessionID",      // 0x25 
+         "SftDel",         // 0x26 
+         "Source",         // 0x27 
+         "SourceRef",      // 0x28 
+         "Status",         // 0x29 
+         "Sync",           // 0x2a 
+         "SyncBody",       // 0x2b 
+         "SyncHdr",        // 0x2c 
+         "SyncML",         // 0x2d 
+         "Target",         // 0x2e 
+         "TargetRef",      // 0x2f 
+         "Reserved for future use",    // 0x30 
+         "VerDTD",         // 0x31 
+         "VerProto",       // 0x32 
+         "NumberOfChanged",// 0x33 
+         "MoreData",       // 0x34 
+         "Field",          // 0x35
+         "Filter",         // 0x36
+         "Record",         // 0x37
+         "FilterType",     // 0x38
+         "SourceParent",   // 0x39
+         "TargetParent",   // 0x3a
+         "Move",           // 0x3b
+         "Correlator"      // 0x3c
+    };  
+    
+    public static final String [] TAG_TABLE_1 = {
+       
+         //  -//SYNCML//DTD MetInf 1.2//EN 
+        
+         "Anchor",         // 0x05 
+         "EMI",            // 0x06 
+         "Format",         // 0x07 
+         "FreeID",         // 0x08 
+         "FreeMem",        // 0x09 
+         "Last",           // 0x0a 
+         "Mark",           // 0x0b 
+         "MaxMsgSize",     // 0x0c 
+         "Mem",            // 0x0d 
+         "MetInf",         // 0x0e 
+         "Next",           // 0x0f 
+         "NextNonce",      // 0x10 
+         "SharedMem",      // 0x11 
+         "Size",           // 0x12 
+         "Type",           // 0x13 
+         "Version",        // 0x14 
+         "MaxObjSize",     // 0x15
+         "FieldLevel"      // 0x16
+         
+    };
+
+    public static final String [] TAG_TABLE_2_DM = {
+        
+        //  -//OMA//DTD-DM-DDF 1.2//EN 
+       
+        "AccessType",         // 0x05 
+        "ACL",                // 0x06 
+        "Add",                // 0x07 
+        "b64",                // 0x08 
+        "bin",                // 0x09 
+        "bool",               // 0x0a 
+        "chr",                // 0x0b 
+        "CaseSense",          // 0x0c 
+        "CIS",                // 0x0d 
+        "Copy",               // 0x0e 
+        "CS",                 // 0x0f 
+        "date",               // 0x10 
+        "DDFName",            // 0x11 
+        "DefaultValue",       // 0x12 
+        "Delete",             // 0x13 
+        "Description",        // 0x14 
+        "DDFFormat",          // 0x15 
+        "DFProperties",       // 0x16 
+        "DFTitle",            // 0x17 
+        "DFType",             // 0x18 
+        "Dynamic",            // 0x19 
+        "Exec",               // 0x1a 
+        "float",              // 0x1b 
+        "Format",             // 0x1c 
+        "Get",                // 0x1d 
+        "int",                // 0x1e 
+        "Man",                // 0x1f 
+        "MgmtTree",           // 0x20 
+        "MIME",               // 0x21 
+        "Mod",                // 0x22 
+        "Name",               // 0x23 
+        "Node",               // 0x24 
+        "node",               // 0x25 
+        "NodeName",           // 0x26 
+        "null",               // 0x27 
+        "Occurence",          // 0x28 
+        "One",                // 0x29 
+        "OneOrMore",          // 0x2a 
+        "OneOrN",             // 0x2b 
+        "Path",               // 0x2c 
+        "Permanent",          // 0x2d 
+        "Replace",            // 0x2e 
+        "RTProperties",       // 0x2f 
+        "Scope",              // 0x30 
+        "Size",               // 0x31 
+        "time",               // 0x32 
+        "Title",              // 0x33 
+        "TStamp",             // 0x34 
+        "Type",               // 0x35
+        "Value",              // 0x36
+        "VerDTD",             // 0x37
+        "VerNo",              // 0x38
+        "xml",                // 0x39
+        "ZeroOrMore",         // 0x3a
+        "ZeroOrN",            // 0x3b
+        "ZeroOrOne"           // 0x3c
+        
+   };
+    
+}
+
diff --git a/xml/src/main/java/org/kxml2/wap/wml/Wml.java b/xml/src/main/java/org/kxml2/wap/wml/Wml.java
new file mode 100644
index 0000000..7e925d8
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/wap/wml/Wml.java
@@ -0,0 +1,233 @@
+package org.kxml2.wap.wml;
+
+import org.kxml2.wap.*;
+
+
+/** This class contains the wml coding tables for elements 
+ *  and attributes needed by the WmlParser. 
+ */
+
+
+public abstract class Wml {
+
+    /** Creates a WbxmlParser with the WML code pages set */
+
+    public static WbxmlParser createParser() {
+        WbxmlParser p = new WbxmlParser();
+        p.setTagTable(0, TAG_TABLE);
+        p.setAttrStartTable(0, ATTR_START_TABLE);
+        p.setAttrValueTable(0, ATTR_VALUE_TABLE);
+        return p;
+    }
+
+    public static WbxmlSerializer createSerializer() {
+        WbxmlSerializer s = new WbxmlSerializer();
+        s.setTagTable(0, TAG_TABLE);
+        s.setAttrStartTable(0, ATTR_START_TABLE);
+        s.setAttrValueTable(0, ATTR_VALUE_TABLE);
+        return s;
+    }
+
+
+    public static final String [] TAG_TABLE = {
+
+    null, // 05
+    null, // 06
+    null, // 07
+    null, // 08
+    null, // 09
+    null, // 0A
+    null, // 0B
+    null, // 0C
+    null, // 0D
+    null, // 0E
+    null, // 0F
+
+    null, // 10
+    null, // 11
+    null, // 12
+    null, // 13
+    null, // 14
+    null, // 15
+    null, // 16
+    null, // 17
+    null, // 18
+    null, // 19
+    null, // 1A
+    null, // 1B
+    "a",  // 1C
+    "td", // 1D
+    "tr", // 1E
+    "table", // 1F
+
+    "p", // 20
+    "postfield", // 21
+    "anchor", // 22
+    "access", // 23
+    "b",  // 24
+    "big", // 25
+    "br", // 26
+    "card", // 27
+    "do", // 28
+    "em", // 29
+    "fieldset", // 2A
+    "go", // 2B
+    "head", // 2C
+    "i", // 2D
+    "img", // 2E
+    "input", // 2F
+
+    "meta", // 30
+    "noop", // 31
+    "prev", // 32
+    "onevent", // 33
+    "optgroup", // 34
+    "option", // 35
+    "refresh", // 36
+    "select", // 37
+    "small", // 38
+    "strong", // 39
+    null, // 3A
+    "template", // 3B
+    "timer", // 3C
+    "u", // 3D
+    "setvar", // 3E
+    "wml", // 3F
+    };
+
+    
+    public static final String [] ATTR_START_TABLE = { 
+    "accept-charset", // 05
+    "align=bottom", // 06
+    "align=center", // 07
+    "align=left", // 08
+    "align=middle", // 09
+    "align=right", // 0A
+    "align=top", // 0B
+    "alt", // 0C
+    "content", // 0D
+    null, // 0E
+    "domain", // 0F
+    
+    "emptyok=false", // 10
+    "emptyok=true", // 11
+    "format", // 12
+    "height", // 13
+    "hspace", // 14
+    "ivalue", // 15
+    "iname", // 16
+    null, // 17
+    "label", // 18
+    "localsrc", // 19
+    "maxlength", // 1A
+    "method=get", // 1B
+    "method=post", // 1C
+    "mode=nowrap", // 1D
+    "mode=wrap", // 1E
+    "multiple=false", // 1F
+
+    "multiple=true", // 20
+    "name", // 21
+    "newcontext=false", // 22
+    "newcontext=true", // 23
+    "onpick", // 24
+    "onenterbackward", // 25
+    "onenterforward", // 26
+    "ontimer", // 27
+    "optimal=false", // 28
+    "optimal=true", // 29
+    "path", // 2A
+    null, // 2B
+    null, // 2C
+    null, // 2D
+    "scheme", // 2E
+    "sendreferer=false", // 2F
+    
+    "sendreferer=true", // 30
+    "size", // 31
+    "src", // 32
+    "ordered=true", // 33
+    "ordered=false", // 34
+    "tabindex", // 35
+    "title", // 36
+    "type", // 37
+    "type=accept", // 38
+    "type=delete", // 39
+    "type=help", // 3A
+    "type=password", // 3B
+    "type=onpick", // 3C
+    "type=onenterbackward", // 3D
+    "type=onenterforward", // 3E
+    "type=ontimer", // 3F
+
+    null, // 40
+    null, // 41
+    null, // 42
+    null, // 43
+    null, // 44
+    "type=options", // 45
+    "type=prev", // 46
+    "type=reset", // 47
+    "type=text", // 48
+    "type=vnd.", // 49
+    "href", // 4A
+    "href=http://", // 4B
+    "href=https://", // 4C
+    "value", // 4D
+    "vspace", // 4E
+    "width", // 4F
+
+    "xml:lang", // 50
+    null, // 51
+    "align", // 52
+    "columns", // 53
+    "class", // 54
+    "id", // 55
+    "forua=false", // 56
+    "forua=true", // 57
+    "src=http://", // 58
+    "src=https://", // 59
+    "http-equiv", // 5A
+    "http-equiv=Content-Type", // 5B
+    "content=application/vnd.wap.wmlc;charset=", // 5C
+    "http-equiv=Expires", // 5D
+    null, // 5E
+    null, // 5F
+    };
+
+
+    public static final String [] ATTR_VALUE_TABLE = {
+    ".com/", // 85
+    ".edu/", // 86
+    ".net/", // 87
+    ".org/", // 88
+    "accept", // 89
+    "bottom", // 8A
+    "clear", // 8B
+    "delete", // 8C
+    "help", // 8D
+    "http://", // 8E
+    "http://www.", // 8F
+    
+    "https://", // 90
+    "https://www.", // 91
+    null, // 92
+    "middle", // 93
+    "nowrap", // 94
+    "onpick", // 95
+    "onenterbackward", // 96
+    "onenterforward", // 97
+    "ontimer", // 98
+    "options", // 99
+    "password", // 9A
+    "reset", // 9B
+    null, // 9C
+    "text", // 9D
+    "top", // 9E
+    "unknown", // 9F
+    
+    "wrap", // A0
+    "www.", // A1
+    };
+}    
+
diff --git a/xml/src/main/java/org/kxml2/wap/wv/WV.java b/xml/src/main/java/org/kxml2/wap/wv/WV.java
new file mode 100644
index 0000000..e2afbfb
--- /dev/null
+++ b/xml/src/main/java/org/kxml2/wap/wv/WV.java
@@ -0,0 +1,593 @@
+package org.kxml2.wap.wv;
+
+import java.io.IOException;
+
+import org.kxml2.wap.*;
+
+/*
+
+ * WV.java
+
+ *
+
+ * Created on 25 September 2003, 10:40
+
+ */
+
+
+
+
+
+   /** 
+     *    Wireless Village CSP 1.1 ("OMA-WV-CSP-V1_1-20021001-A.pdf")
+     *    Wireless Village CSP 1.2 ("OMA-IMPS-WV-CSP_WBXML-v1_2-20030221-C.PDF")
+     *    There are some bugs in the 1.2 spec but this is Ok. 1.2 is candidate  
+ *
+
+ * @author  Bogdan Onoiu
+
+ */
+
+public abstract class WV {
+
+    
+
+    
+    
+    public static WbxmlParser createParser () throws IOException {
+        
+        WbxmlParser parser = new WbxmlParser();
+
+        parser.setTagTable (0, WV.tagTablePage0);
+        parser.setTagTable (1, WV.tagTablePage1);
+        parser.setTagTable (2, WV.tagTablePage2);
+        parser.setTagTable (3, WV.tagTablePage3);
+        parser.setTagTable (4, WV.tagTablePage4);
+        parser.setTagTable (5, WV.tagTablePage5);
+        parser.setTagTable (6, WV.tagTablePage6);
+        parser.setTagTable (7, WV.tagTablePage7);
+        parser.setTagTable (8, WV.tagTablePage8);
+        parser.setTagTable (9, WV.tagTablePage9);
+        parser.setTagTable (10, WV.tagTablePageA);
+
+        parser.setAttrStartTable (0, WV.attrStartTable);
+        
+        parser.setAttrValueTable (0, WV.attrValueTable);
+
+        return parser;
+    }
+    
+   
+    
+    public static final String [] tagTablePage0 = {
+        /* Common ... continue on Page 0x09 */
+        "Acceptance",     //0x00, 0x05
+        "AddList",        //0x00, 0x06
+        "AddNickList",    //0x00, 0x07
+        "SName",          //0x00, 0x08
+        "WV-CSP-Message", //0x00, 0x09
+        "ClientID",       //0x00, 0x0A
+        "Code",           //0x00, 0x0B
+        "ContactList",    //0x00, 0x0C
+        "ContentData",    //0x00, 0x0D
+        "ContentEncoding",//0x00, 0x0E
+        "ContentSize",    //0x00, 0x0F
+        "ContentType",    //0x00, 0x10
+        "DateTime",       //0x00, 0x11
+        "Description",    //0x00, 0x12
+        "DetailedResult", //0x00, 0x13
+        "EntityList",     //0x00, 0x14
+        "Group",          //0x00, 0x15
+        "GroupID",        //0x00, 0x16
+        "GroupList",      //0x00, 0x17
+        "InUse",          //0x00, 0x18
+        "Logo",           //0x00, 0x19
+        "MessageCount",   //0x00, 0x1A
+        "MessageID",      //0x00, 0x1B
+        "MessageURI",     //0x00, 0x1C
+        "MSISDN",         //0x00, 0x1D
+        "Name",           //0x00, 0x1E
+        "NickList",       //0x00, 0x1F
+        "NickName",       //0x00, 0x20
+        "Poll",           //0x00, 0x21
+        "Presence",       //0x00, 0x22
+        "PresenceSubList",//0x00, 0x23
+        "PresenceValue",  //0x00, 0x24
+        "Property",       //0x00, 0x25
+        "Qualifier",      //0x00, 0x26
+        "Recipient",      //0x00, 0x27
+        "RemoveList",     //0x00, 0x28
+        "RemoveNickList", //0x00, 0x29
+        "Result",         //0x00, 0x2A
+        "ScreenName",     //0x00, 0x2B
+        "Sender",         //0x00, 0x2C
+        "Session",        //0x00, 0x2D
+        "SessionDescriptor",//0x00, 0x2E
+        "SessionID",      //0x00, 0x2F
+        "SessionType",    //0x00, 0x30
+        "Status",         //0x00, 0x31
+        "Transaction",    //0x00, 0x32
+        "TransactionContent",//0x00, 0x33
+        "TransactionDescriptor",//0x00, 0x34
+        "TransactionID",  //0x00, 0x35
+        "TransactionMode",//0x00, 0x36
+        "URL",            //0x00, 0x37
+        "URLList",        //0x00, 0x38
+        "User",           //0x00, 0x39
+        "UserID",         //0x00, 0x3A
+        "UserList",       //0x00, 0x3B
+        "Validity",       //0x00, 0x3C
+        "Value",          //0x00, 0x3D
+    };
+    
+    public static final String [] tagTablePage1 = {
+        /* Access ... continue on Page 0x0A */
+        "AllFunctions",             //  0x01, 0x05
+        "AllFunctionsRequest",      //  0x01, 0x06
+        "CancelInvite-Request",     //  0x01, 0x07
+        "CancelInviteUser-Request", //  0x01, 0x08
+        "Capability",               //  0x01, 0x09
+        "CapabilityList",           //  0x01, 0x0A
+        "CapabilityRequest",        //  0x01, 0x0B
+        "ClientCapability-Request", //  0x01, 0x0C
+        "ClientCapability-Response",//  0x01, 0x0D
+        "DigestBytes",          //  0x01, 0x0E
+        "DigestSchema",         //  0x01, 0x0F
+        "Disconnect",           //  0x01, 0x10
+        "Functions",            //  0x01, 0x11
+        "GetSPInfo-Request",    //  0x01, 0x12
+        "GetSPInfo-Response",   //  0x01, 0x13
+        "InviteID",             //  0x01, 0x14
+        "InviteNote",           //  0x01, 0x15
+        "Invite-Request",       //  0x01, 0x16
+        "Invite-Response",      //  0x01, 0x17
+        "InviteType",           //  0x01, 0x18
+        "InviteUser-Request",   //  0x01, 0x19
+        "InviteUser-Response",  //  0x01, 0x1A
+        "KeepAlive-Request",    //  0x01, 0x1B
+        "KeepAliveTime",        //  0x01, 0x1C
+        "Login-Request",        //  0x01, 0x1D
+        "Login-Response",       //  0x01, 0x1E
+        "Logout-Request",       //  0x01, 0x1F
+        "Nonce",                //  0x01, 0x20
+        "Password",             //  0x01, 0x21
+        "Polling-Request",      //  0x01, 0x22
+        "ResponseNote",         //  0x01, 0x23
+        "SearchElement",        //  0x01, 0x24
+        "SearchFindings",       //  0x01, 0x25
+        "SearchID",             //  0x01, 0x26
+        "SearchIndex",          //  0x01, 0x27
+        "SearchLimit",          //  0x01, 0x28
+        "KeepAlive-Response",   //  0x01, 0x29
+        "SearchPairList",       //  0x01, 0x2A
+        "Search-Request",       //  0x01, 0x2B
+        "Search-Response",      //  0x01, 0x2C
+        "SearchResult",         //  0x01, 0x2D
+        "Service-Request",      //  0x01, 0x2E
+        "Service-Response",     //  0x01, 0x2F
+        "SessionCookie",        //  0x01, 0x30
+        "StopSearch-Request",   //  0x01, 0x31
+        "TimeToLive",           //  0x01, 0x32
+        "SearchString",         //  0x01, 0x33
+        "CompletionFlag",       //  0x01, 0x34
+        null,                   //  0x01, 0x35
+        "ReceiveList",          //  0x01, 0x36 /* WV 1.2 */
+        "VerifyID-Request",     //  0x01, 0x37 /* WV 1.2 */
+        "Extended-Request",     //  0x01, 0x38 /* WV 1.2 */
+        "Extended-Response",    //  0x01, 0x39 /* WV 1.2 */
+        "AgreedCapabilityList", //  0x01, 0x3A /* WV 1.2 */
+        "Extended-Data",        //  0x01, 0x3B /* WV 1.2 */
+        "OtherServer",          //  0x01, 0x3C /* WV 1.2 */
+        "PresenceAttributeNSName",//0x01, 0x3D /* WV 1.2 */
+        "SessionNSName",        //  0x01, 0x3E /* WV 1.2 */
+        "TransactionNSName",    //  0x01, 0x3F /* WV 1.2 */
+    };
+    
+    public static final String [] tagTablePage2 = {
+        /* Service ... continue on Page 0x08 */
+        "ADDGM",        //  0x02, 0x05
+        "AttListFunc",  //  0x02, 0x06
+        "BLENT",        //  0x02, 0x07
+        "CAAUT",        //  0x02, 0x08
+        "CAINV",        //  0x02, 0x09
+        "CALI",         //  0x02, 0x0A
+        "CCLI",         //  0x02, 0x0B
+        "ContListFunc", //  0x02, 0x0C
+        "CREAG",        //  0x02, 0x0D
+        "DALI",         //  0x02, 0x0E
+        "DCLI",         //  0x02, 0x0F
+        "DELGR",        //  0x02, 0x10
+        "FundamentalFeat",//0x02, 0x11
+        "FWMSG",        //  0x02, 0x12
+        "GALS",         //  0x02, 0x13
+        "GCLI",         //  0x02, 0x14
+        "GETGM",        //  0x02, 0x15
+        "GETGP",        //  0x02, 0x16
+        "GETLM",        //  0x02, 0x17
+        "GETM",         //  0x02, 0x18
+        "GETPR",        //  0x02, 0x19
+        "GETSPI",       //  0x02, 0x1A
+        "GETWL",        //  0x02, 0x1B
+        "GLBLU",        //  0x02, 0x1C
+        "GRCHN",        //  0x02, 0x1D
+        "GroupAuthFunc",//  0x02, 0x1E
+        "GroupFeat",    //  0x02, 0x1F
+        "GroupMgmtFunc",//  0x02, 0x20
+        "GroupUseFunc", //  0x02, 0x21
+        "IMAuthFunc",   //  0x02, 0x22
+        "IMFeat",       //  0x02, 0x23
+        "IMReceiveFunc",//  0x02, 0x24
+        "IMSendFunc",   //  0x02, 0x25
+        "INVIT",        //  0x02, 0x26
+        "InviteFunc",   //  0x02, 0x27
+        "MBRAC",        //  0x02, 0x28
+        "MCLS",         //  0x02, 0x29
+        "MDELIV",       //  0x02, 0x2A
+        "NEWM",         //  0x02, 0x2B
+        "NOTIF",        //  0x02, 0x2C
+        "PresenceAuthFunc",//0x02, 0x2D
+        "PresenceDeliverFunc",//0x02, 0x2E
+        "PresenceFeat", //  0x02, 0x2F
+        "REACT",        //  0x02, 0x30
+        "REJCM",        //  0x02, 0x31
+        "REJEC",        //  0x02, 0x32
+        "RMVGM",        //  0x02, 0x33
+        "SearchFunc",   //  0x02, 0x34
+        "ServiceFunc",  //  0x02, 0x35
+        "SETD",         //  0x02, 0x36
+        "SETGP",        //  0x02, 0x37
+        "SRCH",         //  0x02, 0x38
+        "STSRC",        //  0x02, 0x39
+        "SUBGCN",       //  0x02, 0x3A
+        "UPDPR",        //  0x02, 0x3B
+        "WVCSPFeat",    //  0x02, 0x3C
+        "MF",           //  0x02, 0x3D /* WV 1.2 */
+        "MG",           //  0x02, 0x3E /* WV 1.2 */
+        "MM"            //  0x02, 0x3F /* WV 1.2 */
+    };
+    
+    public static final String [] tagTablePage3 = {
+        /* Client Capability */
+        "AcceptedCharset",          //  0x03, 0x05
+        "AcceptedContentLength",    //  0x03, 0x06
+        "AcceptedContentType",      //  0x03, 0x07
+        "AcceptedTransferEncoding", //  0x03, 0x08
+        "AnyContent",               //  0x03, 0x09
+        "DefaultLanguage",          //  0x03, 0x0A
+        "InitialDeliveryMethod",    //  0x03, 0x0B
+        "MultiTrans",               //  0x03, 0x0C
+        "ParserSize",               //  0x03, 0x0D
+        "ServerPollMin",            //  0x03, 0x0E
+        "SupportedBearer",          //  0x03, 0x0F
+        "SupportedCIRMethod",       //  0x03, 0x10
+        "TCPAddress",               //  0x03, 0x11
+        "TCPPort",                  //  0x03, 0x12
+        "UDPPort"                  //  0x03, 0x13
+    };
+    
+    public static final String [] tagTablePage4 = {
+        /* Presence Primitive */
+        "CancelAuth-Request",           //  0x04, 0x05
+        "ContactListProperties",        //  0x04, 0x06
+        "CreateAttributeList-Request",  //  0x04, 0x07
+        "CreateList-Request",           //  0x04, 0x08
+        "DefaultAttributeList",         //  0x04, 0x09
+        "DefaultContactList",           //  0x04, 0x0A
+        "DefaultList",                  //  0x04, 0x0B
+        "DeleteAttributeList-Request",  //  0x04, 0x0C
+        "DeleteList-Request",           //  0x04, 0x0D
+        "GetAttributeList-Request",     //  0x04, 0x0E
+        "GetAttributeList-Response",    //  0x04, 0x0F
+        "GetList-Request",              //  0x04, 0x10
+        "GetList-Response",             //  0x04, 0x11
+        "GetPresence-Request",          //  0x04, 0x12
+        "GetPresence-Response",         //  0x04, 0x13
+        "GetWatcherList-Request",       //  0x04, 0x14
+        "GetWatcherList-Response",      //  0x04, 0x15
+        "ListManage-Request",           //  0x04, 0x16
+        "ListManage-Response",          //  0x04, 0x17
+        "UnsubscribePresence-Request",  //  0x04, 0x18
+        "PresenceAuth-Request",         //  0x04, 0x19
+        "PresenceAuth-User",            //  0x04, 0x1A
+        "PresenceNotification-Request", //  0x04, 0x1B
+        "UpdatePresence-Request",       //  0x04, 0x1C
+        "SubscribePresence-Request",    //  0x04, 0x1D
+        "Auto-Subscribe",               //  0x04, 0x1E /* WV 1.2 */
+        "GetReactiveAuthStatus-Request",//  0x04, 0x1F /* WV 1.2 */
+        "GetReactiveAuthStatus-Response",// 0x04, 0x20 /* WV 1.2 */
+    };
+    
+    public static final String [] tagTablePage5 = {
+        /* Presence Attribute */
+        "Accuracy",         //  0x05, 0x05
+        "Address",          //  0x05, 0x06
+        "AddrPref",         //  0x05, 0x07
+        "Alias",            //  0x05, 0x08
+        "Altitude",         //  0x05, 0x09
+        "Building",         //  0x05, 0x0A
+        "Caddr",            //  0x05, 0x0B
+        "City",             //  0x05, 0x0C
+        "ClientInfo",       //  0x05, 0x0D
+        "ClientProducer",   //  0x05, 0x0E
+        "ClientType",       //  0x05, 0x0F
+        "ClientVersion",    //  0x05, 0x10
+        "CommC",            //  0x05, 0x11
+        "CommCap",          //  0x05, 0x12
+        "ContactInfo",      //  0x05, 0x13
+        "ContainedvCard",   //  0x05, 0x14
+        "Country",          //  0x05, 0x15
+        "Crossing1",        //  0x05, 0x16
+        "Crossing2",        //  0x05, 0x17
+        "DevManufacturer",  //  0x05, 0x18
+        "DirectContent",    //  0x05, 0x19
+        "FreeTextLocation", //  0x05, 0x1A
+        "GeoLocation",      //  0x05, 0x1B
+        "Language",         //  0x05, 0x1C
+        "Latitude",         //  0x05, 0x1D
+        "Longitude",        //  0x05, 0x1E
+        "Model",            //  0x05, 0x1F
+        "NamedArea",        //  0x05, 0x20
+        "OnlineStatus",     //  0x05, 0x21
+        "PLMN",             //  0x05, 0x22
+        "PrefC",            //  0x05, 0x23
+        "PreferredContacts",//  0x05, 0x24
+        "PreferredLanguage",//  0x05, 0x25
+        "PreferredContent", //  0x05, 0x26
+        "PreferredvCard",   //  0x05, 0x27
+        "Registration",     //  0x05, 0x28
+        "StatusContent",    //  0x05, 0x29
+        "StatusMood",       //  0x05, 0x2A
+        "StatusText",       //  0x05, 0x2B
+        "Street",           //  0x05, 0x2C
+        "TimeZone",         //  0x05, 0x2D
+        "UserAvailability", //  0x05, 0x2E
+        "Cap",              //  0x05, 0x2F
+        "Cname",            //  0x05, 0x30
+        "Contact",          //  0x05, 0x31
+        "Cpriority",        //  0x05, 0x32
+        "Cstatus",          //  0x05, 0x33
+        "Note",             //  0x05, 0x34 /* WV 1.2 */
+        "Zone",             //  0x05, 0x35
+        null,
+        "Inf_link",         //  0x05, 0x37 /* WV 1.2 */
+        "InfoLink",         //  0x05, 0x38 /* WV 1.2 */
+        "Link",             //  0x05, 0x39 /* WV 1.2 */
+        "Text",             //  0x05, 0x3A /* WV 1.2 */
+    };
+    
+    public static final String [] tagTablePage6 = {
+        /* Messaging */
+        "BlockList",                //  0x06, 0x05
+//      "BlockUser-Request",        //  0x06, 0x06  //This is a bug in the spec
+        "BlockEntity-Request",        //  0x06, 0x06  
+        "DeliveryMethod",           //  0x06, 0x07
+        "DeliveryReport",           //  0x06, 0x08
+        "DeliveryReport-Request",   //  0x06, 0x09
+        "ForwardMessage-Request",   //  0x06, 0x0A
+        "GetBlockedList-Request",   //  0x06, 0x0B
+        "GetBlockedList-Response",  //  0x06, 0x0C
+        "GetMessageList-Request",   //  0x06, 0x0D
+        "GetMessageList-Response",  //  0x06, 0x0E
+        "GetMessage-Request",       //  0x06, 0x0F
+        "GetMessage-Response",      //  0x06, 0x10
+        "GrantList",                //  0x06, 0x11
+        "MessageDelivered",         //  0x06, 0x12
+        "MessageInfo",              //  0x06, 0x13
+        "MessageNotification",      //  0x06, 0x14
+        "NewMessage",               //  0x06, 0x15
+        "RejectMessage-Request",    //  0x06, 0x16
+        "SendMessage-Request",      //  0x06, 0x17
+        "SendMessage-Response",     //  0x06, 0x18
+        "SetDeliveryMethod-Request",//  0x06, 0x19
+        "DeliveryTime",             //  0x06, 0x1A
+    };
+    
+    public static final String [] tagTablePage7 = {
+        /* Group */
+        "AddGroupMembers-Request",  //  0x07, 0x05
+        "Admin",                    //  0x07, 0x06
+        "CreateGroup-Request",      //  0x07, 0x07
+        "DeleteGroup-Request",      //  0x07, 0x08
+        "GetGroupMembers-Request",  //  0x07, 0x09
+        "GetGroupMembers-Response", //  0x07, 0x0A
+        "GetGroupProps-Request",    //  0x07, 0x0B
+        "GetGroupProps-Response",   //  0x07, 0x0C
+        "GroupChangeNotice",        //  0x07, 0x0D
+        "GroupProperties",          //  0x07, 0x0E
+        "Joined",                   //  0x07, 0x0F
+        "JoinedRequest",            //  0x07, 0x10
+        "JoinGroup-Request",        //  0x07, 0x11
+        "JoinGroup-Response",       //  0x07, 0x12
+        "LeaveGroup-Request",       //  0x07, 0x13
+        "LeaveGroup-Response",      //  0x07, 0x14
+        "Left",                     //  0x07, 0x15
+        "MemberAccess-Request",     //  0x07, 0x16
+        "Mod",                      //  0x07, 0x17
+        "OwnProperties",            //  0x07, 0x18
+        "RejectList-Request",       //  0x07, 0x19
+        "RejectList-Response",      //  0x07, 0x1A
+        "RemoveGroupMembers-Request",// 0x07, 0x1B
+        "SetGroupProps-Request",    //  0x07, 0x1C
+        "SubscribeGroupNotice-Request", //  0x07, 0x1D
+        "SubscribeGroupNotice-Response",//  0x07, 0x1E
+        "Users",                    //  0x07, 0x1F
+        "WelcomeNote",              //  0x07, 0x20
+        "JoinGroup",                //  0x07, 0x21
+        "SubscribeNotification",    //  0x07, 0x22
+        "SubscribeType",            //  0x07, 0x23
+        "GetJoinedUsers-Request",   //  0x07, 0x24 /* WV 1.2 */
+        "GetJoinedUsers-Response",  //  0x07, 0x25 /* WV 1.2 */
+        "AdminMapList",             //  0x07, 0x26 /* WV 1.2 */
+        "AdminMapping",             //  0x07, 0x27 /* WV 1.2 */
+        "Mapping",                  //  0x07, 0x28 /* WV 1.2 */
+        "ModMapping",               //  0x07, 0x29 /* WV 1.2 */
+        "UserMapList",              //  0x07, 0x2A /* WV 1.2 */
+        "UserMapping",              //  0x07, 0x2B /* WV 1.2 */
+    };
+    
+    public static final String [] tagTablePage8 = {
+        /* Service ... continued */
+        "MP",                       //  0x08, 0x05 /* WV 1.2 */
+        "GETAUT",                   //  0x08, 0x06 /* WV 1.2 */
+        "GETJU",                    //  0x08, 0x07 /* WV 1.2 */
+        "VRID",                     //  0x08, 0x08 /* WV 1.2 */
+        "VerifyIDFunc",             //  0x08, 0x09 /* WV 1.2 */
+    };
+    
+    public static final String [] tagTablePage9 = {
+        /* Common ... continued */
+        "CIR",                      //  0x09, 0x05 /* WV 1.2 */
+        "Domain",                   //  0x09, 0x06 /* WV 1.2 */
+        "ExtBlock",                 //  0x09, 0x07 /* WV 1.2 */
+        "HistoryPeriod",            //  0x09, 0x08 /* WV 1.2 */
+        "IDList",                   //  0x09, 0x09 /* WV 1.2 */
+        "MaxWatcherList",           //  0x09, 0x0A /* WV 1.2 */
+        "ReactiveAuthState",        //  0x09, 0x0B /* WV 1.2 */
+        "ReactiveAuthStatus",       //  0x09, 0x0C /* WV 1.2 */
+        "ReactiveAuthStatusList",   //  0x09, 0x0D /* WV 1.2 */
+        "Watcher",                  //  0x09, 0x0E /* WV 1.2 */
+        "WatcherStatus"             //  0x09, 0x0F /* WV 1.2 */
+    };
+    
+    public static final String [] tagTablePageA = {
+        /* Access ... continued */
+        "WV-CSP-NSDiscovery-Request",  //0x0A, 0x05 /* WV 1.2 */
+        "WV-CSP-NSDiscovery-Response", //0x0A, 0x06 /* WV 1.2 */
+        "VersionList"                  //0x0A, 0x07 /* WV 1.2 */
+    };
+    
+    public static final String [] attrStartTable = {
+        "xmlns=http://www.wireless-village.org/CSP",//  0x00, 0x05
+        "xmlns=http://www.wireless-village.org/PA", //  0x00, 0x06
+        "xmlns=http://www.wireless-village.org/TRC",//  0x00, 0x07
+        "xmlns=http://www.openmobilealliance.org/DTD/WV-CSP",   //  0x00, 0x08
+        "xmlns=http://www.openmobilealliance.org/DTD/WV-PA",    //  0x00, 0x09
+        "xmlns=http://www.openmobilealliance.org/DTD/WV-TRC",   //  0x00, 0x0A
+    };
+    
+    public static final String [] attrValueTable = {
+      
+        "AccessType",                           // 0x00 /* Common value token */
+        "ActiveUsers",                          // 0x01 /* Common value token */
+        "Admin",                                // 0x02 /* Common value token */
+        "application/",                         // 0x03 /* Common value token */
+        "application/vnd.wap.mms-message",      // 0x04 /* Common value token */
+        "application/x-sms",                    // 0x05 /* Common value token */
+        "AutoJoin",                             // 0x06 /* Common value token */
+        "BASE64",                               // 0x07 /* Common value token */
+        "Closed",                               // 0x08 /* Common value token */
+        "Default",                              // 0x09 /* Common value token */
+        "DisplayName",                          // 0x0a /* Common value token */
+        "F",                                    // 0x0b /* Common value token */
+        "G",                                    // 0x0c /* Common value token */
+        "GR",                                   // 0x0d /* Common value token */
+        "http://",                              // 0x0e /* Common value token */
+        "https://",                             // 0x0f /* Common value token */
+        "image/",                               // 0x10 /* Common value token */
+        "Inband",                               // 0x11 /* Common value token */
+        "IM",                                   // 0x12 /* Common value token */
+        "MaxActiveUsers",                       // 0x13 /* Common value token */
+        "Mod",                                  // 0x14 /* Common value token */
+        "Name",                                 // 0x15 /* Common value token */
+        "None",                                 // 0x16 /* Common value token */
+        "N",                                    // 0x17 /* Common value token */
+        "Open",                                 // 0x18 /* Common value token */
+        "Outband",                              // 0x19 /* Common value token */
+        "PR",                                   // 0x1a /* Common value token */
+        "Private",                              // 0x1b /* Common value token */
+        "PrivateMessaging",                     // 0x1c /* Common value token */
+        "PrivilegeLevel",                       // 0x1d /* Common value token */
+        "Public",                               // 0x1e /* Common value token */
+        "P",                                    // 0x1f /* Common value token */
+        "Request",                              // 0x20 /* Common value token */
+        "Response",                             // 0x21 /* Common value token */
+        "Restricted",                           // 0x22 /* Common value token */
+        "ScreenName",                           // 0x23 /* Common value token */
+        "Searchable",                           // 0x24 /* Common value token */
+        "S",                                    // 0x25 /* Common value token */
+        "SC",                                   // 0x26 /* Common value token */
+        "text/",                                // 0x27 /* Common value token */
+        "text/plain",                           // 0x28 /* Common value token */
+        "text/x-vCalendar",                     // 0x29 /* Common value token */
+        "text/x-vCard",                         // 0x2a /* Common value token */
+        "Topic",                                // 0x2b /* Common value token */
+        "T",                                    // 0x2c /* Common value token */
+        "Type",                                 // 0x2d /* Common value token */
+        "U",                                    // 0x2e /* Common value token */
+        "US",                                   // 0x2f /* Common value token */
+        "www.wireless-village.org",             // 0x30 /* Common value token */
+        "AutoDelete",                           // 0x31 /* Common value token */ /* WV 1.2 */
+        "GM",                                   // 0x32 /* Common value token */ /* WV 1.2 */
+        "Validity",                             // 0x33 /* Common value token */ /* WV 1.2 */
+        "ShowID",                               // 0x34 /* Common value token */ /* WV 1.2 */
+        "GRANTED",                              // 0x35 /* Common value token */ /* WV 1.2 */
+        "PENDING",                              // 0x36 /* Common value token */ /* WV 1.2 */
+        null,                                   // 0x37
+        null,                                   // 0x38
+        null,                                   // 0x39
+        null,                                   // 0x3a
+        null,                                   // 0x3b
+        null,                                   // 0x3c
+        "GROUP_ID",                             // 0x3d /* Access value token */
+        "GROUP_NAME",                           // 0x3e /* Access value token */
+        "GROUP_TOPIC",                          // 0x3f /* Access value token */
+        "GROUP_USER_ID_JOINED",                 // 0x40 /* Access value token */
+        "GROUP_USER_ID_OWNER",                  // 0x41 /* Access value token */
+        "HTTP",                                 // 0x42 /* Access value token */
+        "SMS",                                  // 0x43 /* Access value token */
+        "STCP",                                 // 0x44 /* Access value token */
+        "SUDP",                                 // 0x45 /* Access value token */
+        "USER_ALIAS",                           // 0x46 /* Access value token */
+        "USER_EMAIL_ADDRESS",                   // 0x47 /* Access value token */
+        "USER_FIRST_NAME",                      // 0x48 /* Access value token */
+        "USER_ID",                              // 0x49 /* Access value token */
+        "USER_LAST_NAME",                       // 0x4a /* Access value token */
+        "USER_MOBILE_NUMBER",                   // 0x4b /* Access value token */
+        "USER_ONLINE_STATUS",                   // 0x4c /* Access value token */
+        "WAPSMS",                               // 0x4d /* Access value token */
+        "WAPUDP",                               // 0x4e /* Access value token */
+        "WSP",                                  // 0x4f /* Access value token */
+        "GROUP_USER_ID_AUTOJOIN",               // 0x50 /* Access value token */ /* WV 1.2 */
+        null,                                   // 0x51
+        null,                                   // 0x52
+        null,                                   // 0x53
+        null,                                   // 0x54
+        null,                                   // 0x55
+        null,                                   // 0x56
+        null,                                   // 0x57
+        null,                                   // 0x58
+        null,                                   // 0x59
+        null,                                   // 0x5a
+        "ANGRY",                                // 0x5b /* Presence value token */
+        "ANXIOUS",                              // 0x5c /* Presence value token */
+        "ASHAMED",                              // 0x5d /* Presence value token */
+        "AUDIO_CALL",                           // 0x5e /* Presence value token */
+        "AVAILABLE",                            // 0x5f /* Presence value token */
+        "BORED",                                // 0x60 /* Presence value token */
+        "CALL",                                 // 0x61 /* Presence value token */
+        "CLI",                                  // 0x62 /* Presence value token */
+        "COMPUTER",                             // 0x63 /* Presence value token */
+        "DISCREET",                             // 0x64 /* Presence value token */
+        "EMAIL",                                // 0x65 /* Presence value token */
+        "EXCITED",                              // 0x66 /* Presence value token */
+        "HAPPY",                                // 0x67 /* Presence value token */
+        "IM",                                   // 0x68 /* Presence value token */
+        "IM_OFFLINE",                           // 0x69 /* Presence value token */
+        "IM_ONLINE",                            // 0x6a /* Presence value token */
+        "IN_LOVE",                              // 0x6b /* Presence value token */
+        "INVINCIBLE",                           // 0x6c /* Presence value token */
+        "JEALOUS",                              // 0x6d /* Presence value token */
+        "MMS",                                  // 0x6e /* Presence value token */
+        "MOBILE_PHONE",                         // 0x6f /* Presence value token */
+        "NOT_AVAILABLE",                        // 0x70 /* Presence value token */
+        "OTHER",                                // 0x71 /* Presence value token */
+        "PDA",                                  // 0x72 /* Presence value token */
+        "SAD",                                  // 0x73 /* Presence value token */
+        "SLEEPY",                               // 0x74 /* Presence value token */
+        "SMS",                                  // 0x75 /* Presence value token */
+        "VIDEO_CALL",                           // 0x76 /* Presence value token */
+        "VIDEO_STREAM",                         // 0x77 /* Presence value token */
+    };
+    
+    
+}
diff --git a/xml/src/main/java/org/w3c/dom/Attr.java b/xml/src/main/java/org/w3c/dom/Attr.java
new file mode 100644
index 0000000..3bfde52
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/Attr.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ *  The <code>Attr</code> interface represents an attribute in an 
+ * <code>Element</code> object. Typically the allowable values for the 
+ * attribute are defined in a document type definition.
+ * <p><code>Attr</code> objects inherit the <code>Node</code> interface, but 
+ * since they are not actually child nodes of the element they describe, the 
+ * DOM does not consider them part of the document tree. Thus, the 
+ * <code>Node</code> attributes <code>parentNode</code>, 
+ * <code>previousSibling</code>, and <code>nextSibling</code> have a 
+ * <code>null</code> value for <code>Attr</code> objects. The DOM takes the 
+ * view that attributes are properties of elements rather than having a 
+ * separate identity from the elements they are associated with; this should 
+ * make it more efficient to implement such features as default attributes 
+ * associated with all elements of a given type. Furthermore, 
+ * <code>Attr</code> nodes may not be immediate children of a 
+ * <code>DocumentFragment</code>. However, they can be associated with 
+ * <code>Element</code> nodes contained within a 
+ * <code>DocumentFragment</code>. In short, users and implementors of the 
+ * DOM need to be aware that <code>Attr</code> nodes have some things in 
+ * common with other objects inheriting the <code>Node</code> interface, but 
+ * they also are quite distinct.
+ * <p> The attribute's effective value is determined as follows: if this 
+ * attribute has been explicitly assigned any value, that value is the 
+ * attribute's effective value; otherwise, if there is a declaration for 
+ * this attribute, and that declaration includes a default value, then that 
+ * default value is the attribute's effective value; otherwise, the 
+ * attribute does not exist on this element in the structure model until it 
+ * has been explicitly added. Note that the <code>nodeValue</code> attribute 
+ * on the <code>Attr</code> instance can also be used to retrieve the string 
+ * version of the attribute's value(s). 
+ * <p>In XML, where the value of an attribute can contain entity references, 
+ * the child nodes of the <code>Attr</code> node may be either 
+ * <code>Text</code> or <code>EntityReference</code> nodes (when these are 
+ * in use; see the description of <code>EntityReference</code> for 
+ * discussion). Because the DOM Core is not aware of attribute types, it 
+ * treats all attribute values as simple strings, even if the DTD or schema 
+ * declares them as having tokenized types. 
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface Attr extends Node {
+    /**
+     * Returns the name of this attribute.
+     * 
+     * @return the name of the attribute.
+     */
+    public String getName();
+
+    /**
+     * If this attribute was explicitly given a value in the original 
+     * document, this is <code>true</code>; otherwise, it is 
+     * <code>false</code>. Note that the implementation is in charge of this 
+     * attribute, not the user. If the user changes the value of the 
+     * attribute (even if it ends up having the same value as the default 
+     * value) then the <code>specified</code> flag is automatically flipped 
+     * to <code>true</code>. To re-specify the attribute as the default 
+     * value from the DTD, the user must delete the attribute. The 
+     * implementation will then make a new attribute available with 
+     * <code>specified</code> set to <code>false</code> and the default 
+     * value (if one exists).
+     * <br>In summary:  If the attribute has an assigned value in the document 
+     * then <code>specified</code> is <code>true</code>, and the value is 
+     * the assigned value.  If the attribute has no assigned value in the 
+     * document and has a default value in the DTD, then 
+     * <code>specified</code> is <code>false</code>, and the value is the 
+     * default value in the DTD. If the attribute has no assigned value in 
+     * the document and has a value of #IMPLIED in the DTD, then the 
+     * attribute does not appear in the structure model of the document. If 
+     * the <code>ownerElement</code> attribute is <code>null</code> (i.e. 
+     * because it was just created or was set to <code>null</code> by the 
+     * various removal and cloning operations) <code>specified</code> is 
+     * <code>true</code>.
+     * 
+     * @return <code>true</code> if the attribute was specified,
+     *         <code>false</false> otherwise.
+     */
+    public boolean getSpecified();
+
+    /**
+     * Returns the value of the attribute is returned as a string. 
+     * Character and general entity references are replaced with their 
+     * values. See also the method <code>getAttribute</code> on the 
+     * <code>Element</code> interface.
+     * 
+     * @return the attribute value as a string.
+     */
+    public String getValue();
+    
+    /**
+     * Sets the value of the attribute. This creates a <code>Text</code> node
+     * with the unparsed contents of the string. I.e. any characters that an
+     * XML processor would recognize as markup are instead treated as literal
+     * text. See also the method <code>setAttribute</code> on the
+     * <code>Element</code> 
+     * interface.
+     * 
+     * @param value the new attribute value.
+     * 
+     * @exception DOMException 
+     *   NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
+     */
+    public void setValue(String value)
+                            throws DOMException;
+
+    /**
+     * The <code>Element</code> node this attribute is attached to or 
+     * <code>null</code> if this attribute is not in use.
+     * 
+     * @return the owner <code>Element</element>, or <code>null</code> is the
+     *         attribute is unused.
+     * 
+     * @since DOM Level 2
+     */
+    public Element getOwnerElement();
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/CDATASection.java b/xml/src/main/java/org/w3c/dom/CDATASection.java
new file mode 100644
index 0000000..9e74734
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/CDATASection.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+/**
+ * CDATA sections are used to escape blocks of text containing characters that 
+ * would otherwise be regarded as markup. The only delimiter that is 
+ * recognized in a CDATA section is the "]]&gt;" string that ends the CDATA 
+ * section. CDATA sections cannot be nested. Their primary purpose is for 
+ * including material such as XML fragments, without needing to escape all 
+ * the delimiters.
+ * <p>The <code>DOMString</code> attribute of the <code>Text</code> node holds 
+ * the text that is contained by the CDATA section. Note that this may 
+ * contain characters that need to be escaped outside of CDATA sections and 
+ * that, depending on the character encoding ("charset") chosen for 
+ * serialization, it may be impossible to write out some characters as part 
+ * of a CDATA section. 
+ * <p> The <code>CDATASection</code> interface inherits from the 
+ * <code>CharacterData</code> interface through the <code>Text</code> 
+ * interface. Adjacent <code>CDATASection</code> nodes are not merged by use 
+ * of the <code>normalize</code> method of the <code>Node</code> interface.
+ * Because no markup is recognized within a <code>CDATASection</code>, 
+ * character numeric references cannot be used as an escape mechanism when 
+ * serializing. Therefore, action needs to be taken when serializing a 
+ * <code>CDATASection</code> with a character encoding where some of the 
+ * contained characters cannot be represented. Failure to do so would not 
+ * produce well-formed XML.One potential solution in the serialization 
+ * process is to end the CDATA section before the character, output the 
+ * character using a character reference or entity reference, and open a new 
+ * CDATA section for any further characters in the text node. Note, however, 
+ * that some code conversion libraries at the time of writing do not return 
+ * an error or exception when a character is missing from the encoding, 
+ * making the task of ensuring that data is not corrupted on serialization 
+ * more difficult.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface CDATASection extends Text {
+}
diff --git a/xml/src/main/java/org/w3c/dom/CharacterData.java b/xml/src/main/java/org/w3c/dom/CharacterData.java
new file mode 100644
index 0000000..47386e9
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/CharacterData.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+// BEGIN android-note
+// Cleaned up @param tags that seemed to be missing spaces between
+// the parameter name and the start of the description.
+// END android-note
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * The <code>CharacterData</code> interface extends Node with a set of 
+ * attributes and methods for accessing character data in the DOM. For 
+ * clarity this set is defined here rather than on each object that uses 
+ * these attributes and methods. No DOM objects correspond directly to 
+ * <code>CharacterData</code>, though <code>Text</code> and others do 
+ * inherit the interface from it. All <code>offsets</code> in this interface 
+ * start from <code>0</code>.
+ * <p>As explained in the <code>DOMString</code> interface, text strings in 
+ * the DOM are represented in UTF-16, i.e. as a sequence of 16-bit units. In 
+ * the following, the term 16-bit units is used whenever necessary to 
+ * indicate that indexing on CharacterData is done in 16-bit units.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface CharacterData extends Node {
+    /**
+     * Returns the character data of the node that implements this interface.
+     * The DOM implementation may not put arbitrary limits on the amount of data 
+     * that may be stored in a <code>CharacterData</code> node. However, 
+     * implementation limits may mean that the entirety of a node's data may 
+     * not fit into a single <code>DOMString</code>. In such cases, the user 
+     * may call <code>substringData</code> to retrieve the data in 
+     * appropriately sized pieces.
+     * 
+     * @return the character data as a string.
+     * 
+     * @exception DOMException
+     *   DOMSTRING_SIZE_ERR: Raised when it would return more characters than 
+     *   fit in a <code>DOMString</code> variable on the implementation 
+     *   platform.
+     */
+    public String getData()
+                            throws DOMException;
+    /**
+     * Sets the character data of the node that implements this interface. The
+     * DOM implementation may not put arbitrary limits on the amount of data 
+     * that may be stored in a <code>CharacterData</code> node. However, 
+     * implementation limits may mean that the entirety of a node's data may 
+     * not fit into a single <code>DOMString</code>. In such cases, the user 
+     * may call <code>substringData</code> to retrieve the data in 
+     * appropriately sized pieces.
+     * 
+     * @param data the new character data.
+     * 
+     * @exception DOMException
+     *   NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
+     */
+    public void setData(String data)
+                            throws DOMException;
+
+    /**
+     * The number of 16-bit units that are available through <code>data</code> 
+     * and the <code>substringData</code> method below. This may have the 
+     * value zero, i.e., <code>CharacterData</code> nodes may be empty.
+     * 
+     * @return the length in characters.
+     */
+    public int getLength();
+
+    /**
+     * Extracts a range of data from the node.
+     * @param offset Start offset of substring to extract.
+     * @param count The number of 16-bit units to extract.
+     * @return The specified substring. If the sum of <code>offset</code> and 
+     *   <code>count</code> exceeds the <code>length</code>, then all 16-bit 
+     *   units to the end of the data are returned.
+     * @exception DOMException
+     *   INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is 
+     *   negative or greater than the number of 16-bit units in 
+     *   <code>data</code>, or if the specified <code>count</code> is 
+     *   negative.
+     *   <br>DOMSTRING_SIZE_ERR: Raised if the specified range of text does 
+     *   not fit into a <code>DOMString</code>.
+     */
+    public String substringData(int offset, 
+                                int count)
+                                throws DOMException;
+
+    /**
+     * Append the string to the end of the character data of the node. Upon 
+     * success, <code>data</code> provides access to the concatenation of 
+     * <code>data</code> and the <code>DOMString</code> specified.
+     * @param arg The <code>DOMString</code> to append.
+     * @exception DOMException
+     *   NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     */
+    public void appendData(String arg)
+                           throws DOMException;
+
+    /**
+     * Insert a string at the specified 16-bit unit offset.
+     * @param offset The character offset at which to insert.
+     * @param arg The <code>DOMString</code> to insert.
+     * @exception DOMException
+     *   INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is 
+     *   negative or greater than the number of 16-bit units in 
+     *   <code>data</code>.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     */
+    public void insertData(int offset, 
+                           String arg)
+                           throws DOMException;
+
+    /**
+     * Remove a range of 16-bit units from the node. Upon success, 
+     * <code>data</code> and <code>length</code> reflect the change.
+     * @param offset The offset from which to start removing.
+     * @param count The number of 16-bit units to delete. If the sum of 
+     *   <code>offset</code> and <code>count</code> exceeds 
+     *   <code>length</code> then all 16-bit units from <code>offset</code> 
+     *   to the end of the data are deleted.
+     * @exception DOMException
+     *   INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is 
+     *   negative or greater than the number of 16-bit units in 
+     *   <code>data</code>, or if the specified <code>count</code> is 
+     *   negative.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     */
+    public void deleteData(int offset, 
+                           int count)
+                           throws DOMException;
+
+    /**
+     * Replace the characters starting at the specified 16-bit unit offset 
+     * with the specified string.
+     * @param offset The offset from which to start replacing.
+     * @param count The number of 16-bit units to replace. If the sum of 
+     *   <code>offset</code> and <code>count</code> exceeds 
+     *   <code>length</code>, then all 16-bit units to the end of the data 
+     *   are replaced; (i.e., the effect is the same as a <code>remove</code>
+     *    method call with the same range, followed by an <code>append</code>
+     *    method invocation).
+     * @param arg The <code>DOMString</code> with which the range must be 
+     *   replaced.
+     * @exception DOMException
+     *   INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is 
+     *   negative or greater than the number of 16-bit units in 
+     *   <code>data</code>, or if the specified <code>count</code> is 
+     *   negative.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     */
+    public void replaceData(int offset, 
+                            int count, 
+                            String arg)
+                            throws DOMException;
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/Comment.java b/xml/src/main/java/org/w3c/dom/Comment.java
new file mode 100644
index 0000000..1097921
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/Comment.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+/**
+ * This interface inherits from <code>CharacterData</code> and represents the 
+ * content of a comment, i.e., all the characters between the starting '
+ * <code>&lt;!--</code>' and ending '<code>--&gt;</code>'. Note that this is 
+ * the definition of a comment in XML, and, in practice, HTML, although some 
+ * HTML tools may implement the full SGML comment structure.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface Comment extends CharacterData {
+}
diff --git a/xml/src/main/java/org/w3c/dom/DOMException.java b/xml/src/main/java/org/w3c/dom/DOMException.java
new file mode 100644
index 0000000..76bac3c
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/DOMException.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * DOM operations only raise exceptions in "exceptional" circumstances, i.e., 
+ * when an operation is impossible to perform (either for logical reasons, 
+ * because data is lost, or because the implementation has become unstable). 
+ * In general, DOM methods return specific error values in ordinary 
+ * processing situations, such as out-of-bound errors when using 
+ * <code>NodeList</code>. 
+ * <p>Implementations should raise other exceptions under other circumstances. 
+ * For example, implementations should raise an implementation-dependent 
+ * exception if a <code>null</code> argument is passed. 
+ * <p>Some languages and object systems do not support the concept of 
+ * exceptions. For such systems, error conditions may be indicated using 
+ * native error reporting mechanisms. For some bindings, for example, 
+ * methods may return error codes similar to those listed in the 
+ * corresponding method descriptions.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public class DOMException extends RuntimeException {
+    /**
+     * Creates a new <code>DOMException</code> with the given error code and
+     * human-readable message.
+     * @param code the error code.
+     * @param message the human-readable message.
+     */
+    public DOMException(short code, String message) {
+       super(message);
+       this.code = code;
+    }
+    /**
+     * Holds the error code of the <code>DOMException</code>.
+     */
+    public short   code;
+    // ExceptionCode
+    /**
+     * If index or size is negative, or greater than the allowed value
+     */
+    public static final short INDEX_SIZE_ERR            = 1;
+    /**
+     * If the specified range of text does not fit into a DOMString
+     */
+    public static final short DOMSTRING_SIZE_ERR        = 2;
+    /**
+     * If any node is inserted somewhere it doesn't belong
+     */
+    public static final short HIERARCHY_REQUEST_ERR     = 3;
+    /**
+     * If a node is used in a different document than the one that created it 
+     * (that doesn't support it)
+     */
+    public static final short WRONG_DOCUMENT_ERR        = 4;
+    /**
+     * If an invalid or illegal character is specified, such as in a name. See 
+     * production 2 in the XML specification for the definition of a legal 
+     * character, and production 5 for the definition of a legal name 
+     * character.
+     */
+    public static final short INVALID_CHARACTER_ERR     = 5;
+    /**
+     * If data is specified for a node which does not support data
+     */
+    public static final short NO_DATA_ALLOWED_ERR       = 6;
+    /**
+     * If an attempt is made to modify an object where modifications are not 
+     * allowed
+     */
+    public static final short NO_MODIFICATION_ALLOWED_ERR = 7;
+    /**
+     * If an attempt is made to reference a node in a context where it does 
+     * not exist
+     */
+    public static final short NOT_FOUND_ERR             = 8;
+    /**
+     * If the implementation does not support the requested type of object or 
+     * operation.
+     */
+    public static final short NOT_SUPPORTED_ERR         = 9;
+    /**
+     * If an attempt is made to add an attribute that is already in use 
+     * elsewhere
+     */
+    public static final short INUSE_ATTRIBUTE_ERR       = 10;
+    /**
+     * If an attempt is made to use an object that is not, or is no longer, 
+     * usable.
+     * @since DOM Level 2
+     */
+    public static final short INVALID_STATE_ERR         = 11;
+    /**
+     * If an invalid or illegal string is specified.
+     * @since DOM Level 2
+     */
+    public static final short SYNTAX_ERR                = 12;
+    /**
+     * If an attempt is made to modify the type of the underlying object.
+     * @since DOM Level 2
+     */
+    public static final short INVALID_MODIFICATION_ERR  = 13;
+    /**
+     * If an attempt is made to create or change an object in a way which is 
+     * incorrect with regard to namespaces.
+     * @since DOM Level 2
+     */
+    public static final short NAMESPACE_ERR             = 14;
+    /**
+     * If a parameter or an operation is not supported by the underlying 
+     * object.
+     * @since DOM Level 2
+     */
+    public static final short INVALID_ACCESS_ERR        = 15;
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/DOMImplementation.java b/xml/src/main/java/org/w3c/dom/DOMImplementation.java
new file mode 100644
index 0000000..dcb19c9
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/DOMImplementation.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+// BEGIN android-note
+// Cleaned up @param tags that seemed to be missing spaces between
+// the parameter name and the start of the description.
+// END android-note
+
+/**
+ * The <code>DOMImplementation</code> interface provides a number of methods 
+ * for performing operations that are independent of any particular instance 
+ * of the document object model.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface DOMImplementation {
+    /**
+     * Test if the DOM implementation implements a specific feature.
+     * @param feature The name of the feature to test (case-insensitive). The 
+     *   values used by DOM features are defined throughout the DOM Level 2 
+     *   specifications and listed in the  section. The name must be an XML 
+     *   name. To avoid possible conflicts, as a convention, names referring 
+     *   to features defined outside the DOM specification should be made 
+     *   unique by reversing the name of the Internet domain name of the 
+     *   person (or the organization that the person belongs to) who defines 
+     *   the feature, component by component, and using this as a prefix. 
+     *   For instance, the W3C SVG Working Group defines the feature 
+     *   "org.w3c.dom.svg".
+     * @param version This is the version number of the feature to test. In 
+     *   Level 2, the string can be either "2.0" or "1.0". If the version is 
+     *   not specified, supporting any version of the feature causes the 
+     *   method to return <code>true</code>.
+     * @return <code>true</code> if the feature is implemented in the 
+     *   specified version, <code>false</code> otherwise.
+     */
+    public boolean hasFeature(String feature, 
+                              String version);
+
+    /**
+     * Creates an empty <code>DocumentType</code> node. Entity declarations 
+     * and notations are not made available. Entity reference expansions and 
+     * default attribute additions do not occur. It is expected that a 
+     * future version of the DOM will provide a way for populating a 
+     * <code>DocumentType</code>.
+     * <br>HTML-only DOM implementations do not need to implement this method.
+     * @param qualifiedName The qualified name of the document type to be 
+     *   created. 
+     * @param publicId The external subset public identifier.
+     * @param systemId The external subset system identifier.
+     * @return A new <code>DocumentType</code> node with 
+     *   <code>Node.ownerDocument</code> set to <code>null</code>.
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified qualified name 
+     *   contains an illegal character.
+     *   <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is 
+     *   malformed.
+     * @since DOM Level 2
+     */
+    public DocumentType createDocumentType(String qualifiedName, 
+                                           String publicId, 
+                                           String systemId)
+                                           throws DOMException;
+
+    /**
+     * Creates an XML <code>Document</code> object of the specified type with 
+     * its document element. HTML-only DOM implementations do not need to 
+     * implement this method.
+     * @param namespaceURI The namespace URI of the document element to create.
+     * @param qualifiedName The qualified name of the document element to be 
+     *   created.
+     * @param doctype The type of document to be created or <code>null</code>.
+     *   When <code>doctype</code> is not <code>null</code>, its 
+     *   <code>Node.ownerDocument</code> attribute is set to the document 
+     *   being created.
+     * @return A new <code>Document</code> object.
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified qualified name 
+     *   contains an illegal character.
+     *   <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is 
+     *   malformed, if the <code>qualifiedName</code> has a prefix and the 
+     *   <code>namespaceURI</code> is <code>null</code>, or if the 
+     *   <code>qualifiedName</code> has a prefix that is "xml" and the 
+     *   <code>namespaceURI</code> is different from "
+     *   http://www.w3.org/XML/1998/namespace" .
+     *   <br>WRONG_DOCUMENT_ERR: Raised if <code>doctype</code> has already 
+     *   been used with a different document or was created from a different 
+     *   implementation.
+     * @since DOM Level 2
+     */
+    public Document createDocument(String namespaceURI, 
+                                   String qualifiedName, 
+                                   DocumentType doctype)
+                                   throws DOMException;
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/Document.java b/xml/src/main/java/org/w3c/dom/Document.java
new file mode 100644
index 0000000..3beddaa
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/Document.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+// BEGIN android-note
+// Cleaned up @param tags that seemed to be missing spaces between
+// the parameter name and the start of the description.
+// END android-note
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * The <code>Document</code> interface represents the entire HTML or XML 
+ * document. Conceptually, it is the root of the document tree, and provides 
+ * the primary access to the document's data.
+ * <p>Since elements, text nodes, comments, processing instructions, etc. 
+ * cannot exist outside the context of a <code>Document</code>, the 
+ * <code>Document</code> interface also contains the factory methods needed 
+ * to create these objects. The <code>Node</code> objects created have a 
+ * <code>ownerDocument</code> attribute which associates them with the 
+ * <code>Document</code> within whose context they were created.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface Document extends Node {
+    /**
+     * The Document Type Declaration (see <code>DocumentType</code>) 
+     * associated with this document. For HTML documents as well as XML 
+     * documents without a document type declaration this returns 
+     * <code>null</code>. The DOM Level 2 does not support editing the 
+     * Document Type Declaration. <code>docType</code> cannot be altered in 
+     * any way, including through the use of methods inherited from the 
+     * <code>Node</code> interface, such as <code>insertNode</code> or 
+     * <code>removeNode</code>.
+     * 
+     * @return the Document Type Declaration associated with this document, if
+     * any.
+     */
+    public DocumentType getDoctype();
+
+    /**
+     * The <code>DOMImplementation</code> object that handles this document. A 
+     * DOM application may use objects from multiple implementations.
+     * 
+     * @return <code>DOMImplementation</code> object that handles this document.
+     */
+    public DOMImplementation getImplementation();
+
+    /**
+     * This is a convenience attribute that allows direct access to the child 
+     * node that is the root element of the document. For HTML documents, 
+     * this is the element with the tagName "HTML".
+     * 
+     * @return the root element of this document. 
+     */
+    public Element getDocumentElement();
+
+    /**
+     * Creates an element of the type specified. Note that the instance 
+     * returned implements the <code>Element</code> interface, so attributes 
+     * can be specified directly on the returned object.
+     * <br>In addition, if there are known attributes with default values, 
+     * <code>Attr</code> nodes representing them are automatically created 
+     * and attached to the element.
+     * <br>To create an element with a qualified name and namespace URI, use 
+     * the <code>createElementNS</code> method.
+     * @param tagName The name of the element type to instantiate. For XML, 
+     *   this is case-sensitive. For HTML, the <code>tagName</code> 
+     *   parameter may be provided in any case, but it must be mapped to the 
+     *   canonical uppercase form by the DOM implementation. 
+     * @return A new <code>Element</code> object with the 
+     *   <code>nodeName</code> attribute set to <code>tagName</code>, and 
+     *   <code>localName</code>, <code>prefix</code>, and 
+     *   <code>namespaceURI</code> set to <code>null</code>.
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified name contains an 
+     *   illegal character.
+     */
+    public Element createElement(String tagName)
+                                 throws DOMException;
+
+    /**
+     * Creates an empty <code>DocumentFragment</code> object. 
+     * @return A new <code>DocumentFragment</code>.
+     */
+    public DocumentFragment createDocumentFragment();
+
+    /**
+     * Creates a <code>Text</code> node given the specified string.
+     * @param data The data for the node.
+     * @return The new <code>Text</code> object.
+     */
+    public Text createTextNode(String data);
+
+    /**
+     * Creates a <code>Comment</code> node given the specified string.
+     * @param data The data for the node.
+     * @return The new <code>Comment</code> object.
+     */
+    public Comment createComment(String data);
+
+    /**
+     * Creates a <code>CDATASection</code> node whose value is the specified 
+     * string.
+     * @param data The data for the <code>CDATASection</code> contents.
+     * @return The new <code>CDATASection</code> object.
+     * @exception DOMException
+     *   NOT_SUPPORTED_ERR: Raised if this document is an HTML document.
+     */
+    public CDATASection createCDATASection(String data)
+                                           throws DOMException;
+
+    /**
+     * Creates a <code>ProcessingInstruction</code> node given the specified 
+     * name and data strings.
+     * @param target The target part of the processing instruction.
+     * @param data The data for the node.
+     * @return The new <code>ProcessingInstruction</code> object.
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified target contains an 
+     *   illegal character.
+     *   <br>NOT_SUPPORTED_ERR: Raised if this document is an HTML document.
+     */
+    public ProcessingInstruction createProcessingInstruction(String target, 
+                                                             String data)
+                                                             throws DOMException;
+
+    /**
+     * Creates an <code>Attr</code> of the given name. Note that the 
+     * <code>Attr</code> instance can then be set on an <code>Element</code> 
+     * using the <code>setAttributeNode</code> method. 
+     * <br>To create an attribute with a qualified name and namespace URI, use 
+     * the <code>createAttributeNS</code> method.
+     * @param name The name of the attribute.
+     * @return A new <code>Attr</code> object with the <code>nodeName</code> 
+     *   attribute set to <code>name</code>, and <code>localName</code>, 
+     *   <code>prefix</code>, and <code>namespaceURI</code> set to 
+     *   <code>null</code>. The value of the attribute is the empty string.
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified name contains an 
+     *   illegal character.
+     */
+    public Attr createAttribute(String name)
+                                throws DOMException;
+
+    /**
+     * Creates an <code>EntityReference</code> object. In addition, if the 
+     * referenced entity is known, the child list of the 
+     * <code>EntityReference</code> node is made the same as that of the 
+     * corresponding <code>Entity</code> node.If any descendant of the 
+     * <code>Entity</code> node has an unbound namespace prefix, the 
+     * corresponding descendant of the created <code>EntityReference</code> 
+     * node is also unbound; (its <code>namespaceURI</code> is 
+     * <code>null</code>). The DOM Level 2 does not support any mechanism to 
+     * resolve namespace prefixes.
+     * @param name The name of the entity to reference. 
+     * @return The new <code>EntityReference</code> object.
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified name contains an 
+     *   illegal character.
+     *   <br>NOT_SUPPORTED_ERR: Raised if this document is an HTML document.
+     */
+    public EntityReference createEntityReference(String name)
+                                                 throws DOMException;
+
+    /**
+     * Returns a <code>NodeList</code> of all the <code>Elements</code> with a 
+     * given tag name in the order in which they are encountered in a 
+     * preorder traversal of the <code>Document</code> tree. 
+     * @param tagname The name of the tag to match on. The special value "*" 
+     *   matches all tags.
+     * @return A new <code>NodeList</code> object containing all the matched 
+     *   <code>Elements</code>.
+     */
+    public NodeList getElementsByTagName(String tagname);
+
+    /**
+     * Imports a node from another document to this document. The returned 
+     * node has no parent; (<code>parentNode</code> is <code>null</code>). 
+     * The source node is not altered or removed from the original document; 
+     * this method creates a new copy of the source node.
+     * <br>For all nodes, importing a node creates a node object owned by the 
+     * importing document, with attribute values identical to the source 
+     * node's <code>nodeName</code> and <code>nodeType</code>, plus the 
+     * attributes related to namespaces (<code>prefix</code>, 
+     * <code>localName</code>, and <code>namespaceURI</code>). As in the 
+     * <code>cloneNode</code> operation on a <code>Node</code>, the source 
+     * node is not altered.
+     * <br>Additional information is copied as appropriate to the 
+     * <code>nodeType</code>, attempting to mirror the behavior expected if 
+     * a fragment of XML or HTML source was copied from one document to 
+     * another, recognizing that the two documents may have different DTDs 
+     * in the XML case. The following list describes the specifics for each 
+     * type of node. 
+     * <dl>
+     * <dt>ATTRIBUTE_NODE</dt>
+     * <dd>The <code>ownerElement</code> attribute 
+     * is set to <code>null</code> and the <code>specified</code> flag is 
+     * set to <code>true</code> on the generated <code>Attr</code>. The 
+     * descendants of the source <code>Attr</code> are recursively imported 
+     * and the resulting nodes reassembled to form the corresponding subtree.
+     * Note that the <code>deep</code> parameter has no effect on 
+     * <code>Attr</code> nodes; they always carry their children with them 
+     * when imported.</dd>
+     * <dt>DOCUMENT_FRAGMENT_NODE</dt>
+     * <dd>If the <code>deep</code> option 
+     * was set to <code>true</code>, the descendants of the source element 
+     * are recursively imported and the resulting nodes reassembled to form 
+     * the corresponding subtree. Otherwise, this simply generates an empty 
+     * <code>DocumentFragment</code>.</dd>
+     * <dt>DOCUMENT_NODE</dt>
+     * <dd><code>Document</code> 
+     * nodes cannot be imported.</dd>
+     * <dt>DOCUMENT_TYPE_NODE</dt>
+     * <dd><code>DocumentType</code> 
+     * nodes cannot be imported.</dd>
+     * <dt>ELEMENT_NODE</dt>
+     * <dd>Specified attribute nodes of the 
+     * source element are imported, and the generated <code>Attr</code> 
+     * nodes are attached to the generated <code>Element</code>. Default 
+     * attributes are not copied, though if the document being imported into 
+     * defines default attributes for this element name, those are assigned. 
+     * If the <code>importNode</code> <code>deep</code> parameter was set to 
+     * <code>true</code>, the descendants of the source element are 
+     * recursively imported and the resulting nodes reassembled to form the 
+     * corresponding subtree.</dd>
+     * <dt>ENTITY_NODE</dt>
+     * <dd><code>Entity</code> nodes can be 
+     * imported, however in the current release of the DOM the 
+     * <code>DocumentType</code> is readonly. Ability to add these imported 
+     * nodes to a <code>DocumentType</code> will be considered for addition 
+     * to a future release of the DOM.On import, the <code>publicId</code>, 
+     * <code>systemId</code>, and <code>notationName</code> attributes are 
+     * copied. If a <code>deep</code> import is requested, the descendants 
+     * of the the source <code>Entity</code> are recursively imported and 
+     * the resulting nodes reassembled to form the corresponding subtree.</dd>
+     * <dt>
+     * ENTITY_REFERENCE_NODE</dt>
+     * <dd>Only the <code>EntityReference</code> itself is 
+     * copied, even if a <code>deep</code> import is requested, since the 
+     * source and destination documents might have defined the entity 
+     * differently. If the document being imported into provides a 
+     * definition for this entity name, its value is assigned.</dd>
+     * <dt>NOTATION_NODE</dt>
+     * <dd>
+     * <code>Notation</code> nodes can be imported, however in the current 
+     * release of the DOM the <code>DocumentType</code> is readonly. Ability 
+     * to add these imported nodes to a <code>DocumentType</code> will be 
+     * considered for addition to a future release of the DOM.On import, the 
+     * <code>publicId</code> and <code>systemId</code> attributes are copied.
+     * Note that the <code>deep</code> parameter has no effect on 
+     * <code>Notation</code> nodes since they never have any children.</dd>
+     * <dt>
+     * PROCESSING_INSTRUCTION_NODE</dt>
+     * <dd>The imported node copies its 
+     * <code>target</code> and <code>data</code> values from those of the 
+     * source node.</dd>
+     * <dt>TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE</dt>
+     * <dd>These three 
+     * types of nodes inheriting from <code>CharacterData</code> copy their 
+     * <code>data</code> and <code>length</code> attributes from those of 
+     * the source node.</dd>
+     *  
+     * @param importedNode The node to import.
+     * @param deep If <code>true</code>, recursively import the subtree under 
+     *   the specified node; if <code>false</code>, import only the node 
+     *   itself, as explained above. This has no effect on <code>Attr</code>
+     *   , <code>EntityReference</code>, and <code>Notation</code> nodes.
+     * @return The imported node that belongs to this <code>Document</code>.
+     * @exception DOMException
+     *   NOT_SUPPORTED_ERR: Raised if the type of node being imported is not 
+     *   supported.
+     * @since DOM Level 2
+     */
+    public Node importNode(Node importedNode, 
+                           boolean deep)
+                           throws DOMException;
+
+    /**
+     * Creates an element of the given qualified name and namespace URI. 
+     * HTML-only DOM implementations do not need to implement this method.
+     * @param namespaceURI The namespace URI of the element to create.
+     * @param qualifiedName The qualified name of the element type to 
+     *   instantiate.
+     * @return A new <code>Element</code> object with the following 
+     *   attributes:AttributeValue<code>Node.nodeName</code>
+     *   <code>qualifiedName</code><code>Node.namespaceURI</code>
+     *   <code>namespaceURI</code><code>Node.prefix</code>prefix, extracted 
+     *   from <code>qualifiedName</code>, or <code>null</code> if there is 
+     *   no prefix<code>Node.localName</code>local name, extracted from 
+     *   <code>qualifiedName</code><code>Element.tagName</code>
+     *   <code>qualifiedName</code>
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified qualified name 
+     *   contains an illegal character.
+     *   <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is 
+     *   malformed, if the <code>qualifiedName</code> has a prefix and the 
+     *   <code>namespaceURI</code> is <code>null</code>, or if the 
+     *   <code>qualifiedName</code> has a prefix that is "xml" and the 
+     *   <code>namespaceURI</code> is different from "
+     *   http://www.w3.org/XML/1998/namespace" .
+     * @since DOM Level 2
+     */
+    public Element createElementNS(String namespaceURI, 
+                                   String qualifiedName)
+                                   throws DOMException;
+
+    /**
+     * Creates an attribute of the given qualified name and namespace URI. 
+     * HTML-only DOM implementations do not need to implement this method.
+     * @param namespaceURI The namespace URI of the attribute to create.
+     * @param qualifiedName The qualified name of the attribute to instantiate.
+     * @return A new <code>Attr</code> object with the following attributes:
+     *   AttributeValue<code>Node.nodeName</code>qualifiedName
+     *   <code>Node.namespaceURI</code><code>namespaceURI</code>
+     *   <code>Node.prefix</code>prefix, extracted from 
+     *   <code>qualifiedName</code>, or <code>null</code> if there is no 
+     *   prefix<code>Node.localName</code>local name, extracted from 
+     *   <code>qualifiedName</code><code>Attr.name</code>
+     *   <code>qualifiedName</code><code>Node.nodeValue</code>the empty 
+     *   string
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified qualified name 
+     *   contains an illegal character.
+     *   <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is 
+     *   malformed, if the <code>qualifiedName</code> has a prefix and the 
+     *   <code>namespaceURI</code> is <code>null</code>, if the 
+     *   <code>qualifiedName</code> has a prefix that is "xml" and the 
+     *   <code>namespaceURI</code> is different from "
+     *   http://www.w3.org/XML/1998/namespace", or if the 
+     *   <code>qualifiedName</code> is "xmlns" and the 
+     *   <code>namespaceURI</code> is different from "
+     *   http://www.w3.org/2000/xmlns/".
+     * @since DOM Level 2
+     */
+    public Attr createAttributeNS(String namespaceURI, 
+                                  String qualifiedName)
+                                  throws DOMException;
+
+    /**
+     * Returns a <code>NodeList</code> of all the <code>Elements</code> with a 
+     * given local name and namespace URI in the order in which they are 
+     * encountered in a preorder traversal of the <code>Document</code> tree.
+     * @param namespaceURI The namespace URI of the elements to match on. The 
+     *   special value "*" matches all namespaces.
+     * @param localName The local name of the elements to match on. The 
+     *   special value "*" matches all local names.
+     * @return A new <code>NodeList</code> object containing all the matched 
+     *   <code>Elements</code>.
+     * @since DOM Level 2
+     */
+    public NodeList getElementsByTagNameNS(String namespaceURI, 
+                                           String localName);
+
+    /**
+     * Returns the <code>Element</code> whose <code>ID</code> is given by 
+     * <code>elementId</code>. If no such element exists, returns 
+     * <code>null</code>. Behavior is not defined if more than one element 
+     * has this <code>ID</code>. The DOM implementation must have 
+     * information that says which attributes are of type ID. Attributes 
+     * with the name "ID" are not of type ID unless so defined. 
+     * Implementations that do not know whether attributes are of type ID or 
+     * not are expected to return <code>null</code>.
+     * @param elementId The unique <code>id</code> value for an element.
+     * @return The matching element.
+     * @since DOM Level 2
+     */
+    public Element getElementById(String elementId);
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/DocumentFragment.java b/xml/src/main/java/org/w3c/dom/DocumentFragment.java
new file mode 100644
index 0000000..6ade30c
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/DocumentFragment.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+/**
+ * <code>DocumentFragment</code> is a "lightweight" or "minimal" 
+ * <code>Document</code> object. It is very common to want to be able to 
+ * extract a portion of a document's tree or to create a new fragment of a 
+ * document. Imagine implementing a user command like cut or rearranging a 
+ * document by moving fragments around. It is desirable to have an object 
+ * which can hold such fragments and it is quite natural to use a Node for 
+ * this purpose. While it is true that a <code>Document</code> object could 
+ * fulfill this role, a <code>Document</code> object can potentially be a 
+ * heavyweight object, depending on the underlying implementation. What is 
+ * really needed for this is a very lightweight object. 
+ * <code>DocumentFragment</code> is such an object.
+ * <p>Furthermore, various operations -- such as inserting nodes as children 
+ * of another <code>Node</code> -- may take <code>DocumentFragment</code> 
+ * objects as arguments; this results in all the child nodes of the 
+ * <code>DocumentFragment</code> being moved to the child list of this node.
+ * <p>The children of a <code>DocumentFragment</code> node are zero or more 
+ * nodes representing the tops of any sub-trees defining the structure of 
+ * the document. <code>DocumentFragment</code> nodes do not need to be 
+ * well-formed XML documents (although they do need to follow the rules 
+ * imposed upon well-formed XML parsed entities, which can have multiple top 
+ * nodes). For example, a <code>DocumentFragment</code> might have only one 
+ * child and that child node could be a <code>Text</code> node. Such a 
+ * structure model represents neither an HTML document nor a well-formed XML 
+ * document.
+ * <p>When a <code>DocumentFragment</code> is inserted into a 
+ * <code>Document</code> (or indeed any other <code>Node</code> that may 
+ * take children) the children of the <code>DocumentFragment</code> and not 
+ * the <code>DocumentFragment</code> itself are inserted into the 
+ * <code>Node</code>. This makes the <code>DocumentFragment</code> very 
+ * useful when the user wishes to create nodes that are siblings; the 
+ * <code>DocumentFragment</code> acts as the parent of these nodes so that 
+ * the user can use the standard methods from the <code>Node</code> 
+ * interface, such as <code>insertBefore</code> and <code>appendChild</code>.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface DocumentFragment extends Node {
+}
diff --git a/xml/src/main/java/org/w3c/dom/DocumentType.java b/xml/src/main/java/org/w3c/dom/DocumentType.java
new file mode 100644
index 0000000..685c073
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/DocumentType.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * Each <code>Document</code> has a <code>doctype</code> attribute whose value 
+ * is either <code>null</code> or a <code>DocumentType</code> object. The 
+ * <code>DocumentType</code> interface in the DOM Core provides an interface 
+ * to the list of entities that are defined for the document, and little 
+ * else because the effect of namespaces and the various XML schema efforts 
+ * on DTD representation are not clearly understood as of this writing.
+ * <p>The DOM Level 2 doesn't support editing <code>DocumentType</code> nodes.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface DocumentType extends Node {
+    /**
+     * The name of DTD; i.e., the name immediately following the 
+     * <code>DOCTYPE</code> keyword.
+     * 
+     * @return the name of the DTD.
+     */
+    public String getName();
+
+    /**
+     * A <code>NamedNodeMap</code> containing the general entities, both 
+     * external and internal, declared in the DTD. Parameter entities are 
+     * not contained. Duplicates are discarded. For example in: 
+     * <pre>&lt;!DOCTYPE 
+     * ex SYSTEM "ex.dtd" [ &lt;!ENTITY foo "foo"&gt; &lt;!ENTITY bar 
+     * "bar"&gt; &lt;!ENTITY bar "bar2"&gt; &lt;!ENTITY % baz "baz"&gt; 
+     * ]&gt; &lt;ex/&gt;</pre>
+     *  the interface provides access to <code>foo</code> 
+     * and the first declaration of <code>bar</code> but not the second 
+     * declaration of <code>bar</code> or <code>baz</code>. Every node in 
+     * this map also implements the <code>Entity</code> interface.
+     * <br>The DOM Level 2 does not support editing entities, therefore 
+     * <code>entities</code> cannot be altered in any way.
+     * 
+     * @return the entities declared in this DTD.
+     */
+    public NamedNodeMap getEntities();
+
+    /**
+     * A <code>NamedNodeMap</code> containing the notations declared in the 
+     * DTD. Duplicates are discarded. Every node in this map also implements 
+     * the <code>Notation</code> interface.
+     * <br>The DOM Level 2 does not support editing notations, therefore 
+     * <code>notations</code> cannot be altered in any way.
+     * 
+     * @return the notations declared in this DTD.
+     */
+    public NamedNodeMap getNotations();
+
+    /**
+     * The public identifier of the external subset.
+     * 
+     * @return the public identifier.
+     * 
+     * @since DOM Level 2
+     */
+    public String getPublicId();
+
+    /**
+     * The system identifier of the external subset.
+     * 
+     * @return the system identifier.
+     * 
+     * @since DOM Level 2
+     */
+    public String getSystemId();
+
+    /**
+     * The internal subset as a string. The actual content returned depends on 
+     * how much information is available to the implementation. This may 
+     * vary depending on various parameters, including the XML processor 
+     * used to build the document.
+     * 
+     * @return the internal subset.
+     * 
+     * @since DOM Level 2
+     */
+    public String getInternalSubset();
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/Element.java b/xml/src/main/java/org/w3c/dom/Element.java
new file mode 100644
index 0000000..72e3478
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/Element.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+// BEGIN android-note
+// Cleaned up @param tags that seemed to be missing spaces between
+// the parameter name and the start of the description.
+// END android-note
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * The <code>Element</code> interface represents an element in an HTML or XML 
+ * document. Elements may have attributes associated with them; since the 
+ * <code>Element</code> interface inherits from <code>Node</code>, the 
+ * generic <code>Node</code> interface attribute <code>attributes</code> may 
+ * be used to retrieve the set of all attributes for an element. There are 
+ * methods on the <code>Element</code> interface to retrieve either an 
+ * <code>Attr</code> object by name or an attribute value by name. In XML, 
+ * where an attribute value may contain entity references, an 
+ * <code>Attr</code> object should be retrieved to examine the possibly 
+ * fairly complex sub-tree representing the attribute value. On the other 
+ * hand, in HTML, where all attributes have simple string values, methods to 
+ * directly access an attribute value can safely be used as a convenience.In 
+ * DOM Level 2, the method <code>normalize</code> is inherited from the 
+ * <code>Node</code> interface where it was moved.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface Element extends Node {
+    /**
+     * The name of the element. For example, in: 
+     * <pre> &lt;elementExample 
+     * id="demo"&gt; ... &lt;/elementExample&gt; , </pre>
+     *  <code>tagName</code> has 
+     * the value <code>"elementExample"</code>. Note that this is 
+     * case-preserving in XML, as are all of the operations of the DOM. The 
+     * HTML DOM returns the <code>tagName</code> of an HTML element in the 
+     * canonical uppercase form, regardless of the case in the source HTML 
+     * document.
+     * 
+     * @return the name of the element.
+     */
+    public String getTagName();
+
+    /**
+     * Retrieves an attribute value by name.
+     * @param name The name of the attribute to retrieve.
+     * @return The <code>Attr</code> value as a string, or the empty string 
+     *   if that attribute does not have a specified or default value.
+     */
+    public String getAttribute(String name);
+
+    /**
+     * Adds a new attribute. If an attribute with that name is already present 
+     * in the element, its value is changed to be that of the value 
+     * parameter. This value is a simple string; it is not parsed as it is 
+     * being set. So any markup (such as syntax to be recognized as an 
+     * entity reference) is treated as literal text, and needs to be 
+     * appropriately escaped by the implementation when it is written out. 
+     * In order to assign an attribute value that contains entity 
+     * references, the user must create an <code>Attr</code> node plus any 
+     * <code>Text</code> and <code>EntityReference</code> nodes, build the 
+     * appropriate subtree, and use <code>setAttributeNode</code> to assign 
+     * it as the value of an attribute.
+     * <br>To set an attribute with a qualified name and namespace URI, use 
+     * the <code>setAttributeNS</code> method.
+     * @param name The name of the attribute to create or alter.
+     * @param value Value to set in string form.
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified name contains an 
+     *   illegal character.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     */
+    public void setAttribute(String name, 
+                             String value)
+                             throws DOMException;
+
+    /**
+     * Removes an attribute by name. If the removed attribute is known to have 
+     * a default value, an attribute immediately appears containing the 
+     * default value as well as the corresponding namespace URI, local name, 
+     * and prefix when applicable.
+     * <br>To remove an attribute by local name and namespace URI, use the 
+     * <code>removeAttributeNS</code> method.
+     * @param name The name of the attribute to remove.
+     * @exception DOMException
+     *   NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     */
+    public void removeAttribute(String name)
+                                throws DOMException;
+
+    /**
+     * Retrieves an attribute node by name.
+     * <br>To retrieve an attribute node by qualified name and namespace URI, 
+     * use the <code>getAttributeNodeNS</code> method.
+     * @param name The name (<code>nodeName</code>) of the attribute to 
+     *   retrieve.
+     * @return The <code>Attr</code> node with the specified name (
+     *   <code>nodeName</code>) or <code>null</code> if there is no such 
+     *   attribute.
+     */
+    public Attr getAttributeNode(String name);
+
+    /**
+     * Adds a new attribute node. If an attribute with that name (
+     * <code>nodeName</code>) is already present in the element, it is 
+     * replaced by the new one.
+     * <br>To add a new attribute node with a qualified name and namespace 
+     * URI, use the <code>setAttributeNodeNS</code> method.
+     * @param newAttr The <code>Attr</code> node to add to the attribute list.
+     * @return If the <code>newAttr</code> attribute replaces an existing 
+     *   attribute, the replaced <code>Attr</code> node is returned, 
+     *   otherwise <code>null</code> is returned.
+     * @exception DOMException
+     *   WRONG_DOCUMENT_ERR: Raised if <code>newAttr</code> was created from a 
+     *   different document than the one that created the element.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     *   <br>INUSE_ATTRIBUTE_ERR: Raised if <code>newAttr</code> is already an 
+     *   attribute of another <code>Element</code> object. The DOM user must 
+     *   explicitly clone <code>Attr</code> nodes to re-use them in other 
+     *   elements.
+     */
+    public Attr setAttributeNode(Attr newAttr)
+                                 throws DOMException;
+
+    /**
+     * Removes the specified attribute node. If the removed <code>Attr</code> 
+     * has a default value it is immediately replaced. The replacing 
+     * attribute has the same namespace URI and local name, as well as the 
+     * original prefix, when applicable.
+     * @param oldAttr The <code>Attr</code> node to remove from the attribute 
+     *   list.
+     * @return The <code>Attr</code> node that was removed.
+     * @exception DOMException
+     *   NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     *   <br>NOT_FOUND_ERR: Raised if <code>oldAttr</code> is not an attribute 
+     *   of the element.
+     */
+    public Attr removeAttributeNode(Attr oldAttr)
+                                    throws DOMException;
+
+    /**
+     * Returns a <code>NodeList</code> of all descendant <code>Elements</code> 
+     * with a given tag name, in the order in which they are encountered in 
+     * a preorder traversal of this <code>Element</code> tree.
+     * @param name The name of the tag to match on. The special value "*" 
+     *   matches all tags.
+     * @return A list of matching <code>Element</code> nodes.
+     */
+    public NodeList getElementsByTagName(String name);
+
+    /**
+     * Retrieves an attribute value by local name and namespace URI. HTML-only 
+     * DOM implementations do not need to implement this method.
+     * @param namespaceURI The namespace URI of the attribute to retrieve.
+     * @param localName The local name of the attribute to retrieve.
+     * @return The <code>Attr</code> value as a string, or the empty string 
+     *   if that attribute does not have a specified or default value.
+     * @since DOM Level 2
+     */
+    public String getAttributeNS(String namespaceURI, 
+                                 String localName);
+
+    /**
+     * Adds a new attribute. If an attribute with the same local name and 
+     * namespace URI is already present on the element, its prefix is 
+     * changed to be the prefix part of the <code>qualifiedName</code>, and 
+     * its value is changed to be the <code>value</code> parameter. This 
+     * value is a simple string; it is not parsed as it is being set. So any 
+     * markup (such as syntax to be recognized as an entity reference) is 
+     * treated as literal text, and needs to be appropriately escaped by the 
+     * implementation when it is written out. In order to assign an 
+     * attribute value that contains entity references, the user must create 
+     * an <code>Attr</code> node plus any <code>Text</code> and 
+     * <code>EntityReference</code> nodes, build the appropriate subtree, 
+     * and use <code>setAttributeNodeNS</code> or 
+     * <code>setAttributeNode</code> to assign it as the value of an 
+     * attribute.
+     * <br>HTML-only DOM implementations do not need to implement this method.
+     * @param namespaceURI The namespace URI of the attribute to create or 
+     *   alter.
+     * @param qualifiedName The qualified name of the attribute to create or 
+     *   alter.
+     * @param value The value to set in string form.
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified qualified name 
+     *   contains an illegal character.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     *   <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is 
+     *   malformed, if the <code>qualifiedName</code> has a prefix and the 
+     *   <code>namespaceURI</code> is <code>null</code>, if the 
+     *   <code>qualifiedName</code> has a prefix that is "xml" and the 
+     *   <code>namespaceURI</code> is different from "
+     *   http://www.w3.org/XML/1998/namespace", or if the 
+     *   <code>qualifiedName</code> is "xmlns" and the 
+     *   <code>namespaceURI</code> is different from "
+     *   http://www.w3.org/2000/xmlns/".
+     * @since DOM Level 2
+     */
+    public void setAttributeNS(String namespaceURI, 
+                               String qualifiedName, 
+                               String value)
+                               throws DOMException;
+
+    /**
+     * Removes an attribute by local name and namespace URI. If the removed 
+     * attribute has a default value it is immediately replaced. The 
+     * replacing attribute has the same namespace URI and local name, as 
+     * well as the original prefix.
+     * <br>HTML-only DOM implementations do not need to implement this method.
+     * @param namespaceURI The namespace URI of the attribute to remove.
+     * @param localName The local name of the attribute to remove.
+     * @exception DOMException
+     *   NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     * @since DOM Level 2
+     */
+    public void removeAttributeNS(String namespaceURI, 
+                                  String localName)
+                                  throws DOMException;
+
+    /**
+     * Retrieves an <code>Attr</code> node by local name and namespace URI. 
+     * HTML-only DOM implementations do not need to implement this method.
+     * @param namespaceURI The namespace URI of the attribute to retrieve.
+     * @param localName The local name of the attribute to retrieve.
+     * @return The <code>Attr</code> node with the specified attribute local 
+     *   name and namespace URI or <code>null</code> if there is no such 
+     *   attribute.
+     * @since DOM Level 2
+     */
+    public Attr getAttributeNodeNS(String namespaceURI, 
+                                   String localName);
+
+    /**
+     * Adds a new attribute. If an attribute with that local name and that 
+     * namespace URI is already present in the element, it is replaced by 
+     * the new one.
+     * <br>HTML-only DOM implementations do not need to implement this method.
+     * @param newAttr The <code>Attr</code> node to add to the attribute list.
+     * @return If the <code>newAttr</code> attribute replaces an existing 
+     *   attribute with the same local name and namespace URI, the replaced 
+     *   <code>Attr</code> node is returned, otherwise <code>null</code> is 
+     *   returned.
+     * @exception DOMException
+     *   WRONG_DOCUMENT_ERR: Raised if <code>newAttr</code> was created from a 
+     *   different document than the one that created the element.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     *   <br>INUSE_ATTRIBUTE_ERR: Raised if <code>newAttr</code> is already an 
+     *   attribute of another <code>Element</code> object. The DOM user must 
+     *   explicitly clone <code>Attr</code> nodes to re-use them in other 
+     *   elements.
+     * @since DOM Level 2
+     */
+    public Attr setAttributeNodeNS(Attr newAttr)
+                                   throws DOMException;
+
+    /**
+     * Returns a <code>NodeList</code> of all the descendant 
+     * <code>Elements</code> with a given local name and namespace URI in 
+     * the order in which they are encountered in a preorder traversal of 
+     * this <code>Element</code> tree.
+     * <br>HTML-only DOM implementations do not need to implement this method.
+     * @param namespaceURI The namespace URI of the elements to match on. The 
+     *   special value "*" matches all namespaces.
+     * @param localName The local name of the elements to match on. The 
+     *   special value "*" matches all local names.
+     * @return A new <code>NodeList</code> object containing all the matched 
+     *   <code>Elements</code>.
+     * @since DOM Level 2
+     */
+    public NodeList getElementsByTagNameNS(String namespaceURI, 
+                                           String localName);
+
+    /**
+     * Returns <code>true</code> when an attribute with a given name is 
+     * specified on this element or has a default value, <code>false</code> 
+     * otherwise.
+     * @param name The name of the attribute to look for.
+     * @return <code>true</code> if an attribute with the given name is 
+     *   specified on this element or has a default value, <code>false</code>
+     *    otherwise.
+     * @since DOM Level 2
+     */
+    public boolean hasAttribute(String name);
+
+    /**
+     * Returns <code>true</code> when an attribute with a given local name and 
+     * namespace URI is specified on this element or has a default value, 
+     * <code>false</code> otherwise. HTML-only DOM implementations do not 
+     * need to implement this method.
+     * @param namespaceURI The namespace URI of the attribute to look for.
+     * @param localName The local name of the attribute to look for.
+     * @return <code>true</code> if an attribute with the given local name 
+     *   and namespace URI is specified or has a default value on this 
+     *   element, <code>false</code> otherwise.
+     * @since DOM Level 2
+     */
+    public boolean hasAttributeNS(String namespaceURI, 
+                                  String localName);
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/Entity.java b/xml/src/main/java/org/w3c/dom/Entity.java
new file mode 100644
index 0000000..5b09608
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/Entity.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * This interface represents an entity, either parsed or unparsed, in an XML 
+ * document. Note that this models the entity itself not the entity 
+ * declaration. <code>Entity</code> declaration modeling has been left for a 
+ * later Level of the DOM specification.
+ * <p>The <code>nodeName</code> attribute that is inherited from 
+ * <code>Node</code> contains the name of the entity.
+ * <p>An XML processor may choose to completely expand entities before the 
+ * structure model is passed to the DOM; in this case there will be no 
+ * <code>EntityReference</code> nodes in the document tree.
+ * <p>XML does not mandate that a non-validating XML processor read and 
+ * process entity declarations made in the external subset or declared in 
+ * external parameter entities. This means that parsed entities declared in 
+ * the external subset need not be expanded by some classes of applications, 
+ * and that the replacement value of the entity may not be available. When 
+ * the replacement value is available, the corresponding <code>Entity</code> 
+ * node's child list represents the structure of that replacement text. 
+ * Otherwise, the child list is empty.
+ * <p>The DOM Level 2 does not support editing <code>Entity</code> nodes; if a 
+ * user wants to make changes to the contents of an <code>Entity</code>, 
+ * every related <code>EntityReference</code> node has to be replaced in the 
+ * structure model by a clone of the <code>Entity</code>'s contents, and 
+ * then the desired changes must be made to each of those clones instead. 
+ * <code>Entity</code> nodes and all their descendants are readonly.
+ * <p>An <code>Entity</code> node does not have any parent.If the entity 
+ * contains an unbound namespace prefix, the <code>namespaceURI</code> of 
+ * the corresponding node in the <code>Entity</code> node subtree is 
+ * <code>null</code>. The same is true for <code>EntityReference</code> 
+ * nodes that refer to this entity, when they are created using the 
+ * <code>createEntityReference</code> method of the <code>Document</code> 
+ * interface. The DOM Level 2 does not support any mechanism to resolve 
+ * namespace prefixes.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface Entity extends Node {
+    /**
+     * The public identifier associated with the entity, if specified. If the 
+     * public identifier was not specified, this is <code>null</code>.
+     * 
+     * @return the public identifier of the entity or <code>null</code>, if the
+     * entity does not have a public identifier.
+     */
+    public String getPublicId();
+
+    /**
+     * The system identifier associated with the entity, if specified. If the 
+     * system identifier was not specified, this is <code>null</code>.
+     * 
+     * @return the system identifier of the entity or <code>null</code>, if the
+     * entity does not have a system identifier.
+     */
+    public String getSystemId();
+
+    /**
+     * For unparsed entities, the name of the notation for the entity. For 
+     * parsed entities, this is <code>null</code>. 
+     * 
+     * @return the notation name of the entity or <code>null</code>, if the
+     * entity is parsed.
+     */
+    public String getNotationName();
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/EntityReference.java b/xml/src/main/java/org/w3c/dom/EntityReference.java
new file mode 100644
index 0000000..ff3cf9d
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/EntityReference.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+/**
+ * <code>EntityReference</code> objects may be inserted into the structure 
+ * model when an entity reference is in the source document, or when the 
+ * user wishes to insert an entity reference. Note that character references 
+ * and references to predefined entities are considered to be expanded by 
+ * the HTML or XML processor so that characters are represented by their 
+ * Unicode equivalent rather than by an entity reference. Moreover, the XML 
+ * processor may completely expand references to entities while building the 
+ * structure model, instead of providing <code>EntityReference</code> 
+ * objects. If it does provide such objects, then for a given 
+ * <code>EntityReference</code> node, it may be that there is no 
+ * <code>Entity</code> node representing the referenced entity. If such an 
+ * <code>Entity</code> exists, then the subtree of the 
+ * <code>EntityReference</code> node is in general a copy of the 
+ * <code>Entity</code> node subtree. However, this may not be true when an 
+ * entity contains an unbound namespace prefix. In such a case, because the 
+ * namespace prefix resolution depends on where the entity reference is, the 
+ * descendants of the <code>EntityReference</code> node may be bound to 
+ * different namespace URIs.
+ * <p>As for <code>Entity</code> nodes, <code>EntityReference</code> nodes and 
+ * all their descendants are readonly.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface EntityReference extends Node {
+}
diff --git a/xml/src/main/java/org/w3c/dom/NamedNodeMap.java b/xml/src/main/java/org/w3c/dom/NamedNodeMap.java
new file mode 100644
index 0000000..a6cbf09
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/NamedNodeMap.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+// BEGIN android-note
+// Cleaned up @param tags that seemed to be missing spaces between
+// the parameter name and the start of the description.
+// END android-note
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * Objects implementing the <code>NamedNodeMap</code> interface are used to 
+ * represent collections of nodes that can be accessed by name. Note that 
+ * <code>NamedNodeMap</code> does not inherit from <code>NodeList</code>; 
+ * <code>NamedNodeMaps</code> are not maintained in any particular order. 
+ * Objects contained in an object implementing <code>NamedNodeMap</code> may 
+ * also be accessed by an ordinal index, but this is simply to allow 
+ * convenient enumeration of the contents of a <code>NamedNodeMap</code>, 
+ * and does not imply that the DOM specifies an order to these Nodes. 
+ * <p><code>NamedNodeMap</code> objects in the DOM are live.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface NamedNodeMap {
+    /**
+     * Retrieves a node specified by name.
+     * @param name The <code>nodeName</code> of a node to retrieve.
+     * @return A <code>Node</code> (of any type) with the specified 
+     *   <code>nodeName</code>, or <code>null</code> if it does not identify 
+     *   any node in this map.
+     */
+    public Node getNamedItem(String name);
+
+    /**
+     * Adds a node using its <code>nodeName</code> attribute. If a node with 
+     * that name is already present in this map, it is replaced by the new 
+     * one.
+     * <br>As the <code>nodeName</code> attribute is used to derive the name 
+     * which the node must be stored under, multiple nodes of certain types 
+     * (those that have a "special" string value) cannot be stored as the 
+     * names would clash. This is seen as preferable to allowing nodes to be 
+     * aliased.
+     * @param arg A node to store in this map. The node will later be 
+     *   accessible using the value of its <code>nodeName</code> attribute.
+     * @return If the new <code>Node</code> replaces an existing node the 
+     *   replaced <code>Node</code> is returned, otherwise <code>null</code> 
+     *   is returned.
+     * @exception DOMException
+     *   WRONG_DOCUMENT_ERR: Raised if <code>arg</code> was created from a 
+     *   different document than the one that created this map.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
+     *   <br>INUSE_ATTRIBUTE_ERR: Raised if <code>arg</code> is an 
+     *   <code>Attr</code> that is already an attribute of another 
+     *   <code>Element</code> object. The DOM user must explicitly clone 
+     *   <code>Attr</code> nodes to re-use them in other elements.
+     */
+    public Node setNamedItem(Node arg)
+                             throws DOMException;
+
+    /**
+     * Removes a node specified by name. When this map contains the attributes 
+     * attached to an element, if the removed attribute is known to have a 
+     * default value, an attribute immediately appears containing the 
+     * default value as well as the corresponding namespace URI, local name, 
+     * and prefix when applicable.
+     * @param name The <code>nodeName</code> of the node to remove.
+     * @return The node removed from this map if a node with such a name 
+     *   exists.
+     * @exception DOMException
+     *   NOT_FOUND_ERR: Raised if there is no node named <code>name</code> in 
+     *   this map.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
+     */
+    public Node removeNamedItem(String name)
+                                throws DOMException;
+
+    /**
+     * Returns the <code>index</code>th item in the map. If <code>index</code> 
+     * is greater than or equal to the number of nodes in this map, this 
+     * returns <code>null</code>.
+     * @param index Index into this map.
+     * @return The node at the <code>index</code>th position in the map, or 
+     *   <code>null</code> if that is not a valid index.
+     */
+    public Node item(int index);
+
+    /**
+     * The number of nodes in this map. The range of valid child node indices 
+     * is <code>0</code> to <code>length-1</code> inclusive.
+     * 
+     * @return the length of the map.
+     */
+    public int getLength();
+
+    /**
+     * Retrieves a node specified by local name and namespace URI. HTML-only 
+     * DOM implementations do not need to implement this method.
+     * @param namespaceURI The namespace URI of the node to retrieve.
+     * @param localName The local name of the node to retrieve.
+     * @return A <code>Node</code> (of any type) with the specified local 
+     *   name and namespace URI, or <code>null</code> if they do not 
+     *   identify any node in this map.
+     * @since DOM Level 2
+     */
+    public Node getNamedItemNS(String namespaceURI, 
+                               String localName);
+
+    /**
+     * Adds a node using its <code>namespaceURI</code> and 
+     * <code>localName</code>. If a node with that namespace URI and that 
+     * local name is already present in this map, it is replaced by the new 
+     * one.
+     * <br>HTML-only DOM implementations do not need to implement this method.
+     * @param arg A node to store in this map. The node will later be 
+     *   accessible using the value of its <code>namespaceURI</code> and 
+     *   <code>localName</code> attributes.
+     * @return If the new <code>Node</code> replaces an existing node the 
+     *   replaced <code>Node</code> is returned, otherwise <code>null</code> 
+     *   is returned.
+     * @exception DOMException
+     *   WRONG_DOCUMENT_ERR: Raised if <code>arg</code> was created from a 
+     *   different document than the one that created this map.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
+     *   <br>INUSE_ATTRIBUTE_ERR: Raised if <code>arg</code> is an 
+     *   <code>Attr</code> that is already an attribute of another 
+     *   <code>Element</code> object. The DOM user must explicitly clone 
+     *   <code>Attr</code> nodes to re-use them in other elements.
+     * @since DOM Level 2
+     */
+    public Node setNamedItemNS(Node arg)
+                               throws DOMException;
+
+    /**
+     * Removes a node specified by local name and namespace URI. A removed 
+     * attribute may be known to have a default value when this map contains 
+     * the attributes attached to an element, as returned by the attributes 
+     * attribute of the <code>Node</code> interface. If so, an attribute 
+     * immediately appears containing the default value as well as the 
+     * corresponding namespace URI, local name, and prefix when applicable.
+     * <br>HTML-only DOM implementations do not need to implement this method.
+     * @param namespaceURI The namespace URI of the node to remove.
+     * @param localName The local name of the node to remove.
+     * @return The node removed from this map if a node with such a local 
+     *   name and namespace URI exists.
+     * @exception DOMException
+     *   NOT_FOUND_ERR: Raised if there is no node with the specified 
+     *   <code>namespaceURI</code> and <code>localName</code> in this map.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
+     * @since DOM Level 2
+     */
+    public Node removeNamedItemNS(String namespaceURI, 
+                                  String localName)
+                                  throws DOMException;
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/Node.java b/xml/src/main/java/org/w3c/dom/Node.java
new file mode 100644
index 0000000..c91c46d
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/Node.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+// BEGIN android-note
+// Cleaned up @param tags that seemed to be missing spaces between
+// the parameter name and the start of the description.
+// END android-note
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * The <code>Node</code> interface is the primary datatype for the entire 
+ * Document Object Model. It represents a single node in the document tree. 
+ * While all objects implementing the <code>Node</code> interface expose 
+ * methods for dealing with children, not all objects implementing the 
+ * <code>Node</code> interface may have children. For example, 
+ * <code>Text</code> nodes may not have children, and adding children to 
+ * such nodes results in a <code>DOMException</code> being raised.
+ * <p>The attributes <code>nodeName</code>, <code>nodeValue</code> and 
+ * <code>attributes</code> are included as a mechanism to get at node 
+ * information without casting down to the specific derived interface. In 
+ * cases where there is no obvious mapping of these attributes for a 
+ * specific <code>nodeType</code> (e.g., <code>nodeValue</code> for an 
+ * <code>Element</code> or <code>attributes</code> for a <code>Comment</code>
+ * ), this returns <code>null</code>. Note that the specialized interfaces 
+ * may contain additional and more convenient mechanisms to get and set the 
+ * relevant information.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface Node {
+    // NodeType
+    /**
+     * The node is an <code>Element</code>.
+     */
+    public static final short ELEMENT_NODE              = 1;
+    /**
+     * The node is an <code>Attr</code>.
+     */
+    public static final short ATTRIBUTE_NODE            = 2;
+    /**
+     * The node is a <code>Text</code> node.
+     */
+    public static final short TEXT_NODE                 = 3;
+    /**
+     * The node is a <code>CDATASection</code>.
+     */
+    public static final short CDATA_SECTION_NODE        = 4;
+    /**
+     * The node is an <code>EntityReference</code>.
+     */
+    public static final short ENTITY_REFERENCE_NODE     = 5;
+    /**
+     * The node is an <code>Entity</code>.
+     */
+    public static final short ENTITY_NODE               = 6;
+    /**
+     * The node is a <code>ProcessingInstruction</code>.
+     */
+    public static final short PROCESSING_INSTRUCTION_NODE = 7;
+    /**
+     * The node is a <code>Comment</code>.
+     */
+    public static final short COMMENT_NODE              = 8;
+    /**
+     * The node is a <code>Document</code>.
+     */
+    public static final short DOCUMENT_NODE             = 9;
+    /**
+     * The node is a <code>DocumentType</code>.
+     */
+    public static final short DOCUMENT_TYPE_NODE        = 10;
+    /**
+     * The node is a <code>DocumentFragment</code>.
+     */
+    public static final short DOCUMENT_FRAGMENT_NODE    = 11;
+    /**
+     * The node is a <code>Notation</code>.
+     */
+    public static final short NOTATION_NODE             = 12;
+
+    /**
+     * The name of this node, depending on its type; see the table above. 
+     * 
+     * @return the name of the node.
+     */
+    public String getNodeName();
+
+    /**
+     * Returns the value of this node, depending on its type; see the table
+     * above.
+     * 
+     * @return the value of the node.
+     * 
+     * @exception DOMException
+     *   DOMSTRING_SIZE_ERR: Raised when it would return more characters than 
+     *   fit in a <code>DOMString</code> variable on the implementation 
+     *   platform.
+     */
+    public String getNodeValue()
+                                 throws DOMException;
+    /**
+     * Sets the value of this node, depending on its type; see the table above. 
+     * When it is defined to be <code>null</code>, setting it has no effect.
+     * 
+     * @param nodeValue the new value of the node.
+     * 
+     * @exception DOMException
+     *   NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
+     */
+    public void setNodeValue(String nodeValue)
+                                 throws DOMException;
+
+    /**
+     * A code representing the type of the underlying object, as defined above.
+     * 
+     * @return the type of the node.
+     */
+    public short getNodeType();
+
+    /**
+     * The parent of this node. All nodes, except <code>Attr</code>, 
+     * <code>Document</code>, <code>DocumentFragment</code>, 
+     * <code>Entity</code>, and <code>Notation</code> may have a parent. 
+     * However, if a node has just been created and not yet added to the 
+     * tree, or if it has been removed from the tree, this is 
+     * <code>null</code>.
+     * 
+     * @return the parent node, if any.
+     */
+    public Node getParentNode();
+
+    /**
+     * A <code>NodeList</code> that contains all children of this node. If 
+     * there are no children, this is a <code>NodeList</code> containing no 
+     * nodes.
+     * 
+     * @return the list of children, which may be empty.
+     */
+    public NodeList getChildNodes();
+
+    /**
+     * The first child of this node. If there is no such node, this returns 
+     * <code>null</code>.
+     * 
+     * @return the first child of the node, if any.
+     */
+    public Node getFirstChild();
+
+    /**
+     * The last child of this node. If there is no such node, this returns 
+     * <code>null</code>.
+     * 
+     * @return the last child of the node, if any.
+     */
+    public Node getLastChild();
+
+    /**
+     * The node immediately preceding this node. If there is no such node, 
+     * this returns <code>null</code>.
+     * 
+     * @return the preceding node, if any.
+     */
+    public Node getPreviousSibling();
+
+    /**
+     * The node immediately following this node. If there is no such node, 
+     * this returns <code>null</code>.
+     * 
+     * @return the following node, if any.
+     */
+    public Node getNextSibling();
+
+    /**
+     * A <code>NamedNodeMap</code> containing the attributes of this node (if 
+     * it is an <code>Element</code>) or <code>null</code> otherwise. 
+     * 
+     * @return the attributes of the node, which may be an empty map, or
+     * <code>null</code>, if this the node cannot have any attributes.
+     */
+    public NamedNodeMap getAttributes();
+
+    /**
+     * The <code>Document</code> object associated with this node. This is 
+     * also the <code>Document</code> object used to create new nodes. When 
+     * this node is a <code>Document</code> or a <code>DocumentType</code> 
+     * which is not used with any <code>Document</code> yet, this is 
+     * <code>null</code>.
+     * 
+     * @return the document this node belongs to, if any.
+     * 
+     * @version DOM Level 2
+     */
+    public Document getOwnerDocument();
+
+    /**
+     * Inserts the node <code>newChild</code> before the existing child node 
+     * <code>refChild</code>. If <code>refChild</code> is <code>null</code>, 
+     * insert <code>newChild</code> at the end of the list of children.
+     * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object, 
+     * all of its children are inserted, in the same order, before 
+     * <code>refChild</code>. If the <code>newChild</code> is already in the 
+     * tree, it is first removed.
+     * @param newChild The node to insert.
+     * @param refChild The reference node, i.e., the node before which the new 
+     *   node must be inserted.
+     * @return The node being inserted.
+     * @exception DOMException
+     *   HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not 
+     *   allow children of the type of the <code>newChild</code> node, or if 
+     *   the node to insert is one of this node's ancestors.
+     *   <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created 
+     *   from a different document than the one that created this node.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or 
+     *   if the parent of the node being inserted is readonly.
+     *   <br>NOT_FOUND_ERR: Raised if <code>refChild</code> is not a child of 
+     *   this node.
+     */
+    public Node insertBefore(Node newChild, 
+                             Node refChild)
+                             throws DOMException;
+
+    /**
+     * Replaces the child node <code>oldChild</code> with <code>newChild</code>
+     *  in the list of children, and returns the <code>oldChild</code> node.
+     * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object, 
+     * <code>oldChild</code> is replaced by all of the 
+     * <code>DocumentFragment</code> children, which are inserted in the 
+     * same order. If the <code>newChild</code> is already in the tree, it 
+     * is first removed.
+     * @param newChild The new node to put in the child list.
+     * @param oldChild The node being replaced in the list.
+     * @return The node replaced.
+     * @exception DOMException
+     *   HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not 
+     *   allow children of the type of the <code>newChild</code> node, or if 
+     *   the node to put in is one of this node's ancestors.
+     *   <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created 
+     *   from a different document than the one that created this node.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node or the parent of 
+     *   the new node is readonly.
+     *   <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of 
+     *   this node.
+     */
+    public Node replaceChild(Node newChild, 
+                             Node oldChild)
+                             throws DOMException;
+
+    /**
+     * Removes the child node indicated by <code>oldChild</code> from the list 
+     * of children, and returns it.
+     * @param oldChild The node being removed.
+     * @return The node removed.
+     * @exception DOMException
+     *   NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     *   <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of 
+     *   this node.
+     */
+    public Node removeChild(Node oldChild)
+                            throws DOMException;
+
+    /**
+     * Adds the node <code>newChild</code> to the end of the list of children 
+     * of this node. If the <code>newChild</code> is already in the tree, it 
+     * is first removed.
+     * @param newChild The node to add.If it is a <code>DocumentFragment</code>
+     *    object, the entire contents of the document fragment are moved 
+     *   into the child list of this node
+     * @return The node added.
+     * @exception DOMException
+     *   HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not 
+     *   allow children of the type of the <code>newChild</code> node, or if 
+     *   the node to append is one of this node's ancestors.
+     *   <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created 
+     *   from a different document than the one that created this node.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     */
+    public Node appendChild(Node newChild)
+                            throws DOMException;
+
+    /**
+     * Returns whether this node has any children.
+     * @return  <code>true</code> if this node has any children, 
+     *   <code>false</code> otherwise.
+     */
+    public boolean hasChildNodes();
+
+    /**
+     * Returns a duplicate of this node, i.e., serves as a generic copy 
+     * constructor for nodes. The duplicate node has no parent; (
+     * <code>parentNode</code> is <code>null</code>.).
+     * <br>Cloning an <code>Element</code> copies all attributes and their 
+     * values, including those generated by the XML processor to represent 
+     * defaulted attributes, but this method does not copy any text it 
+     * contains unless it is a deep clone, since the text is contained in a 
+     * child <code>Text</code> node. Cloning an <code>Attribute</code> 
+     * directly, as opposed to be cloned as part of an <code>Element</code> 
+     * cloning operation, returns a specified attribute (
+     * <code>specified</code> is <code>true</code>). Cloning any other type 
+     * of node simply returns a copy of this node.
+     * <br>Note that cloning an immutable subtree results in a mutable copy, 
+     * but the children of an <code>EntityReference</code> clone are readonly
+     * . In addition, clones of unspecified <code>Attr</code> nodes are 
+     * specified. And, cloning <code>Document</code>, 
+     * <code>DocumentType</code>, <code>Entity</code>, and 
+     * <code>Notation</code> nodes is implementation dependent.
+     * @param deep If <code>true</code>, recursively clone the subtree under 
+     *   the specified node; if <code>false</code>, clone only the node 
+     *   itself (and its attributes, if it is an <code>Element</code>). 
+     * @return The duplicate node.
+     */
+    public Node cloneNode(boolean deep);
+
+    /**
+     * Puts all <code>Text</code> nodes in the full depth of the sub-tree 
+     * underneath this <code>Node</code>, including attribute nodes, into a 
+     * "normal" form where only structure (e.g., elements, comments, 
+     * processing instructions, CDATA sections, and entity references) 
+     * separates <code>Text</code> nodes, i.e., there are neither adjacent 
+     * <code>Text</code> nodes nor empty <code>Text</code> nodes. This can 
+     * be used to ensure that the DOM view of a document is the same as if 
+     * it were saved and re-loaded, and is useful when operations (such as 
+     * XPointer  lookups) that depend on a particular document tree 
+     * structure are to be used.In cases where the document contains 
+     * <code>CDATASections</code>, the normalize operation alone may not be 
+     * sufficient, since XPointers do not differentiate between 
+     * <code>Text</code> nodes and <code>CDATASection</code> nodes.
+     * @version DOM Level 2
+     */
+    public void normalize();
+
+    /**
+     * Tests whether the DOM implementation implements a specific feature and 
+     * that feature is supported by this node.
+     * @param feature The name of the feature to test. This is the same name 
+     *   which can be passed to the method <code>hasFeature</code> on 
+     *   <code>DOMImplementation</code>.
+     * @param version This is the version number of the feature to test. In 
+     *   Level 2, version 1, this is the string "2.0". If the version is not 
+     *   specified, supporting any version of the feature will cause the 
+     *   method to return <code>true</code>.
+     * @return Returns <code>true</code> if the specified feature is 
+     *   supported on this node, <code>false</code> otherwise.
+     * @since DOM Level 2
+     */
+    public boolean isSupported(String feature, 
+                               String version);
+
+    /**
+     * The namespace URI of this node, or <code>null</code> if it is 
+     * unspecified.
+     * <br>This is not a computed value that is the result of a namespace 
+     * lookup based on an examination of the namespace declarations in 
+     * scope. It is merely the namespace URI given at creation time.
+     * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
+     * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
+     * method, such as <code>createElement</code> from the 
+     * <code>Document</code> interface, this is always <code>null</code>.Per 
+     * the Namespaces in XML Specification  an attribute does not inherit 
+     * its namespace from the element it is attached to. If an attribute is 
+     * not explicitly given a namespace, it simply has no namespace.
+     * 
+     * @return the namespace URI, if any.
+     * 
+     * @since DOM Level 2
+     */
+    public String getNamespaceURI();
+
+    /**
+     * Returns the namespace prefix of this node, or <code>null</code> if it is 
+     * unspecified.
+     * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
+     * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
+     * method, such as <code>createElement</code> from the 
+     * <code>Document</code> interface, this is always <code>null</code>.
+     * 
+     * @return the namespace prefix, if any.
+     * 
+     * @exception DOMException
+     * @since DOM Level 2
+     */
+    public String getPrefix();
+    
+    /**
+     * Sets the namespace prefix of this node.
+     * <br>Note that setting this attribute, when permitted, changes the 
+     * <code>nodeName</code> attribute, which holds the qualified name, as 
+     * well as the <code>tagName</code> and <code>name</code> attributes of 
+     * the <code>Element</code> and <code>Attr</code> interfaces, when 
+     * applicable.
+     * <br>Note also that changing the prefix of an attribute that is known to 
+     * have a default value, does not make a new attribute with the default 
+     * value and the original prefix appear, since the 
+     * <code>namespaceURI</code> and <code>localName</code> do not change.
+     * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
+     * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
+     * method, such as <code>createElement</code> from the 
+     * <code>Document</code> interface, this is always <code>null</code>.
+     * @exception DOMException
+     *   INVALID_CHARACTER_ERR: Raised if the specified prefix contains an 
+     *   illegal character.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     *   <br>NAMESPACE_ERR: Raised if the specified <code>prefix</code> is 
+     *   malformed, if the <code>namespaceURI</code> of this node is 
+     *   <code>null</code>, if the specified prefix is "xml" and the 
+     *   <code>namespaceURI</code> of this node is different from "
+     *   http://www.w3.org/XML/1998/namespace", if this node is an attribute 
+     *   and the specified prefix is "xmlns" and the 
+     *   <code>namespaceURI</code> of this node is different from "
+     *   http://www.w3.org/2000/xmlns/", or if this node is an attribute and 
+     *   the <code>qualifiedName</code> of this node is "xmlns" .
+     *   
+     * @param prefix the new namespace prefix.
+     * 
+     * @since DOM Level 2
+     */
+    public void setPrefix(String prefix)
+                               throws DOMException;
+
+    /**
+     * Returns the local part of the qualified name of this node.
+     * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
+     * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
+     * method, such as <code>createElement</code> from the 
+     * <code>Document</code> interface, this is always <code>null</code>.
+     * 
+     * @return the local name, if any.
+     * 
+     * @since DOM Level 2
+     */
+    public String getLocalName();
+
+    /**
+     * Returns whether this node (if it is an element) has any attributes.
+     * @return <code>true</code> if this node has any attributes, 
+     *   <code>false</code> otherwise.
+     * @since DOM Level 2
+     */
+    public boolean hasAttributes();
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/NodeList.java b/xml/src/main/java/org/w3c/dom/NodeList.java
new file mode 100644
index 0000000..0dbadda
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/NodeList.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+// BEGIN android-note
+// Cleaned up @param tags that seemed to be missing spaces between
+// the parameter name and the start of the description.
+// END android-note
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * The <code>NodeList</code> interface provides the abstraction of an ordered 
+ * collection of nodes, without defining or constraining how this collection 
+ * is implemented. <code>NodeList</code> objects in the DOM are live.
+ * <p>The items in the <code>NodeList</code> are accessible via an integral 
+ * index, starting from 0.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface NodeList {
+    /**
+     * Returns the <code>index</code>th item in the collection. If 
+     * <code>index</code> is greater than or equal to the number of nodes in 
+     * the list, this returns <code>null</code>.
+     * @param index Index into the collection.
+     * @return The node at the <code>index</code>th position in the 
+     *   <code>NodeList</code>, or <code>null</code> if that is not a valid 
+     *   index.
+     */
+    public Node item(int index);
+
+    /**
+     * The number of nodes in the list. The range of valid child node indices 
+     * is 0 to <code>length-1</code> inclusive.
+     * 
+     * @return the length of the list. 
+     */
+    public int getLength();
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/Notation.java b/xml/src/main/java/org/w3c/dom/Notation.java
new file mode 100644
index 0000000..00c702f
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/Notation.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * This interface represents a notation declared in the DTD. A notation either 
+ * declares, by name, the format of an unparsed entity (see section 4.7 of 
+ * the XML 1.0 specification ), or is used for formal declaration of 
+ * processing instruction targets (see section 2.6 of the XML 1.0 
+ * specification ). The <code>nodeName</code> attribute inherited from 
+ * <code>Node</code> is set to the declared name of the notation.
+ * <p>The DOM Level 1 does not support editing <code>Notation</code> nodes; 
+ * they are therefore readonly.
+ * <p>A <code>Notation</code> node does not have any parent.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface Notation extends Node {
+    /**
+     * The public identifier of this notation. If the public identifier was 
+     * not specified, this is <code>null</code>.
+     * 
+     * @return the public identifier of this notation, if any.
+     */
+    public String getPublicId();
+
+    /**
+     * The system identifier of this notation. If the system identifier was 
+     * not specified, this is <code>null</code>.
+     * 
+     * @return the system identifier of this notation, if any.
+     */
+    public String getSystemId();
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/ProcessingInstruction.java b/xml/src/main/java/org/w3c/dom/ProcessingInstruction.java
new file mode 100644
index 0000000..a702aa6
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/ProcessingInstruction.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+//BEGIN android-note
+//Filled some gaps in the documentation and refactored parts of the existing
+//documentation to make the Doclet happy.
+//END android-note
+
+/**
+ * The <code>ProcessingInstruction</code> interface represents a "processing 
+ * instruction", used in XML as a way to keep processor-specific information 
+ * in the text of the document.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface ProcessingInstruction extends Node {
+    /**
+     * The target of this processing instruction. XML defines this as being 
+     * the first token following the markup that begins the processing 
+     * instruction.
+     * 
+     * @return the target of this processing instruction.
+     */
+    public String getTarget();
+
+    /**
+     * Returns the content of this processing instruction. This is from the
+     * first non white space character after the target to the character
+     * immediately preceding the <code>?&gt;</code>.
+     * 
+     * @return the data of this processing instruction.
+     */
+    public String getData();
+
+    /**
+     * Sets the content of this processing instruction. This is from the first
+     * non white space character after the target to the character immediately 
+     * preceding the <code>?&gt;</code>.
+     * 
+     * @param data the new data of the processing instruction.
+     * 
+     * @exception DOMException
+     *   NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
+     */
+    public void setData(String data)
+                          throws DOMException;
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/Text.java b/xml/src/main/java/org/w3c/dom/Text.java
new file mode 100644
index 0000000..4d1746b
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/Text.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2000 World Wide Web Consortium,
+ * (Massachusetts Institute of Technology, Institut National de
+ * Recherche en Informatique et en Automatique, Keio University). All
+ * Rights Reserved. This program is distributed under the W3C's Software
+ * Intellectual Property License. This program is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ * See W3C License http://www.w3.org/Consortium/Legal/ for more details.
+ */
+
+package org.w3c.dom;
+
+// BEGIN android-note
+// Cleaned up @param tags that seemed to be missing spaces between
+// the parameter name and the start of the description.
+// END android-note
+
+/**
+ * The <code>Text</code> interface inherits from <code>CharacterData</code> 
+ * and represents the textual content (termed character data in XML) of an 
+ * <code>Element</code> or <code>Attr</code>. If there is no markup inside 
+ * an element's content, the text is contained in a single object 
+ * implementing the <code>Text</code> interface that is the only child of 
+ * the element. If there is markup, it is parsed into the information items 
+ * (elements, comments, etc.) and <code>Text</code> nodes that form the list 
+ * of children of the element.
+ * <p>When a document is first made available via the DOM, there is only one 
+ * <code>Text</code> node for each block of text. Users may create adjacent 
+ * <code>Text</code> nodes that represent the contents of a given element 
+ * without any intervening markup, but should be aware that there is no way 
+ * to represent the separations between these nodes in XML or HTML, so they 
+ * will not (in general) persist between DOM editing sessions. The 
+ * <code>normalize()</code> method on <code>Node</code> merges any such 
+ * adjacent <code>Text</code> objects into a single node for each block of 
+ * text.
+ * <p>See also the <a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>Document Object Model (DOM) Level 2 Core Specification</a>.
+ */
+public interface Text extends CharacterData {
+    /**
+     * Breaks this node into two nodes at the specified <code>offset</code>, 
+     * keeping both in the tree as siblings. After being split, this node 
+     * will contain all the content up to the <code>offset</code> point. A 
+     * new node of the same type, which contains all the content at and 
+     * after the <code>offset</code> point, is returned. If the original 
+     * node had a parent node, the new node is inserted as the next sibling 
+     * of the original node. When the <code>offset</code> is equal to the 
+     * length of this node, the new node has no data.
+     * @param offset The 16-bit unit offset at which to split, starting from 
+     *   <code>0</code>.
+     * @return The new node, of the same type as this node.
+     * @exception DOMException
+     *   INDEX_SIZE_ERR: Raised if the specified offset is negative or greater 
+     *   than the number of 16-bit units in <code>data</code>.
+     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+     */
+    public Text splitText(int offset)
+                          throws DOMException;
+
+}
diff --git a/xml/src/main/java/org/w3c/dom/package.html b/xml/src/main/java/org/w3c/dom/package.html
new file mode 100644
index 0000000..8189944
--- /dev/null
+++ b/xml/src/main/java/org/w3c/dom/package.html
@@ -0,0 +1,12 @@
+<html>
+  <body>
+    <p>
+      Provides the official W3C Java bindings for the Document Object Model,
+      level 2 core. XML documents returned by
+      {@link javax.xml.parsers.DocumentBuilder} are accessed and manipulated
+      through these interfaces.
+    </p>
+    
+  @since Android 1.0
+  </body>
+</html>
\ No newline at end of file
diff --git a/xml/src/main/java/org/xml/sax/AttributeList.java b/xml/src/main/java/org/xml/sax/AttributeList.java
new file mode 100644
index 0000000..9285eac
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/AttributeList.java
@@ -0,0 +1,193 @@
+// SAX Attribute List Interface.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: AttributeList.java,v 1.7 2004/04/26 17:34:34 dmegginson Exp $
+
+package org.xml.sax;
+
+/**
+ * Interface for an element's attribute specifications.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This is the original SAX1 interface for reporting an element's
+ * attributes.  Unlike the new {@link org.xml.sax.Attributes Attributes}
+ * interface, it does not support Namespace-related information.</p>
+ *
+ * <p>When an attribute list is supplied as part of a
+ * {@link org.xml.sax.DocumentHandler#startElement startElement}
+ * event, the list will return valid results only during the
+ * scope of the event; once the event handler returns control
+ * to the parser, the attribute list is invalid.  To save a
+ * persistent copy of the attribute list, use the SAX1
+ * {@link org.xml.sax.helpers.AttributeListImpl AttributeListImpl}
+ * helper class.</p>
+ *
+ * <p>An attribute list includes only attributes that have been
+ * specified or defaulted: #IMPLIED attributes will not be included.</p>
+ *
+ * <p>There are two ways for the SAX application to obtain information
+ * from the AttributeList.  First, it can iterate through the entire
+ * list:</p>
+ *
+ * <pre>
+ * public void startElement (String name, AttributeList atts) {
+ *   for (int i = 0; i < atts.getLength(); i++) {
+ *     String name = atts.getName(i);
+ *     String type = atts.getType(i);
+ *     String value = atts.getValue(i);
+ *     [...]
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>(Note that the result of getLength() will be zero if there
+ * are no attributes.)
+ *
+ * <p>As an alternative, the application can request the value or
+ * type of specific attributes:</p>
+ *
+ * <pre>
+ * public void startElement (String name, AttributeList atts) {
+ *   String identifier = atts.getValue("id");
+ *   String label = atts.getValue("label");
+ *   [...]
+ * }
+ * </pre>
+ *
+ * @deprecated This interface has been replaced by the SAX2
+ *             {@link org.xml.sax.Attributes Attributes}
+ *             interface, which includes Namespace support.
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.DocumentHandler#startElement startElement
+ * @see org.xml.sax.helpers.AttributeListImpl AttributeListImpl
+ */
+public interface AttributeList {
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Iteration methods.
+    ////////////////////////////////////////////////////////////////////
+    
+
+    /**
+     * Return the number of attributes in this list.
+     *
+     * <p>The SAX parser may provide attributes in any
+     * arbitrary order, regardless of the order in which they were
+     * declared or specified.  The number of attributes may be
+     * zero.</p>
+     *
+     * @return The number of attributes in the list.  
+     */
+    public abstract int getLength ();
+    
+    
+    /**
+     * Return the name of an attribute in this list (by position).
+     *
+     * <p>The names must be unique: the SAX parser shall not include the
+     * same attribute twice.  Attributes without values (those declared
+     * #IMPLIED without a value specified in the start tag) will be
+     * omitted from the list.</p>
+     *
+     * <p>If the attribute name has a namespace prefix, the prefix
+     * will still be attached.</p>
+     *
+     * @param i The index of the attribute in the list (starting at 0).
+     * @return The name of the indexed attribute, or null
+     *         if the index is out of range.
+     * @see #getLength 
+     */
+    public abstract String getName (int i);
+    
+    
+    /**
+     * Return the type of an attribute in the list (by position).
+     *
+     * <p>The attribute type is one of the strings "CDATA", "ID",
+     * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES",
+     * or "NOTATION" (always in upper case).</p>
+     *
+     * <p>If the parser has not read a declaration for the attribute,
+     * or if the parser does not report attribute types, then it must
+     * return the value "CDATA" as stated in the XML 1.0 Recommentation
+     * (clause 3.3.3, "Attribute-Value Normalization").</p>
+     *
+     * <p>For an enumerated attribute that is not a notation, the
+     * parser will report the type as "NMTOKEN".</p>
+     *
+     * @param i The index of the attribute in the list (starting at 0).
+     * @return The attribute type as a string, or
+     *         null if the index is out of range.
+     * @see #getLength 
+     * @see #getType(java.lang.String)
+     */
+    public abstract String getType (int i);
+    
+    
+    /**
+     * Return the value of an attribute in the list (by position).
+     *
+     * <p>If the attribute value is a list of tokens (IDREFS,
+     * ENTITIES, or NMTOKENS), the tokens will be concatenated
+     * into a single string separated by whitespace.</p>
+     *
+     * @param i The index of the attribute in the list (starting at 0).
+     * @return The attribute value as a string, or
+     *         null if the index is out of range.
+     * @see #getLength
+     * @see #getValue(java.lang.String)
+     */
+    public abstract String getValue (int i);
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Lookup methods.
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Return the type of an attribute in the list (by name).
+     *
+     * <p>The return value is the same as the return value for
+     * getType(int).</p>
+     *
+     * <p>If the attribute name has a namespace prefix in the document,
+     * the application must include the prefix here.</p>
+     *
+     * @param name The name of the attribute.
+     * @return The attribute type as a string, or null if no
+     *         such attribute exists.
+     * @see #getType(int)
+     */
+    public abstract String getType (String name);
+    
+    
+    /**
+     * Return the value of an attribute in the list (by name).
+     *
+     * <p>The return value is the same as the return value for
+     * getValue(int).</p>
+     *
+     * <p>If the attribute name has a namespace prefix in the document,
+     * the application must include the prefix here.</p>
+     *
+     * @param name the name of the attribute to return
+     * @return The attribute value as a string, or null if
+     *         no such attribute exists.
+     * @see #getValue(int)
+     */
+    public abstract String getValue (String name);
+    
+}
+
+// end of AttributeList.java
diff --git a/xml/src/main/java/org/xml/sax/Attributes.java b/xml/src/main/java/org/xml/sax/Attributes.java
new file mode 100644
index 0000000..b25432d
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/Attributes.java
@@ -0,0 +1,257 @@
+// Attributes.java - attribute list with Namespace support
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the public domain.
+// $Id: Attributes.java,v 1.13 2004/03/18 12:28:05 dmegginson Exp $
+
+package org.xml.sax;
+
+
+/**
+ * Interface for a list of XML attributes.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This interface allows access to a list of attributes in
+ * three different ways:</p>
+ *
+ * <ol>
+ * <li>by attribute index;</li>
+ * <li>by Namespace-qualified name; or</li>
+ * <li>by qualified (prefixed) name.</li>
+ * </ol>
+ *
+ * <p>The list will not contain attributes that were declared
+ * #IMPLIED but not specified in the start tag.  It will also not
+ * contain attributes used as Namespace declarations (xmlns*) unless
+ * the <code>http://xml.org/sax/features/namespace-prefixes</code> 
+ * feature is set to <var>true</var> (it is <var>false</var> by 
+ * default).
+ * Because SAX2 conforms to the original "Namespaces in XML"
+ * recommendation, it normally does not
+ * give namespace declaration attributes a namespace URI.
+ * </p>
+ *
+ * <p>Some SAX2 parsers may support using an optional feature flag
+ * (<code>http://xml.org/sax/features/xmlns-uris</code>) to request
+ * that those attributes be given URIs, conforming to a later
+ * backwards-incompatible revision of that recommendation.  (The
+ * attribute's "local name" will be the prefix, or "xmlns" when
+ * defining a default element namespace.)  For portability, handler
+ * code should always resolve that conflict, rather than requiring
+ * parsers that can change the setting of that feature flag.  </p>
+ *
+ * <p>If the namespace-prefixes feature (see above) is
+ * <var>false</var>, access by qualified name may not be available; if
+ * the <code>http://xml.org/sax/features/namespaces</code> feature is
+ * <var>false</var>, access by Namespace-qualified names may not be
+ * available.</p>
+ *
+ * <p>This interface replaces the now-deprecated SAX1 {@link
+ * org.xml.sax.AttributeList AttributeList} interface, which does not 
+ * contain Namespace support.  In addition to Namespace support, it 
+ * adds the <var>getIndex</var> methods (below).</p>
+ *
+ * <p>The order of attributes in the list is unspecified, and will
+ * vary from implementation to implementation.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.helpers.AttributesImpl
+ * @see org.xml.sax.ext.DeclHandler#attributeDecl
+ */
+public interface Attributes
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Indexed access.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Return the number of attributes in the list.
+     *
+     * <p>Once you know the number of attributes, you can iterate
+     * through the list.</p>
+     *
+     * @return The number of attributes in the list.
+     * @see #getURI(int)
+     * @see #getLocalName(int)
+     * @see #getQName(int)
+     * @see #getType(int)
+     * @see #getValue(int)
+     */
+    public abstract int getLength ();
+
+
+    /**
+     * Look up an attribute's Namespace URI by index.
+     *
+     * @param index The attribute index (zero-based).
+     * @return The Namespace URI, or the empty string if none
+     *         is available, or null if the index is out of
+     *         range.
+     * @see #getLength
+     */
+    public abstract String getURI (int index);
+
+
+    /**
+     * Look up an attribute's local name by index.
+     *
+     * @param index The attribute index (zero-based).
+     * @return The local name, or the empty string if Namespace
+     *         processing is not being performed, or null
+     *         if the index is out of range.
+     * @see #getLength
+     */
+    public abstract String getLocalName (int index);
+
+
+    /**
+     * Look up an attribute's XML qualified (prefixed) name by index.
+     *
+     * @param index The attribute index (zero-based).
+     * @return The XML qualified name, or the empty string
+     *         if none is available, or null if the index
+     *         is out of range.
+     * @see #getLength
+     */
+    public abstract String getQName (int index);
+
+
+    /**
+     * Look up an attribute's type by index.
+     *
+     * <p>The attribute type is one of the strings "CDATA", "ID",
+     * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES",
+     * or "NOTATION" (always in upper case).</p>
+     *
+     * <p>If the parser has not read a declaration for the attribute,
+     * or if the parser does not report attribute types, then it must
+     * return the value "CDATA" as stated in the XML 1.0 Recommendation
+     * (clause 3.3.3, "Attribute-Value Normalization").</p>
+     *
+     * <p>For an enumerated attribute that is not a notation, the
+     * parser will report the type as "NMTOKEN".</p>
+     *
+     * @param index The attribute index (zero-based).
+     * @return The attribute's type as a string, or null if the
+     *         index is out of range.
+     * @see #getLength
+     */
+    public abstract String getType (int index);
+
+
+    /**
+     * Look up an attribute's value by index.
+     *
+     * <p>If the attribute value is a list of tokens (IDREFS,
+     * ENTITIES, or NMTOKENS), the tokens will be concatenated
+     * into a single string with each token separated by a
+     * single space.</p>
+     *
+     * @param index The attribute index (zero-based).
+     * @return The attribute's value as a string, or null if the
+     *         index is out of range.
+     * @see #getLength
+     */
+    public abstract String getValue (int index);
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Name-based query.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Look up the index of an attribute by Namespace name.
+     *
+     * @param uri The Namespace URI, or the empty string if
+     *        the name has no Namespace URI.
+     * @param localName The attribute's local name.
+     * @return The index of the attribute, or -1 if it does not
+     *         appear in the list.
+     */
+    public int getIndex (String uri, String localName);
+
+
+    /**
+     * Look up the index of an attribute by XML qualified (prefixed) name.
+     *
+     * @param qName The qualified (prefixed) name.
+     * @return The index of the attribute, or -1 if it does not
+     *         appear in the list.
+     */
+    public int getIndex (String qName);
+
+
+    /**
+     * Look up an attribute's type by Namespace name.
+     *
+     * <p>See {@link #getType(int) getType(int)} for a description
+     * of the possible types.</p>
+     *
+     * @param uri The Namespace URI, or the empty String if the
+     *        name has no Namespace URI.
+     * @param localName The local name of the attribute.
+     * @return The attribute type as a string, or null if the
+     *         attribute is not in the list or if Namespace
+     *         processing is not being performed.
+     */
+    public abstract String getType (String uri, String localName);
+
+
+    /**
+     * Look up an attribute's type by XML qualified (prefixed) name.
+     *
+     * <p>See {@link #getType(int) getType(int)} for a description
+     * of the possible types.</p>
+     *
+     * @param qName The XML qualified name.
+     * @return The attribute type as a string, or null if the
+     *         attribute is not in the list or if qualified names
+     *         are not available.
+     */
+    public abstract String getType (String qName);
+
+
+    /**
+     * Look up an attribute's value by Namespace name.
+     *
+     * <p>See {@link #getValue(int) getValue(int)} for a description
+     * of the possible values.</p>
+     *
+     * @param uri The Namespace URI, or the empty String if the
+     *        name has no Namespace URI.
+     * @param localName The local name of the attribute.
+     * @return The attribute value as a string, or null if the
+     *         attribute is not in the list.
+     */
+    public abstract String getValue (String uri, String localName);
+
+
+    /**
+     * Look up an attribute's value by XML qualified (prefixed) name.
+     *
+     * <p>See {@link #getValue(int) getValue(int)} for a description
+     * of the possible values.</p>
+     *
+     * @param qName The XML qualified name.
+     * @return The attribute value as a string, or null if the
+     *         attribute is not in the list or if qualified names
+     *         are not available.
+     */
+    public abstract String getValue (String qName);
+
+}
+
+// end of Attributes.java
diff --git a/xml/src/main/java/org/xml/sax/ContentHandler.java b/xml/src/main/java/org/xml/sax/ContentHandler.java
new file mode 100644
index 0000000..db66c0d
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ContentHandler.java
@@ -0,0 +1,419 @@
+// ContentHandler.java - handle main document content.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the public domain.
+// $Id: ContentHandler.java,v 1.13 2004/04/26 17:50:49 dmegginson Exp $
+
+package org.xml.sax;
+
+
+/**
+ * Receive notification of the logical content of a document.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This is the main interface that most SAX applications
+ * implement: if the application needs to be informed of basic parsing 
+ * events, it implements this interface and registers an instance with 
+ * the SAX parser using the {@link org.xml.sax.XMLReader#setContentHandler 
+ * setContentHandler} method.  The parser uses the instance to report 
+ * basic document-related events like the start and end of elements 
+ * and character data.</p>
+ *
+ * <p>The order of events in this interface is very important, and
+ * mirrors the order of information in the document itself.  For
+ * example, all of an element's content (character data, processing
+ * instructions, and/or subelements) will appear, in order, between
+ * the startElement event and the corresponding endElement event.</p>
+ *
+ * <p>This interface is similar to the now-deprecated SAX 1.0
+ * DocumentHandler interface, but it adds support for Namespaces
+ * and for reporting skipped entities (in non-validating XML
+ * processors).</p>
+ *
+ * <p>Implementors should note that there is also a 
+ * <code>ContentHandler</code> class in the <code>java.net</code>
+ * package; that means that it's probably a bad idea to do</p>
+ *
+ * <pre>import java.net.*;
+ * import org.xml.sax.*;
+ * </pre>
+ *
+ * <p>In fact, "import ...*" is usually a sign of sloppy programming
+ * anyway, so the user should consider this a feature rather than a
+ * bug.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1+ (sax2r3pre1)
+ * @see org.xml.sax.XMLReader
+ * @see org.xml.sax.DTDHandler
+ * @see org.xml.sax.ErrorHandler
+ */
+public interface ContentHandler
+{
+
+    /**
+     * Receive an object for locating the origin of SAX document events.
+     *
+     * <p>SAX parsers are strongly encouraged (though not absolutely
+     * required) to supply a locator: if it does so, it must supply
+     * the locator to the application by invoking this method before
+     * invoking any of the other methods in the ContentHandler
+     * interface.</p>
+     *
+     * <p>The locator allows the application to determine the end
+     * position of any document-related event, even if the parser is
+     * not reporting an error.  Typically, the application will
+     * use this information for reporting its own errors (such as
+     * character content that does not match an application's
+     * business rules).  The information returned by the locator
+     * is probably not sufficient for use with a search engine.</p>
+     *
+     * <p>Note that the locator will return correct information only
+     * during the invocation SAX event callbacks after
+     * {@link #startDocument startDocument} returns and before
+     * {@link #endDocument endDocument} is called.  The
+     * application should not attempt to use it at any other time.</p>
+     *
+     * @param locator an object that can return the location of
+     *                any SAX document event
+     * @see org.xml.sax.Locator
+     */
+    public void setDocumentLocator (Locator locator);
+
+
+    /**
+     * Receive notification of the beginning of a document.
+     *
+     * <p>The SAX parser will invoke this method only once, before any
+     * other event callbacks (except for {@link #setDocumentLocator 
+     * setDocumentLocator}).</p>
+     *
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #endDocument
+     */
+    public void startDocument ()
+    throws SAXException;
+
+
+    /**
+     * Receive notification of the end of a document.
+     *
+     * <p><strong>There is an apparent contradiction between the
+     * documentation for this method and the documentation for {@link
+     * org.xml.sax.ErrorHandler#fatalError}.  Until this ambiguity is
+     * resolved in a future major release, clients should make no
+     * assumptions about whether endDocument() will or will not be
+     * invoked when the parser has reported a fatalError() or thrown
+     * an exception.</strong></p>
+     *
+     * <p>The SAX parser will invoke this method only once, and it will
+     * be the last method invoked during the parse.  The parser shall
+     * not invoke this method until it has either abandoned parsing
+     * (because of an unrecoverable error) or reached the end of
+     * input.</p>
+     *
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #startDocument
+     */
+    public void endDocument()
+    throws SAXException;
+
+
+    /**
+     * Begin the scope of a prefix-URI Namespace mapping.
+     *
+     * <p>The information from this event is not necessary for
+     * normal Namespace processing: the SAX XML reader will 
+     * automatically replace prefixes for element and attribute
+     * names when the <code>http://xml.org/sax/features/namespaces</code>
+     * feature is <var>true</var> (the default).</p>
+     *
+     * <p>There are cases, however, when applications need to
+     * use prefixes in character data or in attribute values,
+     * where they cannot safely be expanded automatically; the
+     * start/endPrefixMapping event supplies the information
+     * to the application to expand prefixes in those contexts
+     * itself, if necessary.</p>
+     *
+     * <p>Note that start/endPrefixMapping events are not
+     * guaranteed to be properly nested relative to each other:
+     * all startPrefixMapping events will occur immediately before the
+     * corresponding {@link #startElement startElement} event, 
+     * and all {@link #endPrefixMapping endPrefixMapping}
+     * events will occur immediately after the corresponding
+     * {@link #endElement endElement} event,
+     * but their order is not otherwise 
+     * guaranteed.</p>
+     *
+     * <p>There should never be start/endPrefixMapping events for the
+     * "xml" prefix, since it is predeclared and immutable.</p>
+     *
+     * @param prefix the Namespace prefix being declared.
+     *    An empty string is used for the default element namespace,
+     *    which has no prefix.
+     * @param uri the Namespace URI the prefix is mapped to
+     * @throws org.xml.sax.SAXException the client may throw
+     *            an exception during processing
+     * @see #endPrefixMapping
+     * @see #startElement
+     */
+    public void startPrefixMapping (String prefix, String uri)
+    throws SAXException;
+
+
+    /**
+     * End the scope of a prefix-URI mapping.
+     *
+     * <p>See {@link #startPrefixMapping startPrefixMapping} for 
+     * details.  These events will always occur immediately after the
+     * corresponding {@link #endElement endElement} event, but the order of 
+     * {@link #endPrefixMapping endPrefixMapping} events is not otherwise
+     * guaranteed.</p>
+     *
+     * @param prefix the prefix that was being mapped.
+     *    This is the empty string when a default mapping scope ends.
+     * @throws org.xml.sax.SAXException the client may throw
+     *            an exception during processing
+     * @see #startPrefixMapping
+     * @see #endElement
+     */
+    public void endPrefixMapping (String prefix)
+    throws SAXException;
+
+
+    /**
+     * Receive notification of the beginning of an element.
+     *
+     * <p>The Parser will invoke this method at the beginning of every
+     * element in the XML document; there will be a corresponding
+     * {@link #endElement endElement} event for every startElement event
+     * (even when the element is empty). All of the element's content will be
+     * reported, in order, before the corresponding endElement
+     * event.</p>
+     *
+     * <p>This event allows up to three name components for each
+     * element:</p>
+     *
+     * <ol>
+     * <li>the Namespace URI;</li>
+     * <li>the local name; and</li>
+     * <li>the qualified (prefixed) name.</li>
+     * </ol>
+     *
+     * <p>Any or all of these may be provided, depending on the
+     * values of the <var>http://xml.org/sax/features/namespaces</var>
+     * and the <var>http://xml.org/sax/features/namespace-prefixes</var>
+     * properties:</p>
+     *
+     * <ul>
+     * <li>the Namespace URI and local name are required when 
+     * the namespaces property is <var>true</var> (the default), and are
+     * optional when the namespaces property is <var>false</var> (if one is
+     * specified, both must be);</li>
+     * <li>the qualified name is required when the namespace-prefixes property
+     * is <var>true</var>, and is optional when the namespace-prefixes property
+     * is <var>false</var> (the default).</li>
+     * </ul>
+     *
+     * <p>Note that the attribute list provided will contain only
+     * attributes with explicit values (specified or defaulted):
+     * #IMPLIED attributes will be omitted.  The attribute list
+     * will contain attributes used for Namespace declarations
+     * (xmlns* attributes) only if the
+     * <code>http://xml.org/sax/features/namespace-prefixes</code>
+     * property is true (it is false by default, and support for a 
+     * true value is optional).</p>
+     *
+     * <p>Like {@link #characters characters()}, attribute values may have
+     * characters that need more than one <code>char</code> value.  </p>
+     *
+     * @param uri the Namespace URI, or the empty string if the
+     *        element has no Namespace URI or if Namespace
+     *        processing is not being performed
+     * @param localName the local name (without prefix), or the
+     *        empty string if Namespace processing is not being
+     *        performed
+     * @param qName the qualified name (with prefix), or the
+     *        empty string if qualified names are not available
+     * @param atts the attributes attached to the element.  If
+     *        there are no attributes, it shall be an empty
+     *        Attributes object.  The value of this object after
+     *        startElement returns is undefined
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #endElement
+     * @see org.xml.sax.Attributes
+     * @see org.xml.sax.helpers.AttributesImpl
+     */
+    public void startElement (String uri, String localName,
+                  String qName, Attributes atts)
+    throws SAXException;
+
+
+    /**
+     * Receive notification of the end of an element.
+     *
+     * <p>The SAX parser will invoke this method at the end of every
+     * element in the XML document; there will be a corresponding
+     * {@link #startElement startElement} event for every endElement 
+     * event (even when the element is empty).</p>
+     *
+     * <p>For information on the names, see startElement.</p>
+     *
+     * @param uri the Namespace URI, or the empty string if the
+     *        element has no Namespace URI or if Namespace
+     *        processing is not being performed
+     * @param localName the local name (without prefix), or the
+     *        empty string if Namespace processing is not being
+     *        performed
+     * @param qName the qualified XML name (with prefix), or the
+     *        empty string if qualified names are not available
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     */
+    public void endElement (String uri, String localName,
+                String qName)
+    throws SAXException;
+
+
+    /**
+     * Receive notification of character data.
+     *
+     * <p>The Parser will call this method to report each chunk of
+     * character data.  SAX parsers may return all contiguous character
+     * data in a single chunk, or they may split it into several
+     * chunks; however, all of the characters in any single event
+     * must come from the same external entity so that the Locator
+     * provides useful information.</p>
+     *
+     * <p>The application must not attempt to read from the array
+     * outside of the specified range.</p>
+     *
+     * <p>Individual characters may consist of more than one Java
+     * <code>char</code> value.  There are two important cases where this
+     * happens, because characters can't be represented in just sixteen bits.
+     * In one case, characters are represented in a <em>Surrogate Pair</em>,
+     * using two special Unicode values. Such characters are in the so-called
+     * "Astral Planes", with a code point above U+FFFF.  A second case involves
+     * composite characters, such as a base character combining with one or
+     * more accent characters. </p>
+     *
+     * <p> Your code should not assume that algorithms using
+     * <code>char</code>-at-a-time idioms will be working in character
+     * units; in some cases they will split characters.  This is relevant
+     * wherever XML permits arbitrary characters, such as attribute values,
+     * processing instruction data, and comments as well as in data reported
+     * from this method.  It's also generally relevant whenever Java code
+     * manipulates internationalized text; the issue isn't unique to XML.</p>
+     *
+     * <p>Note that some parsers will report whitespace in element
+     * content using the {@link #ignorableWhitespace ignorableWhitespace}
+     * method rather than this one (validating parsers <em>must</em> 
+     * do so).</p>
+     *
+     * @param ch the characters from the XML document
+     * @param start the start position in the array
+     * @param length the number of characters to read from the array
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #ignorableWhitespace 
+     * @see org.xml.sax.Locator
+     */
+    public void characters (char ch[], int start, int length)
+    throws SAXException;
+
+
+    /**
+     * Receive notification of ignorable whitespace in element content.
+     *
+     * <p>Validating Parsers must use this method to report each chunk
+     * of whitespace in element content (see the W3C XML 1.0
+     * recommendation, section 2.10): non-validating parsers may also
+     * use this method if they are capable of parsing and using
+     * content models.</p>
+     *
+     * <p>SAX parsers may return all contiguous whitespace in a single
+     * chunk, or they may split it into several chunks; however, all of
+     * the characters in any single event must come from the same
+     * external entity, so that the Locator provides useful
+     * information.</p>
+     *
+     * <p>The application must not attempt to read from the array
+     * outside of the specified range.</p>
+     *
+     * @param ch the characters from the XML document
+     * @param start the start position in the array
+     * @param length the number of characters to read from the array
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     * @see #characters
+     */
+    public void ignorableWhitespace (char ch[], int start, int length)
+    throws SAXException;
+
+
+    /**
+     * Receive notification of a processing instruction.
+     *
+     * <p>The Parser will invoke this method once for each processing
+     * instruction found: note that processing instructions may occur
+     * before or after the main document element.</p>
+     *
+     * <p>A SAX parser must never report an XML declaration (XML 1.0,
+     * section 2.8) or a text declaration (XML 1.0, section 4.3.1)
+     * using this method.</p>
+     *
+     * <p>Like {@link #characters characters()}, processing instruction
+     * data may have characters that need more than one <code>char</code>
+     * value. </p>
+     *
+     * @param target the processing instruction target
+     * @param data the processing instruction data, or null if
+     *        none was supplied.  The data does not include any
+     *        whitespace separating it from the target
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     */
+    public void processingInstruction (String target, String data)
+    throws SAXException;
+
+
+    /**
+     * Receive notification of a skipped entity.
+     * This is not called for entity references within markup constructs
+     * such as element start tags or markup declarations.  (The XML
+     * recommendation requires reporting skipped external entities.
+     * SAX also reports internal entity expansion/non-expansion, except
+     * within markup constructs.)
+     *
+     * <p>The Parser will invoke this method each time the entity is
+     * skipped.  Non-validating processors may skip entities if they
+     * have not seen the declarations (because, for example, the
+     * entity was declared in an external DTD subset).  All processors
+     * may skip external entities, depending on the values of the
+     * <code>http://xml.org/sax/features/external-general-entities</code>
+     * and the
+     * <code>http://xml.org/sax/features/external-parameter-entities</code>
+     * properties.</p>
+     *
+     * @param name the name of the skipped entity.  If it is a 
+     *        parameter entity, the name will begin with '%', and if
+     *        it is the external DTD subset, it will be the string
+     *        "[dtd]"
+     * @throws org.xml.sax.SAXException any SAX exception, possibly
+     *            wrapping another exception
+     */
+    public void skippedEntity (String name)
+    throws SAXException;
+}
+
+// end of ContentHandler.java
diff --git a/xml/src/main/java/org/xml/sax/DTDHandler.java b/xml/src/main/java/org/xml/sax/DTDHandler.java
new file mode 100644
index 0000000..13d5eee
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/DTDHandler.java
@@ -0,0 +1,117 @@
+// SAX DTD handler.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: DTDHandler.java,v 1.8 2002/01/30 21:13:43 dbrownell Exp $
+
+package org.xml.sax;
+
+/**
+ * Receive notification of basic DTD-related events.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>If a SAX application needs information about notations and
+ * unparsed entities, then the application implements this 
+ * interface and registers an instance with the SAX parser using 
+ * the parser's setDTDHandler method.  The parser uses the 
+ * instance to report notation and unparsed entity declarations to 
+ * the application.</p>
+ *
+ * <p>Note that this interface includes only those DTD events that
+ * the XML recommendation <em>requires</em> processors to report:
+ * notation and unparsed entity declarations.</p>
+ *
+ * <p>The SAX parser may report these events in any order, regardless
+ * of the order in which the notations and unparsed entities were
+ * declared; however, all DTD events must be reported after the
+ * document handler's startDocument event, and before the first
+ * startElement event.
+ * (If the {@link org.xml.sax.ext.LexicalHandler LexicalHandler} is
+ * used, these events must also be reported before the endDTD event.)
+ * </p>
+ *
+ * <p>It is up to the application to store the information for 
+ * future use (perhaps in a hash table or object tree).
+ * If the application encounters attributes of type "NOTATION",
+ * "ENTITY", or "ENTITIES", it can use the information that it
+ * obtained through this interface to find the entity and/or
+ * notation corresponding with the attribute value.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.XMLReader#setDTDHandler
+ */
+public interface DTDHandler {
+    
+    
+    /**
+     * Receive notification of a notation declaration event.
+     *
+     * <p>It is up to the application to record the notation for later
+     * reference, if necessary;
+     * notations may appear as attribute values and in unparsed entity
+     * declarations, and are sometime used with processing instruction
+     * target names.</p>
+     *
+     * <p>At least one of publicId and systemId must be non-null.
+     * If a system identifier is present, and it is a URL, the SAX
+     * parser must resolve it fully before passing it to the
+     * application through this event.</p>
+     *
+     * <p>There is no guarantee that the notation declaration will be
+     * reported before any unparsed entities that use it.</p>
+     *
+     * @param name The notation name.
+     * @param publicId The notation's public identifier, or null if
+     *        none was given.
+     * @param systemId The notation's system identifier, or null if
+     *        none was given.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see #unparsedEntityDecl
+     * @see org.xml.sax.Attributes
+     */
+    public abstract void notationDecl (String name,
+                       String publicId,
+                       String systemId)
+    throws SAXException;
+    
+    
+    /**
+     * Receive notification of an unparsed entity declaration event.
+     *
+     * <p>Note that the notation name corresponds to a notation
+     * reported by the {@link #notationDecl notationDecl} event.  
+     * It is up to the application to record the entity for later 
+     * reference, if necessary;
+     * unparsed entities may appear as attribute values. 
+     * </p>
+     *
+     * <p>If the system identifier is a URL, the parser must resolve it
+     * fully before passing it to the application.</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @param name The unparsed entity's name.
+     * @param publicId The entity's public identifier, or null if none
+     *        was given.
+     * @param systemId The entity's system identifier.
+     * @param notationName The name of the associated notation.
+     * @see #notationDecl
+     * @see org.xml.sax.Attributes
+     */
+    public abstract void unparsedEntityDecl (String name,
+                         String publicId,
+                         String systemId,
+                         String notationName)
+    throws SAXException;
+    
+}
+
+// end of DTDHandler.java
diff --git a/xml/src/main/java/org/xml/sax/DocumentHandler.java b/xml/src/main/java/org/xml/sax/DocumentHandler.java
new file mode 100644
index 0000000..500fe4c
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/DocumentHandler.java
@@ -0,0 +1,232 @@
+// SAX document handler.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: DocumentHandler.java,v 1.6 2002/01/30 21:13:43 dbrownell Exp $
+
+package org.xml.sax;
+
+/**
+ * Receive notification of general document events.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This was the main event-handling interface for SAX1; in
+ * SAX2, it has been replaced by {@link org.xml.sax.ContentHandler
+ * ContentHandler}, which provides Namespace support and reporting
+ * of skipped entities.  This interface is included in SAX2 only
+ * to support legacy SAX1 applications.</p>
+ *
+ * <p>The order of events in this interface is very important, and
+ * mirrors the order of information in the document itself.  For
+ * example, all of an element's content (character data, processing
+ * instructions, and/or subelements) will appear, in order, between
+ * the startElement event and the corresponding endElement event.</p>
+ *
+ * <p>Application writers who do not want to implement the entire
+ * interface can derive a class from HandlerBase, which implements
+ * the default functionality; parser writers can instantiate
+ * HandlerBase to obtain a default handler.  The application can find
+ * the location of any document event using the Locator interface
+ * supplied by the Parser through the setDocumentLocator method.</p>
+ *
+ * @deprecated This interface has been replaced by the SAX2
+ *             {@link org.xml.sax.ContentHandler ContentHandler}
+ *             interface, which includes Namespace support.
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.Parser#setDocumentHandler
+ * @see org.xml.sax.Locator
+ * @see org.xml.sax.HandlerBase
+ */
+public interface DocumentHandler {
+    
+    
+    /**
+     * Receive an object for locating the origin of SAX document events.
+     *
+     * <p>SAX parsers are strongly encouraged (though not absolutely
+     * required) to supply a locator: if it does so, it must supply
+     * the locator to the application by invoking this method before
+     * invoking any of the other methods in the DocumentHandler
+     * interface.</p>
+     *
+     * <p>The locator allows the application to determine the end
+     * position of any document-related event, even if the parser is
+     * not reporting an error.  Typically, the application will
+     * use this information for reporting its own errors (such as
+     * character content that does not match an application's
+     * business rules).  The information returned by the locator
+     * is probably not sufficient for use with a search engine.</p>
+     *
+     * <p>Note that the locator will return correct information only
+     * during the invocation of the events in this interface.  The
+     * application should not attempt to use it at any other time.</p>
+     *
+     * @param locator An object that can return the location of
+     *                any SAX document event.
+     * @see org.xml.sax.Locator
+     */
+    public abstract void setDocumentLocator (Locator locator);
+    
+    
+    /**
+     * Receive notification of the beginning of a document.
+     *
+     * <p>The SAX parser will invoke this method only once, before any
+     * other methods in this interface or in DTDHandler (except for
+     * setDocumentLocator).</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     */
+    public abstract void startDocument ()
+    throws SAXException;
+    
+    
+    /**
+     * Receive notification of the end of a document.
+     *
+     * <p>The SAX parser will invoke this method only once, and it will
+     * be the last method invoked during the parse.  The parser shall
+     * not invoke this method until it has either abandoned parsing
+     * (because of an unrecoverable error) or reached the end of
+     * input.</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     */
+    public abstract void endDocument ()
+    throws SAXException;
+    
+    
+    /**
+     * Receive notification of the beginning of an element.
+     *
+     * <p>The Parser will invoke this method at the beginning of every
+     * element in the XML document; there will be a corresponding
+     * endElement() event for every startElement() event (even when the
+     * element is empty). All of the element's content will be
+     * reported, in order, before the corresponding endElement()
+     * event.</p>
+     *
+     * <p>If the element name has a namespace prefix, the prefix will
+     * still be attached.  Note that the attribute list provided will
+     * contain only attributes with explicit values (specified or
+     * defaulted): #IMPLIED attributes will be omitted.</p>
+     *
+     * @param name The element type name.
+     * @param atts The attributes attached to the element, if any.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see #endElement
+     * @see org.xml.sax.AttributeList 
+     */
+    public abstract void startElement (String name, AttributeList atts)
+    throws SAXException;
+    
+    
+    /**
+     * Receive notification of the end of an element.
+     *
+     * <p>The SAX parser will invoke this method at the end of every
+     * element in the XML document; there will be a corresponding
+     * startElement() event for every endElement() event (even when the
+     * element is empty).</p>
+     *
+     * <p>If the element name has a namespace prefix, the prefix will
+     * still be attached to the name.</p>
+     *
+     * @param name The element type name
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     */
+    public abstract void endElement (String name)
+    throws SAXException;
+    
+    
+    /**
+     * Receive notification of character data.
+     *
+     * <p>The Parser will call this method to report each chunk of
+     * character data.  SAX parsers may return all contiguous character
+     * data in a single chunk, or they may split it into several
+     * chunks; however, all of the characters in any single event
+     * must come from the same external entity, so that the Locator
+     * provides useful information.</p>
+     *
+     * <p>The application must not attempt to read from the array
+     * outside of the specified range.</p>
+     *
+     * <p>Note that some parsers will report whitespace using the
+     * ignorableWhitespace() method rather than this one (validating
+     * parsers must do so).</p>
+     *
+     * @param ch The characters from the XML document.
+     * @param start The start position in the array.
+     * @param length The number of characters to read from the array.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see #ignorableWhitespace 
+     * @see org.xml.sax.Locator
+     */
+    public abstract void characters (char ch[], int start, int length)
+    throws SAXException;
+    
+    
+    /**
+     * Receive notification of ignorable whitespace in element content.
+     *
+     * <p>Validating Parsers must use this method to report each chunk
+     * of ignorable whitespace (see the W3C XML 1.0 recommendation,
+     * section 2.10): non-validating parsers may also use this method
+     * if they are capable of parsing and using content models.</p>
+     *
+     * <p>SAX parsers may return all contiguous whitespace in a single
+     * chunk, or they may split it into several chunks; however, all of
+     * the characters in any single event must come from the same
+     * external entity, so that the Locator provides useful
+     * information.</p>
+     *
+     * <p>The application must not attempt to read from the array
+     * outside of the specified range.</p>
+     *
+     * @param ch The characters from the XML document.
+     * @param start The start position in the array.
+     * @param length The number of characters to read from the array.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see #characters
+     */
+    public abstract void ignorableWhitespace (char ch[], int start, int length)
+    throws SAXException;
+    
+    
+    /**
+     * Receive notification of a processing instruction.
+     *
+     * <p>The Parser will invoke this method once for each processing
+     * instruction found: note that processing instructions may occur
+     * before or after the main document element.</p>
+     *
+     * <p>A SAX parser should never report an XML declaration (XML 1.0,
+     * section 2.8) or a text declaration (XML 1.0, section 4.3.1)
+     * using this method.</p>
+     *
+     * @param target The processing instruction target.
+     * @param data The processing instruction data, or null if
+     *        none was supplied.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     */
+    public abstract void processingInstruction (String target, String data)
+    throws SAXException;
+    
+}
+
+// end of DocumentHandler.java
diff --git a/xml/src/main/java/org/xml/sax/EntityResolver.java b/xml/src/main/java/org/xml/sax/EntityResolver.java
new file mode 100644
index 0000000..06ac725
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/EntityResolver.java
@@ -0,0 +1,119 @@
+// SAX entity resolver.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: EntityResolver.java,v 1.10 2002/01/30 21:13:44 dbrownell Exp $
+
+package org.xml.sax;
+
+import java.io.IOException;
+
+
+/**
+ * Basic interface for resolving entities.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>If a SAX application needs to implement customized handling
+ * for external entities, it must implement this interface and
+ * register an instance with the SAX driver using the
+ * {@link org.xml.sax.XMLReader#setEntityResolver setEntityResolver}
+ * method.</p>
+ *
+ * <p>The XML reader will then allow the application to intercept any
+ * external entities (including the external DTD subset and external
+ * parameter entities, if any) before including them.</p>
+ *
+ * <p>Many SAX applications will not need to implement this interface,
+ * but it will be especially useful for applications that build
+ * XML documents from databases or other specialised input sources,
+ * or for applications that use URI types other than URLs.</p>
+ *
+ * <p>The following resolver would provide the application
+ * with a special character stream for the entity with the system
+ * identifier "http://www.myhost.com/today":</p>
+ *
+ * <pre>
+ * import org.xml.sax.EntityResolver;
+ * import org.xml.sax.InputSource;
+ *
+ * public class MyResolver implements EntityResolver {
+ *   public InputSource resolveEntity (String publicId, String systemId)
+ *   {
+ *     if (systemId.equals("http://www.myhost.com/today")) {
+ *              // return a special input source
+ *       MyReader reader = new MyReader();
+ *       return new InputSource(reader);
+ *     } else {
+ *              // use the default behaviour
+ *       return null;
+ *     }
+ *   }
+ * }
+ * </pre>
+ *
+ * <p>The application can also use this interface to redirect system
+ * identifiers to local URIs or to look up replacements in a catalog
+ * (possibly by using the public identifier).</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.XMLReader#setEntityResolver
+ * @see org.xml.sax.InputSource
+ */
+public interface EntityResolver {
+    
+    
+    /**
+     * Allow the application to resolve external entities.
+     *
+     * <p>The parser will call this method before opening any external
+     * entity except the top-level document entity.  Such entities include
+     * the external DTD subset and external parameter entities referenced
+     * within the DTD (in either case, only if the parser reads external
+     * parameter entities), and external general entities referenced
+     * within the document element (if the parser reads external general
+     * entities).  The application may request that the parser locate
+     * the entity itself, that it use an alternative URI, or that it
+     * use data provided by the application (as a character or byte
+     * input stream).</p>
+     *
+     * <p>Application writers can use this method to redirect external
+     * system identifiers to secure and/or local URIs, to look up
+     * public identifiers in a catalogue, or to read an entity from a
+     * database or other input source (including, for example, a dialog
+     * box).  Neither XML nor SAX specifies a preferred policy for using
+     * public or system IDs to resolve resources.  However, SAX specifies
+     * how to interpret any InputSource returned by this method, and that
+     * if none is returned, then the system ID will be dereferenced as
+     * a URL.  </p>
+     *
+     * <p>If the system identifier is a URL, the SAX parser must
+     * resolve it fully before reporting it to the application.</p>
+     *
+     * @param publicId The public identifier of the external entity
+     *        being referenced, or null if none was supplied.
+     * @param systemId The system identifier of the external entity
+     *        being referenced.
+     * @return An InputSource object describing the new input source,
+     *         or null to request that the parser open a regular
+     *         URI connection to the system identifier.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException A Java-specific IO exception,
+     *            possibly the result of creating a new InputStream
+     *            or Reader for the InputSource.
+     * @see org.xml.sax.InputSource
+     */
+    public abstract InputSource resolveEntity (String publicId,
+                           String systemId)
+    throws SAXException, IOException;
+    
+}
+
+// end of EntityResolver.java
diff --git a/xml/src/main/java/org/xml/sax/ErrorHandler.java b/xml/src/main/java/org/xml/sax/ErrorHandler.java
new file mode 100644
index 0000000..e4e4206
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ErrorHandler.java
@@ -0,0 +1,139 @@
+// SAX error handler.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: ErrorHandler.java,v 1.10 2004/03/08 13:01:00 dmegginson Exp $
+
+package org.xml.sax;
+
+
+/**
+ * Basic interface for SAX error handlers.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>If a SAX application needs to implement customized error
+ * handling, it must implement this interface and then register an
+ * instance with the XML reader using the
+ * {@link org.xml.sax.XMLReader#setErrorHandler setErrorHandler}
+ * method.  The parser will then report all errors and warnings
+ * through this interface.</p>
+ *
+ * <p><strong>WARNING:</strong> If an application does <em>not</em>
+ * register an ErrorHandler, XML parsing errors will go unreported,
+ * except that <em>SAXParseException</em>s will be thrown for fatal errors.
+ * In order to detect validity errors, an ErrorHandler that does something
+ * with {@link #error error()} calls must be registered.</p>
+ *
+ * <p>For XML processing errors, a SAX driver must use this interface 
+ * in preference to throwing an exception: it is up to the application 
+ * to decide whether to throw an exception for different types of 
+ * errors and warnings.  Note, however, that there is no requirement that 
+ * the parser continue to report additional errors after a call to 
+ * {@link #fatalError fatalError}.  In other words, a SAX driver class 
+ * may throw an exception after reporting any fatalError.
+ * Also parsers may throw appropriate exceptions for non-XML errors.
+ * For example, {@link XMLReader#parse XMLReader.parse()} would throw
+ * an IOException for errors accessing entities or the document.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1+ (sax2r3pre1)
+ * @see org.xml.sax.XMLReader#setErrorHandler
+ * @see org.xml.sax.SAXParseException 
+ */
+public interface ErrorHandler {
+    
+    
+    /**
+     * Receive notification of a warning.
+     *
+     * <p>SAX parsers will use this method to report conditions that
+     * are not errors or fatal errors as defined by the XML
+     * recommendation.  The default behaviour is to take no
+     * action.</p>
+     *
+     * <p>The SAX parser must continue to provide normal parsing events
+     * after invoking this method: it should still be possible for the
+     * application to process the document through to the end.</p>
+     *
+     * <p>Filters may use this method to report other, non-XML warnings
+     * as well.</p>
+     *
+     * @param exception The warning information encapsulated in a
+     *                  SAX parse exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.SAXParseException 
+     */
+    public abstract void warning (SAXParseException exception)
+    throws SAXException;
+    
+    
+    /**
+     * Receive notification of a recoverable error.
+     *
+     * <p>This corresponds to the definition of "error" in section 1.2
+     * of the W3C XML 1.0 Recommendation.  For example, a validating
+     * parser would use this callback to report the violation of a
+     * validity constraint.  The default behaviour is to take no
+     * action.</p>
+     *
+     * <p>The SAX parser must continue to provide normal parsing
+     * events after invoking this method: it should still be possible
+     * for the application to process the document through to the end.
+     * If the application cannot do so, then the parser should report
+     * a fatal error even if the XML recommendation does not require
+     * it to do so.</p>
+     *
+     * <p>Filters may use this method to report other, non-XML errors
+     * as well.</p>
+     *
+     * @param exception The error information encapsulated in a
+     *                  SAX parse exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.SAXParseException 
+     */
+    public abstract void error (SAXParseException exception)
+    throws SAXException;
+    
+    
+    /**
+     * Receive notification of a non-recoverable error.
+     *
+     * <p><strong>There is an apparent contradiction between the
+     * documentation for this method and the documentation for {@link
+     * org.xml.sax.ContentHandler#endDocument}.  Until this ambiguity
+     * is resolved in a future major release, clients should make no
+     * assumptions about whether endDocument() will or will not be
+     * invoked when the parser has reported a fatalError() or thrown
+     * an exception.</strong></p>
+     *
+     * <p>This corresponds to the definition of "fatal error" in
+     * section 1.2 of the W3C XML 1.0 Recommendation.  For example, a
+     * parser would use this callback to report the violation of a
+     * well-formedness constraint.</p>
+     *
+     * <p>The application must assume that the document is unusable
+     * after the parser has invoked this method, and should continue
+     * (if at all) only for the sake of collecting additional error
+     * messages: in fact, SAX parsers are free to stop reporting any
+     * other events once this method has been invoked.</p>
+     *
+     * @param exception The error information encapsulated in a
+     *                  SAX parse exception.  
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.SAXParseException
+     */
+    public abstract void fatalError (SAXParseException exception)
+    throws SAXException;
+    
+}
+
+// end of ErrorHandler.java
diff --git a/xml/src/main/java/org/xml/sax/HandlerBase.java b/xml/src/main/java/org/xml/sax/HandlerBase.java
new file mode 100644
index 0000000..15ea2d4
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/HandlerBase.java
@@ -0,0 +1,369 @@
+// SAX default handler base class.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: HandlerBase.java,v 1.7 2004/04/26 17:34:34 dmegginson Exp $
+
+package org.xml.sax;
+
+/**
+ * Default base class for handlers.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class implements the default behaviour for four SAX1
+ * interfaces: EntityResolver, DTDHandler, DocumentHandler,
+ * and ErrorHandler.  It is now obsolete, but is included in SAX2 to
+ * support legacy SAX1 applications.  SAX2 applications should use
+ * the {@link org.xml.sax.helpers.DefaultHandler DefaultHandler}
+ * class instead.</p>
+ *
+ * <p>Application writers can extend this class when they need to
+ * implement only part of an interface; parser writers can
+ * instantiate this class to provide default handlers when the
+ * application has not supplied its own.</p>
+ *
+ * <p>Note that the use of this class is optional.</p>
+ *
+ * @deprecated This class works with the deprecated
+ *             {@link org.xml.sax.DocumentHandler DocumentHandler}
+ *             interface.  It has been replaced by the SAX2
+ *             {@link org.xml.sax.helpers.DefaultHandler DefaultHandler}
+ *             class.
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.EntityResolver
+ * @see org.xml.sax.DTDHandler
+ * @see org.xml.sax.DocumentHandler
+ * @see org.xml.sax.ErrorHandler
+ */
+public class HandlerBase
+    implements EntityResolver, DTDHandler, DocumentHandler, ErrorHandler
+{
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of the EntityResolver interface.
+    ////////////////////////////////////////////////////////////////////
+    
+    /**
+     * Resolve an external entity.
+     *
+     * <p>Always return null, so that the parser will use the system
+     * identifier provided in the XML document.  This method implements
+     * the SAX default behaviour: application writers can override it
+     * in a subclass to do special translations such as catalog lookups
+     * or URI redirection.</p>
+     *
+     * @param publicId The public identifer, or null if none is
+     *                 available.
+     * @param systemId The system identifier provided in the XML 
+     *                 document.
+     * @return The new input source, or null to require the
+     *         default behaviour.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.EntityResolver#resolveEntity
+     */
+    public InputSource resolveEntity (String publicId, String systemId)
+    throws SAXException
+    {
+    return null;
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of DTDHandler interface.
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Receive notification of a notation declaration.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass if they wish to keep track of the notations
+     * declared in a document.</p>
+     *
+     * @param name The notation name.
+     * @param publicId The notation public identifier, or null if not
+     *                 available.
+     * @param systemId The notation system identifier.
+     * @see org.xml.sax.DTDHandler#notationDecl
+     */
+    public void notationDecl (String name, String publicId, String systemId)
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of an unparsed entity declaration.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to keep track of the unparsed entities
+     * declared in a document.</p>
+     *
+     * @param name The entity name.
+     * @param publicId The entity public identifier, or null if not
+     *                 available.
+     * @param systemId The entity system identifier.
+     * @param notationName The name of the associated notation.
+     * @see org.xml.sax.DTDHandler#unparsedEntityDecl
+     */
+    public void unparsedEntityDecl (String name, String publicId,
+                    String systemId, String notationName)
+    {
+    // no op
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of DocumentHandler interface.
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Receive a Locator object for document events.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass if they wish to store the locator for use
+     * with other document events.</p>
+     *
+     * @param locator A locator for all SAX document events.
+     * @see org.xml.sax.DocumentHandler#setDocumentLocator
+     * @see org.xml.sax.Locator
+     */
+    public void setDocumentLocator (Locator locator)
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of the beginning of the document.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the beginning
+     * of a document (such as allocating the root node of a tree or
+     * creating an output file).</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DocumentHandler#startDocument
+     */
+    public void startDocument ()
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of the end of the document.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the beginning
+     * of a document (such as finalising a tree or closing an output
+     * file).</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DocumentHandler#endDocument
+     */
+    public void endDocument ()
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of the start of an element.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the start of
+     * each element (such as allocating a new tree node or writing
+     * output to a file).</p>
+     *
+     * @param name The element type name.
+     * @param attributes The specified or defaulted attributes.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DocumentHandler#startElement
+     */
+    public void startElement (String name, AttributeList attributes)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of the end of an element.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the end of
+     * each element (such as finalising a tree node or writing
+     * output to a file).</p>
+     *
+     * @param name the element name
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DocumentHandler#endElement
+     */
+    public void endElement (String name)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of character data inside an element.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method to take specific actions for each chunk of character data
+     * (such as adding the data to a node or buffer, or printing it to
+     * a file).</p>
+     *
+     * @param ch The characters.
+     * @param start The start position in the character array.
+     * @param length The number of characters to use from the
+     *               character array.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DocumentHandler#characters
+     */
+    public void characters (char ch[], int start, int length)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of ignorable whitespace in element content.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method to take specific actions for each chunk of ignorable
+     * whitespace (such as adding data to a node or buffer, or printing
+     * it to a file).</p>
+     *
+     * @param ch The whitespace characters.
+     * @param start The start position in the character array.
+     * @param length The number of characters to use from the
+     *               character array.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DocumentHandler#ignorableWhitespace
+     */
+    public void ignorableWhitespace (char ch[], int start, int length)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of a processing instruction.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions for each
+     * processing instruction, such as setting status variables or
+     * invoking other methods.</p>
+     *
+     * @param target The processing instruction target.
+     * @param data The processing instruction data, or null if
+     *             none is supplied.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DocumentHandler#processingInstruction
+     */
+    public void processingInstruction (String target, String data)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of the ErrorHandler interface.
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Receive notification of a parser warning.
+     *
+     * <p>The default implementation does nothing.  Application writers
+     * may override this method in a subclass to take specific actions
+     * for each warning, such as inserting the message in a log file or
+     * printing it to the console.</p>
+     *
+     * @param e The warning information encoded as an exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ErrorHandler#warning
+     * @see org.xml.sax.SAXParseException
+     */
+    public void warning (SAXParseException e)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of a recoverable parser error.
+     *
+     * <p>The default implementation does nothing.  Application writers
+     * may override this method in a subclass to take specific actions
+     * for each error, such as inserting the message in a log file or
+     * printing it to the console.</p>
+     *
+     * @param e The warning information encoded as an exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ErrorHandler#warning
+     * @see org.xml.sax.SAXParseException
+     */
+    public void error (SAXParseException e)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Report a fatal XML parsing error.
+     *
+     * <p>The default implementation throws a SAXParseException.
+     * Application writers may override this method in a subclass if
+     * they need to take specific actions for each fatal error (such as
+     * collecting all of the errors into a single report): in any case,
+     * the application must stop all regular processing when this
+     * method is invoked, since the document is no longer reliable, and
+     * the parser may no longer report parsing events.</p>
+     *
+     * @param e The error information encoded as an exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ErrorHandler#fatalError
+     * @see org.xml.sax.SAXParseException
+     */
+    public void fatalError (SAXParseException e)
+    throws SAXException
+    {
+    throw e;
+    }
+    
+}
+
+// end of HandlerBase.java
diff --git a/xml/src/main/java/org/xml/sax/InputSource.java b/xml/src/main/java/org/xml/sax/InputSource.java
new file mode 100644
index 0000000..b1342ee
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/InputSource.java
@@ -0,0 +1,337 @@
+// SAX input source.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: InputSource.java,v 1.9 2002/01/30 21:13:45 dbrownell Exp $
+
+package org.xml.sax;
+
+import java.io.Reader;
+import java.io.InputStream;
+
+/**
+ * A single input source for an XML entity.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class allows a SAX application to encapsulate information
+ * about an input source in a single object, which may include
+ * a public identifier, a system identifier, a byte stream (possibly
+ * with a specified encoding), and/or a character stream.</p>
+ *
+ * <p>There are two places that the application can deliver an
+ * input source to the parser: as the argument to the Parser.parse
+ * method, or as the return value of the EntityResolver.resolveEntity
+ * method.</p>
+ *
+ * <p>The SAX parser will use the InputSource object to determine how
+ * to read XML input.  If there is a character stream available, the
+ * parser will read that stream directly, disregarding any text
+ * encoding declaration found in that stream.
+ * If there is no character stream, but there is
+ * a byte stream, the parser will use that byte stream, using the
+ * encoding specified in the InputSource or else (if no encoding is
+ * specified) autodetecting the character encoding using an algorithm
+ * such as the one in the XML specification.  If neither a character
+ * stream nor a
+ * byte stream is available, the parser will attempt to open a URI
+ * connection to the resource identified by the system
+ * identifier.</p>
+ *
+ * <p>An InputSource object belongs to the application: the SAX parser
+ * shall never modify it in any way (it may modify a copy if 
+ * necessary).  However, standard processing of both byte and
+ * character streams is to close them on as part of end-of-parse cleanup,
+ * so applications should not attempt to re-use such streams after they
+ * have been handed to a parser.  </p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource)
+ * @see org.xml.sax.EntityResolver#resolveEntity
+ * @see java.io.InputStream
+ * @see java.io.Reader
+ */
+public class InputSource {
+    
+    /**
+     * Zero-argument default constructor.
+     *
+     * @see #setPublicId
+     * @see #setSystemId
+     * @see #setByteStream
+     * @see #setCharacterStream
+     * @see #setEncoding
+     */
+    public InputSource ()
+    {
+    }
+    
+    
+    /**
+     * Create a new input source with a system identifier.
+     *
+     * <p>Applications may use setPublicId to include a 
+     * public identifier as well, or setEncoding to specify
+     * the character encoding, if known.</p>
+     *
+     * <p>If the system identifier is a URL, it must be fully
+     * resolved (it may not be a relative URL).</p>
+     *
+     * @param systemId The system identifier (URI).
+     * @see #setPublicId
+     * @see #setSystemId
+     * @see #setByteStream
+     * @see #setEncoding
+     * @see #setCharacterStream
+     */
+    public InputSource (String systemId)
+    {
+    setSystemId(systemId);
+    }
+    
+    
+    /**
+     * Create a new input source with a byte stream.
+     *
+     * <p>Application writers should use setSystemId() to provide a base 
+     * for resolving relative URIs, may use setPublicId to include a 
+     * public identifier, and may use setEncoding to specify the object's
+     * character encoding.</p>
+     *
+     * @param byteStream The raw byte stream containing the document.
+     * @see #setPublicId
+     * @see #setSystemId
+     * @see #setEncoding
+     * @see #setByteStream
+     * @see #setCharacterStream
+     */
+    public InputSource (InputStream byteStream)
+    {
+    setByteStream(byteStream);
+    }
+    
+    
+    /**
+     * Create a new input source with a character stream.
+     *
+     * <p>Application writers should use setSystemId() to provide a base 
+     * for resolving relative URIs, and may use setPublicId to include a 
+     * public identifier.</p>
+     *
+     * <p>The character stream shall not include a byte order mark.</p>
+     *
+     * @param characterStream The raw character stream containing the document.
+     * @see #setPublicId
+     * @see #setSystemId
+     * @see #setByteStream
+     * @see #setCharacterStream
+     */
+    public InputSource (Reader characterStream)
+    {
+    setCharacterStream(characterStream);
+    }
+    
+    
+    /**
+     * Set the public identifier for this input source.
+     *
+     * <p>The public identifier is always optional: if the application
+     * writer includes one, it will be provided as part of the
+     * location information.</p>
+     *
+     * @param publicId The public identifier as a string.
+     * @see #getPublicId
+     * @see org.xml.sax.Locator#getPublicId
+     * @see org.xml.sax.SAXParseException#getPublicId
+     */
+    public void setPublicId (String publicId)
+    {
+    this.publicId = publicId;
+    }
+    
+    
+    /**
+     * Get the public identifier for this input source.
+     *
+     * @return The public identifier, or null if none was supplied.
+     * @see #setPublicId
+     */
+    public String getPublicId ()
+    {
+    return publicId;
+    }
+    
+    
+    /**
+     * Set the system identifier for this input source.
+     *
+     * <p>The system identifier is optional if there is a byte stream
+     * or a character stream, but it is still useful to provide one,
+     * since the application can use it to resolve relative URIs
+     * and can include it in error messages and warnings (the parser
+     * will attempt to open a connection to the URI only if
+     * there is no byte stream or character stream specified).</p>
+     *
+     * <p>If the application knows the character encoding of the
+     * object pointed to by the system identifier, it can register
+     * the encoding using the setEncoding method.</p>
+     *
+     * <p>If the system identifier is a URL, it must be fully
+     * resolved (it may not be a relative URL).</p>
+     *
+     * @param systemId The system identifier as a string.
+     * @see #setEncoding
+     * @see #getSystemId
+     * @see org.xml.sax.Locator#getSystemId
+     * @see org.xml.sax.SAXParseException#getSystemId
+     */
+    public void setSystemId (String systemId)
+    {
+    this.systemId = systemId;
+    }
+    
+    
+    /**
+     * Get the system identifier for this input source.
+     *
+     * <p>The getEncoding method will return the character encoding
+     * of the object pointed to, or null if unknown.</p>
+     *
+     * <p>If the system ID is a URL, it will be fully resolved.</p>
+     *
+     * @return The system identifier, or null if none was supplied.
+     * @see #setSystemId
+     * @see #getEncoding
+     */
+    public String getSystemId ()
+    {
+    return systemId;
+    }
+    
+    
+    /**
+     * Set the byte stream for this input source.
+     *
+     * <p>The SAX parser will ignore this if there is also a character
+     * stream specified, but it will use a byte stream in preference
+     * to opening a URI connection itself.</p>
+     *
+     * <p>If the application knows the character encoding of the
+     * byte stream, it should set it with the setEncoding method.</p>
+     *
+     * @param byteStream A byte stream containing an XML document or
+     *        other entity.
+     * @see #setEncoding
+     * @see #getByteStream
+     * @see #getEncoding
+     * @see java.io.InputStream
+     */
+    public void setByteStream (InputStream byteStream)
+    {
+    this.byteStream = byteStream;
+    }
+    
+    
+    /**
+     * Get the byte stream for this input source.
+     *
+     * <p>The getEncoding method will return the character
+     * encoding for this byte stream, or null if unknown.</p>
+     *
+     * @return The byte stream, or null if none was supplied.
+     * @see #getEncoding
+     * @see #setByteStream
+     */
+    public InputStream getByteStream ()
+    {
+    return byteStream;
+    }
+    
+    
+    /** 
+     * Set the character encoding, if known.
+     *
+     * <p>The encoding must be a string acceptable for an
+     * XML encoding declaration (see section 4.3.3 of the XML 1.0
+     * recommendation).</p>
+     *
+     * <p>This method has no effect when the application provides a
+     * character stream.</p>
+     *
+     * @param encoding A string describing the character encoding.
+     * @see #setSystemId
+     * @see #setByteStream
+     * @see #getEncoding
+     */
+    public void setEncoding (String encoding)
+    {
+    this.encoding = encoding;
+    }
+    
+    
+    /**
+     * Get the character encoding for a byte stream or URI.
+     * This value will be ignored when the application provides a
+     * character stream.
+     *
+     * @return The encoding, or null if none was supplied.
+     * @see #setByteStream
+     * @see #getSystemId
+     * @see #getByteStream
+     */
+    public String getEncoding ()
+    {
+    return encoding;
+    }
+    
+    
+    /**
+     * Set the character stream for this input source.
+     *
+     * <p>If there is a character stream specified, the SAX parser
+     * will ignore any byte stream and will not attempt to open
+     * a URI connection to the system identifier.</p>
+     *
+     * @param characterStream The character stream containing the
+     *        XML document or other entity.
+     * @see #getCharacterStream
+     * @see java.io.Reader
+     */
+    public void setCharacterStream (Reader characterStream)
+    {
+    this.characterStream = characterStream;
+    }
+    
+    
+    /**
+     * Get the character stream for this input source.
+     *
+     * @return The character stream, or null if none was supplied.
+     * @see #setCharacterStream
+     */
+    public Reader getCharacterStream ()
+    {
+    return characterStream;
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////////
+    
+    private String publicId;
+    private String systemId;
+    private InputStream byteStream;
+    private String encoding;
+    private Reader characterStream;
+    
+}
+
+// end of InputSource.java
diff --git a/xml/src/main/java/org/xml/sax/Locator.java b/xml/src/main/java/org/xml/sax/Locator.java
new file mode 100644
index 0000000..f8f3484
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/Locator.java
@@ -0,0 +1,136 @@
+// SAX locator interface for document events.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: Locator.java,v 1.8 2002/01/30 21:13:47 dbrownell Exp $
+
+package org.xml.sax;
+
+
+/**
+ * Interface for associating a SAX event with a document location.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>If a SAX parser provides location information to the SAX
+ * application, it does so by implementing this interface and then
+ * passing an instance to the application using the content
+ * handler's {@link org.xml.sax.ContentHandler#setDocumentLocator
+ * setDocumentLocator} method.  The application can use the
+ * object to obtain the location of any other SAX event
+ * in the XML source document.</p>
+ *
+ * <p>Note that the results returned by the object will be valid only
+ * during the scope of each callback method: the application
+ * will receive unpredictable results if it attempts to use the
+ * locator at any other time, or after parsing completes.</p>
+ *
+ * <p>SAX parsers are not required to supply a locator, but they are
+ * very strongly encouraged to do so.  If the parser supplies a
+ * locator, it must do so before reporting any other document events.
+ * If no locator has been set by the time the application receives
+ * the {@link org.xml.sax.ContentHandler#startDocument startDocument}
+ * event, the application should assume that a locator is not 
+ * available.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.ContentHandler#setDocumentLocator 
+ */
+public interface Locator {
+    
+    
+    /**
+     * Return the public identifier for the current document event.
+     *
+     * <p>The return value is the public identifier of the document
+     * entity or of the external parsed entity in which the markup
+     * triggering the event appears.</p>
+     *
+     * @return A string containing the public identifier, or
+     *         null if none is available.
+     * @see #getSystemId
+     */
+    public abstract String getPublicId ();
+    
+    
+    /**
+     * Return the system identifier for the current document event.
+     *
+     * <p>The return value is the system identifier of the document
+     * entity or of the external parsed entity in which the markup
+     * triggering the event appears.</p>
+     *
+     * <p>If the system identifier is a URL, the parser must resolve it
+     * fully before passing it to the application.  For example, a file
+     * name must always be provided as a <em>file:...</em> URL, and other
+     * kinds of relative URI are also resolved against their bases.</p>
+     *
+     * @return A string containing the system identifier, or null
+     *         if none is available.
+     * @see #getPublicId
+     */
+    public abstract String getSystemId ();
+    
+    
+    /**
+     * Return the line number where the current document event ends.
+     * Lines are delimited by line ends, which are defined in
+     * the XML specification.
+     *
+     * <p><strong>Warning:</strong> The return value from the method
+     * is intended only as an approximation for the sake of diagnostics;
+     * it is not intended to provide sufficient information
+     * to edit the character content of the original XML document.
+     * In some cases, these "line" numbers match what would be displayed
+     * as columns, and in others they may not match the source text
+     * due to internal entity expansion.  </p>
+     *
+     * <p>The return value is an approximation of the line number
+     * in the document entity or external parsed entity where the
+     * markup triggering the event appears.</p>
+     *
+     * <p>If possible, the SAX driver should provide the line position 
+     * of the first character after the text associated with the document 
+     * event.  The first line is line 1.</p>
+     *
+     * @return The line number, or -1 if none is available.
+     * @see #getColumnNumber
+     */
+    public abstract int getLineNumber ();
+    
+    
+    /**
+     * Return the column number where the current document event ends.
+     * This is one-based number of Java <code>char</code> values since
+     * the last line end.
+     *
+     * <p><strong>Warning:</strong> The return value from the method
+     * is intended only as an approximation for the sake of diagnostics;
+     * it is not intended to provide sufficient information
+     * to edit the character content of the original XML document.
+     * For example, when lines contain combining character sequences, wide
+     * characters, surrogate pairs, or bi-directional text, the value may
+     * not correspond to the column in a text editor's display. </p>
+     *
+     * <p>The return value is an approximation of the column number
+     * in the document entity or external parsed entity where the
+     * markup triggering the event appears.</p>
+     *
+     * <p>If possible, the SAX driver should provide the line position 
+     * of the first character after the text associated with the document 
+     * event.  The first column in each line is column 1.</p>
+     *
+     * @return The column number, or -1 if none is available.
+     * @see #getLineNumber
+     */
+    public abstract int getColumnNumber ();
+    
+}
+
+// end of Locator.java
diff --git a/xml/src/main/java/org/xml/sax/Parser.java b/xml/src/main/java/org/xml/sax/Parser.java
new file mode 100644
index 0000000..67a5512
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/Parser.java
@@ -0,0 +1,209 @@
+// SAX parser interface.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: Parser.java,v 1.6 2002/01/30 21:13:47 dbrownell Exp $
+
+package org.xml.sax;
+
+import java.io.IOException;
+import java.util.Locale;
+
+
+/**
+ * Basic interface for SAX (Simple API for XML) parsers.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This was the main event supplier interface for SAX1; it has
+ * been replaced in SAX2 by {@link org.xml.sax.XMLReader XMLReader},
+ * which includes Namespace support and sophisticated configurability
+ * and extensibility.</p>
+ *
+ * <p>All SAX1 parsers must implement this basic interface: it allows
+ * applications to register handlers for different types of events
+ * and to initiate a parse from a URI, or a character stream.</p>
+ *
+ * <p>All SAX1 parsers must also implement a zero-argument constructor
+ * (though other constructors are also allowed).</p>
+ *
+ * <p>SAX1 parsers are reusable but not re-entrant: the application
+ * may reuse a parser object (possibly with a different input source)
+ * once the first parse has completed successfully, but it may not
+ * invoke the parse() methods recursively within a parse.</p>
+ *
+ * @deprecated This interface has been replaced by the SAX2
+ *             {@link org.xml.sax.XMLReader XMLReader}
+ *             interface, which includes Namespace support.
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.EntityResolver
+ * @see org.xml.sax.DTDHandler
+ * @see org.xml.sax.DocumentHandler
+ * @see org.xml.sax.ErrorHandler
+ * @see org.xml.sax.HandlerBase
+ * @see org.xml.sax.InputSource
+ */
+public interface Parser 
+{
+    
+    /**
+     * Allow an application to request a locale for errors and warnings.
+     *
+     * <p>SAX parsers are not required to provide localisation for errors
+     * and warnings; if they cannot support the requested locale,
+     * however, they must throw a SAX exception.  Applications may
+     * not request a locale change in the middle of a parse.</p>
+     *
+     * @param locale A Java Locale object.
+     * @exception org.xml.sax.SAXException Throws an exception
+     *            (using the previous or default locale) if the 
+     *            requested locale is not supported.
+     * @see org.xml.sax.SAXException
+     * @see org.xml.sax.SAXParseException
+     */
+    public abstract void setLocale (Locale locale)
+    throws SAXException;
+    
+    
+    /**
+     * Allow an application to register a custom entity resolver.
+     *
+     * <p>If the application does not register an entity resolver, the
+     * SAX parser will resolve system identifiers and open connections
+     * to entities itself (this is the default behaviour implemented in
+     * HandlerBase).</p>
+     *
+     * <p>Applications may register a new or different entity resolver
+     * in the middle of a parse, and the SAX parser must begin using
+     * the new resolver immediately.</p>
+     *
+     * @param resolver The object for resolving entities.
+     * @see EntityResolver
+     * @see HandlerBase
+     */
+    public abstract void setEntityResolver (EntityResolver resolver);
+    
+    
+    /**
+     * Allow an application to register a DTD event handler.
+     *
+     * <p>If the application does not register a DTD handler, all DTD
+     * events reported by the SAX parser will be silently
+     * ignored (this is the default behaviour implemented by
+     * HandlerBase).</p>
+     *
+     * <p>Applications may register a new or different
+     * handler in the middle of a parse, and the SAX parser must
+     * begin using the new handler immediately.</p>
+     *
+     * @param handler The DTD handler.
+     * @see DTDHandler
+     * @see HandlerBase
+     */
+    public abstract void setDTDHandler (DTDHandler handler);
+    
+    
+    /**
+     * Allow an application to register a document event handler.
+     *
+     * <p>If the application does not register a document handler, all
+     * document events reported by the SAX parser will be silently
+     * ignored (this is the default behaviour implemented by
+     * HandlerBase).</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param handler The document handler.
+     * @see DocumentHandler
+     * @see HandlerBase
+     */
+    public abstract void setDocumentHandler (DocumentHandler handler);
+    
+    
+    /**
+     * Allow an application to register an error event handler.
+     *
+     * <p>If the application does not register an error event handler,
+     * all error events reported by the SAX parser will be silently
+     * ignored, except for fatalError, which will throw a SAXException
+     * (this is the default behaviour implemented by HandlerBase).</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param handler The error handler.
+     * @see ErrorHandler
+     * @see SAXException
+     * @see HandlerBase
+     */
+    public abstract void setErrorHandler (ErrorHandler handler);
+    
+    
+    /**
+     * Parse an XML document.
+     *
+     * <p>The application can use this method to instruct the SAX parser
+     * to begin parsing an XML document from any valid input
+     * source (a character stream, a byte stream, or a URI).</p>
+     *
+     * <p>Applications may not invoke this method while a parse is in
+     * progress (they should create a new Parser instead for each
+     * additional XML document).  Once a parse is complete, an
+     * application may reuse the same Parser object, possibly with a
+     * different input source.</p>
+     *
+     * @param source The input source for the top-level of the
+     *        XML document.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException An IO exception from the parser,
+     *            possibly from a byte stream or character stream
+     *            supplied by the application.
+     * @see org.xml.sax.InputSource
+     * @see #parse(java.lang.String)
+     * @see #setEntityResolver
+     * @see #setDTDHandler
+     * @see #setDocumentHandler
+     * @see #setErrorHandler
+     */
+    public abstract void parse (InputSource source)
+    throws SAXException, IOException;
+    
+    
+    /**
+     * Parse an XML document from a system identifier (URI).
+     *
+     * <p>This method is a shortcut for the common case of reading a
+     * document from a system identifier.  It is the exact
+     * equivalent of the following:</p>
+     *
+     * <pre>
+     * parse(new InputSource(systemId));
+     * </pre>
+     *
+     * <p>If the system identifier is a URL, it must be fully resolved
+     * by the application before it is passed to the parser.</p>
+     *
+     * @param systemId The system identifier (URI).
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException An IO exception from the parser,
+     *            possibly from a byte stream or character stream
+     *            supplied by the application.
+     * @see #parse(org.xml.sax.InputSource)
+     */
+    public abstract void parse (String systemId)
+    throws SAXException, IOException;
+    
+}
+
+// end of Parser.java
diff --git a/xml/src/main/java/org/xml/sax/SAXException.java b/xml/src/main/java/org/xml/sax/SAXException.java
new file mode 100644
index 0000000..2e5b4cd
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/SAXException.java
@@ -0,0 +1,153 @@
+// SAX exception class.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: SAXException.java,v 1.7 2002/01/30 21:13:48 dbrownell Exp $
+
+package org.xml.sax;
+
+/**
+ * Encapsulate a general SAX error or warning.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class can contain basic error or warning information from
+ * either the XML parser or the application: a parser writer or
+ * application writer can subclass it to provide additional
+ * functionality.  SAX handlers may throw this exception or
+ * any exception subclassed from it.</p>
+ *
+ * <p>If the application needs to pass through other types of
+ * exceptions, it must wrap those exceptions in a SAXException
+ * or an exception derived from a SAXException.</p>
+ *
+ * <p>If the parser or application needs to include information about a
+ * specific location in an XML document, it should use the
+ * {@link org.xml.sax.SAXParseException SAXParseException} subclass.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.SAXParseException
+ */
+public class SAXException extends Exception {
+
+
+    /**
+     * Create a new SAXException.
+     */
+    public SAXException ()
+    {
+    super();
+    this.exception = null;
+    }
+    
+    
+    /**
+     * Create a new SAXException.
+     *
+     * @param message The error or warning message.
+     */
+    public SAXException (String message) {
+    super(message);
+    this.exception = null;
+    }
+    
+    
+    /**
+     * Create a new SAXException wrapping an existing exception.
+     *
+     * <p>The existing exception will be embedded in the new
+     * one, and its message will become the default message for
+     * the SAXException.</p>
+     *
+     * @param e The exception to be wrapped in a SAXException.
+     */
+    public SAXException (Exception e)
+    {
+    super();
+    this.exception = e;
+    }
+    
+    
+    /**
+     * Create a new SAXException from an existing exception.
+     *
+     * <p>The existing exception will be embedded in the new
+     * one, but the new exception will have its own message.</p>
+     *
+     * @param message The detail message.
+     * @param e The exception to be wrapped in a SAXException.
+     */
+    public SAXException (String message, Exception e)
+    {
+    super(message);
+    this.exception = e;
+    }
+    
+    
+    /**
+     * Return a detail message for this exception.
+     *
+     * <p>If there is an embedded exception, and if the SAXException
+     * has no detail message of its own, this method will return
+     * the detail message from the embedded exception.</p>
+     *
+     * @return The error or warning message.
+     */
+    public String getMessage ()
+    {
+    String message = super.getMessage();
+    
+    if (message == null && exception != null) {
+        return exception.getMessage();
+    } else {
+        return message;
+    }
+    }
+    
+    
+    /**
+     * Return the embedded exception, if any.
+     *
+     * @return The embedded exception, or null if there is none.
+     */
+    public Exception getException ()
+    {
+    return exception;
+    }
+
+
+    /**
+     * Override toString to pick up any embedded exception.
+     *
+     * @return A string representation of this exception.
+     */
+    public String toString ()
+    {
+    if (exception != null) {
+        return exception.toString();
+    } else {
+        return super.toString();
+    }
+    }
+    
+    
+    
+    //////////////////////////////////////////////////////////////////////
+    // Internal state.
+    //////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * @serial The embedded exception if tunnelling, or null.
+     */    
+    private Exception exception;
+    
+}
+
+// end of SAXException.java
diff --git a/xml/src/main/java/org/xml/sax/SAXNotRecognizedException.java b/xml/src/main/java/org/xml/sax/SAXNotRecognizedException.java
new file mode 100644
index 0000000..69ba807
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/SAXNotRecognizedException.java
@@ -0,0 +1,53 @@
+// SAXNotRecognizedException.java - unrecognized feature or value.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: SAXNotRecognizedException.java,v 1.7 2002/01/30 21:13:48 dbrownell Exp $
+
+package org.xml.sax;
+
+
+/**
+ * Exception class for an unrecognized identifier.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>An XMLReader will throw this exception when it finds an
+ * unrecognized feature or property identifier; SAX applications and
+ * extensions may use this class for other, similar purposes.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.SAXNotSupportedException
+ */
+public class SAXNotRecognizedException extends SAXException
+{
+
+    /**
+     * Default constructor.
+     */
+    public SAXNotRecognizedException ()
+    {
+    super();
+    }
+
+
+    /**
+     * Construct a new exception with the given message.
+     *
+     * @param message The text message of the exception.
+     */
+    public SAXNotRecognizedException (String message)
+    {
+    super(message);
+    }
+
+}
+
+// end of SAXNotRecognizedException.java
diff --git a/xml/src/main/java/org/xml/sax/SAXNotSupportedException.java b/xml/src/main/java/org/xml/sax/SAXNotSupportedException.java
new file mode 100644
index 0000000..bd5b239
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/SAXNotSupportedException.java
@@ -0,0 +1,53 @@
+// SAXNotSupportedException.java - unsupported feature or value.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: SAXNotSupportedException.java,v 1.7 2002/01/30 21:13:48 dbrownell Exp $
+
+package org.xml.sax;
+
+/**
+ * Exception class for an unsupported operation.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>An XMLReader will throw this exception when it recognizes a
+ * feature or property identifier, but cannot perform the requested
+ * operation (setting a state or value).  Other SAX2 applications and
+ * extensions may use this class for similar purposes.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.SAXNotRecognizedException 
+ */
+public class SAXNotSupportedException extends SAXException
+{
+
+    /**
+     * Construct a new exception with no message.
+     */
+    public SAXNotSupportedException ()
+    {
+    super();
+    }
+
+
+    /**
+     * Construct a new exception with the given message.
+     *
+     * @param message The text message of the exception.
+     */
+    public SAXNotSupportedException (String message)
+    {
+    super(message);
+    }
+
+}
+
+// end of SAXNotSupportedException.java
diff --git a/xml/src/main/java/org/xml/sax/SAXParseException.java b/xml/src/main/java/org/xml/sax/SAXParseException.java
new file mode 100644
index 0000000..a6a93e9
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/SAXParseException.java
@@ -0,0 +1,269 @@
+// SAX exception class.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: SAXParseException.java,v 1.11 2004/04/21 13:05:02 dmegginson Exp $
+
+package org.xml.sax;
+
+/**
+ * Encapsulate an XML parse error or warning.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This exception may include information for locating the error
+ * in the original XML document, as if it came from a {@link Locator}
+ * object.  Note that although the application
+ * will receive a SAXParseException as the argument to the handlers
+ * in the {@link org.xml.sax.ErrorHandler ErrorHandler} interface, 
+ * the application is not actually required to throw the exception; 
+ * instead, it can simply read the information in it and take a 
+ * different action.</p>
+ *
+ * <p>Since this exception is a subclass of {@link org.xml.sax.SAXException 
+ * SAXException}, it inherits the ability to wrap another exception.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.SAXException
+ * @see org.xml.sax.Locator
+ * @see org.xml.sax.ErrorHandler
+ */
+public class SAXParseException extends SAXException {
+    
+    
+    //////////////////////////////////////////////////////////////////////
+    // Constructors.
+    //////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Create a new SAXParseException from a message and a Locator.
+     *
+     * <p>This constructor is especially useful when an application is
+     * creating its own exception from within a {@link org.xml.sax.ContentHandler
+     * ContentHandler} callback.</p>
+     *
+     * @param message The error or warning message.
+     * @param locator The locator object for the error or warning (may be
+     *        null).
+     * @see org.xml.sax.Locator
+     */
+    public SAXParseException (String message, Locator locator) {
+    super(message);
+    if (locator != null) {
+        init(locator.getPublicId(), locator.getSystemId(),
+         locator.getLineNumber(), locator.getColumnNumber());
+    } else {
+        init(null, null, -1, -1);
+    }
+    }
+    
+    
+    /**
+     * Wrap an existing exception in a SAXParseException.
+     *
+     * <p>This constructor is especially useful when an application is
+     * creating its own exception from within a {@link org.xml.sax.ContentHandler
+     * ContentHandler} callback, and needs to wrap an existing exception that is not a
+     * subclass of {@link org.xml.sax.SAXException SAXException}.</p>
+     *
+     * @param message The error or warning message, or null to
+     *                use the message from the embedded exception.
+     * @param locator The locator object for the error or warning (may be
+     *        null).
+     * @param e Any exception.
+     * @see org.xml.sax.Locator
+     */
+    public SAXParseException (String message, Locator locator,
+                  Exception e) {
+    super(message, e);
+    if (locator != null) {
+        init(locator.getPublicId(), locator.getSystemId(),
+         locator.getLineNumber(), locator.getColumnNumber());
+    } else {
+        init(null, null, -1, -1);
+    }
+    }
+    
+    
+    /**
+     * Create a new SAXParseException.
+     *
+     * <p>This constructor is most useful for parser writers.</p>
+     *
+     * <p>All parameters except the message are as if
+     * they were provided by a {@link Locator}.  For example, if the
+     * system identifier is a URL (including relative filename), the
+     * caller must resolve it fully before creating the exception.</p>
+     *
+     *
+     * @param message The error or warning message.
+     * @param publicId The public identifier of the entity that generated
+     *                 the error or warning.
+     * @param systemId The system identifier of the entity that generated
+     *                 the error or warning.
+     * @param lineNumber The line number of the end of the text that
+     *                   caused the error or warning.
+     * @param columnNumber The column number of the end of the text that
+     *                     cause the error or warning.
+     */
+    public SAXParseException (String message, String publicId, String systemId,
+                  int lineNumber, int columnNumber)
+    {
+    super(message);
+    init(publicId, systemId, lineNumber, columnNumber);
+    }
+    
+    
+    /**
+     * Create a new SAXParseException with an embedded exception.
+     *
+     * <p>This constructor is most useful for parser writers who
+     * need to wrap an exception that is not a subclass of
+     * {@link org.xml.sax.SAXException SAXException}.</p>
+     *
+     * <p>All parameters except the message and exception are as if
+     * they were provided by a {@link Locator}.  For example, if the
+     * system identifier is a URL (including relative filename), the
+     * caller must resolve it fully before creating the exception.</p>
+     *
+     * @param message The error or warning message, or null to use
+     *                the message from the embedded exception.
+     * @param publicId The public identifier of the entity that generated
+     *                 the error or warning.
+     * @param systemId The system identifier of the entity that generated
+     *                 the error or warning.
+     * @param lineNumber The line number of the end of the text that
+     *                   caused the error or warning.
+     * @param columnNumber The column number of the end of the text that
+     *                     cause the error or warning.
+     * @param e Another exception to embed in this one.
+     */
+    public SAXParseException (String message, String publicId, String systemId,
+                  int lineNumber, int columnNumber, Exception e)
+    {
+    super(message, e);
+    init(publicId, systemId, lineNumber, columnNumber);
+    }
+
+
+    /**
+     * Internal initialization method.
+     *
+     * @param publicId The public identifier of the entity which generated the exception,
+     *        or null.
+     * @param systemId The system identifier of the entity which generated the exception,
+     *        or null.
+     * @param lineNumber The line number of the error, or -1.
+     * @param columnNumber The column number of the error, or -1.
+     */
+    private void init (String publicId, String systemId,
+               int lineNumber, int columnNumber)
+    {
+    this.publicId = publicId;
+    this.systemId = systemId;
+    this.lineNumber = lineNumber;
+    this.columnNumber = columnNumber;
+    }
+    
+    
+    /**
+     * Get the public identifier of the entity where the exception occurred.
+     *
+     * @return A string containing the public identifier, or null
+     *         if none is available.
+     * @see org.xml.sax.Locator#getPublicId
+     */
+    public String getPublicId ()
+    {
+    return this.publicId;
+    }
+    
+    
+    /**
+     * Get the system identifier of the entity where the exception occurred.
+     *
+     * <p>If the system identifier is a URL, it will have been resolved
+     * fully.</p>
+     *
+     * @return A string containing the system identifier, or null
+     *         if none is available.
+     * @see org.xml.sax.Locator#getSystemId
+     */
+    public String getSystemId ()
+    {
+    return this.systemId;
+    }
+    
+    
+    /**
+     * The line number of the end of the text where the exception occurred.
+     *
+     * <p>The first line is line 1.</p>
+     *
+     * @return An integer representing the line number, or -1
+     *         if none is available.
+     * @see org.xml.sax.Locator#getLineNumber
+     */
+    public int getLineNumber ()
+    {
+    return this.lineNumber;
+    }
+    
+    
+    /**
+     * The column number of the end of the text where the exception occurred.
+     *
+     * <p>The first column in a line is position 1.</p>
+     *
+     * @return An integer representing the column number, or -1
+     *         if none is available.
+     * @see org.xml.sax.Locator#getColumnNumber
+     */
+    public int getColumnNumber ()
+    {
+    return this.columnNumber;
+    }
+    
+    
+    //////////////////////////////////////////////////////////////////////
+    // Internal state.
+    //////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * @serial The public identifier, or null.
+     * @see #getPublicId
+     */    
+    private String publicId;
+
+
+    /**
+     * @serial The system identifier, or null.
+     * @see #getSystemId
+     */
+    private String systemId;
+
+
+    /**
+     * @serial The line number, or -1.
+     * @see #getLineNumber
+     */
+    private int lineNumber;
+
+
+    /**
+     * @serial The column number, or -1.
+     * @see #getColumnNumber
+     */
+    private int columnNumber;
+    
+}
+
+// end of SAXParseException.java
diff --git a/xml/src/main/java/org/xml/sax/XMLFilter.java b/xml/src/main/java/org/xml/sax/XMLFilter.java
new file mode 100644
index 0000000..5a399fa
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/XMLFilter.java
@@ -0,0 +1,65 @@
+// XMLFilter.java - filter SAX2 events.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: XMLFilter.java,v 1.6 2002/01/30 21:13:48 dbrownell Exp $
+
+package org.xml.sax;
+
+
+/**
+ * Interface for an XML filter.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>An XML filter is like an XML reader, except that it obtains its
+ * events from another XML reader rather than a primary source like
+ * an XML document or database.  Filters can modify a stream of
+ * events as they pass on to the final application.</p>
+ *
+ * <p>The XMLFilterImpl helper class provides a convenient base
+ * for creating SAX2 filters, by passing on all {@link org.xml.sax.EntityResolver
+ * EntityResolver}, {@link org.xml.sax.DTDHandler DTDHandler},
+ * {@link org.xml.sax.ContentHandler ContentHandler} and {@link org.xml.sax.ErrorHandler
+ * ErrorHandler} events automatically.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.helpers.XMLFilterImpl
+ */
+public interface XMLFilter extends XMLReader
+{
+
+    /**
+     * Set the parent reader.
+     *
+     * <p>This method allows the application to link the filter to
+     * a parent reader (which may be another filter).  The argument
+     * may not be null.</p>
+     *
+     * @param parent The parent reader.
+     */
+    public abstract void setParent (XMLReader parent);
+
+
+    /**
+     * Get the parent reader.
+     *
+     * <p>This method allows the application to query the parent
+     * reader (which may be another filter).  It is generally a
+     * bad idea to perform any operations on the parent reader
+     * directly: they should all pass through this filter.</p>
+     *
+     * @return The parent filter, or null if none has been set.
+     */
+    public abstract XMLReader getParent ();
+
+}
+
+// end of XMLFilter.java
diff --git a/xml/src/main/java/org/xml/sax/XMLReader.java b/xml/src/main/java/org/xml/sax/XMLReader.java
new file mode 100644
index 0000000..d58a4bd
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/XMLReader.java
@@ -0,0 +1,404 @@
+// XMLReader.java - read an XML document.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: XMLReader.java,v 1.9 2004/04/26 17:34:34 dmegginson Exp $
+
+package org.xml.sax;
+
+import java.io.IOException;
+
+
+/**
+ * Interface for reading an XML document using callbacks.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p><strong>Note:</strong> despite its name, this interface does 
+ * <em>not</em> extend the standard Java {@link java.io.Reader Reader} 
+ * interface, because reading XML is a fundamentally different activity 
+ * than reading character data.</p>
+ *
+ * <p>XMLReader is the interface that an XML parser's SAX2 driver must
+ * implement.  This interface allows an application to set and
+ * query features and properties in the parser, to register
+ * event handlers for document processing, and to initiate
+ * a document parse.</p>
+ *
+ * <p>All SAX interfaces are assumed to be synchronous: the
+ * {@link #parse parse} methods must not return until parsing
+ * is complete, and readers must wait for an event-handler callback
+ * to return before reporting the next event.</p>
+ *
+ * <p>This interface replaces the (now deprecated) SAX 1.0 {@link
+ * org.xml.sax.Parser Parser} interface.  The XMLReader interface
+ * contains two important enhancements over the old Parser
+ * interface (as well as some minor ones):</p>
+ *
+ * <ol>
+ * <li>it adds a standard way to query and set features and 
+ *  properties; and</li>
+ * <li>it adds Namespace support, which is required for many
+ *  higher-level XML standards.</li>
+ * </ol>
+ *
+ * <p>There are adapters available to convert a SAX1 Parser to
+ * a SAX2 XMLReader and vice-versa.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1+ (sax2r3pre1)
+ * @see org.xml.sax.XMLFilter
+ * @see org.xml.sax.helpers.ParserAdapter
+ * @see org.xml.sax.helpers.XMLReaderAdapter 
+ */
+public interface XMLReader
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Configuration.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Look up the value of a feature flag.
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for an XMLReader to recognize a feature name but
+     * temporarily be unable to return its value.
+     * Some feature values may be available only in specific
+     * contexts, such as before, during, or after a parse.
+     * Also, some feature values may not be programmatically accessible.
+     * (In the case of an adapter for SAX1 {@link Parser}, there is no
+     * implementation-independent way to expose whether the underlying
+     * parser is performing validation, expanding external entities,
+     * and so forth.) </p>
+     *
+     * <p>All XMLReaders are required to recognize the
+     * http://xml.org/sax/features/namespaces and the
+     * http://xml.org/sax/features/namespace-prefixes feature names.</p>
+     *
+     * <p>Typical usage is something like this:</p>
+     *
+     * <pre>
+     * XMLReader r = new MySAXDriver();
+     *
+     *                         // try to activate validation
+     * try {
+     *   r.setFeature("http://xml.org/sax/features/validation", true);
+     * } catch (SAXException e) {
+     *   System.err.println("Cannot activate validation."); 
+     * }
+     *
+     *                         // register event handlers
+     * r.setContentHandler(new MyContentHandler());
+     * r.setErrorHandler(new MyErrorHandler());
+     *
+     *                         // parse the first document
+     * try {
+     *   r.parse("http://www.foo.com/mydoc.xml");
+     * } catch (IOException e) {
+     *   System.err.println("I/O exception reading XML document");
+     * } catch (SAXException e) {
+     *   System.err.println("XML exception reading document.");
+     * }
+     * </pre>
+     *
+     * <p>Implementors are free (and encouraged) to invent their own features,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The feature name, which is a fully-qualified URI.
+     * @return The current value of the feature (true or false).
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the feature name but 
+     *            cannot determine its value at this time.
+     * @see #setFeature
+     */
+    public boolean getFeature (String name)
+        throws SAXNotRecognizedException, SAXNotSupportedException;
+
+
+    /**
+     * Set the value of a feature flag.
+     *
+     * <p>The feature name is any fully-qualified URI.  It is
+     * possible for an XMLReader to expose a feature value but
+     * to be unable to change the current value.
+     * Some feature values may be immutable or mutable only 
+     * in specific contexts, such as before, during, or after 
+     * a parse.</p>
+     *
+     * <p>All XMLReaders are required to support setting
+     * http://xml.org/sax/features/namespaces to true and
+     * http://xml.org/sax/features/namespace-prefixes to false.</p>
+     *
+     * @param name The feature name, which is a fully-qualified URI.
+     * @param value The requested value of the feature (true or false).
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the feature name but 
+     *            cannot set the requested value.
+     * @see #getFeature
+     */
+    public void setFeature (String name, boolean value)
+    throws SAXNotRecognizedException, SAXNotSupportedException;
+
+
+    /**
+     * Look up the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for an XMLReader to recognize a property name but
+     * temporarily be unable to return its value.
+     * Some property values may be available only in specific
+     * contexts, such as before, during, or after a parse.</p>
+     *
+     * <p>XMLReaders are not required to recognize any specific
+     * property names, though an initial core set is documented for
+     * SAX2.</p>
+     *
+     * <p>Implementors are free (and encouraged) to invent their own properties,
+     * using names built on their own URIs.</p>
+     *
+     * @param name The property name, which is a fully-qualified URI.
+     * @return The current value of the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the property name but 
+     *            cannot determine its value at this time.
+     * @see #setProperty
+     */
+    public Object getProperty (String name)
+    throws SAXNotRecognizedException, SAXNotSupportedException;
+
+
+    /**
+     * Set the value of a property.
+     *
+     * <p>The property name is any fully-qualified URI.  It is
+     * possible for an XMLReader to recognize a property name but
+     * to be unable to change the current value.
+     * Some property values may be immutable or mutable only 
+     * in specific contexts, such as before, during, or after 
+     * a parse.</p>
+     *
+     * <p>XMLReaders are not required to recognize setting
+     * any specific property names, though a core set is defined by 
+     * SAX2.</p>
+     *
+     * <p>This method is also the standard mechanism for setting
+     * extended handlers.</p>
+     *
+     * @param name The property name, which is a fully-qualified URI.
+     * @param value The requested value for the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            XMLReader recognizes the property name but 
+     *            cannot set the requested value.
+     */
+    public void setProperty (String name, Object value)
+    throws SAXNotRecognizedException, SAXNotSupportedException;
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Event handlers.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Allow an application to register an entity resolver.
+     *
+     * <p>If the application does not register an entity resolver,
+     * the XMLReader will perform its own default resolution.</p>
+     *
+     * <p>Applications may register a new or different resolver in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * resolver immediately.</p>
+     *
+     * @param resolver The entity resolver.
+     * @see #getEntityResolver
+     */
+    public void setEntityResolver (EntityResolver resolver);
+
+
+    /**
+     * Return the current entity resolver.
+     *
+     * @return The current entity resolver, or null if none
+     *         has been registered.
+     * @see #setEntityResolver
+     */
+    public EntityResolver getEntityResolver ();
+
+
+    /**
+     * Allow an application to register a DTD event handler.
+     *
+     * <p>If the application does not register a DTD handler, all DTD
+     * events reported by the SAX parser will be silently ignored.</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param handler The DTD handler.
+     * @see #getDTDHandler
+     */
+    public void setDTDHandler (DTDHandler handler);
+
+
+    /**
+     * Return the current DTD handler.
+     *
+     * @return The current DTD handler, or null if none
+     *         has been registered.
+     * @see #setDTDHandler
+     */
+    public DTDHandler getDTDHandler ();
+
+
+    /**
+     * Allow an application to register a content event handler.
+     *
+     * <p>If the application does not register a content handler, all
+     * content events reported by the SAX parser will be silently
+     * ignored.</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param handler The content handler.
+     * @see #getContentHandler
+     */
+    public void setContentHandler (ContentHandler handler);
+
+
+    /**
+     * Return the current content handler.
+     *
+     * @return The current content handler, or null if none
+     *         has been registered.
+     * @see #setContentHandler
+     */
+    public ContentHandler getContentHandler ();
+
+
+    /**
+     * Allow an application to register an error event handler.
+     *
+     * <p>If the application does not register an error handler, all
+     * error events reported by the SAX parser will be silently
+     * ignored; however, normal processing may not continue.  It is
+     * highly recommended that all SAX applications implement an
+     * error handler to avoid unexpected bugs.</p>
+     *
+     * <p>Applications may register a new or different handler in the
+     * middle of a parse, and the SAX parser must begin using the new
+     * handler immediately.</p>
+     *
+     * @param handler The error handler.
+     * @see #getErrorHandler
+     */
+    public void setErrorHandler (ErrorHandler handler);
+
+
+    /**
+     * Return the current error handler.
+     *
+     * @return The current error handler, or null if none
+     *         has been registered.
+     * @see #setErrorHandler
+     */
+    public ErrorHandler getErrorHandler ();
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Parsing.
+    ////////////////////////////////////////////////////////////////////
+
+    /**
+     * Parse an XML document.
+     *
+     * <p>The application can use this method to instruct the XML
+     * reader to begin parsing an XML document from any valid input
+     * source (a character stream, a byte stream, or a URI).</p>
+     *
+     * <p>Applications may not invoke this method while a parse is in
+     * progress (they should create a new XMLReader instead for each
+     * nested XML document).  Once a parse is complete, an
+     * application may reuse the same XMLReader object, possibly with a
+     * different input source.
+     * Configuration of the XMLReader object (such as handler bindings and
+     * values established for feature flags and properties) is unchanged
+     * by completion of a parse, unless the definition of that aspect of
+     * the configuration explicitly specifies other behavior.
+     * (For example, feature flags or properties exposing
+     * characteristics of the document being parsed.)
+     * </p>
+     *
+     * <p>During the parse, the XMLReader will provide information
+     * about the XML document through the registered event
+     * handlers.</p>
+     *
+     * <p>This method is synchronous: it will not return until parsing
+     * has ended.  If a client application wants to terminate 
+     * parsing early, it should throw an exception.</p>
+     *
+     * @param input The input source for the top-level of the
+     *        XML document.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException An IO exception from the parser,
+     *            possibly from a byte stream or character stream
+     *            supplied by the application.
+     * @see org.xml.sax.InputSource
+     * @see #parse(java.lang.String)
+     * @see #setEntityResolver
+     * @see #setDTDHandler
+     * @see #setContentHandler
+     * @see #setErrorHandler 
+     */
+    public void parse (InputSource input)
+    throws IOException, SAXException;
+
+
+    /**
+     * Parse an XML document from a system identifier (URI).
+     *
+     * <p>This method is a shortcut for the common case of reading a
+     * document from a system identifier.  It is the exact
+     * equivalent of the following:</p>
+     *
+     * <pre>
+     * parse(new InputSource(systemId));
+     * </pre>
+     *
+     * <p>If the system identifier is a URL, it must be fully resolved
+     * by the application before it is passed to the parser.</p>
+     *
+     * @param systemId The system identifier (URI).
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException An IO exception from the parser,
+     *            possibly from a byte stream or character stream
+     *            supplied by the application.
+     * @see #parse(org.xml.sax.InputSource)
+     */
+    public void parse (String systemId)
+    throws IOException, SAXException;
+
+}
diff --git a/xml/src/main/java/org/xml/sax/ext/Attributes2.java b/xml/src/main/java/org/xml/sax/ext/Attributes2.java
new file mode 100644
index 0000000..45cd551
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ext/Attributes2.java
@@ -0,0 +1,132 @@
+// Attributes2.java - extended Attributes
+// http://www.saxproject.org
+// Public Domain: no warranty.
+// $Id: Attributes2.java,v 1.6 2004/03/08 13:01:00 dmegginson Exp $
+
+package org.xml.sax.ext;
+
+import org.xml.sax.Attributes;
+
+
+/**
+ * SAX2 extension to augment the per-attribute information
+ * provided though {@link Attributes}.
+ * If an implementation supports this extension, the attributes
+ * provided in {@link org.xml.sax.ContentHandler#startElement
+ * ContentHandler.startElement() } will implement this interface,
+ * and the <em>http://xml.org/sax/features/use-attributes2</em>
+ * feature flag will have the value <em>true</em>.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * </blockquote>
+ *
+ * <p> XMLReader implementations are not required to support this
+ * information, and it is not part of core-only SAX2 distributions.</p>
+ *
+ * <p>Note that if an attribute was defaulted (<em>!isSpecified()</em>)
+ * it will of necessity also have been declared (<em>isDeclared()</em>)
+ * in the DTD.
+ * Similarly if an attribute's type is anything except CDATA, then it
+ * must have been declared.
+ * </p>
+ *
+ * @since SAX 2.0 (extensions 1.1 alpha)
+ * @author David Brownell
+ * @version TBS
+ */
+public interface Attributes2 extends Attributes
+{
+    /**
+     * Returns false unless the attribute was declared in the DTD.
+     * This helps distinguish two kinds of attributes that SAX reports
+     * as CDATA:  ones that were declared (and hence are usually valid),
+     * and those that were not (and which are never valid).
+     *
+     * @param index The attribute index (zero-based).
+     * @return true if the attribute was declared in the DTD,
+     *        false otherwise.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not identify an attribute.
+     */
+    public boolean isDeclared (int index);
+
+    /**
+     * Returns false unless the attribute was declared in the DTD.
+     * This helps distinguish two kinds of attributes that SAX reports
+     * as CDATA:  ones that were declared (and hence are usually valid),
+     * and those that were not (and which are never valid).
+     *
+     * @param qName The XML qualified (prefixed) name.
+     * @return true if the attribute was declared in the DTD,
+     *        false otherwise.
+     * @exception java.lang.IllegalArgumentException When the
+     *            supplied name does not identify an attribute.
+     */
+    public boolean isDeclared (String qName);
+
+    /**
+     * Returns false unless the attribute was declared in the DTD.
+     * This helps distinguish two kinds of attributes that SAX reports
+     * as CDATA:  ones that were declared (and hence are usually valid),
+     * and those that were not (and which are never valid).
+     *
+     * <p>Remember that since DTDs do not "understand" namespaces, the
+     * namespace URI associated with an attribute may not have come from
+     * the DTD.  The declaration will have applied to the attribute's
+     * <em>qName</em>.
+     *
+     * @param uri The Namespace URI, or the empty string if
+     *        the name has no Namespace URI.
+     * @param localName The attribute's local name.
+     * @return true if the attribute was declared in the DTD,
+     *        false otherwise.
+     * @exception java.lang.IllegalArgumentException When the
+     *            supplied names do not identify an attribute.
+     */
+    public boolean isDeclared (String uri, String localName);
+
+    /**
+     * Returns true unless the attribute value was provided
+     * by DTD defaulting.
+     *
+     * @param index The attribute index (zero-based).
+     * @return true if the value was found in the XML text,
+     *        false if the value was provided by DTD defaulting.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not identify an attribute.
+     */
+    public boolean isSpecified (int index);
+
+    /**
+     * Returns true unless the attribute value was provided
+     * by DTD defaulting.
+     *
+     * <p>Remember that since DTDs do not "understand" namespaces, the
+     * namespace URI associated with an attribute may not have come from
+     * the DTD.  The declaration will have applied to the attribute's
+     * <em>qName</em>.
+     *
+     * @param uri The Namespace URI, or the empty string if
+     *        the name has no Namespace URI.
+     * @param localName The attribute's local name.
+     * @return true if the value was found in the XML text,
+     *        false if the value was provided by DTD defaulting.
+     * @exception java.lang.IllegalArgumentException When the
+     *            supplied names do not identify an attribute.
+     */
+    public boolean isSpecified (String uri, String localName);
+
+    /**
+     * Returns true unless the attribute value was provided
+     * by DTD defaulting.
+     *
+     * @param qName The XML qualified (prefixed) name.
+     * @return true if the value was found in the XML text,
+     *        false if the value was provided by DTD defaulting.
+     * @exception java.lang.IllegalArgumentException When the
+     *            supplied name does not identify an attribute.
+     */
+    public boolean isSpecified (String qName);
+}
diff --git a/xml/src/main/java/org/xml/sax/ext/Attributes2Impl.java b/xml/src/main/java/org/xml/sax/ext/Attributes2Impl.java
new file mode 100644
index 0000000..fc36805
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ext/Attributes2Impl.java
@@ -0,0 +1,320 @@
+// Attributes2Impl.java - extended AttributesImpl
+// http://www.saxproject.org
+// Public Domain: no warranty.
+// $Id: Attributes2Impl.java,v 1.5 2004/03/08 13:01:01 dmegginson Exp $
+
+package org.xml.sax.ext;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
+
+
+/**
+ * SAX2 extension helper for additional Attributes information,
+ * implementing the {@link Attributes2} interface.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * </blockquote>
+ *
+ * <p>This is not part of core-only SAX2 distributions.</p>
+ *
+ * <p>The <em>specified</em> flag for each attribute will always
+ * be true, unless it has been set to false in the copy constructor
+ * or using {@link #setSpecified}.
+ * Similarly, the <em>declared</em> flag for each attribute will
+ * always be false, except for defaulted attributes (<em>specified</em>
+ * is false), non-CDATA attributes, or when it is set to true using
+ * {@link #setDeclared}.
+ * If you change an attribute's type by hand, you may need to modify
+ * its <em>declared</em> flag to match. 
+ * </p>
+ *
+ * @since SAX 2.0 (extensions 1.1 alpha)
+ * @author David Brownell
+ * @version TBS
+ */
+public class Attributes2Impl extends AttributesImpl implements Attributes2
+{
+    private boolean    declared [];
+    private boolean    specified [];
+
+
+    /**
+     * Construct a new, empty Attributes2Impl object.
+     */
+    public Attributes2Impl () {
+        // BEGIN android-added
+        declared = new boolean[0];
+        specified = new boolean[0];
+        // END android-added
+    }
+
+
+    /**
+     * Copy an existing Attributes or Attributes2 object.
+     * If the object implements Attributes2, values of the
+     * <em>specified</em> and <em>declared</em> flags for each
+     * attribute are copied.
+     * Otherwise the flag values are defaulted to assume no DTD was used,
+     * unless there is evidence to the contrary (such as attributes with
+     * type other than CDATA, which must have been <em>declared</em>).
+     *
+     * <p>This constructor is especially useful inside a
+     * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
+     *
+     * @param atts The existing Attributes object.
+     */
+    public Attributes2Impl (Attributes atts)
+    {
+    super (atts);
+    }
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of Attributes2
+    ////////////////////////////////////////////////////////////////////
+
+
+    /*
+     * Returns the current value of the attribute's "declared" flag.
+     */
+    // javadoc mostly from interface
+    public boolean isDeclared (int index)
+    {
+    if (index < 0 || index >= getLength ())
+        throw new ArrayIndexOutOfBoundsException (
+        "No attribute at index: " + index);
+    return declared [index];
+    }
+
+
+    /*
+     * Returns the current value of the attribute's "declared" flag.
+     */
+    // javadoc mostly from interface
+    public boolean isDeclared (String uri, String localName)
+    {
+    int index = getIndex (uri, localName);
+
+    if (index < 0)
+        throw new IllegalArgumentException (
+        "No such attribute: local=" + localName
+        + ", namespace=" + uri);
+    return declared [index];
+    }
+
+
+    /*
+     * Returns the current value of the attribute's "declared" flag.
+     */
+    // javadoc mostly from interface
+    public boolean isDeclared (String qName)
+    {
+    int index = getIndex (qName);
+
+    if (index < 0)
+        throw new IllegalArgumentException (
+        "No such attribute: " + qName);
+    return declared [index];
+    }
+
+
+    /**
+     * Returns the current value of an attribute's "specified" flag.
+     *
+     * @param index The attribute index (zero-based).
+     * @return current flag value
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not identify an attribute.
+     */
+    public boolean isSpecified (int index)
+    {
+    if (index < 0 || index >= getLength ())
+        throw new ArrayIndexOutOfBoundsException (
+        "No attribute at index: " + index);
+    return specified [index];
+    }
+
+
+    /**
+     * Returns the current value of an attribute's "specified" flag.
+     *
+     * @param uri The Namespace URI, or the empty string if
+     *        the name has no Namespace URI.
+     * @param localName The attribute's local name.
+     * @return current flag value
+     * @exception java.lang.IllegalArgumentException When the
+     *            supplied names do not identify an attribute.
+     */
+    public boolean isSpecified (String uri, String localName)
+    {
+    int index = getIndex (uri, localName);
+
+    if (index < 0)
+        throw new IllegalArgumentException (
+        "No such attribute: local=" + localName
+        + ", namespace=" + uri);
+    return specified [index];
+    }
+
+
+    /**
+     * Returns the current value of an attribute's "specified" flag.
+     *
+     * @param qName The XML qualified (prefixed) name.
+     * @return current flag value
+     * @exception java.lang.IllegalArgumentException When the
+     *            supplied name does not identify an attribute.
+     */
+    public boolean isSpecified (String qName)
+    {
+    int index = getIndex (qName);
+
+    if (index < 0)
+        throw new IllegalArgumentException (
+        "No such attribute: " + qName);
+    return specified [index];
+    }
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Manipulators
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Copy an entire Attributes object.  The "specified" flags are
+     * assigned as true, and "declared" flags as false (except when
+     * an attribute's type is not CDATA),
+     * unless the object is an Attributes2 object.
+     * In that case those flag values are all copied.
+     *
+     * @param atts The attributes to copy.
+     * 
+     * @see AttributesImpl#setAttributes
+     */
+    public void setAttributes (Attributes atts)
+    {
+    int length = atts.getLength ();
+
+    super.setAttributes (atts);
+    declared = new boolean [length];
+    specified = new boolean [length];
+
+    if (atts instanceof Attributes2) {
+        Attributes2    a2 = (Attributes2) atts;
+        for (int i = 0; i < length; i++) {
+        declared [i] = a2.isDeclared (i);
+        specified [i] = a2.isSpecified (i);
+        }
+    } else {
+        for (int i = 0; i < length; i++) {
+        declared [i] = !"CDATA".equals (atts.getType (i));
+        specified [i] = true;
+        }
+    }
+    }
+
+
+    /**
+     * Add an attribute to the end of the list, setting its
+     * "specified" flag to true.  To set that flag's value
+     * to false, use {@link #setSpecified}.
+     *
+     * <p>Unless the attribute <em>type</em> is CDATA, this attribute
+     * is marked as being declared in the DTD.  To set that flag's value
+     * to true for CDATA attributes, use {@link #setDeclared}.
+     *
+     * @param uri The Namespace URI, or the empty string if
+     *        none is available or Namespace processing is not
+     *        being performed.
+     * @param localName The local name, or the empty string if
+     *        Namespace processing is not being performed.
+     * @param qName The qualified (prefixed) name, or the empty string
+     *        if qualified names are not available.
+     * @param type The attribute type as a string.
+     * @param value The attribute value.
+     * 
+     * @see AttributesImpl#addAttribute
+     */
+    public void addAttribute (String uri, String localName, String qName,
+                  String type, String value)
+    {
+    super.addAttribute (uri, localName, qName, type, value);
+
+    int length = getLength ();
+
+    // BEGIN android-changed
+    if (length > specified.length) {
+    // END android-changed
+        boolean    newFlags [];
+
+        newFlags = new boolean [length];
+        System.arraycopy (declared, 0, newFlags, 0, declared.length);
+        declared = newFlags;
+
+        newFlags = new boolean [length];
+        System.arraycopy (specified, 0, newFlags, 0, specified.length);
+        specified = newFlags;
+    }
+
+    specified [length - 1] = true;
+    declared [length - 1] = !"CDATA".equals (type);
+    }
+
+
+    // javadoc entirely from superclass
+    public void removeAttribute (int index)
+    {
+    int origMax = getLength () - 1;
+
+    super.removeAttribute (index);
+    if (index != origMax) {
+        System.arraycopy (declared, index + 1, declared, index,
+            origMax - index);
+        System.arraycopy (specified, index + 1, specified, index,
+            origMax - index);
+    }
+    }
+
+
+    /**
+     * Assign a value to the "declared" flag of a specific attribute.
+     * This is normally needed only for attributes of type CDATA,
+     * including attributes whose type is changed to or from CDATA.
+     *
+     * @param index The index of the attribute (zero-based).
+     * @param value The desired flag value.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not identify an attribute.
+     * @see #setType
+     */
+    public void setDeclared (int index, boolean value)
+    {
+    if (index < 0 || index >= getLength ())
+        throw new ArrayIndexOutOfBoundsException (
+        "No attribute at index: " + index);
+    declared [index] = value;
+    }
+
+
+    /**
+     * Assign a value to the "specified" flag of a specific attribute.
+     * This is the only way this flag can be cleared, except clearing
+     * by initialization with the copy constructor.
+     *
+     * @param index The index of the attribute (zero-based).
+     * @param value The desired flag value.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not identify an attribute.
+     */
+    public void setSpecified (int index, boolean value)
+    {
+    if (index < 0 || index >= getLength ())
+        throw new ArrayIndexOutOfBoundsException (
+        "No attribute at index: " + index);
+    specified [index] = value;
+    }
+}
diff --git a/xml/src/main/java/org/xml/sax/ext/DeclHandler.java b/xml/src/main/java/org/xml/sax/ext/DeclHandler.java
new file mode 100644
index 0000000..26471f3
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ext/DeclHandler.java
@@ -0,0 +1,146 @@
+// DeclHandler.java - Optional handler for DTD declaration events.
+// http://www.saxproject.org
+// Public Domain: no warranty.
+// $Id: DeclHandler.java,v 1.6 2004/04/22 13:28:49 dmegginson Exp $
+
+package org.xml.sax.ext;
+
+import org.xml.sax.SAXException;
+
+
+/**
+ * SAX2 extension handler for DTD declaration events.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This is an optional extension handler for SAX2 to provide more
+ * complete information about DTD declarations in an XML document.
+ * XML readers are not required to recognize this handler, and it
+ * is not part of core-only SAX2 distributions.</p>
+ *
+ * <p>Note that data-related DTD declarations (unparsed entities and
+ * notations) are already reported through the {@link
+ * org.xml.sax.DTDHandler DTDHandler} interface.</p>
+ *
+ * <p>If you are using the declaration handler together with a lexical
+ * handler, all of the events will occur between the
+ * {@link org.xml.sax.ext.LexicalHandler#startDTD startDTD} and the
+ * {@link org.xml.sax.ext.LexicalHandler#endDTD endDTD} events.</p>
+ *
+ * <p>To set the DeclHandler for an XML reader, use the
+ * {@link org.xml.sax.XMLReader#setProperty setProperty} method
+ * with the property name
+ * <code>http://xml.org/sax/properties/declaration-handler</code>
+ * and an object implementing this interface (or null) as the value.
+ * If the reader does not report declaration events, it will throw a
+ * {@link org.xml.sax.SAXNotRecognizedException SAXNotRecognizedException}
+ * when you attempt to register the handler.</p>
+ *
+ * @since SAX 2.0 (extensions 1.0)
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ */
+public interface DeclHandler
+{
+
+    /**
+     * Report an element type declaration.
+     *
+     * <p>The content model will consist of the string "EMPTY", the
+     * string "ANY", or a parenthesised group, optionally followed
+     * by an occurrence indicator.  The model will be normalized so
+     * that all parameter entities are fully resolved and all whitespace 
+     * is removed,and will include the enclosing parentheses.  Other
+     * normalization (such as removing redundant parentheses or 
+     * simplifying occurrence indicators) is at the discretion of the
+     * parser.</p>
+     *
+     * @param name The element type name.
+     * @param model The content model as a normalized string.
+     * @exception SAXException The application may raise an exception.
+     */
+    public abstract void elementDecl (String name, String model)
+    throws SAXException;
+
+
+    /**
+     * Report an attribute type declaration.
+     *
+     * <p>Only the effective (first) declaration for an attribute will
+     * be reported.  The type will be one of the strings "CDATA",
+     * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY",
+     * "ENTITIES", a parenthesized token group with 
+     * the separator "|" and all whitespace removed, or the word
+     * "NOTATION" followed by a space followed by a parenthesized
+     * token group with all whitespace removed.</p>
+     *
+     * <p>The value will be the value as reported to applications,
+     * appropriately normalized and with entity and character
+     * references expanded.  </p>
+     *
+     * @param eName The name of the associated element.
+     * @param aName The name of the attribute.
+     * @param type A string representing the attribute type.
+     * @param mode A string representing the attribute defaulting mode
+     *        ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if
+     *        none of these applies.
+     * @param value A string representing the attribute's default value,
+     *        or null if there is none.
+     * @exception SAXException The application may raise an exception.
+     */
+    public abstract void attributeDecl (String eName,
+                    String aName,
+                    String type,
+                    String mode,
+                    String value)
+    throws SAXException;
+
+
+    /**
+     * Report an internal entity declaration.
+     *
+     * <p>Only the effective (first) declaration for each entity
+     * will be reported.  All parameter entities in the value
+     * will be expanded, but general entities will not.</p>
+     *
+     * @param name The name of the entity.  If it is a parameter
+     *        entity, the name will begin with '%'.
+     * @param value The replacement text of the entity.
+     * @exception SAXException The application may raise an exception.
+     * @see #externalEntityDecl
+     * @see org.xml.sax.DTDHandler#unparsedEntityDecl
+     */
+    public abstract void internalEntityDecl (String name, String value)
+    throws SAXException;
+
+
+    /**
+     * Report a parsed external entity declaration.
+     *
+     * <p>Only the effective (first) declaration for each entity
+     * will be reported.</p>
+     *
+     * <p>If the system identifier is a URL, the parser must resolve it
+     * fully before passing it to the application.</p>
+     *
+     * @param name The name of the entity.  If it is a parameter
+     *        entity, the name will begin with '%'.
+     * @param publicId The entity's public identifier, or null if none
+     *        was given.
+     * @param systemId The entity's system identifier.
+     * @exception SAXException The application may raise an exception.
+     * @see #internalEntityDecl
+     * @see org.xml.sax.DTDHandler#unparsedEntityDecl
+     */
+    public abstract void externalEntityDecl (String name, String publicId,
+                         String systemId)
+    throws SAXException;
+
+}
+
+// end of DeclHandler.java
diff --git a/xml/src/main/java/org/xml/sax/ext/DefaultHandler2.java b/xml/src/main/java/org/xml/sax/ext/DefaultHandler2.java
new file mode 100644
index 0000000..f26564f
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ext/DefaultHandler2.java
@@ -0,0 +1,185 @@
+// DefaultHandler2.java - extended DefaultHandler
+// http://www.saxproject.org
+// Public Domain: no warranty.
+// $Id: DefaultHandler2.java,v 1.3 2002/01/12 19:04:19 dbrownell Exp $
+
+package org.xml.sax.ext;
+
+import java.io.IOException;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+/**
+ * This class extends the SAX2 base handler class to support the
+ * SAX2 {@link LexicalHandler}, {@link DeclHandler}, and
+ * {@link EntityResolver2} extensions.  Except for overriding the
+ * original SAX1 {@link DefaultHandler#resolveEntity resolveEntity()}
+ * method the added handler methods just return.  Subclassers may
+ * override everything on a method-by-method basis.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * </blockquote>
+ *
+ * <p> <em>Note:</em> this class might yet learn that the
+ * <em>ContentHandler.setDocumentLocator()</em> call might be passed a
+ * {@link Locator2} object, and that the
+ * <em>ContentHandler.startElement()</em> call might be passed a
+ * {@link Attributes2} object.
+ *
+ * @since SAX 2.0 (extensions 1.1 alpha)
+ * @author David Brownell
+ * @version TBS
+ */
+public class DefaultHandler2 extends DefaultHandler
+    implements LexicalHandler, DeclHandler, EntityResolver2
+{
+    /** Constructs a handler which ignores all parsing events. */
+    public DefaultHandler2 () { }
+
+
+    // SAX2 ext-1.0 LexicalHandler
+
+    public void startCDATA ()
+    throws SAXException
+    {}
+
+    public void endCDATA ()
+    throws SAXException
+    {}
+
+    public void startDTD (String name, String publicId, String systemId)
+    throws SAXException
+    {}
+
+    public void endDTD ()
+    throws SAXException
+    {}
+
+    public void startEntity (String name)
+    throws SAXException
+    {}
+
+    public void endEntity (String name)
+    throws SAXException
+    {}
+
+    public void comment (char ch [], int start, int length)
+    throws SAXException
+    { }
+
+
+    // SAX2 ext-1.0 DeclHandler
+
+    public void attributeDecl (String eName, String aName,
+        String type, String mode, String value)
+    throws SAXException
+    {}
+
+    public void elementDecl (String name, String model)
+    throws SAXException
+    {}
+
+    public void externalEntityDecl (String name,
+        String publicId, String systemId)
+    throws SAXException
+    {}
+
+    public void internalEntityDecl (String name, String value)
+    throws SAXException
+    {}
+
+    // SAX2 ext-1.1 EntityResolver2
+
+    /**
+     * Tells the parser that if no external subset has been declared
+     * in the document text, none should be used.
+     * 
+     * @param name Identifies the document root element.  This name comes
+     *    from a DOCTYPE declaration (where available) or from the actual
+     *    root element. The parameter is ignored.
+     * @param baseURI The document's base URI, serving as an additional
+     *    hint for selecting the external subset.  This is always an absolute
+     *    URI, unless it is null because the XMLReader was given an InputSource
+     *    without one. The parameter is ignored.
+     *    
+     * @return null (always).
+     * 
+     * @exception SAXException Any SAX exception, possibly wrapping
+     *    another exception.
+     * @exception IOException Probably indicating a failure to create
+     *    a new InputStream or Reader, or an illegal URL.
+     */
+    public InputSource getExternalSubset (String name, String baseURI)
+    throws SAXException, IOException
+    { return null; }
+
+    /**
+     * Tells the parser to resolve the systemId against the baseURI
+     * and read the entity text from that resulting absolute URI.
+     * Note that because the older
+     * {@link DefaultHandler#resolveEntity DefaultHandler.resolveEntity()},
+     * method is overridden to call this one, this method may sometimes 
+     * be invoked with null <em>name</em> and <em>baseURI</em>, and
+     * with the <em>systemId</em> already absolutized.
+     * 
+     * @param name Identifies the external entity being resolved.
+     *    Either "[dtd]" for the external subset, or a name starting
+     *    with "%" to indicate a parameter entity, or else the name of
+     *    a general entity.  This is never null when invoked by a SAX2
+     *    parser.
+     * @param publicId The public identifier of the external entity being
+     *    referenced (normalized as required by the XML specification), or
+     *    null if none was supplied.
+     * @param baseURI The URI with respect to which relative systemIDs
+     *    are interpreted.  This is always an absolute URI, unless it is
+     *    null (likely because the XMLReader was given an InputSource without
+     *  one).  This URI is defined by the XML specification to be the one
+     *    associated with the "&lt;" starting the relevant declaration.
+     * @param systemId The system identifier of the external entity
+     *    being referenced; either a relative or absolute URI.
+     *  This is never null when invoked by a SAX2 parser; only declared
+     *    entities, and any external subset, are resolved by such parsers.
+     *
+     * @return An InputSource object describing the new input source.
+     * 
+     * @exception SAXException Any SAX exception, possibly wrapping
+     *    another exception.
+     * @exception IOException Probably indicating a failure to create
+     *    a new InputStream or Reader, or an illegal URL.
+     */
+    public InputSource resolveEntity (String name, String publicId,
+        String baseURI, String systemId)
+    throws SAXException, IOException
+    { return null; }
+    
+    // SAX1 EntityResolver
+
+    /**
+     * Invokes
+     * {@link EntityResolver2#resolveEntity EntityResolver2.resolveEntity()}
+     * with null entity name and base URI.
+     * You only need to override that method to use this class.
+     * 
+     * @param publicId The public identifier of the external entity being
+     *    referenced (normalized as required by the XML specification), or
+     *    null if none was supplied.
+     * @param systemId The system identifier of the external entity
+     *    being referenced; either a relative or absolute URI.
+     *  This is never null when invoked by a SAX2 parser; only declared
+     *    entities, and any external subset, are resolved by such parsers.
+     *
+     * @return An InputSource object describing the new input source.
+     * 
+     * @exception SAXException Any SAX exception, possibly wrapping
+     *    another exception.
+     * @exception IOException Probably indicating a failure to create
+     *    a new InputStream or Reader, or an illegal URL.
+     */
+    public InputSource resolveEntity (String publicId, String systemId)
+    throws SAXException, IOException
+    { return resolveEntity (null, publicId, null, systemId); }
+}
diff --git a/xml/src/main/java/org/xml/sax/ext/EntityResolver2.java b/xml/src/main/java/org/xml/sax/ext/EntityResolver2.java
new file mode 100644
index 0000000..5437a9b
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ext/EntityResolver2.java
@@ -0,0 +1,197 @@
+// EntityResolver2.java - Extended SAX entity resolver.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: EntityResolver2.java,v 1.2 2002/01/12 19:20:08 dbrownell Exp $
+
+package org.xml.sax.ext;
+
+import java.io.IOException;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Extended interface for mapping external entity references to input
+ * sources, or providing a missing external subset.  The
+ * {@link XMLReader#setEntityResolver XMLReader.setEntityResolver()} method
+ * is used to provide implementations of this interface to parsers.
+ * When a parser uses the methods in this interface, the
+ * {@link EntityResolver2#resolveEntity EntityResolver2.resolveEntity()}
+ * method (in this interface) is used <em>instead of</em> the older (SAX 1.0)
+ * {@link EntityResolver#resolveEntity EntityResolver.resolveEntity()} method.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * </blockquote>
+ *
+ * <p>If a SAX application requires the customized handling which this
+ * interface defines for external entities, it must ensure that it uses
+ * an XMLReader with the
+ * <em>http://xml.org/sax/features/use-entity-resolver2</em> feature flag
+ * set to <em>true</em> (which is its default value when the feature is
+ * recognized).  If that flag is unrecognized, or its value is false,
+ * or the resolver does not implement this interface, then only the
+ * {@link EntityResolver} method will be used.
+ * </p>
+ *
+ * <p>That supports three categories of application that modify entity
+ * resolution.  <em>Old Style</em> applications won't know about this interface;
+ * they will provide an EntityResolver.
+ * <em>Transitional Mode</em> provide an EntityResolver2 and automatically
+ * get the benefit of its methods in any systems (parsers or other tools)
+ * supporting it, due to polymorphism.
+ * Both <em>Old Style</em> and <em>Transitional Mode</em> applications will
+ * work with any SAX2 parser.
+ * <em>New style</em> applications will fail to run except on SAX2 parsers
+ * that support this particular feature.
+ * They will insist that feature flag have a value of "true", and the
+ * EntityResolver2 implementation they provide  might throw an exception
+ * if the original SAX 1.0 style entity resolution method is invoked.
+ * </p>
+ *
+ * @see org.xml.sax.XMLReader#setEntityResolver
+ *
+ * @since SAX 2.0 (extensions 1.1 alpha)
+ * @author David Brownell
+ * @version TBD
+ */
+public interface EntityResolver2 extends EntityResolver
+{
+    /**
+     * Allows applications to provide an external subset for documents
+     * that don't explicitly define one.  Documents with DOCTYPE declarations
+     * that omit an external subset can thus augment the declarations
+     * available for validation, entity processing, and attribute processing
+     * (normalization, defaulting, and reporting types including ID).
+     * This augmentation is reported
+     * through the {@link LexicalHandler#startDTD startDTD()} method as if
+     * the document text had originally included the external subset;
+     * this callback is made before any internal subset data or errors
+     * are reported.</p>
+     *
+     * <p>This method can also be used with documents that have no DOCTYPE
+     * declaration.  When the root element is encountered,
+     * but no DOCTYPE declaration has been seen, this method is
+     * invoked.  If it returns a value for the external subset, that root
+     * element is declared to be the root element, giving the effect of
+     * splicing a DOCTYPE declaration at the end the prolog of a document
+     * that could not otherwise be valid.  The sequence of parser callbacks
+     * in that case logically resembles this:</p>
+     *
+     * <pre>
+     * ... comments and PIs from the prolog (as usual)
+     * startDTD ("rootName", source.getPublicId (), source.getSystemId ());
+     * startEntity ("[dtd]");
+     * ... declarations, comments, and PIs from the external subset
+     * endEntity ("[dtd]");
+     * endDTD ();
+     * ... then the rest of the document (as usual)
+     * startElement (..., "rootName", ...);
+     * </pre>
+     *
+     * <p>Note that the InputSource gets no further resolution.
+     * Implementations of this method may wish to invoke
+     * {@link #resolveEntity resolveEntity()} to gain benefits such as use
+     * of local caches of DTD entities.  Also, this method will never be
+     * used by a (non-validating) processor that is not including external
+     * parameter entities. </p>
+     *
+     * <p>Uses for this method include facilitating data validation when
+     * interoperating with XML processors that would always require
+     * undesirable network accesses for external entities, or which for
+     * other reasons adopt a "no DTDs" policy.
+     * Non-validation motives include forcing documents to include DTDs so
+     * that attributes are handled consistently.
+     * For example, an XPath processor needs to know which attibutes have
+     * type "ID" before it can process a widely used type of reference.</p>
+     * 
+     * <p><strong>Warning:</strong> Returning an external subset modifies
+     * the input document.  By providing definitions for general entities,
+     * it can make a malformed document appear to be well formed.
+     * </p>
+     *
+     * @param name Identifies the document root element.  This name comes
+     *    from a DOCTYPE declaration (where available) or from the actual
+     *    root element. 
+     * @param baseURI The document's base URI, serving as an additional
+     *    hint for selecting the external subset.  This is always an absolute
+     *    URI, unless it is null because the XMLReader was given an InputSource
+     *    without one.
+     *
+     * @return An InputSource object describing the new external subset
+     *    to be used by the parser, or null to indicate that no external
+     *    subset is provided.
+     *
+     * @exception SAXException Any SAX exception, possibly wrapping
+     *    another exception.
+     * @exception IOException Probably indicating a failure to create
+     *    a new InputStream or Reader, or an illegal URL.
+     */
+    public InputSource getExternalSubset (String name, String baseURI)
+    throws SAXException, IOException;
+
+    /**
+     * Allows applications to map references to external entities into input
+     * sources, or tell the parser it should use conventional URI resolution.
+     * This method is only called for external entities which have been
+     * properly declared.
+     * This method provides more flexibility than the {@link EntityResolver}
+     * interface, supporting implementations of more complex catalogue
+     * schemes such as the one defined by the <a href=
+    "http://www.oasis-open.org/committees/entity/spec-2001-08-06.html"
+    >OASIS XML Catalogs</a> specification.</p>
+     *
+     * <p>Parsers configured to use this resolver method will call it
+     * to determine the input source to use for any external entity
+     * being included because of a reference in the XML text.
+     * That excludes the document entity, and any external entity returned
+     * by {@link #getExternalSubset getExternalSubset()}.
+     * When a (non-validating) processor is configured not to include
+     * a class of entities (parameter or general) through use of feature
+     * flags, this method is not invoked for such entities.  </p>
+     *
+     * <p>Note that the entity naming scheme used here is the same one
+     * used in the {@link LexicalHandler}, or in the {@link
+    org.xml.sax.ContentHandler#skippedEntity
+    ContentHandler.skippedEntity()}
+     * method. </p>
+     *
+     * @param name Identifies the external entity being resolved.
+     *    Either "[dtd]" for the external subset, or a name starting
+     *    with "%" to indicate a parameter entity, or else the name of
+     *    a general entity.  This is never null when invoked by a SAX2
+     *    parser.
+     * @param publicId The public identifier of the external entity being
+     *    referenced (normalized as required by the XML specification), or
+     *    null if none was supplied.
+     * @param baseURI The URI with respect to which relative systemIDs
+     *    are interpreted.  This is always an absolute URI, unless it is
+     *    null (likely because the XMLReader was given an InputSource without
+     *  one).  This URI is defined by the XML specification to be the one
+     *    associated with the "&lt;" starting the relevant declaration.
+     * @param systemId The system identifier of the external entity
+     *    being referenced; either a relative or absolute URI.
+     *  This is never null when invoked by a SAX2 parser; only declared
+     *    entities, and any external subset, are resolved by such parsers.
+     *
+     * @return An InputSource object describing the new input source to
+     *    be used by the parser.  Returning null directs the parser to
+     *    resolve the system ID against the base URI and open a connection
+     *    to resulting URI.
+     *
+     * @exception SAXException Any SAX exception, possibly wrapping
+     *    another exception.
+     * @exception IOException Probably indicating a failure to create
+     *    a new InputStream or Reader, or an illegal URL.
+     */
+    public InputSource resolveEntity (
+        String name,
+        String publicId,
+        String baseURI,
+        String systemId
+    ) throws SAXException, IOException;
+}
diff --git a/xml/src/main/java/org/xml/sax/ext/LexicalHandler.java b/xml/src/main/java/org/xml/sax/ext/LexicalHandler.java
new file mode 100644
index 0000000..e551b61
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ext/LexicalHandler.java
@@ -0,0 +1,212 @@
+// LexicalHandler.java - optional handler for lexical parse events.
+// http://www.saxproject.org
+// Public Domain: no warranty.
+// $Id: LexicalHandler.java,v 1.5 2002/01/30 21:00:44 dbrownell Exp $
+
+package org.xml.sax.ext;
+
+import org.xml.sax.SAXException;
+
+/**
+ * SAX2 extension handler for lexical events.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This is an optional extension handler for SAX2 to provide
+ * lexical information about an XML document, such as comments
+ * and CDATA section boundaries.
+ * XML readers are not required to recognize this handler, and it
+ * is not part of core-only SAX2 distributions.</p>
+ *
+ * <p>The events in the lexical handler apply to the entire document,
+ * not just to the document element, and all lexical handler events
+ * must appear between the content handler's startDocument and
+ * endDocument events.</p>
+ *
+ * <p>To set the LexicalHandler for an XML reader, use the
+ * {@link org.xml.sax.XMLReader#setProperty setProperty} method
+ * with the property name
+ * <code>http://xml.org/sax/properties/lexical-handler</code>
+ * and an object implementing this interface (or null) as the value.
+ * If the reader does not report lexical events, it will throw a
+ * {@link org.xml.sax.SAXNotRecognizedException SAXNotRecognizedException}
+ * when you attempt to register the handler.</p>
+ *
+ * @since SAX 2.0 (extensions 1.0)
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ */
+public interface LexicalHandler
+{
+
+    /**
+     * Report the start of DTD declarations, if any.
+     *
+     * <p>This method is intended to report the beginning of the
+     * DOCTYPE declaration; if the document has no DOCTYPE declaration,
+     * this method will not be invoked.</p>
+     *
+     * <p>All declarations reported through 
+     * {@link org.xml.sax.DTDHandler DTDHandler} or
+     * {@link org.xml.sax.ext.DeclHandler DeclHandler} events must appear
+     * between the startDTD and {@link #endDTD endDTD} events.
+     * Declarations are assumed to belong to the internal DTD subset
+     * unless they appear between {@link #startEntity startEntity}
+     * and {@link #endEntity endEntity} events.  Comments and
+     * processing instructions from the DTD should also be reported
+     * between the startDTD and endDTD events, in their original 
+     * order of (logical) occurrence; they are not required to
+     * appear in their correct locations relative to DTDHandler
+     * or DeclHandler events, however.</p>
+     *
+     * <p>Note that the start/endDTD events will appear within
+     * the start/endDocument events from ContentHandler and
+     * before the first 
+     * {@link org.xml.sax.ContentHandler#startElement startElement}
+     * event.</p>
+     *
+     * @param name The document type name.
+     * @param publicId The declared public identifier for the
+     *        external DTD subset, or null if none was declared.
+     * @param systemId The declared system identifier for the
+     *        external DTD subset, or null if none was declared.
+     *        (Note that this is not resolved against the document
+     *        base URI.)
+     * @exception SAXException The application may raise an
+     *            exception.
+     * @see #endDTD
+     * @see #startEntity
+     */
+    public abstract void startDTD (String name, String publicId,
+                   String systemId)
+    throws SAXException;
+
+
+    /**
+     * Report the end of DTD declarations.
+     *
+     * <p>This method is intended to report the end of the
+     * DOCTYPE declaration; if the document has no DOCTYPE declaration,
+     * this method will not be invoked.</p>
+     *
+     * @exception SAXException The application may raise an exception.
+     * @see #startDTD
+     */
+    public abstract void endDTD ()
+    throws SAXException;
+
+
+    /**
+     * Report the beginning of some internal and external XML entities.
+     *
+     * <p>The reporting of parameter entities (including
+     * the external DTD subset) is optional, and SAX2 drivers that
+     * report LexicalHandler events may not implement it; you can use the
+     * <code
+     * >http://xml.org/sax/features/lexical-handler/parameter-entities</code>
+     * feature to query or control the reporting of parameter entities.</p>
+     *
+     * <p>General entities are reported with their regular names,
+     * parameter entities have '%' prepended to their names, and 
+     * the external DTD subset has the pseudo-entity name "[dtd]".</p>
+     *
+     * <p>When a SAX2 driver is providing these events, all other 
+     * events must be properly nested within start/end entity 
+     * events.  There is no additional requirement that events from 
+     * {@link org.xml.sax.ext.DeclHandler DeclHandler} or
+     * {@link org.xml.sax.DTDHandler DTDHandler} be properly ordered.</p>
+     *
+     * <p>Note that skipped entities will be reported through the
+     * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity}
+     * event, which is part of the ContentHandler interface.</p>
+     *
+     * <p>Because of the streaming event model that SAX uses, some
+     * entity boundaries cannot be reported under any 
+     * circumstances:</p>
+     *
+     * <ul>
+     * <li>general entities within attribute values</li>
+     * <li>parameter entities within declarations</li>
+     * </ul>
+     *
+     * <p>These will be silently expanded, with no indication of where
+     * the original entity boundaries were.</p>
+     *
+     * <p>Note also that the boundaries of character references (which
+     * are not really entities anyway) are not reported.</p>
+     *
+     * <p>All start/endEntity events must be properly nested.
+     *
+     * @param name The name of the entity.  If it is a parameter
+     *        entity, the name will begin with '%', and if it is the
+     *        external DTD subset, it will be "[dtd]".
+     * @exception SAXException The application may raise an exception.
+     * @see #endEntity
+     * @see org.xml.sax.ext.DeclHandler#internalEntityDecl
+     * @see org.xml.sax.ext.DeclHandler#externalEntityDecl 
+     */
+    public abstract void startEntity (String name)
+    throws SAXException;
+
+
+    /**
+     * Report the end of an entity.
+     *
+     * @param name The name of the entity that is ending.
+     * @exception SAXException The application may raise an exception.
+     * @see #startEntity
+     */
+    public abstract void endEntity (String name)
+    throws SAXException;
+
+
+    /**
+     * Report the start of a CDATA section.
+     *
+     * <p>The contents of the CDATA section will be reported through
+     * the regular {@link org.xml.sax.ContentHandler#characters
+     * characters} event; this event is intended only to report
+     * the boundary.</p>
+     *
+     * @exception SAXException The application may raise an exception.
+     * @see #endCDATA
+     */
+    public abstract void startCDATA ()
+    throws SAXException;
+
+
+    /**
+     * Report the end of a CDATA section.
+     *
+     * @exception SAXException The application may raise an exception.
+     * @see #startCDATA
+     */
+    public abstract void endCDATA ()
+    throws SAXException;
+
+
+    /**
+     * Report an XML comment anywhere in the document.
+     *
+     * <p>This callback will be used for comments inside or outside the
+     * document element, including comments in the external DTD
+     * subset (if read).  Comments in the DTD must be properly
+     * nested inside start/endDTD and start/endEntity events (if
+     * used).</p>
+     *
+     * @param ch An array holding the characters in the comment.
+     * @param start The starting position in the array.
+     * @param length The number of characters to use from the array.
+     * @exception SAXException The application may raise an exception.
+     */
+    public abstract void comment (char ch[], int start, int length)
+    throws SAXException;
+
+}
+
+// end of LexicalHandler.java
diff --git a/xml/src/main/java/org/xml/sax/ext/Locator2.java b/xml/src/main/java/org/xml/sax/ext/Locator2.java
new file mode 100644
index 0000000..6de9a16
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ext/Locator2.java
@@ -0,0 +1,75 @@
+// Locator2.java - extended Locator
+// http://www.saxproject.org
+// Public Domain: no warranty.
+// $Id: Locator2.java,v 1.5 2004/03/17 14:30:10 dmegginson Exp $
+
+package org.xml.sax.ext;
+
+import org.xml.sax.Locator;
+
+
+/**
+ * SAX2 extension to augment the entity information provided 
+ * though a {@link Locator}.
+ * If an implementation supports this extension, the Locator
+ * provided in {@link org.xml.sax.ContentHandler#setDocumentLocator
+ * ContentHandler.setDocumentLocator() } will implement this
+ * interface, and the
+ * <em>http://xml.org/sax/features/use-locator2</em> feature
+ * flag will have the value <em>true</em>.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * </blockquote>
+ *
+ * <p> XMLReader implementations are not required to support this
+ * information, and it is not part of core-only SAX2 distributions.</p>
+ *
+ * @since SAX 2.0 (extensions 1.1 alpha)
+ * @author David Brownell
+ * @version TBS
+ */
+public interface Locator2 extends Locator
+{
+    /**
+     * Returns the version of XML used for the entity.  This will
+     * normally be the identifier from the current entity's
+     * <em>&lt;?xml&nbsp;version='...'&nbsp;...?&gt;</em> declaration,
+     * or be defaulted by the parser.
+     *
+     * @return Identifier for the XML version being used to interpret
+     * the entity's text, or null if that information is not yet
+     * available in the current parsing state.
+     */
+    public String getXMLVersion ();
+
+    /**
+     * Returns the name of the character encoding for the entity.
+     * If the encoding was declared externally (for example, in a MIME
+     * Content-Type header), that will be the name returned.  Else if there
+     * was an <em>&lt;?xml&nbsp;...encoding='...'?&gt;</em> declaration at
+     * the start of the document, that encoding name will be returned.
+     * Otherwise the encoding will been inferred (normally to be UTF-8, or
+     * some UTF-16 variant), and that inferred name will be returned.
+     *
+     * <p>When an {@link org.xml.sax.InputSource InputSource} is used
+     * to provide an entity's character stream, this method returns the
+     * encoding provided in that input stream.
+     *
+     * <p> Note that some recent W3C specifications require that text
+     * in some encodings be normalized, using Unicode Normalization
+     * Form C, before processing.  Such normalization must be performed
+     * by applications, and would normally be triggered based on the
+     * value returned by this method.
+     *
+     * <p> Encoding names may be those used by the underlying JVM,
+     * and comparisons should be case-insensitive.
+     *
+     * @return Name of the character encoding being used to interpret
+     * * the entity's text, or null if this was not provided for a *
+     * character stream passed through an InputSource or is otherwise
+     * not yet available in the current parsing state.
+     */
+    public String getEncoding ();
+}
diff --git a/xml/src/main/java/org/xml/sax/ext/Locator2Impl.java b/xml/src/main/java/org/xml/sax/ext/Locator2Impl.java
new file mode 100644
index 0000000..91f912a
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ext/Locator2Impl.java
@@ -0,0 +1,105 @@
+// Locator2Impl.java - extended LocatorImpl
+// http://www.saxproject.org
+// Public Domain: no warranty.
+// $Id: Locator2Impl.java,v 1.3 2004/04/26 17:34:35 dmegginson Exp $
+
+package org.xml.sax.ext;
+
+import org.xml.sax.Locator;
+import org.xml.sax.helpers.LocatorImpl;
+
+
+/**
+ * SAX2 extension helper for holding additional Entity information,
+ * implementing the {@link Locator2} interface.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * </blockquote>
+ *
+ * <p> This is not part of core-only SAX2 distributions.</p>
+ *
+ * @since SAX 2.0.2
+ * @author David Brownell
+ * @version TBS
+ */
+public class Locator2Impl extends LocatorImpl implements Locator2
+{
+    private String    encoding;
+    private String    version;
+
+
+    /**
+     * Construct a new, empty Locator2Impl object.
+     * This will not normally be useful, since the main purpose
+     * of this class is to make a snapshot of an existing Locator.
+     */
+    public Locator2Impl () { }
+
+    /**
+     * Copy an existing Locator or Locator2 object.
+     * If the object implements Locator2, values of the
+     * <em>encoding</em> and <em>version</em>strings are copied,
+     * otherwise they set to <em>null</em>. 
+     *
+     * @param locator The existing Locator object.
+     */
+    public Locator2Impl (Locator locator)
+    {
+    super (locator);
+    if (locator instanceof Locator2) {
+        Locator2    l2 = (Locator2) locator;
+
+        version = l2.getXMLVersion ();
+        encoding = l2.getEncoding ();
+    }
+    }
+
+    ////////////////////////////////////////////////////////////////////
+    // Locator2 method implementations
+    ////////////////////////////////////////////////////////////////////
+    
+    /**
+     * Returns the current value of the version property.
+     *
+     * @return the current value of the version property.
+     *
+     * @see #setXMLVersion
+     */
+    public String getXMLVersion ()
+    { return version; }
+
+    /**
+     * Returns the current value of the encoding property.
+     * 
+     * @return the current value of the encoding property.
+     *
+     * @see #setEncoding
+     */
+    public String getEncoding ()
+    { return encoding; }
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Setters 
+    ////////////////////////////////////////////////////////////////////
+    
+    /**
+     * Assigns the current value of the version property.
+     *
+     * @param version the new "version" value
+     * @see #getXMLVersion
+     */
+    public void setXMLVersion (String version)
+    { this.version = version; }
+
+    /**
+     * Assigns the current value of the encoding property.
+     *
+     * @param encoding the new "encoding" value
+     * @see #getEncoding
+     */
+    public void setEncoding (String encoding)
+    { this.encoding = encoding; }
+}
diff --git a/xml/src/main/java/org/xml/sax/ext/package.html b/xml/src/main/java/org/xml/sax/ext/package.html
new file mode 100644
index 0000000..9b79d77
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/ext/package.html
@@ -0,0 +1,48 @@
+<HTML><HEAD>
+<!-- $Id: package.html,v 1.8 2002/01/30 21:00:44 dbrownell Exp $ -->
+</HEAD><BODY>
+
+<p>
+This package contains interfaces to SAX2 facilities that
+conformant SAX drivers won't necessarily support.
+
+<p>See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+for more information about SAX.</p>
+
+<p> This package is independent of the SAX2 core, though the functionality
+exposed generally needs to be implemented within a parser core.
+That independence has several consequences:</p>
+
+<ul>
+
+<li>SAX2 drivers are <em>not</em> required to recognize these handlers.
+</li>
+
+<li>You cannot assume that the class files will be present in every SAX2
+installation.</li>
+
+<li>This package may be updated independently of SAX2 (i.e. new
+handlers and classes may be added without updating SAX2 itself).</li>
+
+<li>The new handlers are not implemented by the SAX2
+<code>org.xml.sax.helpers.DefaultHandler</code> or
+<code>org.xml.sax.helpers.XMLFilterImpl</code> classes.
+You can subclass these if you need such behavior, or
+use the helper classes found here.</li>
+
+<li>The handlers need to be registered differently than core SAX2
+handlers.</li>
+
+</ul>
+
+<p>This package, SAX2-ext, is a standardized extension to SAX2.  It is
+designed both to allow SAX parsers to pass certain types of information
+to applications, and to serve as a simple model for other SAX2 parser
+extension packages.  Not all such extension packages should need to
+be recognized directly by parsers, however.
+As an example, most validation systems can be cleanly layered on top
+of parsers supporting the standardized SAX2 interfaces.  </p>
+
+@since Android 1.0
+
+</BODY></HTML>
diff --git a/xml/src/main/java/org/xml/sax/helpers/AttributeListImpl.java b/xml/src/main/java/org/xml/sax/helpers/AttributeListImpl.java
new file mode 100644
index 0000000..fb4aee3
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/AttributeListImpl.java
@@ -0,0 +1,314 @@
+// SAX default implementation for AttributeList.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: AttributeListImpl.java,v 1.6 2002/01/30 20:52:22 dbrownell Exp $
+
+package org.xml.sax.helpers;
+
+import org.xml.sax.AttributeList;
+
+import java.util.Vector;
+
+
+/**
+ * Default implementation for AttributeList.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>AttributeList implements the deprecated SAX1 {@link
+ * org.xml.sax.AttributeList AttributeList} interface, and has been
+ * replaced by the new SAX2 {@link org.xml.sax.helpers.AttributesImpl
+ * AttributesImpl} interface.</p>
+ *
+ * <p>This class provides a convenience implementation of the SAX
+ * {@link org.xml.sax.AttributeList AttributeList} interface.  This 
+ * implementation is useful both for SAX parser writers, who can use 
+ * it to provide attributes to the application, and for SAX application 
+ * writers, who can use it to create a persistent copy of an element's 
+ * attribute specifications:</p>
+ *
+ * <pre>
+ * private AttributeList myatts;
+ *
+ * public void startElement (String name, AttributeList atts)
+ * {
+ *              // create a persistent copy of the attribute list
+ *              // for use outside this method
+ *   myatts = new AttributeListImpl(atts);
+ *   [...]
+ * }
+ * </pre>
+ *
+ * <p>Please note that SAX parsers are not required to use this
+ * class to provide an implementation of AttributeList; it is
+ * supplied only as an optional convenience.  In particular, 
+ * parser writers are encouraged to invent more efficient
+ * implementations.</p>
+ *
+ * @deprecated This class implements a deprecated interface,
+ *             {@link org.xml.sax.AttributeList AttributeList};
+ *             that interface has been replaced by
+ *             {@link org.xml.sax.Attributes Attributes},
+ *             which is implemented in the
+ *             {@link org.xml.sax.helpers.AttributesImpl 
+ *            AttributesImpl} helper class.
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.AttributeList
+ * @see org.xml.sax.DocumentHandler#startElement 
+ */
+public class AttributeListImpl implements AttributeList
+{
+    
+    /**
+     * Create an empty attribute list.
+     *
+     * <p>This constructor is most useful for parser writers, who
+     * will use it to create a single, reusable attribute list that
+     * can be reset with the clear method between elements.</p>
+     *
+     * @see #addAttribute
+     * @see #clear
+     */
+    public AttributeListImpl ()
+    {
+    }
+    
+    
+    /**
+     * Construct a persistent copy of an existing attribute list.
+     *
+     * <p>This constructor is most useful for application writers,
+     * who will use it to create a persistent copy of an existing
+     * attribute list.</p>
+     *
+     * @param atts The attribute list to copy
+     * @see org.xml.sax.DocumentHandler#startElement
+     */
+    public AttributeListImpl (AttributeList atts)
+    {
+    setAttributeList(atts);
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Methods specific to this class.
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Set the attribute list, discarding previous contents.
+     *
+     * <p>This method allows an application writer to reuse an
+     * attribute list easily.</p>
+     *
+     * @param atts The attribute list to copy.
+     */
+    public void setAttributeList (AttributeList atts)
+    {
+    int count = atts.getLength();
+    
+    clear();
+    
+    for (int i = 0; i < count; i++) {
+        addAttribute(atts.getName(i), atts.getType(i), atts.getValue(i));
+    }
+    }
+    
+    
+    /**
+     * Add an attribute to an attribute list.
+     *
+     * <p>This method is provided for SAX parser writers, to allow them
+     * to build up an attribute list incrementally before delivering
+     * it to the application.</p>
+     *
+     * @param name The attribute name.
+     * @param type The attribute type ("NMTOKEN" for an enumeration).
+     * @param value The attribute value (must not be null).
+     * @see #removeAttribute
+     * @see org.xml.sax.DocumentHandler#startElement
+     */
+    public void addAttribute (String name, String type, String value)
+    {
+    names.addElement(name);
+    types.addElement(type);
+    values.addElement(value);
+    }
+    
+    
+    /**
+     * Remove an attribute from the list.
+     *
+     * <p>SAX application writers can use this method to filter an
+     * attribute out of an AttributeList.  Note that invoking this
+     * method will change the length of the attribute list and
+     * some of the attribute's indices.</p>
+     *
+     * <p>If the requested attribute is not in the list, this is
+     * a no-op.</p>
+     *
+     * @param name The attribute name.
+     * @see #addAttribute
+     */
+    public void removeAttribute (String name)
+    {
+    int i = names.indexOf(name);
+    
+    if (i >= 0) {
+        names.removeElementAt(i);
+        types.removeElementAt(i);
+        values.removeElementAt(i);
+    }
+    }
+    
+    
+    /**
+     * Clear the attribute list.
+     *
+     * <p>SAX parser writers can use this method to reset the attribute
+     * list between DocumentHandler.startElement events.  Normally,
+     * it will make sense to reuse the same AttributeListImpl object
+     * rather than allocating a new one each time.</p>
+     *
+     * @see org.xml.sax.DocumentHandler#startElement
+     */
+    public void clear ()
+    {
+    names.removeAllElements();
+    types.removeAllElements();
+    values.removeAllElements();
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.AttributeList
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Return the number of attributes in the list.
+     *
+     * @return The number of attributes in the list.
+     * @see org.xml.sax.AttributeList#getLength
+     */
+    public int getLength ()
+    {
+    return names.size();
+    }
+    
+    
+    /**
+     * Get the name of an attribute (by position).
+     *
+     * @param i The position of the attribute in the list.
+     * @return The attribute name as a string, or null if there
+     *         is no attribute at that position.
+     * @see org.xml.sax.AttributeList#getName(int)
+     */
+    public String getName (int i)
+    {
+    if (i < 0) {
+        return null;
+    }
+    try {
+        return (String)names.elementAt(i);
+    } catch (ArrayIndexOutOfBoundsException e) {
+        return null;
+    }
+    }
+    
+    
+    /**
+     * Get the type of an attribute (by position).
+     *
+     * @param i The position of the attribute in the list.
+     * @return The attribute type as a string ("NMTOKEN" for an
+     *         enumeration, and "CDATA" if no declaration was
+     *         read), or null if there is no attribute at
+     *         that position.
+     * @see org.xml.sax.AttributeList#getType(int)
+     */
+    public String getType (int i)
+    {
+    if (i < 0) {
+        return null;
+    }
+    try {
+        return (String)types.elementAt(i);
+    } catch (ArrayIndexOutOfBoundsException e) {
+        return null;
+    }
+    }
+    
+    
+    /**
+     * Get the value of an attribute (by position).
+     *
+     * @param i The position of the attribute in the list.
+     * @return The attribute value as a string, or null if
+     *         there is no attribute at that position.
+     * @see org.xml.sax.AttributeList#getValue(int)
+     */
+    public String getValue (int i)
+    {
+    if (i < 0) {
+        return null;
+    }
+    try {
+        return (String)values.elementAt(i);
+    } catch (ArrayIndexOutOfBoundsException e) {
+        return null;
+    }
+    }
+    
+    
+    /**
+     * Get the type of an attribute (by name).
+     *
+     * @param name The attribute name.
+     * @return The attribute type as a string ("NMTOKEN" for an
+     *         enumeration, and "CDATA" if no declaration was
+     *         read).
+     * @see org.xml.sax.AttributeList#getType(java.lang.String)
+     */
+    public String getType (String name)
+    {
+    return getType(names.indexOf(name));
+    }
+    
+    
+    /**
+     * Get the value of an attribute (by name).
+     *
+     * @param name The attribute name.
+     * @return the named attribute's value or null, if the attribute does not
+     *         exist.
+     * @see org.xml.sax.AttributeList#getValue(java.lang.String)
+     */
+    public String getValue (String name)
+    {
+    return getValue(names.indexOf(name));
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////////
+
+    Vector names = new Vector();
+    Vector types = new Vector();
+    Vector values = new Vector();
+
+}
+
+// end of AttributeListImpl.java
diff --git a/xml/src/main/java/org/xml/sax/helpers/AttributesImpl.java b/xml/src/main/java/org/xml/sax/helpers/AttributesImpl.java
new file mode 100644
index 0000000..b740e23
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/AttributesImpl.java
@@ -0,0 +1,618 @@
+// AttributesImpl.java - default implementation of Attributes.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the public domain.
+// $Id: AttributesImpl.java,v 1.9 2002/01/30 20:52:24 dbrownell Exp $
+
+package org.xml.sax.helpers;
+
+import org.xml.sax.Attributes;
+
+
+/**
+ * Default implementation of the Attributes interface.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class provides a default implementation of the SAX2
+ * {@link org.xml.sax.Attributes Attributes} interface, with the 
+ * addition of manipulators so that the list can be modified or 
+ * reused.</p>
+ *
+ * <p>There are two typical uses of this class:</p>
+ *
+ * <ol>
+ * <li>to take a persistent snapshot of an Attributes object
+ *  in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li>
+ * <li>to construct or modify an Attributes object in a SAX2 driver or filter.</li>
+ * </ol>
+ *
+ * <p>This class replaces the now-deprecated SAX1 {@link 
+ * org.xml.sax.helpers.AttributeListImpl AttributeListImpl}
+ * class; in addition to supporting the updated Attributes
+ * interface rather than the deprecated {@link org.xml.sax.AttributeList
+ * AttributeList} interface, it also includes a much more efficient 
+ * implementation using a single array rather than a set of Vectors.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ */
+public class AttributesImpl implements Attributes
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Constructors.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Construct a new, empty AttributesImpl object.
+     */
+    public AttributesImpl ()
+    {
+    length = 0;
+    data = null;
+    }
+
+
+    /**
+     * Copy an existing Attributes object.
+     *
+     * <p>This constructor is especially useful inside a
+     * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
+     *
+     * @param atts The existing Attributes object.
+     */
+    public AttributesImpl (Attributes atts)
+    {
+    setAttributes(atts);
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.Attributes.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Return the number of attributes in the list.
+     *
+     * @return The number of attributes in the list.
+     * @see org.xml.sax.Attributes#getLength
+     */
+    public int getLength ()
+    {
+    return length;
+    }
+
+
+    /**
+     * Return an attribute's Namespace URI.
+     *
+     * @param index The attribute's index (zero-based).
+     * @return The Namespace URI, the empty string if none is
+     *         available, or null if the index is out of range.
+     * @see org.xml.sax.Attributes#getURI
+     */
+    public String getURI (int index)
+    {
+    if (index >= 0 && index < length) {
+        return data[index*5];
+    } else {
+        return null;
+    }
+    }
+
+
+    /**
+     * Return an attribute's local name.
+     *
+     * @param index The attribute's index (zero-based).
+     * @return The attribute's local name, the empty string if 
+     *         none is available, or null if the index if out of range.
+     * @see org.xml.sax.Attributes#getLocalName
+     */
+    public String getLocalName (int index)
+    {
+    if (index >= 0 && index < length) {
+        return data[index*5+1];
+    } else {
+        return null;
+    }
+    }
+
+
+    /**
+     * Return an attribute's qualified (prefixed) name.
+     *
+     * @param index The attribute's index (zero-based).
+     * @return The attribute's qualified name, the empty string if 
+     *         none is available, or null if the index is out of bounds.
+     * @see org.xml.sax.Attributes#getQName
+     */
+    public String getQName (int index)
+    {
+    if (index >= 0 && index < length) {
+        return data[index*5+2];
+    } else {
+        return null;
+    }
+    }
+
+
+    /**
+     * Return an attribute's type by index.
+     *
+     * @param index The attribute's index (zero-based).
+     * @return The attribute's type, "CDATA" if the type is unknown, or null
+     *         if the index is out of bounds.
+     * @see org.xml.sax.Attributes#getType(int)
+     */
+    public String getType (int index)
+    {
+    if (index >= 0 && index < length) {
+        return data[index*5+3];
+    } else {
+        return null;
+    }
+    }
+
+
+    /**
+     * Return an attribute's value by index.
+     *
+     * @param index The attribute's index (zero-based).
+     * @return The attribute's value or null if the index is out of bounds.
+     * @see org.xml.sax.Attributes#getValue(int)
+     */
+    public String getValue (int index)
+    {
+    if (index >= 0 && index < length) {
+        return data[index*5+4];
+    } else {
+        return null;
+    }
+    }
+
+
+    /**
+     * Look up an attribute's index by Namespace name.
+     *
+     * <p>In many cases, it will be more efficient to look up the name once and
+     * use the index query methods rather than using the name query methods
+     * repeatedly.</p>
+     *
+     * @param uri The attribute's Namespace URI, or the empty
+     *        string if none is available.
+     * @param localName The attribute's local name.
+     * @return The attribute's index, or -1 if none matches.
+     * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
+     */
+    public int getIndex (String uri, String localName)
+    {
+    int max = length * 5;
+    for (int i = 0; i < max; i += 5) {
+        if (data[i].equals(uri) && data[i+1].equals(localName)) {
+        return i / 5;
+        }
+    } 
+    return -1;
+    }
+
+
+    /**
+     * Look up an attribute's index by qualified (prefixed) name.
+     *
+     * @param qName The qualified name.
+     * @return The attribute's index, or -1 if none matches.
+     * @see org.xml.sax.Attributes#getIndex(java.lang.String)
+     */
+    public int getIndex (String qName)
+    {
+    int max = length * 5;
+    for (int i = 0; i < max; i += 5) {
+        if (data[i+2].equals(qName)) {
+        return i / 5;
+        }
+    } 
+    return -1;
+    }
+
+
+    /**
+     * Look up an attribute's type by Namespace-qualified name.
+     *
+     * @param uri The Namespace URI, or the empty string for a name
+     *        with no explicit Namespace URI.
+     * @param localName The local name.
+     * @return The attribute's type, or null if there is no
+     *         matching attribute.
+     * @see org.xml.sax.Attributes#getType(java.lang.String,java.lang.String)
+     */
+    public String getType (String uri, String localName)
+    {
+    int max = length * 5;
+    for (int i = 0; i < max; i += 5) {
+        if (data[i].equals(uri) && data[i+1].equals(localName)) {
+        return data[i+3];
+        }
+    } 
+    return null;
+    }
+
+
+    /**
+     * Look up an attribute's type by qualified (prefixed) name.
+     *
+     * @param qName The qualified name.
+     * @return The attribute's type, or null if there is no
+     *         matching attribute.
+     * @see org.xml.sax.Attributes#getType(java.lang.String)
+     */
+    public String getType (String qName)
+    {
+    int max = length * 5;
+    for (int i = 0; i < max; i += 5) {
+        if (data[i+2].equals(qName)) {
+        return data[i+3];
+        }
+    }
+    return null;
+    }
+
+
+    /**
+     * Look up an attribute's value by Namespace-qualified name.
+     *
+     * @param uri The Namespace URI, or the empty string for a name
+     *        with no explicit Namespace URI.
+     * @param localName The local name.
+     * @return The attribute's value, or null if there is no
+     *         matching attribute.
+     * @see org.xml.sax.Attributes#getValue(java.lang.String,java.lang.String)
+     */
+    public String getValue (String uri, String localName)
+    {
+    int max = length * 5;
+    for (int i = 0; i < max; i += 5) {
+        if (data[i].equals(uri) && data[i+1].equals(localName)) {
+        return data[i+4];
+        }
+    }
+    return null;
+    }
+
+
+    /**
+     * Look up an attribute's value by qualified (prefixed) name.
+     *
+     * @param qName The qualified name.
+     * @return The attribute's value, or null if there is no
+     *         matching attribute.
+     * @see org.xml.sax.Attributes#getValue(java.lang.String)
+     */
+    public String getValue (String qName)
+    {
+    int max = length * 5;
+    for (int i = 0; i < max; i += 5) {
+        if (data[i+2].equals(qName)) {
+        return data[i+4];
+        }
+    }
+    return null;
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Manipulators.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Clear the attribute list for reuse.
+     *
+     * <p>Note that little memory is freed by this call:
+     * the current array is kept so it can be 
+     * reused.</p>
+     */
+    public void clear ()
+    {
+    if (data != null) {
+        for (int i = 0; i < (length * 5); i++)
+        data [i] = null;
+    }
+    length = 0;
+    }
+
+
+    /**
+     * Copy an entire Attributes object.
+     *
+     * <p>It may be more efficient to reuse an existing object
+     * rather than constantly allocating new ones.</p>
+     * 
+     * @param atts The attributes to copy.
+     */
+    public void setAttributes (Attributes atts)
+    {
+        clear();
+        length = atts.getLength();
+        if (length > 0) {
+            data = new String[length*5];
+            for (int i = 0; i < length; i++) {
+                data[i*5] = atts.getURI(i);
+                data[i*5+1] = atts.getLocalName(i);
+                data[i*5+2] = atts.getQName(i);
+                data[i*5+3] = atts.getType(i);
+                data[i*5+4] = atts.getValue(i);
+            }
+    }
+    }
+
+
+    /**
+     * Add an attribute to the end of the list.
+     *
+     * <p>For the sake of speed, this method does no checking
+     * to see if the attribute is already in the list: that is
+     * the responsibility of the application.</p>
+     *
+     * @param uri The Namespace URI, or the empty string if
+     *        none is available or Namespace processing is not
+     *        being performed.
+     * @param localName The local name, or the empty string if
+     *        Namespace processing is not being performed.
+     * @param qName The qualified (prefixed) name, or the empty string
+     *        if qualified names are not available.
+     * @param type The attribute type as a string.
+     * @param value The attribute value.
+     */
+    public void addAttribute (String uri, String localName, String qName,
+                  String type, String value)
+    {
+    ensureCapacity(length+1);
+    data[length*5] = uri;
+    data[length*5+1] = localName;
+    data[length*5+2] = qName;
+    data[length*5+3] = type;
+    data[length*5+4] = value;
+    length++;
+    }
+
+
+    /**
+     * Set an attribute in the list.
+     *
+     * <p>For the sake of speed, this method does no checking
+     * for name conflicts or well-formedness: such checks are the
+     * responsibility of the application.</p>
+     *
+     * @param index The index of the attribute (zero-based).
+     * @param uri The Namespace URI, or the empty string if
+     *        none is available or Namespace processing is not
+     *        being performed.
+     * @param localName The local name, or the empty string if
+     *        Namespace processing is not being performed.
+     * @param qName The qualified name, or the empty string
+     *        if qualified names are not available.
+     * @param type The attribute type as a string.
+     * @param value The attribute value.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not point to an attribute
+     *            in the list.
+     */
+    public void setAttribute (int index, String uri, String localName,
+                  String qName, String type, String value)
+    {
+    if (index >= 0 && index < length) {
+        data[index*5] = uri;
+        data[index*5+1] = localName;
+        data[index*5+2] = qName;
+        data[index*5+3] = type;
+        data[index*5+4] = value;
+    } else {
+        badIndex(index);
+    }
+    }
+
+
+    /**
+     * Remove an attribute from the list.
+     *
+     * @param index The index of the attribute (zero-based).
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not point to an attribute
+     *            in the list.
+     */
+    public void removeAttribute (int index)
+    {
+    if (index >= 0 && index < length) {
+        if (index < length - 1) {
+        System.arraycopy(data, (index+1)*5, data, index*5,
+                 (length-index-1)*5);
+        }
+        index = (length - 1) * 5;
+        data [index++] = null;
+        data [index++] = null;
+        data [index++] = null;
+        data [index++] = null;
+        data [index] = null;
+        length--;
+    } else {
+        badIndex(index);
+    }
+    }
+
+
+    /**
+     * Set the Namespace URI of a specific attribute.
+     *
+     * @param index The index of the attribute (zero-based).
+     * @param uri The attribute's Namespace URI, or the empty
+     *        string for none.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not point to an attribute
+     *            in the list.
+     */
+    public void setURI (int index, String uri)
+    {
+    if (index >= 0 && index < length) {
+        data[index*5] = uri;
+    } else {
+        badIndex(index);
+    }
+    }
+
+
+    /**
+     * Set the local name of a specific attribute.
+     *
+     * @param index The index of the attribute (zero-based).
+     * @param localName The attribute's local name, or the empty
+     *        string for none.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not point to an attribute
+     *            in the list.
+     */
+    public void setLocalName (int index, String localName)
+    {
+    if (index >= 0 && index < length) {
+        data[index*5+1] = localName;
+    } else {
+        badIndex(index);
+    }
+    }
+
+
+    /**
+     * Set the qualified name of a specific attribute.
+     *
+     * @param index The index of the attribute (zero-based).
+     * @param qName The attribute's qualified name, or the empty
+     *        string for none.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not point to an attribute
+     *            in the list.
+     */
+    public void setQName (int index, String qName)
+    {
+    if (index >= 0 && index < length) {
+        data[index*5+2] = qName;
+    } else {
+        badIndex(index);
+    }
+    }
+
+
+    /**
+     * Set the type of a specific attribute.
+     *
+     * @param index The index of the attribute (zero-based).
+     * @param type The attribute's type.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not point to an attribute
+     *            in the list.
+     */
+    public void setType (int index, String type)
+    {
+    if (index >= 0 && index < length) {
+        data[index*5+3] = type;
+    } else {
+        badIndex(index);
+    }
+    }
+
+
+    /**
+     * Set the value of a specific attribute.
+     *
+     * @param index The index of the attribute (zero-based).
+     * @param value The attribute's value.
+     * @exception java.lang.ArrayIndexOutOfBoundsException When the
+     *            supplied index does not point to an attribute
+     *            in the list.
+     */
+    public void setValue (int index, String value)
+    {
+    if (index >= 0 && index < length) {
+        data[index*5+4] = value;
+    } else {
+        badIndex(index);
+    }
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal methods.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Ensure the internal array's capacity.
+     *
+     * @param n The minimum number of attributes that the array must
+     *        be able to hold.
+     */
+    private void ensureCapacity (int n)    {
+        if (n <= 0) {
+            return;
+        }
+        int max;
+        if (data == null || data.length == 0) {
+            max = 25;
+        }
+        else if (data.length >= n * 5) {
+            return;
+        }
+        else {
+            max = data.length;
+        }
+        while (max < n * 5) {
+            max *= 2;
+        }
+
+        String newData[] = new String[max];
+        if (length > 0) {
+            System.arraycopy(data, 0, newData, 0, length*5);
+        }
+        data = newData;
+    }
+
+
+    /**
+     * Report a bad array index in a manipulator.
+     *
+     * @param index The index to report.
+     * @exception java.lang.ArrayIndexOutOfBoundsException Always.
+     */
+    private void badIndex (int index)
+    throws ArrayIndexOutOfBoundsException
+    {
+    String msg =
+        "Attempt to modify attribute at illegal index: " + index;
+    throw new ArrayIndexOutOfBoundsException(msg);
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////////
+
+    int length;
+    String data [];
+
+}
+
+// end of AttributesImpl.java
+
diff --git a/xml/src/main/java/org/xml/sax/helpers/DefaultHandler.java b/xml/src/main/java/org/xml/sax/helpers/DefaultHandler.java
new file mode 100644
index 0000000..8308be7
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/DefaultHandler.java
@@ -0,0 +1,467 @@
+// DefaultHandler.java - default implementation of the core handlers.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the public domain.
+// $Id: DefaultHandler.java,v 1.9 2004/04/26 17:34:35 dmegginson Exp $
+
+package org.xml.sax.helpers;
+
+import java.io.IOException;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+
+/**
+ * Default base class for SAX2 event handlers.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class is available as a convenience base class for SAX2
+ * applications: it provides default implementations for all of the
+ * callbacks in the four core SAX2 handler classes:</p>
+ *
+ * <ul>
+ * <li>{@link org.xml.sax.EntityResolver EntityResolver}</li>
+ * <li>{@link org.xml.sax.DTDHandler DTDHandler}</li>
+ * <li>{@link org.xml.sax.ContentHandler ContentHandler}</li>
+ * <li>{@link org.xml.sax.ErrorHandler ErrorHandler}</li>
+ * </ul>
+ *
+ * <p>Application writers can extend this class when they need to
+ * implement only part of an interface; parser writers can
+ * instantiate this class to provide default handlers when the
+ * application has not supplied its own.</p>
+ *
+ * <p>This class replaces the deprecated SAX1
+ * {@link org.xml.sax.HandlerBase HandlerBase} class.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson,
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.EntityResolver
+ * @see org.xml.sax.DTDHandler
+ * @see org.xml.sax.ContentHandler
+ * @see org.xml.sax.ErrorHandler
+ */
+public class DefaultHandler
+    implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler
+{
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of the EntityResolver interface.
+    ////////////////////////////////////////////////////////////////////
+    
+    /**
+     * Resolve an external entity.
+     *
+     * <p>Always return null, so that the parser will use the system
+     * identifier provided in the XML document.  This method implements
+     * the SAX default behaviour: application writers can override it
+     * in a subclass to do special translations such as catalog lookups
+     * or URI redirection.</p>
+     *
+     * @param publicId The public identifer, or null if none is
+     *                 available.
+     * @param systemId The system identifier provided in the XML 
+     *                 document.
+     * @return The new input source, or null to require the
+     *         default behaviour.
+     * @exception java.io.IOException If there is an error setting
+     *            up the new input source.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.EntityResolver#resolveEntity
+     */
+    public InputSource resolveEntity (String publicId, String systemId)
+    throws IOException, SAXException
+    {
+    return null;
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of DTDHandler interface.
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Receive notification of a notation declaration.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass if they wish to keep track of the notations
+     * declared in a document.</p>
+     *
+     * @param name The notation name.
+     * @param publicId The notation public identifier, or null if not
+     *                 available.
+     * @param systemId The notation system identifier.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DTDHandler#notationDecl
+     */
+    public void notationDecl (String name, String publicId, String systemId)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of an unparsed entity declaration.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to keep track of the unparsed entities
+     * declared in a document.</p>
+     *
+     * @param name The entity name.
+     * @param publicId The entity public identifier, or null if not
+     *                 available.
+     * @param systemId The entity system identifier.
+     * @param notationName The name of the associated notation.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.DTDHandler#unparsedEntityDecl
+     */
+    public void unparsedEntityDecl (String name, String publicId,
+                    String systemId, String notationName)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of ContentHandler interface.
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Receive a Locator object for document events.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass if they wish to store the locator for use
+     * with other document events.</p>
+     *
+     * @param locator A locator for all SAX document events.
+     * @see org.xml.sax.ContentHandler#setDocumentLocator
+     * @see org.xml.sax.Locator
+     */
+    public void setDocumentLocator (Locator locator)
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of the beginning of the document.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the beginning
+     * of a document (such as allocating the root node of a tree or
+     * creating an output file).</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#startDocument
+     */
+    public void startDocument ()
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of the end of the document.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the end
+     * of a document (such as finalising a tree or closing an output
+     * file).</p>
+     *
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#endDocument
+     */
+    public void endDocument ()
+    throws SAXException
+    {
+    // no op
+    }
+
+
+    /**
+     * Receive notification of the start of a Namespace mapping.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the start of
+     * each Namespace prefix scope (such as storing the prefix mapping).</p>
+     *
+     * @param prefix The Namespace prefix being declared.
+     * @param uri The Namespace URI mapped to the prefix.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#startPrefixMapping
+     */
+    public void startPrefixMapping (String prefix, String uri)
+    throws SAXException
+    {
+    // no op
+    }
+
+
+    /**
+     * Receive notification of the end of a Namespace mapping.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the end of
+     * each prefix mapping.</p>
+     *
+     * @param prefix The Namespace prefix being declared.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#endPrefixMapping
+     */
+    public void endPrefixMapping (String prefix)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of the start of an element.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the start of
+     * each element (such as allocating a new tree node or writing
+     * output to a file).</p>
+     *
+     * @param uri The Namespace URI, or the empty string if the
+     *        element has no Namespace URI or if Namespace
+     *        processing is not being performed.
+     * @param localName The local name (without prefix), or the
+     *        empty string if Namespace processing is not being
+     *        performed.
+     * @param qName The qualified name (with prefix), or the
+     *        empty string if qualified names are not available.
+     * @param attributes The attributes attached to the element.  If
+     *        there are no attributes, it shall be an empty
+     *        Attributes object.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#startElement
+     */
+    public void startElement (String uri, String localName,
+                  String qName, Attributes attributes)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of the end of an element.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions at the end of
+     * each element (such as finalising a tree node or writing
+     * output to a file).</p>
+     *
+     * @param uri The Namespace URI, or the empty string if the
+     *        element has no Namespace URI or if Namespace
+     *        processing is not being performed.
+     * @param localName The local name (without prefix), or the
+     *        empty string if Namespace processing is not being
+     *        performed.
+     * @param qName The qualified name (with prefix), or the
+     *        empty string if qualified names are not available.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#endElement
+     */
+    public void endElement (String uri, String localName, String qName)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of character data inside an element.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method to take specific actions for each chunk of character data
+     * (such as adding the data to a node or buffer, or printing it to
+     * a file).</p>
+     *
+     * @param ch The characters.
+     * @param start The start position in the character array.
+     * @param length The number of characters to use from the
+     *               character array.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#characters
+     */
+    public void characters (char ch[], int start, int length)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of ignorable whitespace in element content.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method to take specific actions for each chunk of ignorable
+     * whitespace (such as adding data to a node or buffer, or printing
+     * it to a file).</p>
+     *
+     * @param ch The whitespace characters.
+     * @param start The start position in the character array.
+     * @param length The number of characters to use from the
+     *               character array.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#ignorableWhitespace
+     */
+    public void ignorableWhitespace (char ch[], int start, int length)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of a processing instruction.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions for each
+     * processing instruction, such as setting status variables or
+     * invoking other methods.</p>
+     *
+     * @param target The processing instruction target.
+     * @param data The processing instruction data, or null if
+     *             none is supplied.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#processingInstruction
+     */
+    public void processingInstruction (String target, String data)
+    throws SAXException
+    {
+    // no op
+    }
+
+
+    /**
+     * Receive notification of a skipped entity.
+     *
+     * <p>By default, do nothing.  Application writers may override this
+     * method in a subclass to take specific actions for each
+     * processing instruction, such as setting status variables or
+     * invoking other methods.</p>
+     *
+     * @param name The name of the skipped entity.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ContentHandler#processingInstruction
+     */
+    public void skippedEntity (String name)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Default implementation of the ErrorHandler interface.
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Receive notification of a parser warning.
+     *
+     * <p>The default implementation does nothing.  Application writers
+     * may override this method in a subclass to take specific actions
+     * for each warning, such as inserting the message in a log file or
+     * printing it to the console.</p>
+     *
+     * @param e The warning information encoded as an exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ErrorHandler#warning
+     * @see org.xml.sax.SAXParseException
+     */
+    public void warning (SAXParseException e)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Receive notification of a recoverable parser error.
+     *
+     * <p>The default implementation does nothing.  Application writers
+     * may override this method in a subclass to take specific actions
+     * for each error, such as inserting the message in a log file or
+     * printing it to the console.</p>
+     *
+     * @param e The warning information encoded as an exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ErrorHandler#warning
+     * @see org.xml.sax.SAXParseException
+     */
+    public void error (SAXParseException e)
+    throws SAXException
+    {
+    // no op
+    }
+    
+    
+    /**
+     * Report a fatal XML parsing error.
+     *
+     * <p>The default implementation throws a SAXParseException.
+     * Application writers may override this method in a subclass if
+     * they need to take specific actions for each fatal error (such as
+     * collecting all of the errors into a single report): in any case,
+     * the application must stop all regular processing when this
+     * method is invoked, since the document is no longer reliable, and
+     * the parser may no longer report parsing events.</p>
+     *
+     * @param e The error information encoded as an exception.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @see org.xml.sax.ErrorHandler#fatalError
+     * @see org.xml.sax.SAXParseException
+     */
+    public void fatalError (SAXParseException e)
+    throws SAXException
+    {
+    throw e;
+    }
+    
+}
+
+// end of DefaultHandler.java
diff --git a/xml/src/main/java/org/xml/sax/helpers/LocatorImpl.java b/xml/src/main/java/org/xml/sax/helpers/LocatorImpl.java
new file mode 100644
index 0000000..18445bc
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/LocatorImpl.java
@@ -0,0 +1,214 @@
+// SAX default implementation for Locator.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: LocatorImpl.java,v 1.6 2002/01/30 20:52:27 dbrownell Exp $
+
+package org.xml.sax.helpers;
+
+import org.xml.sax.Locator;
+
+
+/**
+ * Provide an optional convenience implementation of Locator.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class is available mainly for application writers, who
+ * can use it to make a persistent snapshot of a locator at any
+ * point during a document parse:</p>
+ *
+ * <pre>
+ * Locator locator;
+ * Locator startloc;
+ *
+ * public void setLocator (Locator locator)
+ * {
+ *         // note the locator
+ *   this.locator = locator;
+ * }
+ *
+ * public void startDocument ()
+ * {
+ *         // save the location of the start of the document
+ *         // for future use.
+ *   Locator startloc = new LocatorImpl(locator);
+ * }
+ *</pre>
+ *
+ * <p>Normally, parser writers will not use this class, since it
+ * is more efficient to provide location information only when
+ * requested, rather than constantly updating a Locator object.</p>
+ *
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.Locator Locator
+ */
+public class LocatorImpl implements Locator
+{
+    
+    
+    /**
+     * Zero-argument constructor.
+     *
+     * <p>This will not normally be useful, since the main purpose
+     * of this class is to make a snapshot of an existing Locator.</p>
+     */
+    public LocatorImpl ()
+    {
+    }
+    
+    
+    /**
+     * Copy constructor.
+     *
+     * <p>Create a persistent copy of the current state of a locator.
+     * When the original locator changes, this copy will still keep
+     * the original values (and it can be used outside the scope of
+     * DocumentHandler methods).</p>
+     *
+     * @param locator The locator to copy.
+     */
+    public LocatorImpl (Locator locator)
+    {
+    setPublicId(locator.getPublicId());
+    setSystemId(locator.getSystemId());
+    setLineNumber(locator.getLineNumber());
+    setColumnNumber(locator.getColumnNumber());
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.Locator
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Return the saved public identifier.
+     *
+     * @return The public identifier as a string, or null if none
+     *         is available.
+     * @see org.xml.sax.Locator#getPublicId
+     * @see #setPublicId
+     */
+    public String getPublicId ()
+    {
+    return publicId;
+    }
+    
+    
+    /**
+     * Return the saved system identifier.
+     *
+     * @return The system identifier as a string, or null if none
+     *         is available.
+     * @see org.xml.sax.Locator#getSystemId
+     * @see #setSystemId
+     */
+    public String getSystemId ()
+    {
+    return systemId;
+    }
+    
+    
+    /**
+     * Return the saved line number (1-based).
+     *
+     * @return The line number as an integer, or -1 if none is available.
+     * @see org.xml.sax.Locator#getLineNumber
+     * @see #setLineNumber
+     */
+    public int getLineNumber ()
+    {
+    return lineNumber;
+    }
+    
+    
+    /**
+     * Return the saved column number (1-based).
+     *
+     * @return The column number as an integer, or -1 if none is available.
+     * @see org.xml.sax.Locator#getColumnNumber
+     * @see #setColumnNumber
+     */
+    public int getColumnNumber ()
+    {
+    return columnNumber;
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Setters for the properties (not in org.xml.sax.Locator)
+    ////////////////////////////////////////////////////////////////////
+    
+    
+    /**
+     * Set the public identifier for this locator.
+     *
+     * @param publicId The new public identifier, or null 
+     *        if none is available.
+     * @see #getPublicId
+     */
+    public void setPublicId (String publicId)
+    {
+    this.publicId = publicId;
+    }
+    
+    
+    /**
+     * Set the system identifier for this locator.
+     *
+     * @param systemId The new system identifier, or null 
+     *        if none is available.
+     * @see #getSystemId
+     */
+    public void setSystemId (String systemId)
+    {
+    this.systemId = systemId;
+    }
+    
+    
+    /**
+     * Set the line number for this locator (1-based).
+     *
+     * @param lineNumber The line number, or -1 if none is available.
+     * @see #getLineNumber
+     */
+    public void setLineNumber (int lineNumber)
+    {
+    this.lineNumber = lineNumber;
+    }
+    
+    
+    /**
+     * Set the column number for this locator (1-based).
+     *
+     * @param columnNumber The column number, or -1 if none is available.
+     * @see #getColumnNumber
+     */
+    public void setColumnNumber (int columnNumber)
+    {
+    this.columnNumber = columnNumber;
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////////
+    
+    private String publicId;
+    private String systemId;
+    private int lineNumber;
+    private int columnNumber;
+    
+}
+
+// end of LocatorImpl.java
diff --git a/xml/src/main/java/org/xml/sax/helpers/NamespaceSupport.java b/xml/src/main/java/org/xml/sax/helpers/NamespaceSupport.java
new file mode 100644
index 0000000..a737d1d
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/NamespaceSupport.java
@@ -0,0 +1,840 @@
+// NamespaceSupport.java - generic Namespace support for SAX.
+// http://www.saxproject.org
+// Written by David Megginson
+// This class is in the Public Domain.  NO WARRANTY!
+// $Id: NamespaceSupport.java,v 1.15 2004/04/26 17:34:35 dmegginson Exp $
+
+package org.xml.sax.helpers;
+
+import java.util.EmptyStackException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+
+/**
+ * Encapsulate Namespace logic for use by applications using SAX,
+ * or internally by SAX drivers.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class encapsulates the logic of Namespace processing: it
+ * tracks the declarations currently in force for each context and
+ * automatically processes qualified XML names into their Namespace
+ * parts; it can also be used in reverse for generating XML qnames
+ * from Namespaces.</p>
+ *
+ * <p>Namespace support objects are reusable, but the reset method
+ * must be invoked between each session.</p>
+ *
+ * <p>Here is a simple session:</p>
+ *
+ * <pre>
+ * String parts[] = new String[3];
+ * NamespaceSupport support = new NamespaceSupport();
+ *
+ * support.pushContext();
+ * support.declarePrefix("", "http://www.w3.org/1999/xhtml");
+ * support.declarePrefix("dc", "http://www.purl.org/dc#");
+ *
+ * parts = support.processName("p", parts, false);
+ * System.out.println("Namespace URI: " + parts[0]);
+ * System.out.println("Local name: " + parts[1]);
+ * System.out.println("Raw name: " + parts[2]);
+ *
+ * parts = support.processName("dc:title", parts, false);
+ * System.out.println("Namespace URI: " + parts[0]);
+ * System.out.println("Local name: " + parts[1]);
+ * System.out.println("Raw name: " + parts[2]);
+ *
+ * support.popContext();
+ * </pre>
+ *
+ * <p>Note that this class is optimized for the use case where most
+ * elements do not contain Namespace declarations: if the same
+ * prefix/URI mapping is repeated for each context (for example), this
+ * class will be somewhat less efficient.</p>
+ *
+ * <p>Although SAX drivers (parsers) may choose to use this class to
+ * implement namespace handling, they are not required to do so.
+ * Applications must track namespace information themselves if they
+ * want to use namespace information.
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ */
+public class NamespaceSupport
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Constants.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * The XML Namespace URI as a constant.
+     * The value is <code>http://www.w3.org/XML/1998/namespace</code>
+     * as defined in the "Namespaces in XML" * recommendation.
+     *
+     * <p>This is the Namespace URI that is automatically mapped
+     * to the "xml" prefix.</p>
+     */
+    public final static String XMLNS =
+    "http://www.w3.org/XML/1998/namespace";
+
+
+    /**
+     * The namespace declaration URI as a constant.
+     * The value is <code>http://www.w3.org/xmlns/2000/</code>, as defined
+     * in a backwards-incompatible erratum to the "Namespaces in XML"
+     * recommendation.  Because that erratum postdated SAX2, SAX2 defaults 
+     * to the original recommendation, and does not normally use this URI.
+     * 
+     *
+     * <p>This is the Namespace URI that is optionally applied to
+     * <em>xmlns</em> and <em>xmlns:*</em> attributes, which are used to
+     * declare namespaces.  </p>
+     *
+     * @since SAX 2.1alpha
+     * @see #setNamespaceDeclUris
+     * @see #isNamespaceDeclUris
+     */
+    public final static String NSDECL =
+    "http://www.w3.org/xmlns/2000/";
+
+
+    /**
+     * An empty enumeration.
+     */
+    private final static Enumeration EMPTY_ENUMERATION =
+    new Vector().elements();
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Constructor.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Create a new Namespace support object.
+     */
+    public NamespaceSupport ()
+    {
+    reset();
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Context management.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Reset this Namespace support object for reuse.
+     *
+     * <p>It is necessary to invoke this method before reusing the
+     * Namespace support object for a new session.  If namespace
+     * declaration URIs are to be supported, that flag must also
+     * be set to a non-default value.
+     * </p>
+     *
+     * @see #setNamespaceDeclUris
+     */
+    public void reset ()
+    {
+    contexts = new Context[32];
+    namespaceDeclUris = false;
+    contextPos = 0;
+    contexts[contextPos] = currentContext = new Context();
+    currentContext.declarePrefix("xml", XMLNS);
+    }
+
+
+    /**
+     * Start a new Namespace context.
+     * The new context will automatically inherit
+     * the declarations of its parent context, but it will also keep
+     * track of which declarations were made within this context.
+     *
+     * <p>Event callback code should start a new context once per element.
+     * This means being ready to call this in either of two places.
+     * For elements that don't include namespace declarations, the
+     * <em>ContentHandler.startElement()</em> callback is the right place.
+     * For elements with such a declaration, it'd done in the first
+     * <em>ContentHandler.startPrefixMapping()</em> callback.
+     * A boolean flag can be used to
+     * track whether a context has been started yet.  When either of
+     * those methods is called, it checks the flag to see if a new context
+     * needs to be started.  If so, it starts the context and sets the
+     * flag.  After <em>ContentHandler.startElement()</em>
+     * does that, it always clears the flag.
+     *
+     * <p>Normally, SAX drivers would push a new context at the beginning
+     * of each XML element.  Then they perform a first pass over the
+     * attributes to process all namespace declarations, making
+     * <em>ContentHandler.startPrefixMapping()</em> callbacks.
+     * Then a second pass is made, to determine the namespace-qualified
+     * names for all attributes and for the element name.
+     * Finally all the information for the
+     * <em>ContentHandler.startElement()</em> callback is available,
+     * so it can then be made.
+     *
+     * <p>The Namespace support object always starts with a base context
+     * already in force: in this context, only the "xml" prefix is
+     * declared.</p>
+     *
+     * @see org.xml.sax.ContentHandler
+     * @see #popContext
+     */
+    public void pushContext ()
+    {
+    int max = contexts.length;
+
+    contexts [contextPos].declsOK = false;
+    contextPos++;
+
+                // Extend the array if necessary
+    if (contextPos >= max) {
+        Context newContexts[] = new Context[max*2];
+        System.arraycopy(contexts, 0, newContexts, 0, max);
+        max *= 2;
+        contexts = newContexts;
+    }
+
+                // Allocate the context if necessary.
+    currentContext = contexts[contextPos];
+    if (currentContext == null) {
+        contexts[contextPos] = currentContext = new Context();
+    }
+
+                // Set the parent, if any.
+    if (contextPos > 0) {
+        currentContext.setParent(contexts[contextPos - 1]);
+    }
+    }
+
+
+    /**
+     * Revert to the previous Namespace context.
+     *
+     * <p>Normally, you should pop the context at the end of each
+     * XML element.  After popping the context, all Namespace prefix
+     * mappings that were previously in force are restored.</p>
+     *
+     * <p>You must not attempt to declare additional Namespace
+     * prefixes after popping a context, unless you push another
+     * context first.</p>
+     *
+     * @see #pushContext
+     */
+    public void popContext ()
+    {
+    contexts[contextPos].clear();
+    contextPos--;
+    if (contextPos < 0) {
+        throw new EmptyStackException();
+    }
+    currentContext = contexts[contextPos];
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Operations within a context.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Declare a Namespace prefix.  All prefixes must be declared
+     * before they are referenced.  For example, a SAX driver (parser)
+     * would scan an element's attributes
+     * in two passes:  first for namespace declarations,
+     * then a second pass using {@link #processName processName()} to
+     * interpret prefixes against (potentially redefined) prefixes.
+     *
+     * <p>This method declares a prefix in the current Namespace
+     * context; the prefix will remain in force until this context
+     * is popped, unless it is shadowed in a descendant context.</p>
+     *
+     * <p>To declare the default element Namespace, use the empty string as
+     * the prefix.</p>
+     *
+     * <p>Note that you must <em>not</em> declare a prefix after
+     * you've pushed and popped another Namespace context, or
+     * treated the declarations phase as complete by processing
+     * a prefixed name.</p>
+     *
+     * <p>Note that there is an asymmetry in this library: {@link
+     * #getPrefix getPrefix} will not return the "" prefix,
+     * even if you have declared a default element namespace.
+     * To check for a default namespace,
+     * you have to look it up explicitly using {@link #getURI getURI}.
+     * This asymmetry exists to make it easier to look up prefixes
+     * for attribute names, where the default prefix is not allowed.</p>
+     *
+     * @param prefix The prefix to declare, or the empty string to
+     *    indicate the default element namespace.  This may never have
+     *    the value "xml" or "xmlns".
+     * @param uri The Namespace URI to associate with the prefix.
+     * @return true if the prefix was legal, false otherwise
+     *
+     * @see #processName
+     * @see #getURI
+     * @see #getPrefix
+     */
+    public boolean declarePrefix (String prefix, String uri)
+    {
+    if (prefix.equals("xml") || prefix.equals("xmlns")) {
+        return false;
+    } else {
+        currentContext.declarePrefix(prefix, uri);
+        return true;
+    }
+    }
+
+
+    /**
+     * Process a raw XML qualified name, after all declarations in the
+     * current context have been handled by {@link #declarePrefix
+     * declarePrefix()}.
+     *
+     * <p>This method processes a raw XML qualified name in the
+     * current context by removing the prefix and looking it up among
+     * the prefixes currently declared.  The return value will be the
+     * array supplied by the caller, filled in as follows:</p>
+     *
+     * <dl>
+     * <dt>parts[0]</dt>
+     * <dd>The Namespace URI, or an empty string if none is
+     *  in use.</dd>
+     * <dt>parts[1]</dt>
+     * <dd>The local name (without prefix).</dd>
+     * <dt>parts[2]</dt>
+     * <dd>The original raw name.</dd>
+     * </dl>
+     *
+     * <p>All of the strings in the array will be internalized.  If
+     * the raw name has a prefix that has not been declared, then
+     * the return value will be null.</p>
+     *
+     * <p>Note that attribute names are processed differently than
+     * element names: an unprefixed element name will receive the
+     * default Namespace (if any), while an unprefixed attribute name
+     * will not.</p>
+     *
+     * @param qName The XML qualified name to be processed.
+     * @param parts An array supplied by the caller, capable of
+     *        holding at least three members.
+     * @param isAttribute A flag indicating whether this is an
+     *        attribute name (true) or an element name (false).
+     * @return The supplied array holding three internalized strings 
+     *        representing the Namespace URI (or empty string), the
+     *        local name, and the XML qualified name; or null if there
+     *        is an undeclared prefix.
+     * @see #declarePrefix
+     * @see java.lang.String#intern */
+    public String [] processName (String qName, String parts[],
+                  boolean isAttribute)
+    {
+    String myParts[] = currentContext.processName(qName, isAttribute);
+    if (myParts == null) {
+        return null;
+    } else {
+        parts[0] = myParts[0];
+        parts[1] = myParts[1];
+        parts[2] = myParts[2];
+        return parts;
+    }
+    }
+
+
+    /**
+     * Look up a prefix and get the currently-mapped Namespace URI.
+     *
+     * <p>This method looks up the prefix in the current context.
+     * Use the empty string ("") for the default Namespace.</p>
+     *
+     * @param prefix The prefix to look up.
+     * @return The associated Namespace URI, or null if the prefix
+     *         is undeclared in this context.
+     * @see #getPrefix
+     * @see #getPrefixes
+     */
+    public String getURI (String prefix)
+    {
+    return currentContext.getURI(prefix);
+    }
+
+
+    /**
+     * Return an enumeration of all prefixes whose declarations are
+     * active in the current context.
+     * This includes declarations from parent contexts that have
+     * not been overridden.
+     *
+     * <p><strong>Note:</strong> if there is a default prefix, it will not be
+     * returned in this enumeration; check for the default prefix
+     * using the {@link #getURI getURI} with an argument of "".</p>
+     *
+     * @return An enumeration of prefixes (never empty).
+     * @see #getDeclaredPrefixes
+     * @see #getURI
+     */
+    public Enumeration getPrefixes ()
+    {
+    return currentContext.getPrefixes();
+    }
+
+
+    /**
+     * Return one of the prefixes mapped to a Namespace URI.
+     *
+     * <p>If more than one prefix is currently mapped to the same
+     * URI, this method will make an arbitrary selection; if you
+     * want all of the prefixes, use the {@link #getPrefixes}
+     * method instead.</p>
+     *
+     * <p><strong>Note:</strong> this will never return the empty (default) prefix;
+     * to check for a default prefix, use the {@link #getURI getURI}
+     * method with an argument of "".</p>
+     *
+     * @param uri the namespace URI
+     * @return one of the prefixes currently mapped to the URI supplied,
+     *         or null if none is mapped or if the URI is assigned to
+     *         the default namespace
+     * @see #getPrefixes(java.lang.String)
+     * @see #getURI
+     */
+    public String getPrefix (String uri)
+    {
+    return currentContext.getPrefix(uri);
+    }
+
+
+    /**
+     * Return an enumeration of all prefixes for a given URI whose
+     * declarations are active in the current context.
+     * This includes declarations from parent contexts that have
+     * not been overridden.
+     *
+     * <p>This method returns prefixes mapped to a specific Namespace
+     * URI.  The xml: prefix will be included.  If you want only one
+     * prefix that's mapped to the Namespace URI, and you don't care 
+     * which one you get, use the {@link #getPrefix getPrefix}
+     *  method instead.</p>
+     *
+     * <p><strong>Note:</strong> the empty (default) prefix is <em>never</em> included
+     * in this enumeration; to check for the presence of a default
+     * Namespace, use the {@link #getURI getURI} method with an
+     * argument of "".</p>
+     *
+     * @param uri The Namespace URI.
+     * @return An enumeration of prefixes (never empty).
+     * @see #getPrefix
+     * @see #getDeclaredPrefixes
+     * @see #getURI
+     */
+    public Enumeration getPrefixes (String uri)
+    {
+    Vector prefixes = new Vector();
+    Enumeration allPrefixes = getPrefixes();
+    while (allPrefixes.hasMoreElements()) {
+        String prefix = (String)allPrefixes.nextElement();
+        if (uri.equals(getURI(prefix))) {
+        prefixes.addElement(prefix);
+        }
+    }
+    return prefixes.elements();
+    }
+
+
+    /**
+     * Return an enumeration of all prefixes declared in this context.
+     *
+     * <p>The empty (default) prefix will be included in this 
+     * enumeration; note that this behaviour differs from that of
+     * {@link #getPrefix} and {@link #getPrefixes}.</p>
+     *
+     * @return An enumeration of all prefixes declared in this
+     *         context.
+     * @see #getPrefixes
+     * @see #getURI
+     */
+    public Enumeration getDeclaredPrefixes ()
+    {
+    return currentContext.getDeclaredPrefixes();
+    }
+
+    /**
+     * Controls whether namespace declaration attributes are placed
+     * into the {@link #NSDECL NSDECL} namespace
+     * by {@link #processName processName()}.  This may only be
+     * changed before any contexts have been pushed.
+     * 
+     * @param value the namespace declaration attribute state. A value of true
+     *              enables this feature, a value of false disables it.
+     *
+     * @since SAX 2.1alpha
+     *
+     * @exception IllegalStateException when attempting to set this
+     *    after any context has been pushed.
+     */
+    public void setNamespaceDeclUris (boolean value)
+    {
+    if (contextPos != 0)
+        throw new IllegalStateException ();
+    if (value == namespaceDeclUris)
+        return;
+    namespaceDeclUris = value;
+    if (value)
+        currentContext.declarePrefix ("xmlns", NSDECL);
+    else {
+        contexts[contextPos] = currentContext = new Context();
+        currentContext.declarePrefix("xml", XMLNS);
+    }
+    }
+
+    /**
+     * Returns true if namespace declaration attributes are placed into
+     * a namespace.  This behavior is not the default.
+     *
+     * @return true if namespace declaration attributes are enabled, false
+     *         otherwise.
+     * @since SAX 2.1alpha
+     */
+    public boolean isNamespaceDeclUris ()
+    { return namespaceDeclUris; }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////////
+
+    private Context contexts[];
+    private Context currentContext;
+    private int contextPos;
+    private boolean namespaceDeclUris;
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal classes.
+    ////////////////////////////////////////////////////////////////////
+
+    /**
+     * Internal class for a single Namespace context.
+     *
+     * <p>This module caches and reuses Namespace contexts,
+     * so the number allocated
+     * will be equal to the element depth of the document, not to the total
+     * number of elements (i.e. 5-10 rather than tens of thousands).
+     * Also, data structures used to represent contexts are shared when
+     * possible (child contexts without declarations) to further reduce
+     * the amount of memory that's consumed.
+     * </p>
+     */
+    final class Context {
+
+    /**
+     * Create the root-level Namespace context.
+     */
+    Context ()
+    {
+        copyTables();
+    }
+    
+    
+    /**
+     * (Re)set the parent of this Namespace context.
+     * The context must either have been freshly constructed,
+     * or must have been cleared.
+     *
+     * @param context The parent Namespace context object.
+     */
+    void setParent (Context parent)
+    {
+        this.parent = parent;
+        declarations = null;
+        prefixTable = parent.prefixTable;
+        uriTable = parent.uriTable;
+        elementNameTable = parent.elementNameTable;
+        attributeNameTable = parent.attributeNameTable;
+        defaultNS = parent.defaultNS;
+        declSeen = false;
+        declsOK = true;
+    }
+
+    /**
+     * Makes associated state become collectible,
+     * invalidating this context.
+     * {@link #setParent} must be called before
+     * this context may be used again.
+     */
+    void clear ()
+    {
+        parent = null;
+        prefixTable = null;
+        uriTable = null;
+        elementNameTable = null;
+        attributeNameTable = null;
+        defaultNS = null;
+    }
+    
+    
+    /**
+     * Declare a Namespace prefix for this context.
+     *
+     * @param prefix The prefix to declare.
+     * @param uri The associated Namespace URI.
+     * @see org.xml.sax.helpers.NamespaceSupport#declarePrefix
+     */
+    void declarePrefix (String prefix, String uri)
+    {
+                // Lazy processing...
+        if (!declsOK)
+        throw new IllegalStateException (
+            "can't declare any more prefixes in this context");
+        if (!declSeen) {
+        copyTables();
+        }
+        if (declarations == null) {
+        declarations = new Vector();
+        }
+        
+        prefix = prefix.intern();
+        uri = uri.intern();
+        if ("".equals(prefix)) {
+        if ("".equals(uri)) {
+            defaultNS = null;
+        } else {
+            defaultNS = uri;
+        }
+        } else {
+        prefixTable.put(prefix, uri);
+        uriTable.put(uri, prefix); // may wipe out another prefix
+        }
+        declarations.addElement(prefix);
+    }
+
+
+    /**
+     * Process an XML qualified name in this context.
+     *
+     * @param qName The XML qualified name.
+     * @param isAttribute true if this is an attribute name.
+     * @return An array of three strings containing the
+     *         URI part (or empty string), the local part,
+     *         and the raw name, all internalized, or null
+     *         if there is an undeclared prefix.
+     * @see org.xml.sax.helpers.NamespaceSupport#processName
+     */
+    String [] processName (String qName, boolean isAttribute)
+    {
+        String name[];
+        Hashtable table;
+        
+                    // detect errors in call sequence
+        declsOK = false;
+
+                // Select the appropriate table.
+        if (isAttribute) {
+        table = attributeNameTable;
+        } else {
+        table = elementNameTable;
+        }
+        
+                // Start by looking in the cache, and
+                // return immediately if the name
+                // is already known in this content
+        name = (String[])table.get(qName);
+        if (name != null) {
+        return name;
+        }
+        
+                // We haven't seen this name in this
+                // context before.  Maybe in the parent
+                // context, but we can't assume prefix
+                // bindings are the same.
+        name = new String[3];
+        name[2] = qName.intern();
+        int index = qName.indexOf(':');
+        
+        
+                // No prefix.
+        if (index == -1) {
+        if (isAttribute) {
+            if (qName == "xmlns" && namespaceDeclUris)
+            name[0] = NSDECL;
+            else
+            name[0] = "";
+        } else if (defaultNS == null) {
+            name[0] = "";
+        } else {
+            name[0] = defaultNS;
+        }
+        name[1] = name[2];
+        }
+        
+                // Prefix
+        else {
+        String prefix = qName.substring(0, index);
+        String local = qName.substring(index+1);
+        String uri;
+        if ("".equals(prefix)) {
+            uri = defaultNS;
+        } else {
+            uri = (String)prefixTable.get(prefix);
+        }
+        if (uri == null
+            || (!isAttribute && "xmlns".equals (prefix))) {
+            return null;
+        }
+        name[0] = uri;
+        name[1] = local.intern();
+        }
+        
+                // Save in the cache for future use.
+                // (Could be shared with parent context...)
+        table.put(name[2], name);
+        return name;
+    }
+    
+
+    /**
+     * Look up the URI associated with a prefix in this context.
+     *
+     * @param prefix The prefix to look up.
+     * @return The associated Namespace URI, or null if none is
+     *         declared.    
+     * @see org.xml.sax.helpers.NamespaceSupport#getURI
+     */
+    String getURI (String prefix)
+    {
+        if ("".equals(prefix)) {
+        return defaultNS;
+        } else if (prefixTable == null) {
+        return null;
+        } else {
+        return (String)prefixTable.get(prefix);
+        }
+    }
+
+
+    /**
+     * Look up one of the prefixes associated with a URI in this context.
+     *
+     * <p>Since many prefixes may be mapped to the same URI,
+     * the return value may be unreliable.</p>
+     *
+     * @param uri The URI to look up.
+     * @return The associated prefix, or null if none is declared.
+     * @see org.xml.sax.helpers.NamespaceSupport#getPrefix
+     */
+    String getPrefix (String uri)
+    {
+        if (uriTable == null) {
+        return null;
+        } else {
+        return (String)uriTable.get(uri);
+        }
+    }
+    
+    
+    /**
+     * Return an enumeration of prefixes declared in this context.
+     *
+     * @return An enumeration of prefixes (possibly empty).
+     * @see org.xml.sax.helpers.NamespaceSupport#getDeclaredPrefixes
+     */
+    Enumeration getDeclaredPrefixes ()
+    {
+        if (declarations == null) {
+        return EMPTY_ENUMERATION;
+        } else {
+        return declarations.elements();
+        }
+    }
+    
+    
+    /**
+     * Return an enumeration of all prefixes currently in force.
+     *
+     * <p>The default prefix, if in force, is <em>not</em>
+     * returned, and will have to be checked for separately.</p>
+     *
+     * @return An enumeration of prefixes (never empty).
+     * @see org.xml.sax.helpers.NamespaceSupport#getPrefixes
+     */
+    Enumeration getPrefixes ()
+    {
+        if (prefixTable == null) {
+        return EMPTY_ENUMERATION;
+        } else {
+        return prefixTable.keys();
+        }
+    }
+    
+    
+
+    ////////////////////////////////////////////////////////////////
+    // Internal methods.
+    ////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Copy on write for the internal tables in this context.
+     *
+     * <p>This class is optimized for the normal case where most
+     * elements do not contain Namespace declarations.</p>
+     */    
+    private void copyTables ()
+    {
+        if (prefixTable != null) {
+        prefixTable = (Hashtable)prefixTable.clone();
+        } else {
+        prefixTable = new Hashtable();
+        }
+        if (uriTable != null) {
+        uriTable = (Hashtable)uriTable.clone();
+        } else {
+        uriTable = new Hashtable();
+        }
+        elementNameTable = new Hashtable();
+        attributeNameTable = new Hashtable();
+        declSeen = true;
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////
+    // Protected state.
+    ////////////////////////////////////////////////////////////////
+    
+    Hashtable prefixTable;
+    Hashtable uriTable;
+    Hashtable elementNameTable;
+    Hashtable attributeNameTable;
+    String defaultNS = null;
+    boolean declsOK = true;
+    
+
+
+    ////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////
+    
+    private Vector declarations = null;
+    private boolean declSeen = false;
+    private Context parent = null;
+    }
+}
+
+// end of NamespaceSupport.java
diff --git a/xml/src/main/java/org/xml/sax/helpers/NewInstance.java b/xml/src/main/java/org/xml/sax/helpers/NewInstance.java
new file mode 100644
index 0000000..e590192
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/NewInstance.java
@@ -0,0 +1,79 @@
+// NewInstance.java - create a new instance of a class by name.
+// http://www.saxproject.org
+// Written by Edwin Goei, edwingo@apache.org
+// and by David Brownell, dbrownell@users.sourceforge.net
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: NewInstance.java,v 1.4 2002/01/30 20:52:27 dbrownell Exp $
+
+package org.xml.sax.helpers;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Create a new instance of a class by name.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class contains a static method for creating an instance of a
+ * class from an explicit class name.  It tries to use the thread's context
+ * ClassLoader if possible and falls back to using
+ * Class.forName(String).</p>
+ *
+ * <p>This code is designed to compile and run on JDK version 1.1 and later
+ * including versions of Java 2.</p>
+ *
+ * @author Edwin Goei, David Brownell
+ * @version 2.0.1 (sax2r2)
+ */
+class NewInstance {
+
+    /**
+     * Creates a new instance of the specified class name
+     *
+     * Package private so this code is not exposed at the API level.
+     */
+    static Object newInstance (ClassLoader classLoader, String className)
+        throws ClassNotFoundException, IllegalAccessException,
+            InstantiationException
+    {
+        Class driverClass;
+        if (classLoader == null) {
+            driverClass = Class.forName(className);
+        } else {
+            driverClass = classLoader.loadClass(className);
+        }
+        return driverClass.newInstance();
+    }
+
+    /**
+     * Figure out which ClassLoader to use.  For JDK 1.2 and later use
+     * the context ClassLoader.
+     */           
+    static ClassLoader getClassLoader ()
+    {
+        Method m = null;
+
+        try {
+            m = Thread.class.getMethod("getContextClassLoader");
+        } catch (NoSuchMethodException e) {
+            // Assume that we are running JDK 1.1, use the current ClassLoader
+            return NewInstance.class.getClassLoader();
+        }
+
+        try {
+            return (ClassLoader) m.invoke(Thread.currentThread());
+        } catch (IllegalAccessException e) {
+            // assert(false)
+            throw new UnknownError(e.getMessage());
+        } catch (InvocationTargetException e) {
+            // assert(e.getTargetException() instanceof SecurityException)
+            throw new UnknownError(e.getMessage());
+        }
+    }
+}
diff --git a/xml/src/main/java/org/xml/sax/helpers/ParserAdapter.java b/xml/src/main/java/org/xml/sax/helpers/ParserAdapter.java
new file mode 100644
index 0000000..7fc3813
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/ParserAdapter.java
@@ -0,0 +1,1046 @@
+// ParserAdapter.java - adapt a SAX1 Parser to a SAX2 XMLReader.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the public domain.
+// $Id: ParserAdapter.java,v 1.16 2004/04/26 17:34:35 dmegginson Exp $
+
+package org.xml.sax.helpers;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.xml.sax.Parser;    // deprecated
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.AttributeList; // deprecated
+import org.xml.sax.EntityResolver;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.DocumentHandler; // deprecated
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import org.xml.sax.XMLReader;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+
+
+/**
+ * Adapt a SAX1 Parser as a SAX2 XMLReader.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class wraps a SAX1 {@link org.xml.sax.Parser Parser}
+ * and makes it act as a SAX2 {@link org.xml.sax.XMLReader XMLReader},
+ * with feature, property, and Namespace support.  Note
+ * that it is not possible to report {@link org.xml.sax.ContentHandler#skippedEntity
+ * skippedEntity} events, since SAX1 does not make that information available.</p>
+ *
+ * <p>This adapter does not test for duplicate Namespace-qualified
+ * attribute names.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.helpers.XMLReaderAdapter
+ * @see org.xml.sax.XMLReader
+ * @see org.xml.sax.Parser
+ */
+public class ParserAdapter implements XMLReader, DocumentHandler
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Constructors.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Construct a new parser adapter.
+     *
+     * <p>Use the "org.xml.sax.parser" property to locate the
+     * embedded SAX1 driver.</p>
+     *
+     * @exception SAXException If the embedded driver
+     *            cannot be instantiated or if the
+     *            org.xml.sax.parser property is not specified.
+     */
+    public ParserAdapter ()
+      throws SAXException
+    {
+    super();
+
+    String driver = System.getProperty("org.xml.sax.parser");
+
+    try {
+        setup(ParserFactory.makeParser());
+    } catch (ClassNotFoundException e1) {
+        throw new
+        SAXException("Cannot find SAX1 driver class " +
+                 driver, e1);
+    } catch (IllegalAccessException e2) {
+        throw new
+        SAXException("SAX1 driver class " +
+                 driver +
+                 " found but cannot be loaded", e2);
+    } catch (InstantiationException e3) {
+        throw new
+        SAXException("SAX1 driver class " +
+                 driver +
+                 " loaded but cannot be instantiated", e3);
+    } catch (ClassCastException e4) {
+        throw new
+        SAXException("SAX1 driver class " +
+                 driver +
+                 " does not implement org.xml.sax.Parser");
+    } catch (NullPointerException e5) {
+        throw new 
+        SAXException("System property org.xml.sax.parser not specified");
+    }
+    }
+
+
+    /**
+     * Construct a new parser adapter.
+     *
+     * <p>Note that the embedded parser cannot be changed once the
+     * adapter is created; to embed a different parser, allocate
+     * a new ParserAdapter.</p>
+     *
+     * @param parser The SAX1 parser to embed.
+     * @exception java.lang.NullPointerException If the parser parameter
+     *            is null.
+     */
+    public ParserAdapter (Parser parser)
+    {
+    super();
+    setup(parser);
+    }
+
+
+    /**
+     * Internal setup method.
+     *
+     * @param parser The embedded parser.
+     * @exception java.lang.NullPointerException If the parser parameter
+     *            is null.
+     */
+    private void setup (Parser parser)
+    {
+    if (parser == null) {
+        throw new
+        NullPointerException("Parser argument must not be null");
+    }
+    this.parser = parser;
+    atts = new AttributesImpl();
+    nsSupport = new NamespaceSupport();
+    attAdapter = new AttributeListAdapter();
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.XMLReader.
+    ////////////////////////////////////////////////////////////////////
+
+
+    //
+    // Internal constants for the sake of convenience.
+    //
+    private final static String FEATURES = "http://xml.org/sax/features/";
+    private final static String NAMESPACES = FEATURES + "namespaces";
+    private final static String NAMESPACE_PREFIXES = FEATURES + "namespace-prefixes";
+    private final static String XMLNS_URIs = FEATURES + "xmlns-uris";
+
+
+    /**
+     * Set a feature flag for the parser.
+     *
+     * <p>The only features recognized are namespaces and 
+     * namespace-prefixes.</p>
+     *
+     * @param name The feature name, as a complete URI.
+     * @param value The requested feature value.
+     * @exception SAXNotRecognizedException If the feature
+     *            can't be assigned or retrieved.
+     * @exception SAXNotSupportedException If the feature
+     *            can't be assigned that value.
+     * @see org.xml.sax.XMLReader#setFeature
+     */
+    public void setFeature (String name, boolean value)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+    if (name.equals(NAMESPACES)) {
+        checkNotParsing("feature", name);
+        namespaces = value;
+        if (!namespaces && !prefixes) {
+        prefixes = true;
+        }
+    } else if (name.equals(NAMESPACE_PREFIXES)) {
+        checkNotParsing("feature", name);
+        prefixes = value;
+        if (!prefixes && !namespaces) {
+        namespaces = true;
+        }
+    } else if (name.equals(XMLNS_URIs)) {
+        checkNotParsing("feature", name);
+        uris = value;
+    } else {
+        throw new SAXNotRecognizedException("Feature: " + name);
+    }
+    }
+
+
+    /**
+     * Check a parser feature flag.
+     *
+     * <p>The only features recognized are namespaces and 
+     * namespace-prefixes.</p>
+     *
+     * @param name The feature name, as a complete URI.
+     * @return The current feature value.
+     * @exception SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved.
+     * @exception SAXNotSupportedException If the
+     *            feature is not currently readable.
+     * @see org.xml.sax.XMLReader#setFeature
+     */
+    public boolean getFeature (String name)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+    if (name.equals(NAMESPACES)) {
+        return namespaces;
+    } else if (name.equals(NAMESPACE_PREFIXES)) {
+        return prefixes;
+    } else if (name.equals(XMLNS_URIs)) {
+        return uris;
+    } else {
+        throw new SAXNotRecognizedException("Feature: " + name);
+    }
+    }
+
+
+    /**
+     * Set a parser property.
+     *
+     * <p>No properties are currently recognized.</p>
+     *
+     * @param name The property name.
+     * @param value The property value.
+     * @exception SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception SAXNotSupportedException If the property
+     *            can't be assigned that value.
+     * @see org.xml.sax.XMLReader#setProperty
+     */
+    public void setProperty (String name, Object value)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+    throw new SAXNotRecognizedException("Property: " + name);
+    }
+
+
+    /**
+     * Get a parser property.
+     *
+     * <p>No properties are currently recognized.</p>
+     *
+     * @param name The property name.
+     * @return The property value.
+     * @exception SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved.
+     * @exception SAXNotSupportedException If the property
+     *            value is not currently readable.
+     * @see org.xml.sax.XMLReader#getProperty
+     */
+    public Object getProperty (String name)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+    throw new SAXNotRecognizedException("Property: " + name);
+    }
+
+
+    /**
+     * Set the entity resolver.
+     *
+     * @param resolver The new entity resolver.
+     * @see org.xml.sax.XMLReader#setEntityResolver
+     */
+    public void setEntityResolver (EntityResolver resolver)
+    {
+    entityResolver = resolver;
+    }
+
+
+    /**
+     * Return the current entity resolver.
+     *
+     * @return The current entity resolver, or null if none was supplied.
+     * @see org.xml.sax.XMLReader#getEntityResolver
+     */
+    public EntityResolver getEntityResolver ()
+    {
+    return entityResolver;
+    }
+
+
+    /**
+     * Set the DTD handler.
+     *
+     * @param handler the new DTD handler
+     * @see org.xml.sax.XMLReader#setEntityResolver
+     */
+    public void setDTDHandler (DTDHandler handler)
+    {
+    dtdHandler = handler;
+    }
+
+
+    /**
+     * Return the current DTD handler.
+     *
+     * @return the current DTD handler, or null if none was supplied
+     * @see org.xml.sax.XMLReader#getEntityResolver
+     */
+    public DTDHandler getDTDHandler ()
+    {
+    return dtdHandler;
+    }
+
+
+    /**
+     * Set the content handler.
+     *
+     * @param handler the new content handler
+     * @see org.xml.sax.XMLReader#setEntityResolver
+     */
+    public void setContentHandler (ContentHandler handler)
+    {
+    contentHandler = handler;
+    }
+
+
+    /**
+     * Return the current content handler.
+     *
+     * @return The current content handler, or null if none was supplied.
+     * @see org.xml.sax.XMLReader#getEntityResolver
+     */
+    public ContentHandler getContentHandler ()
+    {
+    return contentHandler;
+    }
+
+
+    /**
+     * Set the error handler.
+     *
+     * @param handler The new error handler.
+     * @see org.xml.sax.XMLReader#setEntityResolver
+     */
+    public void setErrorHandler (ErrorHandler handler)
+    {
+    errorHandler = handler;
+    }
+
+
+    /**
+     * Return the current error handler.
+     *
+     * @return The current error handler, or null if none was supplied.
+     * @see org.xml.sax.XMLReader#getEntityResolver
+     */
+    public ErrorHandler getErrorHandler ()
+    {
+    return errorHandler;
+    }
+
+
+    /**
+     * Parse an XML document.
+     *
+     * @param systemId The absolute URL of the document.
+     * @exception java.io.IOException If there is a problem reading
+     *            the raw content of the document.
+     * @exception SAXException If there is a problem
+     *            processing the document.
+     * @see #parse(org.xml.sax.InputSource)
+     * @see org.xml.sax.Parser#parse(java.lang.String)
+     */
+    public void parse (String systemId)
+    throws IOException, SAXException
+    {
+    parse(new InputSource(systemId));
+    }
+
+
+    /**
+     * Parse an XML document.
+     *
+     * @param input An input source for the document.
+     * @exception java.io.IOException If there is a problem reading
+     *            the raw content of the document.
+     * @exception SAXException If there is a problem
+     *            processing the document.
+     * @see #parse(java.lang.String)
+     * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
+     */
+    public void parse (InputSource input)
+    throws IOException, SAXException
+    {
+    if (parsing) {
+        throw new SAXException("Parser is already in use");
+    }
+    setupParser();
+    parsing = true;
+    try {
+        parser.parse(input);
+    } finally {
+        parsing = false;
+    }
+    parsing = false;
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.DocumentHandler.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Adapter implementation method; do not call.
+     * Adapt a SAX1 document locator event.
+     *
+     * @param locator A document locator.
+     * @see org.xml.sax.ContentHandler#setDocumentLocator
+     */
+    public void setDocumentLocator (Locator locator)
+    {
+    this.locator = locator;
+    if (contentHandler != null) {
+        contentHandler.setDocumentLocator(locator);
+    }
+    }
+
+
+    /**
+     * Adapter implementation method; do not call.
+     * Adapt a SAX1 start document event.
+     *
+     * @exception SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.DocumentHandler#startDocument
+     */
+    public void startDocument ()
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.startDocument();
+    }
+    }
+
+
+    /**
+     * Adapter implementation method; do not call.
+     * Adapt a SAX1 end document event.
+     *
+     * @exception SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.DocumentHandler#endDocument
+     */
+    public void endDocument ()
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.endDocument();
+    }
+    }
+
+
+    /**
+     * Adapter implementation method; do not call.
+     * Adapt a SAX1 startElement event.
+     *
+     * <p>If necessary, perform Namespace processing.</p>
+     *
+     * @param qName The qualified (prefixed) name.
+     * @param qAtts The XML attribute list (with qnames).
+     * @exception SAXException The client may raise a
+     *            processing exception.
+     */
+    public void startElement (String qName, AttributeList qAtts)
+    throws SAXException
+    {
+                // These are exceptions from the
+                // first pass; they should be
+                // ignored if there's a second pass,
+                // but reported otherwise.
+    Vector exceptions = null;
+
+                // If we're not doing Namespace
+                // processing, dispatch this quickly.
+    if (!namespaces) {
+        if (contentHandler != null) {
+        attAdapter.setAttributeList(qAtts);
+        contentHandler.startElement("", "", qName.intern(),
+                        attAdapter);
+        }
+        return;
+    }
+
+
+                // OK, we're doing Namespace processing.
+    nsSupport.pushContext();
+    int length = qAtts.getLength();
+    
+                // First pass:  handle NS decls
+    for (int i = 0; i < length; i++) {
+        String attQName = qAtts.getName(i);
+
+        if (!attQName.startsWith("xmlns"))
+        continue;
+                // Could be a declaration...
+        String prefix;
+        int n = attQName.indexOf(':');
+
+                    // xmlns=...
+        if (n == -1 && attQName.length () == 5) {
+        prefix = "";
+        } else if (n != 5) {
+        // XML namespaces spec doesn't discuss "xmlnsf:oo"
+        // (and similarly named) attributes ... at most, warn
+        continue;
+        } else         // xmlns:foo=...
+        prefix = attQName.substring(n+1);
+
+        String value = qAtts.getValue(i);
+        if (!nsSupport.declarePrefix(prefix, value)) {
+        reportError("Illegal Namespace prefix: " + prefix);
+        continue;
+        }
+        if (contentHandler != null)
+        contentHandler.startPrefixMapping(prefix, value);
+    }
+    
+                // Second pass: copy all relevant
+                // attributes into the SAX2 AttributeList
+                // using updated prefix bindings
+    atts.clear();
+    for (int i = 0; i < length; i++) {
+        String attQName = qAtts.getName(i);
+        String type = qAtts.getType(i);
+        String value = qAtts.getValue(i);
+
+                // Declaration?
+        if (attQName.startsWith("xmlns")) {
+        String prefix;
+        int n = attQName.indexOf(':');
+
+        if (n == -1 && attQName.length () == 5) {
+            prefix = "";
+        } else if (n != 5) {
+            // XML namespaces spec doesn't discuss "xmlnsf:oo"
+            // (and similarly named) attributes ... ignore
+            prefix = null;
+        } else {
+            prefix = attQName.substring(6);
+        }
+                // Yes, decl:  report or prune
+        if (prefix != null) {
+            if (prefixes) {
+            if (uris)
+                // note funky case:  localname can be null
+                // when declaring the default prefix, and
+                // yet the uri isn't null.
+                atts.addAttribute (nsSupport.XMLNS, prefix,
+                    attQName.intern(), type, value);
+            else
+                atts.addAttribute ("", "",
+                    attQName.intern(), type, value);
+            }
+            continue;
+        }
+        } 
+
+                // Not a declaration -- report
+        try {
+        String attName[] = processName(attQName, true, true);
+        atts.addAttribute(attName[0], attName[1], attName[2],
+                  type, value);
+        } catch (SAXException e) {
+        if (exceptions == null)
+            exceptions = new Vector();
+        exceptions.addElement(e);
+        atts.addAttribute("", attQName, attQName, type, value);
+        }
+    }
+    
+    // now handle the deferred exception reports
+    if (exceptions != null && errorHandler != null) {
+        for (int i = 0; i < exceptions.size(); i++)
+        errorHandler.error((SAXParseException)
+                (exceptions.elementAt(i)));
+    }
+
+                // OK, finally report the event.
+    if (contentHandler != null) {
+        String name[] = processName(qName, false, false);
+        contentHandler.startElement(name[0], name[1], name[2], atts);
+    }
+    }
+
+
+    /**
+     * Adapter implementation method; do not call.
+     * Adapt a SAX1 end element event.
+     *
+     * @param qName The qualified (prefixed) name.
+     * @exception SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.DocumentHandler#endElement
+     */
+    public void endElement (String qName)
+    throws SAXException
+    {
+                // If we're not doing Namespace
+                // processing, dispatch this quickly.
+    if (!namespaces) {
+        if (contentHandler != null) {
+        contentHandler.endElement("", "", qName.intern());
+        }
+        return;
+    }
+
+                // Split the name.
+    String names[] = processName(qName, false, false);
+    if (contentHandler != null) {
+        contentHandler.endElement(names[0], names[1], names[2]);
+        Enumeration prefixes = nsSupport.getDeclaredPrefixes();
+        while (prefixes.hasMoreElements()) {
+        String prefix = (String)prefixes.nextElement();
+        contentHandler.endPrefixMapping(prefix);
+        }
+    }
+    nsSupport.popContext();
+    }
+
+
+    /**
+     * Adapter implementation method; do not call.
+     * Adapt a SAX1 characters event.
+     *
+     * @param ch An array of characters.
+     * @param start The starting position in the array.
+     * @param length The number of characters to use.
+     * @exception SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.DocumentHandler#characters
+     */
+    public void characters (char ch[], int start, int length)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.characters(ch, start, length);
+    }
+    }
+
+
+    /**
+     * Adapter implementation method; do not call.
+     * Adapt a SAX1 ignorable whitespace event.
+     *
+     * @param ch An array of characters.
+     * @param start The starting position in the array.
+     * @param length The number of characters to use.
+     * @exception SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.DocumentHandler#ignorableWhitespace
+     */
+    public void ignorableWhitespace (char ch[], int start, int length)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.ignorableWhitespace(ch, start, length);
+    }
+    }
+
+
+    /**
+     * Adapter implementation method; do not call.
+     * Adapt a SAX1 processing instruction event.
+     *
+     * @param target The processing instruction target.
+     * @param data The remainder of the processing instruction
+     * @exception SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.DocumentHandler#processingInstruction
+     */
+    public void processingInstruction (String target, String data)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.processingInstruction(target, data);
+    }
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal utility methods.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Initialize the parser before each run.
+     */
+    private void setupParser ()
+    {
+    // catch an illegal "nonsense" state.
+    if (!prefixes && !namespaces)
+        throw new IllegalStateException ();
+
+    nsSupport.reset();
+    if (uris)
+        nsSupport.setNamespaceDeclUris (true);
+
+    if (entityResolver != null) {
+        parser.setEntityResolver(entityResolver);
+    }
+    if (dtdHandler != null) {
+        parser.setDTDHandler(dtdHandler);
+    }
+    if (errorHandler != null) {
+        parser.setErrorHandler(errorHandler);
+    }
+    parser.setDocumentHandler(this);
+    locator = null;
+    }
+
+
+    /**
+     * Process a qualified (prefixed) name.
+     *
+     * <p>If the name has an undeclared prefix, use only the qname
+     * and make an ErrorHandler.error callback in case the app is
+     * interested.</p>
+     *
+     * @param qName The qualified (prefixed) name.
+     * @param isAttribute true if this is an attribute name.
+     * @return The name split into three parts.
+     * @exception SAXException The client may throw
+     *            an exception if there is an error callback.
+     */
+    private String [] processName (String qName, boolean isAttribute,
+                   boolean useException)
+    throws SAXException
+    {
+    String parts[] = nsSupport.processName(qName, nameParts,
+                           isAttribute);
+    if (parts == null) {
+        if (useException)
+        throw makeException("Undeclared prefix: " + qName);
+        reportError("Undeclared prefix: " + qName);
+        parts = new String[3];
+        parts[0] = parts[1] = "";
+        parts[2] = qName.intern();
+    }
+    return parts;
+    }
+
+
+    /**
+     * Report a non-fatal error.
+     *
+     * @param message The error message.
+     * @exception SAXException The client may throw
+     *            an exception.
+     */
+    void reportError (String message)
+    throws SAXException
+    {
+    if (errorHandler != null)
+        errorHandler.error(makeException(message));
+    }
+
+    
+    /**
+     * Construct an exception for the current context.
+     *
+     * @param message The error message.
+     */
+    private SAXParseException makeException (String message)
+    {
+    if (locator != null) {
+        return new SAXParseException(message, locator);
+    } else {
+        return new SAXParseException(message, null, null, -1, -1);
+    }
+    }
+
+
+    /**
+     * Throw an exception if we are parsing.
+     *
+     * <p>Use this method to detect illegal feature or
+     * property changes.</p>
+     *
+     * @param type The type of thing (feature or property).
+     * @param name The feature or property name.
+     * @exception SAXNotSupportedException If a
+     *            document is currently being parsed.
+     */
+    private void checkNotParsing (String type, String name)
+    throws SAXNotSupportedException
+    {
+    if (parsing) {
+        throw new SAXNotSupportedException("Cannot change " +
+                           type + ' ' +
+                           name + " while parsing");
+                           
+    }
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////////
+
+    private NamespaceSupport nsSupport;
+    private AttributeListAdapter attAdapter;
+
+    private boolean parsing = false;
+    private String nameParts[] = new String[3];
+
+    private Parser parser = null;
+
+    private AttributesImpl atts = null;
+
+                // Features
+    private boolean namespaces = true;
+    private boolean prefixes = false;
+    private boolean uris = false;
+
+                // Properties
+
+                // Handlers
+    Locator locator;
+
+    EntityResolver entityResolver = null;
+    DTDHandler dtdHandler = null;
+    ContentHandler contentHandler = null;
+    ErrorHandler errorHandler = null;
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Inner class to wrap an AttributeList when not doing NS proc.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Adapt a SAX1 AttributeList as a SAX2 Attributes object.
+     *
+     * <p>This class is in the Public Domain, and comes with NO
+     * WARRANTY of any kind.</p>
+     *
+     * <p>This wrapper class is used only when Namespace support
+     * is disabled -- it provides pretty much a direct mapping
+     * from SAX1 to SAX2, except that names and types are 
+     * interned whenever requested.</p>
+     */
+    final class AttributeListAdapter implements Attributes
+    {
+
+    /**
+     * Construct a new adapter.
+     */
+    AttributeListAdapter ()
+    {
+    }
+
+
+    /**
+     * Set the embedded AttributeList.
+     *
+     * <p>This method must be invoked before any of the others
+     * can be used.</p>
+     *
+     * @param The SAX1 attribute list (with qnames).
+     */
+    void setAttributeList (AttributeList qAtts)
+    {
+        this.qAtts = qAtts;
+    }
+
+
+    /**
+     * Return the length of the attribute list.
+     *
+     * @return The number of attributes in the list.
+     * @see org.xml.sax.Attributes#getLength
+     */
+    public int getLength ()
+    {
+        return qAtts.getLength();
+    }
+
+
+    /**
+     * Return the Namespace URI of the specified attribute.
+     *
+     * @param The attribute's index.
+     * @return Always the empty string.
+     * @see org.xml.sax.Attributes#getURI
+     */
+    public String getURI (int i)
+    {
+        return "";
+    }
+
+
+    /**
+     * Return the local name of the specified attribute.
+     *
+     * @param The attribute's index.
+     * @return Always the empty string.
+     * @see org.xml.sax.Attributes#getLocalName
+     */
+    public String getLocalName (int i)
+    {
+        return "";
+    }
+
+
+    /**
+     * Return the qualified (prefixed) name of the specified attribute.
+     *
+     * @param The attribute's index.
+     * @return The attribute's qualified name, internalized.
+     */
+    public String getQName (int i)
+    {
+        return qAtts.getName(i).intern();
+    }
+
+
+    /**
+     * Return the type of the specified attribute.
+     *
+     * @param The attribute's index.
+     * @return The attribute's type as an internalized string.
+     */
+    public String getType (int i)
+    {
+        return qAtts.getType(i).intern();
+    }
+
+
+    /**
+     * Return the value of the specified attribute.
+     *
+     * @param The attribute's index.
+     * @return The attribute's value.
+     */
+    public String getValue (int i)
+    {
+        return qAtts.getValue(i);
+    }
+
+
+    /**
+     * Look up an attribute index by Namespace name.
+     *
+     * @param uri The Namespace URI or the empty string.
+     * @param localName The local name.
+     * @return The attributes index, or -1 if none was found.
+     * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
+     */
+    public int getIndex (String uri, String localName)
+    {
+        return -1;
+    }
+
+
+    /**
+     * Look up an attribute index by qualified (prefixed) name.
+     *
+     * @param qName The qualified name.
+     * @return The attributes index, or -1 if none was found.
+     * @see org.xml.sax.Attributes#getIndex(java.lang.String)
+     */
+    public int getIndex (String qName)
+    {
+        int max = atts.getLength();
+        for (int i = 0; i < max; i++) {
+        if (qAtts.getName(i).equals(qName)) {
+            return i;
+        }
+        }
+        return -1;
+    }
+
+
+    /**
+     * Look up the type of an attribute by Namespace name.
+     *
+     * @param uri The Namespace URI
+     * @param localName The local name.
+     * @return The attribute's type as an internalized string.
+     */
+    public String getType (String uri, String localName)
+    {
+        return null;
+    }
+
+
+    /**
+     * Look up the type of an attribute by qualified (prefixed) name.
+     *
+     * @param qName The qualified name.
+     * @return The attribute's type as an internalized string.
+     */
+    public String getType (String qName)
+    {
+        return qAtts.getType(qName).intern();
+    }
+
+
+    /**
+     * Look up the value of an attribute by Namespace name.
+     *
+     * @param uri The Namespace URI
+     * @param localName The local name.
+     * @return The attribute's value.
+     */
+    public String getValue (String uri, String localName)
+    {
+        return null;
+    }
+
+
+    /**
+     * Look up the value of an attribute by qualified (prefixed) name.
+     *
+     * @param qName The qualified name.
+     * @return The attribute's value.
+     */
+    public String getValue (String qName)
+    {
+        return qAtts.getValue(qName);
+    }
+
+    private AttributeList qAtts;
+    }
+}
+
+// end of ParserAdapter.java
diff --git a/xml/src/main/java/org/xml/sax/helpers/ParserFactory.java b/xml/src/main/java/org/xml/sax/helpers/ParserFactory.java
new file mode 100644
index 0000000..ffe2a60
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/ParserFactory.java
@@ -0,0 +1,133 @@
+// SAX parser factory.
+// http://www.saxproject.org
+// No warranty; no copyright -- use this as you will.
+// $Id: ParserFactory.java,v 1.7 2002/01/30 20:52:36 dbrownell Exp $
+
+package org.xml.sax.helpers;
+
+import java.lang.ClassNotFoundException;
+import java.lang.IllegalAccessException;
+import java.lang.InstantiationException;
+import java.lang.SecurityException;
+import java.lang.ClassCastException;
+
+import org.xml.sax.Parser;
+
+
+/**
+ * Java-specific class for dynamically loading SAX parsers.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p><strong>Note:</strong> This class is designed to work with the now-deprecated
+ * SAX1 {@link org.xml.sax.Parser Parser} class.  SAX2 applications should use
+ * {@link org.xml.sax.helpers.XMLReaderFactory XMLReaderFactory} instead.</p>
+ *
+ * <p>ParserFactory is not part of the platform-independent definition
+ * of SAX; it is an additional convenience class designed
+ * specifically for Java XML application writers.  SAX applications
+ * can use the static methods in this class to allocate a SAX parser
+ * dynamically at run-time based either on the value of the
+ * `org.xml.sax.parser' system property or on a string containing the class
+ * name.</p>
+ *
+ * <p>Note that the application still requires an XML parser that
+ * implements SAX1.</p>
+ *
+ * @deprecated This class works with the deprecated
+ *             {@link org.xml.sax.Parser Parser}
+ *             interface.
+ * @since SAX 1.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ */
+public class ParserFactory {
+    
+    
+    /**
+     * Private null constructor.
+     */
+    private ParserFactory ()
+    {
+    }
+    
+    
+    /**
+     * Create a new SAX parser using the `org.xml.sax.parser' system property.
+     *
+     * <p>The named class must exist and must implement the
+     * {@link org.xml.sax.Parser Parser} interface.</p>
+     * 
+     * @return the newly created parser.
+     *
+     * @exception java.lang.NullPointerException There is no value
+     *            for the `org.xml.sax.parser' system property.
+     * @exception java.lang.ClassNotFoundException The SAX parser
+     *            class was not found (check your CLASSPATH).
+     * @exception IllegalAccessException The SAX parser class was
+     *            found, but you do not have permission to load
+     *            it.
+     * @exception InstantiationException The SAX parser class was
+     *            found but could not be instantiated.
+     * @exception java.lang.ClassCastException The SAX parser class
+     *            was found and instantiated, but does not implement
+     *            org.xml.sax.Parser.
+     * @see #makeParser(java.lang.String)
+     * @see org.xml.sax.Parser
+     */
+    public static Parser makeParser ()
+    throws ClassNotFoundException,
+    IllegalAccessException, 
+    InstantiationException,
+    NullPointerException,
+    ClassCastException
+    {
+    String className = System.getProperty("org.xml.sax.parser");
+    if (className == null) {
+        throw new NullPointerException("No value for sax.parser property");
+    } else {
+        return makeParser(className);
+    }
+    }
+    
+    
+    /**
+     * Create a new SAX parser object using the class name provided.
+     *
+     * <p>The named class must exist and must implement the
+     * {@link org.xml.sax.Parser Parser} interface.</p>
+     *
+     * @return the newly created parser.
+     *
+     * @param className A string containing the name of the
+     *                  SAX parser class.
+     * @exception java.lang.ClassNotFoundException The SAX parser
+     *            class was not found (check your CLASSPATH).
+     * @exception IllegalAccessException The SAX parser class was
+     *            found, but you do not have permission to load
+     *            it.
+     * @exception InstantiationException The SAX parser class was
+     *            found but could not be instantiated.
+     * @exception java.lang.ClassCastException The SAX parser class
+     *            was found and instantiated, but does not implement
+     *            org.xml.sax.Parser.
+     * @see #makeParser()
+     * @see org.xml.sax.Parser
+     */
+    public static Parser makeParser (String className)
+    throws ClassNotFoundException,
+    IllegalAccessException, 
+    InstantiationException,
+    ClassCastException
+    {
+    return (Parser) NewInstance.newInstance (
+        NewInstance.getClassLoader (), className);
+    }
+    
+}
+
diff --git a/xml/src/main/java/org/xml/sax/helpers/XMLFilterImpl.java b/xml/src/main/java/org/xml/sax/helpers/XMLFilterImpl.java
new file mode 100644
index 0000000..68e2579
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/XMLFilterImpl.java
@@ -0,0 +1,715 @@
+// XMLFilterImpl.java - base SAX2 filter implementation.
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: XMLFilterImpl.java,v 1.9 2004/04/26 17:34:35 dmegginson Exp $
+
+package org.xml.sax.helpers;
+
+import java.io.IOException;
+
+import org.xml.sax.XMLReader;
+import org.xml.sax.XMLFilter;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXNotRecognizedException;
+
+
+/**
+ * Base class for deriving an XML filter.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class is designed to sit between an {@link org.xml.sax.XMLReader
+ * XMLReader} and the client application's event handlers.  By default, it
+ * does nothing but pass requests up to the reader and events
+ * on to the handlers unmodified, but subclasses can override
+ * specific methods to modify the event stream or the configuration
+ * requests as they pass through.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.XMLFilter
+ * @see org.xml.sax.XMLReader
+ * @see org.xml.sax.EntityResolver
+ * @see org.xml.sax.DTDHandler
+ * @see org.xml.sax.ContentHandler
+ * @see org.xml.sax.ErrorHandler
+ */
+public class XMLFilterImpl
+    implements XMLFilter, EntityResolver, DTDHandler, ContentHandler, ErrorHandler
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Constructors.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Construct an empty XML filter, with no parent.
+     *
+     * <p>This filter will have no parent: you must assign a parent
+     * before you start a parse or do any configuration with
+     * setFeature or setProperty, unless you use this as a pure event
+     * consumer rather than as an {@link XMLReader}.</p>
+     *
+     * @see org.xml.sax.XMLReader#setFeature
+     * @see org.xml.sax.XMLReader#setProperty
+     * @see #setParent
+     */
+    public XMLFilterImpl ()
+    {
+    super();
+    }
+
+
+    /**
+     * Construct an XML filter with the specified parent.
+     * 
+     * @param parent the XML reader from which this filter receives its events. 
+     *
+     * @see #setParent
+     * @see #getParent
+     */
+    public XMLFilterImpl (XMLReader parent)
+    {
+        super();
+    setParent(parent);
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.XMLFilter.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Set the parent reader.
+     *
+     * <p>This is the {@link org.xml.sax.XMLReader XMLReader} from which 
+     * this filter will obtain its events and to which it will pass its 
+     * configuration requests.  The parent may itself be another filter.</p>
+     *
+     * <p>If there is no parent reader set, any attempt to parse
+     * or to set or get a feature or property will fail.</p>
+     *
+     * @param parent The parent XML reader.
+     * @see #getParent
+     */
+    public void setParent (XMLReader parent)
+    {
+    this.parent = parent;
+    }
+
+
+    /**
+     * Get the parent reader.
+     *
+     * @return The parent XML reader, or null if none is set.
+     * @see #setParent
+     */
+    public XMLReader getParent ()
+    {
+    return parent;
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.XMLReader.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Set the value of a feature.
+     *
+     * <p>This will always fail if the parent is null.</p>
+     *
+     * @param name The feature name.
+     * @param value The requested feature value.
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved from the parent.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            parent recognizes the feature name but 
+     *            cannot set the requested value.
+     */
+    public void setFeature (String name, boolean value)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+    if (parent != null) {
+        parent.setFeature(name, value);
+    } else {
+        throw new SAXNotRecognizedException("Feature: " + name);
+    }
+    }
+
+
+    /**
+     * Look up the value of a feature.
+     *
+     * <p>This will always fail if the parent is null.</p>
+     *
+     * @param name The feature name.
+     * @return The current value of the feature.
+     * @exception org.xml.sax.SAXNotRecognizedException If the feature
+     *            value can't be assigned or retrieved from the parent.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            parent recognizes the feature name but 
+     *            cannot determine its value at this time.
+     */
+    public boolean getFeature (String name)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+    if (parent != null) {
+        return parent.getFeature(name);
+    } else {
+        throw new SAXNotRecognizedException("Feature: " + name);
+    }
+    }
+
+
+    /**
+     * Set the value of a property.
+     *
+     * <p>This will always fail if the parent is null.</p>
+     *
+     * @param name The property name.
+     * @param value The requested property value.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved from the parent.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            parent recognizes the property name but 
+     *            cannot set the requested value.
+     */
+    public void setProperty (String name, Object value)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+    if (parent != null) {
+        parent.setProperty(name, value);
+    } else {
+        throw new SAXNotRecognizedException("Property: " + name);
+    }
+    }
+
+
+    /**
+     * Look up the value of a property.
+     *
+     * @param name The property name.
+     * @return The current value of the property.
+     * @exception org.xml.sax.SAXNotRecognizedException If the property
+     *            value can't be assigned or retrieved from the parent.
+     * @exception org.xml.sax.SAXNotSupportedException When the
+     *            parent recognizes the property name but 
+     *            cannot determine its value at this time.
+     */
+    public Object getProperty (String name)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+    if (parent != null) {
+        return parent.getProperty(name);
+    } else {
+        throw new SAXNotRecognizedException("Property: " + name);
+    }
+    }
+
+
+    /**
+     * Set the entity resolver.
+     *
+     * @param resolver The new entity resolver.
+     */
+    public void setEntityResolver (EntityResolver resolver)
+    {
+    entityResolver = resolver;
+    }
+
+
+    /**
+     * Get the current entity resolver.
+     *
+     * @return The current entity resolver, or null if none was set.
+     */
+    public EntityResolver getEntityResolver ()
+    {
+    return entityResolver;
+    }
+
+
+    /**
+     * Set the DTD event handler.
+     *
+     * @param handler the new DTD handler
+     */
+    public void setDTDHandler (DTDHandler handler)
+    {
+    dtdHandler = handler;
+    }
+
+
+    /**
+     * Get the current DTD event handler.
+     *
+     * @return The current DTD handler, or null if none was set.
+     */
+    public DTDHandler getDTDHandler ()
+    {
+    return dtdHandler;
+    }
+
+
+    /**
+     * Set the content event handler.
+     *
+     * @param handler the new content handler
+     */
+    public void setContentHandler (ContentHandler handler)
+    {
+    contentHandler = handler;
+    }
+
+
+    /**
+     * Get the content event handler.
+     *
+     * @return The current content handler, or null if none was set.
+     */
+    public ContentHandler getContentHandler ()
+    {
+    return contentHandler;
+    }
+
+
+    /**
+     * Set the error event handler.
+     *
+     * @param handler the new error handler
+     */
+    public void setErrorHandler (ErrorHandler handler)
+    {
+    errorHandler = handler;
+    }
+
+
+    /**
+     * Get the current error event handler.
+     *
+     * @return The current error handler, or null if none was set.
+     */
+    public ErrorHandler getErrorHandler ()
+    {
+    return errorHandler;
+    }
+
+
+    /**
+     * Parse a document.
+     *
+     * @param input The input source for the document entity.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException An IO exception from the parser,
+     *            possibly from a byte stream or character stream
+     *            supplied by the application.
+     */
+    public void parse (InputSource input)
+    throws SAXException, IOException
+    {
+    setupParse();
+    parent.parse(input);
+    }
+
+
+    /**
+     * Parse a document.
+     *
+     * @param systemId The system identifier as a fully-qualified URI.
+     * @exception org.xml.sax.SAXException Any SAX exception, possibly
+     *            wrapping another exception.
+     * @exception java.io.IOException An IO exception from the parser,
+     *            possibly from a byte stream or character stream
+     *            supplied by the application.
+     */
+    public void parse (String systemId)
+    throws SAXException, IOException
+    {
+    parse(new InputSource(systemId));
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.EntityResolver.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Filter an external entity resolution.
+     *
+     * @param publicId The entity's public identifier, or null.
+     * @param systemId The entity's system identifier.
+     * @return A new InputSource or null for the default.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     * @exception java.io.IOException The client may throw an
+     *            I/O-related exception while obtaining the
+     *            new InputSource.
+     */
+    public InputSource resolveEntity (String publicId, String systemId)
+    throws SAXException, IOException
+    {
+    if (entityResolver != null) {
+        return entityResolver.resolveEntity(publicId, systemId);
+    } else {
+        return null;
+    }
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.DTDHandler.
+    ////////////////////////////////////////////////////////////////////
+
+    
+    /**
+     * Filter a notation declaration event.
+     *
+     * @param name The notation name.
+     * @param publicId The notation's public identifier, or null.
+     * @param systemId The notation's system identifier, or null.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void notationDecl (String name, String publicId, String systemId)
+    throws SAXException
+    {
+    if (dtdHandler != null) {
+        dtdHandler.notationDecl(name, publicId, systemId);
+    }
+    }
+
+    
+    /**
+     * Filter an unparsed entity declaration event.
+     *
+     * @param name The entity name.
+     * @param publicId The entity's public identifier, or null.
+     * @param systemId The entity's system identifier, or null.
+     * @param notationName The name of the associated notation.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void unparsedEntityDecl (String name, String publicId,
+                    String systemId, String notationName)
+    throws SAXException
+    {
+    if (dtdHandler != null) {
+        dtdHandler.unparsedEntityDecl(name, publicId, systemId,
+                      notationName);
+    }
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.ContentHandler.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Filter a new document locator event.
+     *
+     * @param locator The document locator.
+     */
+    public void setDocumentLocator (Locator locator)
+    {
+    this.locator = locator;
+    if (contentHandler != null) {
+        contentHandler.setDocumentLocator(locator);
+    }
+    }
+
+
+    /**
+     * Filter a start document event.
+     *
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void startDocument ()
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.startDocument();
+    }
+    }
+
+
+    /**
+     * Filter an end document event.
+     *
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void endDocument ()
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.endDocument();
+    }
+    }
+
+
+    /**
+     * Filter a start Namespace prefix mapping event.
+     *
+     * @param prefix The Namespace prefix.
+     * @param uri The Namespace URI.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void startPrefixMapping (String prefix, String uri)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.startPrefixMapping(prefix, uri);
+    }
+    }
+
+
+    /**
+     * Filter an end Namespace prefix mapping event.
+     *
+     * @param prefix The Namespace prefix.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void endPrefixMapping (String prefix)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.endPrefixMapping(prefix);
+    }
+    }
+
+
+    /**
+     * Filter a start element event.
+     *
+     * @param uri The element's Namespace URI, or the empty string.
+     * @param localName The element's local name, or the empty string.
+     * @param qName The element's qualified (prefixed) name, or the empty
+     *        string.
+     * @param atts The element's attributes.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void startElement (String uri, String localName, String qName,
+                  Attributes atts)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.startElement(uri, localName, qName, atts);
+    }
+    }
+
+
+    /**
+     * Filter an end element event.
+     *
+     * @param uri The element's Namespace URI, or the empty string.
+     * @param localName The element's local name, or the empty string.
+     * @param qName The element's qualified (prefixed) name, or the empty
+     *        string.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void endElement (String uri, String localName, String qName)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.endElement(uri, localName, qName);
+    }
+    }
+
+
+    /**
+     * Filter a character data event.
+     *
+     * @param ch An array of characters.
+     * @param start The starting position in the array.
+     * @param length The number of characters to use from the array.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void characters (char ch[], int start, int length)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.characters(ch, start, length);
+    }
+    }
+
+
+    /**
+     * Filter an ignorable whitespace event.
+     *
+     * @param ch An array of characters.
+     * @param start The starting position in the array.
+     * @param length The number of characters to use from the array.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void ignorableWhitespace (char ch[], int start, int length)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.ignorableWhitespace(ch, start, length);
+    }
+    }
+
+
+    /**
+     * Filter a processing instruction event.
+     *
+     * @param target The processing instruction target.
+     * @param data The text following the target.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void processingInstruction (String target, String data)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.processingInstruction(target, data);
+    }
+    }
+
+
+    /**
+     * Filter a skipped entity event.
+     *
+     * @param name The name of the skipped entity.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void skippedEntity (String name)
+    throws SAXException
+    {
+    if (contentHandler != null) {
+        contentHandler.skippedEntity(name);
+    }
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.ErrorHandler.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Filter a warning event.
+     *
+     * @param e The warning as an exception.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void warning (SAXParseException e)
+    throws SAXException
+    {
+    if (errorHandler != null) {
+        errorHandler.warning(e);
+    }
+    }
+
+
+    /**
+     * Filter an error event.
+     *
+     * @param e The error as an exception.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void error (SAXParseException e)
+    throws SAXException
+    {
+    if (errorHandler != null) {
+        errorHandler.error(e);
+    }
+    }
+
+
+    /**
+     * Filter a fatal error event.
+     *
+     * @param e The error as an exception.
+     * @exception org.xml.sax.SAXException The client may throw
+     *            an exception during processing.
+     */
+    public void fatalError (SAXParseException e)
+    throws SAXException
+    {
+    if (errorHandler != null) {
+        errorHandler.fatalError(e);
+    }
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal methods.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Set up before a parse.
+     *
+     * <p>Before every parse, check whether the parent is
+     * non-null, and re-register the filter for all of the 
+     * events.</p>
+     */
+    private void setupParse ()
+    {
+    if (parent == null) {
+        throw new NullPointerException("No parent for filter");
+    }
+    parent.setEntityResolver(this);
+    parent.setDTDHandler(this);
+    parent.setContentHandler(this);
+    parent.setErrorHandler(this);
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////////
+
+    private XMLReader parent = null;
+    private Locator locator = null;
+    private EntityResolver entityResolver = null;
+    private DTDHandler dtdHandler = null;
+    private ContentHandler contentHandler = null;
+    private ErrorHandler errorHandler = null;
+
+}
+
+// end of XMLFilterImpl.java
diff --git a/xml/src/main/java/org/xml/sax/helpers/XMLReaderAdapter.java b/xml/src/main/java/org/xml/sax/helpers/XMLReaderAdapter.java
new file mode 100644
index 0000000..cc8f431
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/XMLReaderAdapter.java
@@ -0,0 +1,538 @@
+// XMLReaderAdapter.java - adapt an SAX2 XMLReader to a SAX1 Parser
+// http://www.saxproject.org
+// Written by David Megginson
+// NO WARRANTY!  This class is in the public domain.
+// $Id: XMLReaderAdapter.java,v 1.9 2004/04/26 17:34:35 dmegginson Exp $
+
+package org.xml.sax.helpers;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import org.xml.sax.Parser;    // deprecated
+import org.xml.sax.Locator;
+import org.xml.sax.InputSource;
+import org.xml.sax.AttributeList; // deprecated
+import org.xml.sax.EntityResolver;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.DocumentHandler; // deprecated
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+
+import org.xml.sax.XMLReader;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXNotSupportedException;
+
+
+/**
+ * Adapt a SAX2 XMLReader as a SAX1 Parser.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class wraps a SAX2 {@link org.xml.sax.XMLReader XMLReader}
+ * and makes it act as a SAX1 {@link org.xml.sax.Parser Parser}.  The XMLReader 
+ * must support a true value for the 
+ * http://xml.org/sax/features/namespace-prefixes property or parsing will fail
+ * with a {@link org.xml.sax.SAXException SAXException}; if the XMLReader 
+ * supports a false value for the http://xml.org/sax/features/namespaces 
+ * property, that will also be used to improve efficiency.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson
+ * @version 2.0.1 (sax2r2)
+ * @see org.xml.sax.Parser
+ * @see org.xml.sax.XMLReader
+ */
+public class XMLReaderAdapter implements Parser, ContentHandler
+{
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Constructor.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Create a new adapter.
+     *
+     * <p>Use the "org.xml.sax.driver" property to locate the SAX2
+     * driver to embed.</p>
+     *
+     * @exception org.xml.sax.SAXException If the embedded driver
+     *            cannot be instantiated or if the
+     *            org.xml.sax.driver property is not specified.
+     */
+    public XMLReaderAdapter ()
+      throws SAXException
+    {
+    setup(XMLReaderFactory.createXMLReader());
+    }
+
+
+    /**
+     * Create a new adapter.
+     *
+     * <p>Create a new adapter, wrapped around a SAX2 XMLReader.
+     * The adapter will make the XMLReader act like a SAX1
+     * Parser.</p>
+     *
+     * @param xmlReader The SAX2 XMLReader to wrap.
+     * @exception java.lang.NullPointerException If the argument is null.
+     */
+    public XMLReaderAdapter (XMLReader xmlReader)
+    {
+    setup(xmlReader);
+    }
+
+
+
+    /**
+     * Internal setup.
+     *
+     * @param xmlReader The embedded XMLReader.
+     */
+    private void setup (XMLReader xmlReader)
+    {
+    if (xmlReader == null) {
+        throw new NullPointerException("XMLReader must not be null");
+    }
+    this.xmlReader = xmlReader;
+    qAtts = new AttributesAdapter();
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.Parser.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Set the locale for error reporting.
+     *
+     * <p>This is not supported in SAX2, and will always throw
+     * an exception.</p>
+     *
+     * @param locale the locale for error reporting.
+     * @see org.xml.sax.Parser#setLocale
+     * @exception org.xml.sax.SAXException Thrown unless overridden.
+     */
+    public void setLocale (Locale locale)
+    throws SAXException
+    {
+    throw new SAXNotSupportedException("setLocale not supported");
+    }
+
+
+    /**
+     * Register the entity resolver.
+     *
+     * @param resolver The new resolver.
+     * @see org.xml.sax.Parser#setEntityResolver
+     */
+    public void setEntityResolver (EntityResolver resolver)
+    {
+    xmlReader.setEntityResolver(resolver);
+    }
+
+
+    /**
+     * Register the DTD event handler.
+     *
+     * @param handler The new DTD event handler.
+     * @see org.xml.sax.Parser#setDTDHandler
+     */
+    public void setDTDHandler (DTDHandler handler)
+    {
+    xmlReader.setDTDHandler(handler);
+    }
+
+
+    /**
+     * Register the SAX1 document event handler.
+     *
+     * <p>Note that the SAX1 document handler has no Namespace
+     * support.</p>
+     *
+     * @param handler The new SAX1 document event handler.
+     * @see org.xml.sax.Parser#setDocumentHandler
+     */
+    public void setDocumentHandler (DocumentHandler handler)
+    {
+    documentHandler = handler;
+    }
+
+
+    /**
+     * Register the error event handler.
+     *
+     * @param handler The new error event handler.
+     * @see org.xml.sax.Parser#setErrorHandler
+     */
+    public void setErrorHandler (ErrorHandler handler)
+    {
+    xmlReader.setErrorHandler(handler);
+    }
+
+
+    /**
+     * Parse the document.
+     *
+     * <p>This method will throw an exception if the embedded
+     * XMLReader does not support the 
+     * http://xml.org/sax/features/namespace-prefixes property.</p>
+     *
+     * @param systemId The absolute URL of the document.
+     * @exception java.io.IOException If there is a problem reading
+     *            the raw content of the document.
+     * @exception org.xml.sax.SAXException If there is a problem
+     *            processing the document.
+     * @see #parse(org.xml.sax.InputSource)
+     * @see org.xml.sax.Parser#parse(java.lang.String)
+     */
+    public void parse (String systemId)
+    throws IOException, SAXException
+    {
+    parse(new InputSource(systemId));
+    }
+
+
+    /**
+     * Parse the document.
+     *
+     * <p>This method will throw an exception if the embedded
+     * XMLReader does not support the 
+     * http://xml.org/sax/features/namespace-prefixes property.</p>
+     *
+     * @param input An input source for the document.
+     * @exception java.io.IOException If there is a problem reading
+     *            the raw content of the document.
+     * @exception org.xml.sax.SAXException If there is a problem
+     *            processing the document.
+     * @see #parse(java.lang.String)
+     * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
+     */
+    public void parse (InputSource input)
+    throws IOException, SAXException
+    {
+    setupXMLReader();
+    xmlReader.parse(input);
+    }
+
+
+    /**
+     * Set up the XML reader.
+     */
+    private void setupXMLReader ()
+    throws SAXException
+    {
+    xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
+    try {
+        xmlReader.setFeature("http://xml.org/sax/features/namespaces",
+                             false);
+    } catch (SAXException e) {
+        // NO OP: it's just extra information, and we can ignore it
+    }
+    xmlReader.setContentHandler(this);
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Implementation of org.xml.sax.ContentHandler.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Set a document locator.
+     *
+     * @param locator The document locator.
+     * @see org.xml.sax.ContentHandler#setDocumentLocator
+     */
+    public void setDocumentLocator (Locator locator)
+    {
+    if (documentHandler != null)
+        documentHandler.setDocumentLocator(locator);
+    }
+
+
+    /**
+     * Start document event.
+     *
+     * @exception org.xml.sax.SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.ContentHandler#startDocument
+     */
+    public void startDocument ()
+    throws SAXException
+    {
+    if (documentHandler != null)
+        documentHandler.startDocument();
+    }
+
+
+    /**
+     * End document event.
+     *
+     * @exception org.xml.sax.SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.ContentHandler#endDocument
+     */
+    public void endDocument ()
+    throws SAXException
+    {
+    if (documentHandler != null)
+        documentHandler.endDocument();
+    }
+
+
+    /**
+     * Adapt a SAX2 start prefix mapping event.
+     *
+     * @param prefix The prefix being mapped.
+     * @param uri The Namespace URI being mapped to.
+     * @see org.xml.sax.ContentHandler#startPrefixMapping
+     */
+    public void startPrefixMapping (String prefix, String uri)
+    {
+    }
+
+
+    /**
+     * Adapt a SAX2 end prefix mapping event.
+     *
+     * @param prefix The prefix being mapped.
+     * @see org.xml.sax.ContentHandler#endPrefixMapping
+     */
+    public void endPrefixMapping (String prefix)
+    {
+    }
+
+
+    /**
+     * Adapt a SAX2 start element event.
+     *
+     * @param uri The Namespace URI.
+     * @param localName The Namespace local name.
+     * @param qName The qualified (prefixed) name.
+     * @param atts The SAX2 attributes.
+     * @exception org.xml.sax.SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.ContentHandler#endDocument
+     */
+    public void startElement (String uri, String localName,
+                  String qName, Attributes atts)
+    throws SAXException
+    {
+    if (documentHandler != null) {
+        qAtts.setAttributes(atts);
+        documentHandler.startElement(qName, qAtts);
+    }
+    }
+
+
+    /**
+     * Adapt a SAX2 end element event.
+     *
+     * @param uri The Namespace URI.
+     * @param localName The Namespace local name.
+     * @param qName The qualified (prefixed) name.
+     * @exception org.xml.sax.SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.ContentHandler#endElement
+     */
+    public void endElement (String uri, String localName,
+                String qName)
+    throws SAXException
+    {
+    if (documentHandler != null)
+        documentHandler.endElement(qName);
+    }
+
+
+    /**
+     * Adapt a SAX2 characters event.
+     *
+     * @param ch An array of characters.
+     * @param start The starting position in the array.
+     * @param length The number of characters to use.
+     * @exception org.xml.sax.SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.ContentHandler#characters
+     */
+    public void characters (char ch[], int start, int length)
+    throws SAXException
+    {
+    if (documentHandler != null)
+        documentHandler.characters(ch, start, length);
+    }
+
+
+    /**
+     * Adapt a SAX2 ignorable whitespace event.
+     *
+     * @param ch An array of characters.
+     * @param start The starting position in the array.
+     * @param length The number of characters to use.
+     * @exception org.xml.sax.SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.ContentHandler#ignorableWhitespace
+     */
+    public void ignorableWhitespace (char ch[], int start, int length)
+    throws SAXException
+    {
+    if (documentHandler != null)
+        documentHandler.ignorableWhitespace(ch, start, length);
+    }
+
+
+    /**
+     * Adapt a SAX2 processing instruction event.
+     *
+     * @param target The processing instruction target.
+     * @param data The remainder of the processing instruction
+     * @exception org.xml.sax.SAXException The client may raise a
+     *            processing exception.
+     * @see org.xml.sax.ContentHandler#processingInstruction
+     */
+    public void processingInstruction (String target, String data)
+    throws SAXException
+    {
+    if (documentHandler != null)
+        documentHandler.processingInstruction(target, data);
+    }
+
+
+    /**
+     * Adapt a SAX2 skipped entity event.
+     *
+     * @param name The name of the skipped entity.
+     * @see org.xml.sax.ContentHandler#skippedEntity
+     * @exception org.xml.sax.SAXException Throwable by subclasses.
+     */
+    public void skippedEntity (String name)
+    throws SAXException
+    {
+    }
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal state.
+    ////////////////////////////////////////////////////////////////////
+
+    XMLReader xmlReader;
+    DocumentHandler documentHandler;
+    AttributesAdapter qAtts;
+
+
+
+    ////////////////////////////////////////////////////////////////////
+    // Internal class.
+    ////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Internal class to wrap a SAX2 Attributes object for SAX1.
+     */
+    final class AttributesAdapter implements AttributeList
+    {
+    AttributesAdapter ()
+    {
+    }
+
+
+    /**
+     * Set the embedded Attributes object.
+     *
+     * @param The embedded SAX2 Attributes.
+     */ 
+    void setAttributes (Attributes attributes)
+    {
+        this.attributes = attributes;
+    }
+
+
+    /**
+     * Return the number of attributes.
+     *
+     * @return The length of the attribute list.
+     * @see org.xml.sax.AttributeList#getLength
+     */
+    public int getLength ()
+    {
+        return attributes.getLength();
+    }
+
+
+    /**
+     * Return the qualified (prefixed) name of an attribute by position.
+     *
+     * @return The qualified name.
+     * @see org.xml.sax.AttributeList#getName
+     */
+    public String getName (int i)
+    {
+        return attributes.getQName(i);
+    }
+
+
+    /**
+     * Return the type of an attribute by position.
+     *
+     * @return The type.
+     * @see org.xml.sax.AttributeList#getType(int)
+     */
+    public String getType (int i)
+    {
+        return attributes.getType(i);
+    }
+
+
+    /**
+     * Return the value of an attribute by position.
+     *
+     * @return The value.
+     * @see org.xml.sax.AttributeList#getValue(int)
+     */
+    public String getValue (int i)
+    {
+        return attributes.getValue(i);
+    }
+
+
+    /**
+     * Return the type of an attribute by qualified (prefixed) name.
+     *
+     * @return The type.
+     * @see org.xml.sax.AttributeList#getType(java.lang.String)
+     */
+    public String getType (String qName)
+    {
+        return attributes.getType(qName);
+    }
+
+
+    /**
+     * Return the value of an attribute by qualified (prefixed) name.
+     *
+     * @return The value.
+     * @see org.xml.sax.AttributeList#getValue(java.lang.String)
+     */
+    public String getValue (String qName)
+    {
+        return attributes.getValue(qName);
+    }
+
+    private Attributes attributes;
+    }
+
+}
+
+// end of XMLReaderAdapter.java
diff --git a/xml/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java b/xml/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
new file mode 100644
index 0000000..96151a1
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
@@ -0,0 +1,206 @@
+// XMLReaderFactory.java - factory for creating a new reader.
+// http://www.saxproject.org
+// Written by David Megginson
+// and by David Brownell
+// NO WARRANTY!  This class is in the Public Domain.
+// $Id: XMLReaderFactory.java,v 1.10 2002/04/22 01:00:13 dbrownell Exp $
+
+package org.xml.sax.helpers;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Factory for creating an XML reader.
+ *
+ * <blockquote>
+ * <em>This module, both source code and documentation, is in the
+ * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
+ * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+ * for further information.
+ * </blockquote>
+ *
+ * <p>This class contains static methods for creating an XML reader
+ * from an explicit class name, or based on runtime defaults:</p>
+ *
+ * <pre>
+ * try {
+ *   XMLReader myReader = XMLReaderFactory.createXMLReader();
+ * } catch (SAXException e) {
+ *   System.err.println(e.getMessage());
+ * }
+ * </pre>
+ *
+ * <p><strong>Note to Distributions bundled with parsers:</strong>
+ * You should modify the implementation of the no-arguments
+ * <em>createXMLReader</em> to handle cases where the external
+ * configuration mechanisms aren't set up.  That method should do its
+ * best to return a parser when one is in the class path, even when
+ * nothing bound its class name to <code>org.xml.sax.driver</code> so
+ * those configuration mechanisms would see it.</p>
+ *
+ * @since SAX 2.0
+ * @author David Megginson, David Brownell
+ * @version 2.0.1 (sax2r2)
+ */
+final public class XMLReaderFactory
+{
+    /**
+     * Private constructor.
+     *
+     * <p>This constructor prevents the class from being instantiated.</p>
+     */
+    private XMLReaderFactory ()
+    {
+    }
+
+    private static final String property = "org.xml.sax.driver";
+
+    /**
+     * Attempt to create an XMLReader from system defaults.
+     * In environments which can support it, the name of the XMLReader
+     * class is determined by trying each these options in order, and
+     * using the first one which succeeds:</p> <ul>
+     *
+     * <li>If the system property <code>org.xml.sax.driver</code>
+     * has a value, that is used as an XMLReader class name. </li>
+     *
+     * <li>The JAR "Services API" is used to look for a class name
+     * in the <em>META-INF/services/org.xml.sax.driver</em> file in
+     * jarfiles available to the runtime.</li>
+     *
+     * <li> SAX parser distributions are strongly encouraged to provide
+     * a default XMLReader class name that will take effect only when
+     * previous options (on this list) are not successful.</li>
+     *
+     * <li>Finally, if {@link ParserFactory#makeParser()} can
+     * return a system default SAX1 parser, that parser is wrapped in
+     * a {@link ParserAdapter}.  (This is a migration aid for SAX1
+     * environments, where the <code>org.xml.sax.parser</code> system
+     * property will often be usable.) </li>
+     *
+     * </ul>
+     *
+     * <p> In environments such as small embedded systems, which can not
+     * support that flexibility, other mechanisms to determine the default
+     * may be used. </p>
+     *
+     * <p>Note that many Java environments allow system properties to be
+     * initialized on a command line.  This means that <em>in most cases</em>
+     * setting a good value for that property ensures that calls to this
+     * method will succeed, except when security policies intervene.
+     * This will also maximize application portability to older SAX
+     * environments, with less robust implementations of this method.
+     * </p>
+     *
+     * @return A new XMLReader.
+     * @exception org.xml.sax.SAXException If no default XMLReader class
+     *            can be identified and instantiated.
+     * @see #createXMLReader(java.lang.String)
+     */
+    public static XMLReader createXMLReader ()
+    throws SAXException
+    {
+    String        className = null;
+    ClassLoader    loader = NewInstance.getClassLoader ();
+    
+    // 1. try the JVM-instance-wide system property
+    try { className = System.getProperty (property); }
+    catch (RuntimeException e) { /* normally fails for applets */ }
+
+    // 2. if that fails, try META-INF/services/
+    if (className == null) {
+        try {
+        String        service = "META-INF/services/" + property;
+        InputStream    in;
+        BufferedReader    reader;
+
+        if (loader == null)
+            in = ClassLoader.getSystemResourceAsStream (service);
+        else
+            in = loader.getResourceAsStream (service);
+
+        if (in != null) {
+            // BEGIN android-modified
+            reader = new BufferedReader (
+                new InputStreamReader (in, "UTF8"), 8192);
+            // END android-modified
+            className = reader.readLine ();
+            in.close ();
+        }
+        } catch (Exception e) {
+        }
+    }
+
+    // 3. Distro-specific fallback
+    if (className == null) {
+// BEGIN DISTRIBUTION-SPECIFIC
+
+        // EXAMPLE:
+        // className = "com.example.sax.XmlReader";
+        // or a $JAVA_HOME/jre/lib/*properties setting...
+
+// END DISTRIBUTION-SPECIFIC
+    }
+    
+    // do we know the XMLReader implementation class yet?
+    if (className != null)
+        return loadClass (loader, className);
+
+    // 4. panic -- adapt any SAX1 parser
+    try {
+        return new ParserAdapter (ParserFactory.makeParser ());
+    } catch (Exception e) {
+        throw new SAXException ("Can't create default XMLReader; "
+            + "is system property org.xml.sax.driver set?");
+    }
+    }
+
+
+    /**
+     * Attempt to create an XML reader from a class name.
+     *
+     * <p>Given a class name, this method attempts to load
+     * and instantiate the class as an XML reader.</p>
+     * 
+     * @param className the name of the class that should be instantiated.
+     *
+     * <p>Note that this method will not be usable in environments where
+     * the caller (perhaps an applet) is not permitted to load classes
+     * dynamically.</p>
+     *
+     * @return A new XML reader.
+     * @exception org.xml.sax.SAXException If the class cannot be
+     *            loaded, instantiated, and cast to XMLReader.
+     * @see #createXMLReader()
+     */
+    public static XMLReader createXMLReader (String className)
+    throws SAXException
+    {
+    return loadClass (NewInstance.getClassLoader (), className);
+    }
+
+    private static XMLReader loadClass (ClassLoader loader, String className)
+    throws SAXException
+    {
+    try {
+        return (XMLReader) NewInstance.newInstance (loader, className);
+    } catch (ClassNotFoundException e1) {
+        throw new SAXException("SAX2 driver class " + className +
+                   " not found", e1);
+    } catch (IllegalAccessException e2) {
+        throw new SAXException("SAX2 driver class " + className +
+                   " found but cannot be loaded", e2);
+    } catch (InstantiationException e3) {
+        throw new SAXException("SAX2 driver class " + className +
+       " loaded but cannot be instantiated (no empty public constructor?)",
+                   e3);
+    } catch (ClassCastException e4) {
+        throw new SAXException("SAX2 driver class " + className +
+                   " does not implement XMLReader", e4);
+    }
+    }
+}
diff --git a/xml/src/main/java/org/xml/sax/helpers/package.html b/xml/src/main/java/org/xml/sax/helpers/package.html
new file mode 100644
index 0000000..3a265fd
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/helpers/package.html
@@ -0,0 +1,13 @@
+<HTML><HEAD>
+<!-- $Id: package.html,v 1.6 2002/01/30 20:52:39 dbrownell Exp $ -->
+</HEAD><BODY>
+
+<p>This package contains "helper" classes, including
+support for bootstrapping SAX-based applications.
+
+<p>See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+for more information about SAX.</p>
+
+@since Android 1.0
+
+</BODY></HTML>
diff --git a/xml/src/main/java/org/xml/sax/package.html b/xml/src/main/java/org/xml/sax/package.html
new file mode 100644
index 0000000..fbe7108
--- /dev/null
+++ b/xml/src/main/java/org/xml/sax/package.html
@@ -0,0 +1,299 @@
+<html><head>
+<!-- $Id: package.html,v 1.18 2004/04/21 13:06:01 dmegginson Exp $ -->
+</head><body>
+
+<p> This package provides the core SAX APIs.
+Some SAX1 APIs are deprecated to encourage integration of
+namespace-awareness into designs of new applications
+and into maintenance of existing infrastructure. </p>
+
+<p>See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
+for more information about SAX.</p>
+
+
+<h2> SAX2 Standard Feature Flags </h2>
+
+<p> One of the essential characteristics of SAX2 is that it added
+feature flags which can be used to examine and perhaps modify
+parser modes, in particular modes such as validation.
+Since features are identified by (absolute) URIs, anyone
+can define such features.   
+Currently defined standard feature URIs have the prefix
+<code>http://xml.org/sax/features/</code> before an identifier such as
+<code>validation</code>.  Turn features on or off using
+<em>setFeature</em>.  Those standard identifiers are: </p>
+
+
+<table border="1" cellpadding="3" cellspacing="0" width="100%">
+    <tr align="center" bgcolor="#ccccff">
+	<th>Feature ID</th>
+	<th>Access</th>
+	<th>Default</th>
+	<th>Description</th>
+	</tr>
+
+    <tr>
+	<td>external-general-entities</td>
+	<td><em>read/write</em></td>
+	<td><em>unspecified</em></td>
+	<td> Reports whether this parser processes external
+	    general entities; always true if validating.
+		</td>
+	</tr>
+
+    <tr>
+	<td>external-parameter-entities</td>
+	<td><em>read/write</em></td>
+	<td><em>unspecified</em></td>
+	<td> Reports whether this parser processes external
+	    parameter entities; always true if validating.
+		</td>
+	</tr>
+
+    <tr>
+	<td>is-standalone</td>
+	<td>(parsing) <em>read-only</em>, (not parsing) <em>none</em></td>
+	<td>not applicable</td>
+	<td> May be examined only during a parse, after the
+	    <em>startDocument()</em> callback has been completed; read-only.
+	    The value is true if the document specified standalone="yes" in 
+	    its XML declaration, and otherwise is false.
+		</td>
+	</tr>
+
+    <tr>
+	<td>lexical-handler/parameter-entities</td>
+	<td><em>read/write</em></td>
+	<td><em>unspecified</em></td>
+	<td> A value of "true" indicates that the LexicalHandler will report
+	    the beginning and end of parameter entities.
+		</td>
+	</tr>
+
+    <tr>
+	<td>namespaces</td>
+	<td><em>read/write</em></td>
+	<td>true</td>
+	<td> A value of "true" indicates namespace URIs and unprefixed local names
+	    for element and attribute names will be available.
+		</td>
+	</tr>
+
+    <tr>
+	<td>namespace-prefixes</td>
+	<td><em>read/write</em></td>
+	<td>false</td>
+	<td> A value of "true" indicates that XML qualified names (with prefixes) and
+	    attributes (including <em>xmlns*</em> attributes) will be available.
+		</td>
+	</tr>
+
+    <tr>
+	<td>resolve-dtd-uris</td>
+	<td><em>read/write</em></td>
+	<td><em>true</em></td>
+	<td> A value of "true" indicates that system IDs in declarations will
+	    be absolutized (relative to their base URIs) before reporting.
+	    (That is the default behavior for all SAX2 XML parsers.)
+	    A value of "false" indicates those IDs will not be absolutized;
+	    parsers will provide the base URI from
+	    <em>Locator.getSystemId()</em>.
+	    This applies to system IDs passed in <ul>
+		<li><em>DTDHandler.notationDecl()</em>,
+		<li><em>DTDHandler.unparsedEntityDecl()</em>, and
+		<li><em>DeclHandler.externalEntityDecl()</em>.
+	    </ul>
+	    It does not apply to <em>EntityResolver.resolveEntity()</em>,
+	    which is not used to report declarations, or to
+	    <em>LexicalHandler.startDTD()</em>, which already provides
+	    the non-absolutized URI.
+	    </td>
+	</tr>
+
+    <tr>
+	<td>string-interning</td>
+	<td><em>read/write</em></td>
+	<td><em>unspecified</em></td>
+	<td> Has a value of "true" if all XML names (for elements, prefixes,
+	    attributes, entities, notations, and local names),
+	    as well as Namespace URIs, will have been interned
+	    using <em>java.lang.String.intern</em>. This supports fast
+	    testing of equality/inequality against string constants,
+	    rather than forcing slower calls to <em>String.equals()</em>.
+	    </td>
+	</tr>
+
+    <tr>
+    <td>unicode-normalization-checking</td>
+    <td><em>read/write</em></td>
+    <td><em>false</em></td>
+    <td> Controls whether the parser reports Unicode normalization 
+        errors as described in section 2.13 and Appendix B of the 
+        XML 1.1 Recommendation. If true, Unicode normalization
+        errors are reported using the ErrorHandler.error() callback.
+        Such errors are not fatal in themselves (though, obviously,
+        other Unicode-related encoding errors may be).
+		</td>
+    </tr>
+    
+    <tr>
+	<td>use-attributes2</td>
+	<td><em>read-only</em></td>
+	<td>not applicable</td>
+	<td> Returns "true" if the <em>Attributes</em> objects passed by
+	    this parser in <em>ContentHandler.startElement()</em>
+	    implement the <a href="ext/Attributes2.html"
+	    ><em>org.xml.sax.ext.Attributes2</em></a> interface.
+	    That interface exposes additional DTD-related information,
+	    such as whether the attribute was specified in the
+	    source text rather than defaulted.
+		</td>
+	</tr>
+
+    <tr>
+	<td>use-locator2</td>
+	<td><em>read-only</em></td>
+	<td>not applicable</td>
+	<td> Returns "true" if the <em>Locator</em> objects passed by
+	    this parser in <em>ContentHandler.setDocumentLocator()</em>
+	    implement the <a href="ext/Locator2.html"
+	    ><em>org.xml.sax.ext.Locator2</em></a> interface.
+	    That interface exposes additional entity information,
+	    such as the character encoding and XML version used.
+		</td>
+	</tr>
+
+    <tr>
+	<td>use-entity-resolver2</td>
+	<td><em>read/write</em></td>
+	<td><em>true</em></td>
+	<td> Returns "true" if, when <em>setEntityResolver</em> is given
+	    an object implementing the <a href="ext/EntityResolver2.html"
+	    ><em>org.xml.sax.ext.EntityResolver2</em></a> interface,
+	    those new methods will be used.
+	    Returns "false" to indicate that those methods will not be used.
+		</td>
+	</tr>
+
+    <tr>
+	<td>validation</td>
+	<td><em>read/write</em></td>
+	<td><em>unspecified</em></td>
+	<td> Controls whether the parser is reporting all validity
+	    errors; if true, all external entities will be read.
+		</td>
+	</tr>
+
+    <tr>
+	<td>xmlns-uris</td>
+	<td><em>read/write</em></td>
+	<td><em>false</em></td>
+	<td> Controls whether, when the <em>namespace-prefixes</em> feature
+	    is set, the parser treats namespace declaration attributes as
+	    being in the <em>http://www.w3.org/2000/xmlns/</em> namespace.
+	    By default, SAX2 conforms to the original "Namespaces in XML"
+	    Recommendation, which explicitly states that such attributes are
+	    not in any namespace.
+	    Setting this optional flag to "true" makes the SAX2 events conform to
+	    a later backwards-incompatible revision of that recommendation,
+	    placing those attributes in a namespace.
+		</td>
+	</tr>
+
+    <tr>
+    <td>xml-1.1</td>
+    <td><em>read-only</em></td>
+    <td>not applicable</td>
+    <td> Returns "true" if the parser supports both XML 1.1 and XML 1.0.
+        Returns "false" if the parser supports only XML 1.0.
+		</td>
+    </tr>
+
+</table>
+
+<p> Support for the default values of the
+<em>namespaces</em> and <em>namespace-prefixes</em>
+properties is required.
+Support for any other feature flags is entirely optional.
+</p>
+
+<p> For default values not specified by SAX2,
+each XMLReader implementation specifies its default,
+or may choose not to expose the feature flag.
+Unless otherwise specified here,
+implementations may support changing current values
+of these standard feature flags, but not while parsing.
+</p>
+
+<h2> SAX2 Standard Handler and Property IDs </h2>
+
+<p> For parser interface characteristics that are described
+as objects, a separate namespace is defined.  The
+objects in this namespace are again identified by URI, and
+the standard property URIs have the prefix
+<code>http://xml.org/sax/properties/</code> before an identifier such as
+<code>lexical-handler</code> or
+<code>dom-node</code>.  Manage those properties using
+<em>setProperty()</em>.  Those identifiers are: </p>
+
+<table border="1" cellpadding="3" cellspacing="0" width="100%">
+    <tr align="center" bgcolor="#ccccff">
+	<th>Property ID</th>
+	<th>Description</th>
+	</tr>
+
+    <tr>
+	<td>declaration-handler</td>
+	<td> Used to see most DTD declarations except those treated
+	    as lexical ("document element name is ...") or which are
+	    mandatory for all SAX parsers (<em>DTDHandler</em>).
+	    The Object must implement <a href="ext/DeclHandler.html"
+	    ><em>org.xml.sax.ext.DeclHandler</em></a>.
+	    </td>
+	</tr>
+
+    <tr>
+        <td>document-xml-version</td>
+        <td> May be examined only during a parse, after the startDocument()
+            callback has been completed; read-only. This property is a 
+            literal string describing the actual XML version of the document, 
+            such as "1.0" or "1.1".
+            </td>
+        </tr>
+    
+    <tr>
+	<td>dom-node</td>
+	<td> For "DOM Walker" style parsers, which ignore their
+	    <em>parser.parse()</em> parameters, this is used to
+	    specify the DOM (sub)tree being walked by the parser.
+	    The Object must implement the
+	    <em>org.w3c.dom.Node</em> interface.
+	    </td>
+	</tr>
+
+    <tr>
+	<td>lexical-handler</td>
+	<td> Used to see some syntax events that are essential in some
+	    applications:  comments, CDATA delimiters, selected general
+	    entity inclusions, and the start and end of the DTD
+	    (and declaration of document element name).
+	    The Object must implement <a href="ext/LexicalHandler.html"
+	    ><em>org.xml.sax.ext.LexicalHandler</em></a>.
+	    </td>
+	</tr>
+
+    <tr>
+	<td>xml-string</td>
+	<td> Readable only during a parser callback, this exposes a <b>TBS</b>
+	    chunk of characters responsible for the current event. </td>
+	</tr>
+
+</table>
+
+<p> All of these standard properties are optional;
+XMLReader implementations need not support them.
+</p>
+
+@since Android 1.0
+
+</body></html>
\ No newline at end of file
diff --git a/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java b/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java
new file mode 100644
index 0000000..2c2946f
--- /dev/null
+++ b/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java
@@ -0,0 +1,1116 @@
+/* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
+// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
+
+package org.xmlpull.v1;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * XML Pull Parser is an interface that defines parsing functionlity provided
+ * in <a href="http://www.xmlpull.org/">XMLPULL V1 API</a> (visit this website to
+ * learn more about API and its implementations).
+ *
+ * <p>There are following different
+ * kinds of parser depending on which features are set:<ul>
+ * <li><b>non-validating</b> parser as defined in XML 1.0 spec when
+ *   FEATURE_PROCESS_DOCDECL is set to true
+ * <li><b>validating parser</b> as defined in XML 1.0 spec when
+ *   FEATURE_VALIDATION is true (and that implies that FEATURE_PROCESS_DOCDECL is true)
+ * <li>when FEATURE_PROCESS_DOCDECL is false (this is default and
+ *   if different value is required necessary must be changed before parsing is started)
+ *   then parser behaves like XML 1.0 compliant non-validating parser under condition that
+ *  <em>no DOCDECL is present</em> in XML documents
+ *   (internal entites can still be defined with defineEntityReplacementText()).
+ *   This mode of operation is intened <b>for operation in constrained environments</b> such as J2ME.
+ * </ul>
+ *
+ *
+ * <p>There are two key methods: next() and nextToken(). While next() provides
+ * access to high level parsing events, nextToken() allows access to lower
+ * level tokens.
+ *
+ * <p>The current event state of the parser
+ * can be determined by calling the
+ * <a href="#getEventType()">getEventType()</a> method.
+ * Initially, the parser is in the <a href="#START_DOCUMENT">START_DOCUMENT</a>
+ * state.
+ *
+ * <p>The method <a href="#next()">next()</a> advances the parser to the
+ * next event. The int value returned from next determines the current parser
+ * state and is identical to the value returned from following calls to
+ * getEventType ().
+ *
+ * <p>Th following event types are seen by next()<dl>
+ * <dt><a href="#START_TAG">START_TAG</a><dd> An XML start tag was read.
+ * <dt><a href="#TEXT">TEXT</a><dd> Text content was read;
+ * the text content can be retreived using the getText() method.
+ *  (when in validating mode next() will not report ignorable whitespaces, use nextToken() instead)
+ * <dt><a href="#END_TAG">END_TAG</a><dd> An end tag was read
+ * <dt><a href="#END_DOCUMENT">END_DOCUMENT</a><dd> No more events are available
+ * </dl>
+ *
+ * <p>after first next() or nextToken() (or any other next*() method)
+ * is called user application can obtain
+ * XML version, standalone and encoding from XML declaration
+ * in following ways:<ul>
+ * <li><b>version</b>:
+ *  getProperty(&quot;<a href="http://xmlpull.org/v1/doc/properties.html#xmldecl-version">http://xmlpull.org/v1/doc/properties.html#xmldecl-version</a>&quot;)
+ *       returns String ("1.0") or null if XMLDecl was not read or if property is not supported
+ * <li><b>standalone</b>:
+ *  getProperty(&quot;<a href="http://xmlpull.org/v1/doc/features.html#xmldecl-standalone">http://xmlpull.org/v1/doc/features.html#xmldecl-standalone</a>&quot;)
+ *       returns Boolean: null if there was no standalone declaration
+ *  or if property is not supported
+ *         otherwise returns Boolean(true) if standalon="yes" and Boolean(false) when standalone="no"
+ * <li><b>encoding</b>: obtained from getInputEncoding()
+ *       null if stream had unknown encoding (not set in setInputStream)
+ *           and it was not declared in XMLDecl
+ * </ul>
+ *
+ * A minimal example for using this API may look as follows:
+ * <pre>
+ * import java.io.IOException;
+ * import java.io.StringReader;
+ *
+ * import org.xmlpull.v1.XmlPullParser;
+ * import org.xmlpull.v1.<a href="XmlPullParserException.html">XmlPullParserException.html</a>;
+ * import org.xmlpull.v1.<a href="XmlPullParserFactory.html">XmlPullParserFactory</a>;
+ *
+ * public class SimpleXmlPullApp
+ * {
+ *
+ *     public static void main (String args[])
+ *         throws XmlPullParserException, IOException
+ *     {
+ *         XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ *         factory.setNamespaceAware(true);
+ *         XmlPullParser xpp = factory.newPullParser();
+ *
+ *         xpp.<a href="#setInput">setInput</a>( new StringReader ( "&lt;foo>Hello World!&lt;/foo>" ) );
+ *         int eventType = xpp.getEventType();
+ *         while (eventType != XmlPullParser.END_DOCUMENT) {
+ *          if(eventType == XmlPullParser.START_DOCUMENT) {
+ *              System.out.println("Start document");
+ *          } else if(eventType == XmlPullParser.END_DOCUMENT) {
+ *              System.out.println("End document");
+ *          } else if(eventType == XmlPullParser.START_TAG) {
+ *              System.out.println("Start tag "+xpp.<a href="#getName()">getName()</a>);
+ *          } else if(eventType == XmlPullParser.END_TAG) {
+ *              System.out.println("End tag "+xpp.getName());
+ *          } else if(eventType == XmlPullParser.TEXT) {
+ *              System.out.println("Text "+xpp.<a href="#getText()">getText()</a>);
+ *          }
+ *          eventType = xpp.next();
+ *         }
+ *     }
+ * }
+ * </pre>
+ *
+ * <p>The above example will generate the following output:
+ * <pre>
+ * Start document
+ * Start tag foo
+ * Text Hello World!
+ * End tag foo
+ * </pre>
+ *
+ * <p>For more details on API usage, please refer to the
+ * quick Introduction available at <a href="http://www.xmlpull.org">http://www.xmlpull.org</a>
+ *
+ * @see XmlPullParserFactory
+ * @see #defineEntityReplacementText
+ * @see #getName
+ * @see #getNamespace
+ * @see #getText
+ * @see #next
+ * @see #nextToken
+ * @see #setInput
+ * @see #FEATURE_PROCESS_DOCDECL
+ * @see #FEATURE_VALIDATION
+ * @see #START_DOCUMENT
+ * @see #START_TAG
+ * @see #TEXT
+ * @see #END_TAG
+ * @see #END_DOCUMENT
+ *
+ * @author <a href="http://www-ai.cs.uni-dortmund.de/PERSONAL/haustein.html">Stefan Haustein</a>
+ * @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
+ */
+
+public interface XmlPullParser {
+
+    /** This constant represents the default namespace (empty string "") */
+    String NO_NAMESPACE = "";
+
+    // ----------------------------------------------------------------------------
+    // EVENT TYPES as reported by next()
+
+    /**
+     * Signalize that parser is at the very beginning of the document
+     * and nothing was read yet.
+     * This event type can only be observed by calling getEvent()
+     * before the first call to next(), nextToken, or nextTag()</a>).
+     *
+     * @see #next
+     * @see #nextToken
+     */
+    int START_DOCUMENT = 0;
+
+    /**
+     * Logical end of the xml document. Returned from getEventType, next()
+     * and nextToken()
+     * when the end of the input document has been reached.
+     * <p><strong>NOTE:</strong> calling again
+     * <a href="#next()">next()</a> or <a href="#nextToken()">nextToken()</a>
+     * will result in exception being thrown.
+     *
+     * @see #next
+     * @see #nextToken
+     */
+    int END_DOCUMENT = 1;
+
+    /**
+     * Returned from getEventType(),
+     * <a href="#next()">next()</a>, <a href="#nextToken()">nextToken()</a> when
+     * a start tag was read.
+     * The name of start tag is available from getName(), its namespace and prefix are
+     * available from getNamespace() and getPrefix()
+     * if <a href='#FEATURE_PROCESS_NAMESPACES'>namespaces are enabled</a>.
+     * See getAttribute* methods to retrieve element attributes.
+     * See getNamespace* methods to retrieve newly declared namespaces.
+     *
+     * @see #next
+     * @see #nextToken
+     * @see #getName
+     * @see #getPrefix
+     * @see #getNamespace
+     * @see #getAttributeCount
+     * @see #getDepth
+     * @see #getNamespaceCount
+     * @see #getNamespace
+     * @see #FEATURE_PROCESS_NAMESPACES
+     */
+    int START_TAG = 2;
+
+    /**
+     * Returned from getEventType(), <a href="#next()">next()</a>, or
+     * <a href="#nextToken()">nextToken()</a> when an end tag was read.
+     * The name of start tag is available from getName(), its
+     * namespace and prefix are
+     * available from getNamespace() and getPrefix().
+     *
+     * @see #next
+     * @see #nextToken
+     * @see #getName
+     * @see #getPrefix
+     * @see #getNamespace
+     * @see #FEATURE_PROCESS_NAMESPACES
+     */
+    int END_TAG = 3;
+
+
+    /**
+     * Character data was read and will is available by calling getText().
+     * <p><strong>Please note:</strong> <a href="#next()">next()</a> will
+     * accumulate multiple
+     * events into one TEXT event, skipping IGNORABLE_WHITESPACE,
+     * PROCESSING_INSTRUCTION and COMMENT events,
+     * In contrast, <a href="#nextToken()">nextToken()</a> will stop reading
+     * text when any other event is observed.
+     * Also, when the state was reached by calling next(), the text value will
+     * be normalized, whereas getText() will
+     * return unnormalized content in the case of nextToken(). This allows
+     * an exact roundtrip without chnanging line ends when examining low
+     * level events, whereas for high level applications the text is
+     * normalized apropriately.
+     *
+     * @see #next
+     * @see #nextToken
+     * @see #getText
+     */
+    int TEXT = 4;
+
+    // ----------------------------------------------------------------------------
+    // additional events exposed by lower level nextToken()
+
+    /**
+     * A CDATA sections was just read;
+     * this token is available only from calls to <a href="#nextToken()">nextToken()</a>.
+     * A call to next() will accumulate various text events into a single event
+     * of type TEXT. The text contained in the CDATA section is available
+     * by callling getText().
+     *
+     * @see #nextToken
+     * @see #getText
+     */
+    int CDSECT = 5;
+
+    /**
+     * An entity reference was just read;
+     * this token is available from <a href="#nextToken()">nextToken()</a>
+     * only. The entity name is available by calling getName(). If available,
+     * the replacement text can be obtained by calling getTextt(); otherwise,
+     * the user is responsibile for resolving the entity reference.
+     * This event type is never returned from next(); next() will
+     * accumulate the replacement text and other text
+     * events to a single TEXT event.
+     *
+     * @see #nextToken
+     * @see #getText
+     */
+    int ENTITY_REF = 6;
+
+    /**
+     * Ignorable whitespace was just read.
+     * This token is available only from <a href="#nextToken()">nextToken()</a>).
+     * For non-validating
+     * parsers, this event is only reported by nextToken() when outside
+     * the root element.
+     * Validating parsers may be able to detect ignorable whitespace at
+     * other locations.
+     * The ignorable whitespace string is available by calling getText()
+     *
+     * <p><strong>NOTE:</strong> this is different from calling the
+     *  isWhitespace() method, since text content
+     *  may be whitespace but not ignorable.
+     *
+     * Ignorable whitespace is skipped by next() automatically; this event
+     * type is never returned from next().
+     *
+     * @see #nextToken
+     * @see #getText
+     */
+    int IGNORABLE_WHITESPACE = 7;
+
+    /**
+     * An XML processing instruction declaration was just read. This
+     * event type is available only via <a href="#nextToken()">nextToken()</a>.
+     * getText() will return text that is inside the processing instruction.
+     * Calls to next() will skip processing instructions automatically.
+     * @see #nextToken
+     * @see #getText
+     */
+    int PROCESSING_INSTRUCTION = 8;
+
+    /**
+     * An XML comment was just read. This event type is this token is
+     * available via <a href="#nextToken()">nextToken()</a> only;
+     * calls to next() will skip comments automatically.
+     * The content of the comment can be accessed using the getText()
+     * method.
+     *
+     * @see #nextToken
+     * @see #getText
+     */
+    int COMMENT = 9;
+
+    /**
+     * An XML document type declaration was just read. This token is
+     * available from <a href="#nextToken()">nextToken()</a> only.
+     * The unparsed text inside the doctype is available via
+     * the getText() method.
+     *
+     * @see #nextToken
+     * @see #getText
+     */
+    int DOCDECL = 10;
+
+    /**
+     * This array can be used to convert the event type integer constants
+     * such as START_TAG or TEXT to
+     * to a string. For example, the value of TYPES[START_TAG] is
+     * the string "START_TAG".
+     *
+     * This array is intended for diagnostic output only. Relying
+     * on the contents of the array may be dangerous since malicous
+     * applications may alter the array, although it is final, due
+     * to limitations of the Java language.
+     */
+    String [] TYPES = {
+        "START_DOCUMENT",
+            "END_DOCUMENT",
+            "START_TAG",
+            "END_TAG",
+            "TEXT",
+            "CDSECT",
+            "ENTITY_REF",
+            "IGNORABLE_WHITESPACE",
+            "PROCESSING_INSTRUCTION",
+            "COMMENT",
+            "DOCDECL"
+    };
+
+
+    // ----------------------------------------------------------------------------
+    // namespace related features
+
+    /**
+     * This feature determines whether the parser processes
+     * namespaces. As for all features, the default value is false.
+     * <p><strong>NOTE:</strong> The value can not be changed during
+     * parsing an must be set before parsing.
+     *
+     * @see #getFeature
+     * @see #setFeature
+     */
+    String FEATURE_PROCESS_NAMESPACES =
+        "http://xmlpull.org/v1/doc/features.html#process-namespaces";
+
+    /**
+     * This feature determines whether namespace attributes are
+     * exposed via the attribute access methods. Like all features,
+     * the default value is false. This feature cannot be changed
+     * during parsing.
+     *
+     * @see #getFeature
+     * @see #setFeature
+     */
+    String FEATURE_REPORT_NAMESPACE_ATTRIBUTES =
+        "http://xmlpull.org/v1/doc/features.html#report-namespace-prefixes";
+
+    /**
+     * This feature determines whether the document declaration
+     * is processed. If set to false,
+     * the DOCDECL event type is reported by nextToken()
+     * and ignored by next().
+     *
+     * If this featue is activated, then the document declaration
+     * must be processed by the parser.
+     *
+     * <p><strong>Please note:</strong> If the document type declaration
+     * was ignored, entity references may cause exceptions
+     * later in the parsing process.
+     * The default value of this feature is false. It cannot be changed
+     * during parsing.
+     *
+     * @see #getFeature
+     * @see #setFeature
+     */
+    String FEATURE_PROCESS_DOCDECL =
+        "http://xmlpull.org/v1/doc/features.html#process-docdecl";
+
+    /**
+     * If this feature is activated, all validation errors as
+     * defined in the XML 1.0 sepcification are reported.
+     * This implies that FEATURE_PROCESS_DOCDECL is true and both, the
+     * internal and external document type declaration will be processed.
+     * <p><strong>Please Note:</strong> This feature can not be changed
+     * during parsing. The default value is false.
+     *
+     * @see #getFeature
+     * @see #setFeature
+     */
+    String FEATURE_VALIDATION =
+        "http://xmlpull.org/v1/doc/features.html#validation";
+
+    /**
+     * Use this call to change the general behaviour of the parser,
+     * such as namespace processing or doctype declaration handling.
+     * This method must be called before the first call to next or
+     * nextToken. Otherwise, an exception is thrown.
+     * <p>Example: call setFeature(FEATURE_PROCESS_NAMESPACES, true) in order
+     * to switch on namespace processing. The initial settings correspond
+     * to the properties requested from the XML Pull Parser factory.
+     * If none were requested, all feautures are deactivated by default.
+     *
+     * @exception XmlPullParserException If the feature is not supported or can not be set
+     * @exception IllegalArgumentException If string with the feature name is null
+     */
+    void setFeature(String name,
+                           boolean state) throws XmlPullParserException;
+
+    /**
+     * Returns the current value of the given feature.
+     * <p><strong>Please note:</strong> unknown features are
+     * <strong>always</strong> returned as false.
+     *
+     * @param name The name of feature to be retrieved.
+     * @return The value of the feature.
+     * @exception IllegalArgumentException if string the feature name is null
+     */
+
+    boolean getFeature(String name);
+
+    /**
+     * Set the value of a property.
+     *
+     * The property name is any fully-qualified URI.
+     *
+     * @exception XmlPullParserException If the property is not supported or can not be set
+     * @exception IllegalArgumentException If string with the property name is null
+     */
+    void setProperty(String name,
+                            Object value) throws XmlPullParserException;
+
+    /**
+     * Look up the value of a property.
+     *
+     * The property name is any fully-qualified URI.
+     * <p><strong>NOTE:</strong> unknown properties are <strong>always</strong>
+     * returned as null.
+     *
+     * @param name The name of property to be retrieved.
+     * @return The value of named property.
+     */
+    Object getProperty(String name);
+
+
+    /**
+     * Set the input source for parser to the given reader and
+     * resets the parser. The event type is set to the initial value
+     * START_DOCUMENT.
+     * Setting the reader to null will just stop parsing and
+     * reset parser state,
+     * allowing the parser to free internal resources
+     * such as parsing buffers.
+     */
+    void setInput(Reader in) throws XmlPullParserException;
+
+
+    /**
+     * Sets the input stream the parser is going to process.
+     * This call resets the parser state and sets the event type
+     * to the initial value START_DOCUMENT.
+     *
+     * <p><strong>NOTE:</strong> If an input encoding string is passed,
+     *  it MUST be used. Otherwise,
+     *  if inputEncoding is null, the parser SHOULD try to determine
+     *  input encoding following XML 1.0 specification (see below).
+     *  If encoding detection is supported then following feature
+     *  <a href="http://xmlpull.org/v1/doc/features.html#detect-encoding">http://xmlpull.org/v1/doc/features.html#detect-encoding</a>
+     *  MUST be true amd otherwise it must be false
+     *
+     * @param inputStream contains a raw byte input stream of possibly
+     *     unknown encoding (when inputEncoding is null).
+     *
+     * @param inputEncoding if not null it MUST be used as encoding for inputStream
+     */
+    void setInput(InputStream inputStream, String inputEncoding)
+        throws XmlPullParserException;
+
+    /**
+     * Returns the input encoding if known, null otherwise.
+     * If setInput(InputStream, inputEncoding) was called with an inputEncoding
+     * value other than null, this value must be returned
+     * from this method. Otherwise, if inputEncoding is null and
+     * the parser suppports the encoding detection feature
+     * (http://xmlpull.org/v1/doc/features.html#detect-encoding),
+     * it must return the detected encoding.
+     * If setInput(Reader) was called, null is returned.
+     * After first call to next if XML declaration was present this method
+     * will return encoding declared.
+     */
+    String getInputEncoding();
+
+    /**
+     * Set new value for entity replacement text as defined in
+     * <a href="http://www.w3.org/TR/REC-xml#intern-replacement">XML 1.0 Section 4.5
+     * Construction of Internal Entity Replacement Text</a>.
+     * If FEATURE_PROCESS_DOCDECL or FEATURE_VALIDATION are set, calling this
+     * function will result in an exception -- when processing of DOCDECL is
+     * enabled, there is no need to the entity replacement text manually.
+     *
+     * <p>The motivation for this function is to allow very small
+     * implementations of XMLPULL that will work in J2ME environments.
+     * Though these implementations may not be able to process the document type
+     * declaration, they still can work with known DTDs by using this function.
+     *
+     * <p><b>Please notes:</b> The given value is used literally as replacement text
+     * and it corresponds to declaring entity in DTD that has all special characters
+     * escaped: left angle bracket is replaced with &amp;lt;, ampersnad with &amp;amp;
+     * and so on.
+     *
+     * <p><b>Note:</b> The given value is the literal replacement text and must not
+     * contain any other entity reference (if it contains any entity reference
+     * there will be no further replacement).
+     *
+     * <p><b>Note:</b> The list of pre-defined entity names will
+     * always contain standard XML entities such as
+     * amp (&amp;amp;), lt (&amp;lt;), gt (&amp;gt;), quot (&amp;quot;), and apos (&amp;apos;).
+     * Those cannot be redefined by this method!
+     *
+     * @see #setInput
+     * @see #FEATURE_PROCESS_DOCDECL
+     * @see #FEATURE_VALIDATION
+     */
+    void defineEntityReplacementText( String entityName,
+                                            String replacementText ) throws XmlPullParserException;
+
+    /**
+     * Returns the numbers of elements in the namespace stack for the given
+     * depth.
+     * If namespaces are not enabled, 0 is returned.
+     *
+     * <p><b>NOTE:</b> when parser is on END_TAG then it is allowed to call
+     *  this function with getDepth()+1 argument to retrieve position of namespace
+     *  prefixes and URIs that were declared on corresponding START_TAG.
+     * <p><b>NOTE:</b> to retrieve lsit of namespaces declared in current element:<pre>
+     *       XmlPullParser pp = ...
+     *       int nsStart = pp.getNamespaceCount(pp.getDepth()-1);
+     *       int nsEnd = pp.getNamespaceCount(pp.getDepth());
+     *       for (int i = nsStart; i < nsEnd; i++) {
+     *          String prefix = pp.getNamespacePrefix(i);
+     *          String ns = pp.getNamespaceUri(i);
+     *           // ...
+     *      }
+     * </pre>
+     *
+     * @see #getNamespacePrefix
+     * @see #getNamespaceUri
+     * @see #getNamespace()
+     * @see #getNamespace(String)
+     */
+    int getNamespaceCount(int depth) throws XmlPullParserException;
+
+    /**
+     * Returns the namespace prefixe for the given position
+     * in the namespace stack.
+     * Default namespace declaration (xmlns='...') will have null as prefix.
+     * If the given index is out of range, an exception is thrown.
+     * <p><b>Please note:</b> when the parser is on an END_TAG,
+     * namespace prefixes that were declared
+     * in the corresponding START_TAG are still accessible
+     * although they are no longer in scope.
+     */
+    String getNamespacePrefix(int pos) throws XmlPullParserException;
+
+    /**
+     * Returns the namespace URI for the given position in the
+     * namespace stack
+     * If the position is out of range, an exception is thrown.
+     * <p><b>NOTE:</b> when parser is on END_TAG then namespace prefixes that were declared
+     *  in corresponding START_TAG are still accessible even though they are not in scope
+     */
+    String getNamespaceUri(int pos) throws XmlPullParserException;
+
+    /**
+     * Returns the URI corresponding to the given prefix,
+     * depending on current state of the parser.
+     *
+     * <p>If the prefix was not declared in the current scope,
+     * null is returned. The default namespace is included
+     * in the namespace table and is available via
+     * getNamespace (null).
+     *
+     * <p>This method is a convenience method for
+     *
+     * <pre>
+     *  for (int i = getNamespaceCount(getDepth ())-1; i >= 0; i--) {
+     *   if (getNamespacePrefix(i).equals( prefix )) {
+     *     return getNamespaceUri(i);
+     *   }
+     *  }
+     *  return null;
+     * </pre>
+     *
+     * <p><strong>Please note:</strong> parser implementations
+     * may provide more efifcient lookup, e.g. using a Hashtable.
+     * The 'xml' prefix is bound to "http://www.w3.org/XML/1998/namespace", as
+     * defined in the
+     * <a href="http://www.w3.org/TR/REC-xml-names/#ns-using">Namespaces in XML</a>
+     * specification. Analogous, the 'xmlns' prefix is resolved to
+     * <a href="http://www.w3.org/2000/xmlns/">http://www.w3.org/2000/xmlns/</a>
+     *
+     * @see #getNamespaceCount
+     * @see #getNamespacePrefix
+     * @see #getNamespaceUri
+     */
+    String getNamespace (String prefix);
+
+
+    // --------------------------------------------------------------------------
+    // miscellaneous reporting methods
+
+    /**
+     * Returns the current depth of the element.
+     * Outside the root element, the depth is 0. The
+     * depth is incremented by 1 when a start tag is reached.
+     * The depth is decremented AFTER the end tag
+     * event was observed.
+     *
+     * <pre>
+     * &lt;!-- outside --&gt;     0
+     * &lt;root>                  1
+     *   sometext                 1
+     *     &lt;foobar&gt;         2
+     *     &lt;/foobar&gt;        2
+     * &lt;/root&gt;              1
+     * &lt;!-- outside --&gt;     0
+     * </pre>
+     */
+    int getDepth();
+
+    /**
+     * Returns a short text describing the current parser state, including
+     * the position, a
+     * description of the current event and the data source if known.
+     * This method is especially useful to provide meaningful
+     * error messages and for debugging purposes.
+     */
+    String getPositionDescription ();
+
+
+    /**
+     * Returns the current line number, starting from 1.
+     * When the parser does not know the current line number
+     * or can not determine it,  -1 is returned (e.g. for WBXML).
+     *
+     * @return current line number or -1 if unknown.
+     */
+    int getLineNumber();
+
+    /**
+     * Returns the current column number, starting from 0.
+     * When the parser does not know the current column number
+     * or can not determine it,  -1 is returned (e.g. for WBXML).
+     *
+     * @return current column number or -1 if unknown.
+     */
+    int getColumnNumber();
+
+
+    // --------------------------------------------------------------------------
+    // TEXT related methods
+
+    /**
+     * Checks whether the current TEXT event contains only whitespace
+     * characters.
+     * For IGNORABLE_WHITESPACE, this is always true.
+     * For TEXT and CDSECT, false is returned when the current event text
+     * contains at least one non-white space character. For any other
+     * event type an exception is thrown.
+     *
+     * <p><b>Please note:</b> non-validating parsers are not
+     * able to distinguish whitespace and ignorable whitespace,
+     * except from whitespace outside the root element. Ignorable
+     * whitespace is reported as separate event, which is exposed
+     * via nextToken only.
+     *
+     */
+    boolean isWhitespace() throws XmlPullParserException;
+
+    /**
+     * Returns the text content of the current event as String.
+     * The value returned depends on current event type,
+     * for example for TEXT event it is element content
+     * (this is typical case when next() is used).
+     *
+     * See description of nextToken() for detailed description of
+     * possible returned values for different types of events.
+     *
+     * <p><strong>NOTE:</strong> in case of ENTITY_REF, this method returns
+     * the entity replacement text (or null if not available). This is
+     * the only case where
+     * getText() and getTextCharacters() return different values.
+     *
+     * @see #getEventType
+     * @see #next
+     * @see #nextToken
+     */
+    String getText ();
+
+
+    /**
+     * Returns the buffer that contains the text of the current event,
+     * as well as the start offset and length relevant for the current
+     * event. See getText(), next() and nextToken() for description of possible returned values.
+     *
+     * <p><strong>Please note:</strong> this buffer must not
+     * be modified and its content MAY change after a call to
+     * next() or nextToken(). This method will always return the
+     * same value as getText(), except for ENTITY_REF. In the case
+     * of ENTITY ref, getText() returns the replacement text and
+     * this method returns the actual input buffer containing the
+     * entity name.
+     * If getText() returns null, this method returns null as well and
+     * the values returned in the holder array MUST be -1 (both start
+     * and length).
+     *
+     * @see #getText
+     * @see #next
+     * @see #nextToken
+     *
+     * @param holderForStartAndLength Must hold an 2-element int array
+     * into which the start offset and length values will be written.
+     * @return char buffer that contains the text of the current event
+     *  (null if the current event has no text associated).
+     */
+    char[] getTextCharacters(int [] holderForStartAndLength);
+
+    // --------------------------------------------------------------------------
+    // START_TAG / END_TAG shared methods
+
+    /**
+     * Returns the namespace URI of the current element.
+     * The default namespace is represented
+     * as empty string.
+     * If namespaces are not enabled, an empty String ("") is always returned.
+     * The current event must be START_TAG or END_TAG; otherwise,
+     * null is returned.
+     */
+    String getNamespace ();
+
+    /**
+     * For START_TAG or END_TAG events, the (local) name of the current
+     * element is returned when namespaces are enabled. When namespace
+     * processing is disabled, the raw name is returned.
+     * For ENTITY_REF events, the entity name is returned.
+     * If the current event is not START_TAG, END_TAG, or ENTITY_REF,
+     * null is returned.
+     * <p><b>Please note:</b> To reconstruct the raw element name
+     *  when namespaces are enabled and the prefix is not null,
+     * you will need to  add the prefix and a colon to localName..
+     *
+     */
+    String getName();
+
+    /**
+     * Returns the prefix of the current element.
+     * If the element is in the default namespace (has no prefix),
+     * null is returned.
+     * If namespaces are not enabled, or the current event
+     * is not  START_TAG or END_TAG, null is returned.
+     */
+    String getPrefix();
+
+    /**
+     * Returns true if the current event is START_TAG and the tag
+     * is degenerated
+     * (e.g. &lt;foobar/&gt;).
+     * <p><b>NOTE:</b> if the parser is not on START_TAG, an exception
+     * will be thrown.
+     */
+    boolean isEmptyElementTag() throws XmlPullParserException;
+
+    // --------------------------------------------------------------------------
+    // START_TAG Attributes retrieval methods
+
+    /**
+     * Returns the number of attributes of the current start tag, or
+     * -1 if the current event type is not START_TAG
+     *
+     * @see #getAttributeNamespace
+     * @see #getAttributeName
+     * @see #getAttributePrefix
+     * @see #getAttributeValue
+     */
+    int getAttributeCount();
+
+    /**
+     * Returns the namespace URI of the attribute
+     * with the given index (starts from 0).
+     * Returns an empty string ("") if namespaces are not enabled
+     * or the attribute has no namespace.
+     * Throws an IndexOutOfBoundsException if the index is out of range
+     * or the current event type is not START_TAG.
+     *
+     * <p><strong>NOTE:</strong> if FEATURE_REPORT_NAMESPACE_ATTRIBUTES is set
+     * then namespace attributes (xmlns:ns='...') must be reported
+     * with namespace
+     * <a href="http://www.w3.org/2000/xmlns/">http://www.w3.org/2000/xmlns/</a>
+     * (visit this URL for description!).
+     * The default namespace attribute (xmlns="...") will be reported with empty namespace.
+     * <p><strong>NOTE:</strong>The xml prefix is bound as defined in
+     * <a href="http://www.w3.org/TR/REC-xml-names/#ns-using">Namespaces in XML</a>
+     * specification to "http://www.w3.org/XML/1998/namespace".
+     *
+     * @param index zero-based index of attribute
+     * @return attribute namespace,
+     *   empty string ("") is returned  if namesapces processing is not enabled or
+     *   namespaces processing is enabled but attribute has no namespace (it has no prefix).
+     */
+    String getAttributeNamespace (int index);
+
+    /**
+     * Returns the local name of the specified attribute
+     * if namespaces are enabled or just attribute name if namespaces are disabled.
+     * Throws an IndexOutOfBoundsException if the index is out of range
+     * or current event type is not START_TAG.
+     *
+     * @param index zero-based index of attribute
+     * @return attribute name (null is never returned)
+     */
+    String getAttributeName (int index);
+
+    /**
+     * Returns the prefix of the specified attribute
+     * Returns null if the element has no prefix.
+     * If namespaces are disabled it will always return null.
+     * Throws an IndexOutOfBoundsException if the index is out of range
+     * or current event type is not START_TAG.
+     *
+     * @param index zero-based index of attribute
+     * @return attribute prefix or null if namespaces processing is not enabled.
+     */
+    String getAttributePrefix(int index);
+
+    /**
+     * Returns the type of the specified attribute
+     * If parser is non-validating it MUST return CDATA.
+     *
+     * @param index zero-based index of attribute
+     * @return attribute type (null is never returned)
+     */
+    String getAttributeType(int index);
+
+    /**
+     * Returns if the specified attribute was not in input was declared in XML.
+     * If parser is non-validating it MUST always return false.
+     * This information is part of XML infoset:
+     *
+     * @param index zero-based index of attribute
+     * @return false if attribute was in input
+     */
+    boolean isAttributeDefault(int index);
+
+    /**
+     * Returns the given attributes value.
+     * Throws an IndexOutOfBoundsException if the index is out of range
+     * or current event type is not START_TAG.
+     *
+     * <p><strong>NOTE:</strong> attribute value must be normalized
+     * (including entity replacement text if PROCESS_DOCDECL is false) as described in
+     * <a href="http://www.w3.org/TR/REC-xml#AVNormalize">XML 1.0 section
+     * 3.3.3 Attribute-Value Normalization</a>
+     *
+     * @see #defineEntityReplacementText
+     *
+     * @param index zero-based index of attribute
+     * @return value of attribute (null is never returned)
+     */
+    String getAttributeValue(int index);
+
+    /**
+     * Returns the attributes value identified by namespace URI and namespace localName.
+     * If namespaces are disabled namespace must be null.
+     * If current event type is not START_TAG then IndexOutOfBoundsException will be thrown.
+     *
+     * <p><strong>NOTE:</strong> attribute value must be normalized
+     * (including entity replacement text if PROCESS_DOCDECL is false) as described in
+     * <a href="http://www.w3.org/TR/REC-xml#AVNormalize">XML 1.0 section
+     * 3.3.3 Attribute-Value Normalization</a>
+     *
+     * @see #defineEntityReplacementText
+     *
+     * @param namespace Namespace of the attribute if namespaces are enabled otherwise must be null
+     * @param name If namespaces enabled local name of attribute otherwise just attribute name
+     * @return value of attribute or null if attribute with given name does not exist
+     */
+    String getAttributeValue(String namespace,
+                                    String name);
+
+    // --------------------------------------------------------------------------
+    // actual parsing methods
+
+    /**
+     * Returns the type of the current event (START_TAG, END_TAG, TEXT, etc.)
+     *
+     * @see #next()
+     * @see #nextToken()
+     */
+    int getEventType()
+        throws XmlPullParserException;
+
+    /**
+     * Get next parsing event - element content wil be coalesced and only one
+     * TEXT event must be returned for whole element content
+     * (comments and processing instructions will be ignored and emtity references
+     * must be expanded or exception mus be thrown if entity reerence can not be exapnded).
+     * If element content is empty (content is "") then no TEXT event will be reported.
+     *
+     * <p><b>NOTE:</b> empty element (such as &lt;tag/>) will be reported
+     *  with  two separate events: START_TAG, END_TAG - it must be so to preserve
+     *   parsing equivalency of empty element to &lt;tag>&lt;/tag>.
+     *  (see isEmptyElementTag ())
+     *
+     * @see #isEmptyElementTag
+     * @see #START_TAG
+     * @see #TEXT
+     * @see #END_TAG
+     * @see #END_DOCUMENT
+     */
+
+    int next()
+        throws XmlPullParserException, IOException;
+
+
+    /**
+     * This method works similarly to next() but will expose
+     * additional event types (COMMENT, CDSECT, DOCDECL, ENTITY_REF, PROCESSING_INSTRUCTION, or
+     * IGNORABLE_WHITESPACE) if they are available in input.
+     *
+     * <p>If special feature
+     * <a href="http://xmlpull.org/v1/doc/features.html#xml-roundtrip">FEATURE_XML_ROUNDTRIP</a>
+     * (identified by URI: http://xmlpull.org/v1/doc/features.html#xml-roundtrip)
+     * is enabled it is possible to do XML document round trip ie. reproduce
+     * exectly on output the XML input using getText():
+     * returned content is always unnormalized (exactly as in input).
+     * Otherwise returned content is end-of-line normalized as described
+     * <a href="http://www.w3.org/TR/REC-xml#sec-line-ends">XML 1.0 End-of-Line Handling</a>
+     * and. Also when this feature is enabled exact content of START_TAG, END_TAG,
+     * DOCDECL and PROCESSING_INSTRUCTION is available.
+     *
+     * <p>Here is the list of tokens that can be  returned from nextToken()
+     * and what getText() and getTextCharacters() returns:<dl>
+     * <dt>START_DOCUMENT<dd>null
+     * <dt>END_DOCUMENT<dd>null
+     * <dt>START_TAG<dd>null unless FEATURE_XML_ROUNDTRIP
+     *   enabled and then returns XML tag, ex: &lt;tag attr='val'>
+     * <dt>END_TAG<dd>null unless FEATURE_XML_ROUNDTRIP
+     *  id enabled and then returns XML tag, ex: &lt;/tag>
+     * <dt>TEXT<dd>return element content.
+     *  <br>Note: that element content may be delivered in multiple consecutive TEXT events.
+     * <dt>IGNORABLE_WHITESPACE<dd>return characters that are determined to be ignorable white
+     * space. If the FEATURE_XML_ROUNDTRIP is enabled all whitespace content outside root
+     * element will always reported as IGNORABLE_WHITESPACE otherise rteporting is optional.
+     *  <br>Note: that element content may be delevered in multiple consecutive IGNORABLE_WHITESPACE events.
+     * <dt>CDSECT<dd>
+     * return text <em>inside</em> CDATA
+     *  (ex. 'fo&lt;o' from &lt;!CDATA[fo&lt;o]]>)
+     * <dt>PROCESSING_INSTRUCTION<dd>
+     *  if FEATURE_XML_ROUNDTRIP is true
+     *  return exact PI content ex: 'pi foo' from &lt;?pi foo?>
+     *  otherwise it may be exact PI content or concatenation of PI target,
+     * space and data so for example for
+     *   &lt;?target    data?> string &quot;target data&quot; may
+     *       be returned if FEATURE_XML_ROUNDTRIP is false.
+     * <dt>COMMENT<dd>return comment content ex. 'foo bar' from &lt;!--foo bar-->
+     * <dt>ENTITY_REF<dd>getText() MUST return entity replacement text if PROCESS_DOCDECL is false
+     * otherwise getText() MAY return null,
+     * additionally getTextCharacters() MUST return entity name
+     * (for example 'entity_name' for &amp;entity_name;).
+     * <br><b>NOTE:</b> this is the only place where value returned from getText() and
+     *   getTextCharacters() <b>are different</b>
+     * <br><b>NOTE:</b> it is user responsibility to resolve entity reference
+     *    if PROCESS_DOCDECL is false and there is no entity replacement text set in
+     *    defineEntityReplacementText() method (getText() will be null)
+     * <br><b>NOTE:</b> character entities (ex. &amp;#32;) and standard entities such as
+     *  &amp;amp; &amp;lt; &amp;gt; &amp;quot; &amp;apos; are reported as well
+     *  and are <b>not</b> reported as TEXT tokens but as ENTITY_REF tokens!
+     *  This requirement is added to allow to do roundtrip of XML documents!
+     * <dt>DOCDECL<dd>
+     * if FEATURE_XML_ROUNDTRIP is true or PROCESS_DOCDECL is false
+     * then return what is inside of DOCDECL for example it returns:<pre>
+     * &quot; titlepage SYSTEM "http://www.foo.bar/dtds/typo.dtd"
+     * [&lt;!ENTITY % active.links "INCLUDE">]&quot;</pre>
+     * <p>for input document that contained:<pre>
+     * &lt;!DOCTYPE titlepage SYSTEM "http://www.foo.bar/dtds/typo.dtd"
+     * [&lt;!ENTITY % active.links "INCLUDE">]></pre>
+     * otherwise if FEATURE_XML_ROUNDTRIP is false and PROCESS_DOCDECL is true
+     *    then what is returned is undefined (it may be even null)
+     * </dd>
+     * </dl>
+     *
+     * <p><strong>NOTE:</strong> there is no gurantee that there will only one TEXT or
+     * IGNORABLE_WHITESPACE event from nextToken() as parser may chose to deliver element content in
+     * multiple tokens (dividing element content into chunks)
+     *
+     * <p><strong>NOTE:</strong> whether returned text of token is end-of-line normalized
+     *  is depending on FEATURE_XML_ROUNDTRIP.
+     *
+     * <p><strong>NOTE:</strong> XMLDecl (&lt;?xml ...?&gt;) is not reported but its content
+     * is available through optional properties (see class description above).
+     *
+     * @see #next
+     * @see #START_TAG
+     * @see #TEXT
+     * @see #END_TAG
+     * @see #END_DOCUMENT
+     * @see #COMMENT
+     * @see #DOCDECL
+     * @see #PROCESSING_INSTRUCTION
+     * @see #ENTITY_REF
+     * @see #IGNORABLE_WHITESPACE
+     */
+    int nextToken()
+        throws XmlPullParserException, IOException;
+
+    //-----------------------------------------------------------------------------
+    // utility methods to mak XML parsing easier ...
+
+    /**
+     * Test if the current event is of the given type and if the
+     * namespace and name do match. null will match any namespace
+     * and any name. If the test is not passed, an exception is
+     * thrown. The exception text indicates the parser position,
+     * the expected event and the current event that is not meeting the
+     * requirement.
+     *
+     * <p>Essentially it does this
+     * <pre>
+     *  if (type != getEventType()
+     *  || (namespace != null &amp;&amp;  !namespace.equals( getNamespace () ) )
+     *  || (name != null &amp;&amp;  !name.equals( getName() ) ) )
+     *     throw new XmlPullParserException( "expected "+ TYPES[ type ]+getPositionDescription());
+     * </pre>
+     */
+    void require(int type, String namespace, String name)
+        throws XmlPullParserException, IOException;
+
+    /**
+     * If current event is START_TAG then if next element is TEXT then element content is returned
+     * or if next event is END_TAG then empty string is returned, otherwise exception is thrown.
+     * After calling this function successfully parser will be positioned on END_TAG.
+     *
+     * <p>The motivation for this function is to allow to parse consistently both
+     * empty elements and elements that has non empty content, for example for input: <ol>
+     * <li>&lt;tag&gt;foo&lt;/tag&gt;
+     * <li>&lt;tag&gt;&lt;/tag&gt; (which is equivalent to &lt;tag/&gt;
+     * both input can be parsed with the same code:
+     * <pre>
+     *   p.nextTag()
+     *   p.requireEvent(p.START_TAG, "", "tag");
+     *   String content = p.nextText();
+     *   p.requireEvent(p.END_TAG, "", "tag");
+     * </pre>
+     * This function together with nextTag make it very easy to parse XML that has
+     * no mixed content.
+     *
+     *
+     * <p>Essentially it does this
+     * <pre>
+     *  if(getEventType() != START_TAG) {
+     *     throw new XmlPullParserException(
+     *       "parser must be on START_TAG to read next text", this, null);
+     *  }
+     *  int eventType = next();
+     *  if(eventType == TEXT) {
+     *     String result = getText();
+     *     eventType = next();
+     *     if(eventType != END_TAG) {
+     *       throw new XmlPullParserException(
+     *          "event TEXT it must be immediately followed by END_TAG", this, null);
+     *      }
+     *      return result;
+     *  } else if(eventType == END_TAG) {
+     *     return "";
+     *  } else {
+     *     throw new XmlPullParserException(
+     *       "parser must be on START_TAG or TEXT to read text", this, null);
+     *  }
+     * </pre>
+     */
+    String nextText() throws XmlPullParserException, IOException;
+
+    /**
+     * Call next() and return event if it is START_TAG or END_TAG
+     * otherwise throw an exception.
+     * It will skip whitespace TEXT before actual tag if any.
+     *
+     * <p>essentially it does this
+     * <pre>
+     *   int eventType = next();
+     *   if(eventType == TEXT &amp;&amp;  isWhitespace()) {   // skip whitespace
+     *      eventType = next();
+     *   }
+     *   if (eventType != START_TAG &amp;&amp;  eventType != END_TAG) {
+     *      throw new XmlPullParserException("expected start or end tag", this, null);
+     *   }
+     *   return eventType;
+     * </pre>
+     */
+    int nextTag() throws XmlPullParserException, IOException;
+
+}
+
diff --git a/xml/src/main/java/org/xmlpull/v1/XmlPullParserException.java b/xml/src/main/java/org/xmlpull/v1/XmlPullParserException.java
new file mode 100644
index 0000000..b4b4b71
--- /dev/null
+++ b/xml/src/main/java/org/xmlpull/v1/XmlPullParserException.java
@@ -0,0 +1,76 @@
+/* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
+// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
+
+package org.xmlpull.v1;
+
+/**
+ * This exception is thrown to signal XML Pull Parser related faults.
+ *
+ * @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
+ */
+public class XmlPullParserException extends Exception {
+    protected Throwable detail;
+    protected int row = -1;
+    protected int column = -1;
+
+    /*    public XmlPullParserException() {
+          }*/
+
+    public XmlPullParserException(String s) {
+        super(s);
+    }
+
+    /*
+    public XmlPullParserException(String s, Throwable thrwble) {
+        super(s);
+        this.detail = thrwble;
+        }
+
+    public XmlPullParserException(String s, int row, int column) {
+        super(s);
+        this.row = row;
+        this.column = column;
+    }
+    */
+
+    public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) {
+        super ((msg == null ? "" : msg+" ")
+               + (parser == null ? "" : "(position:"+parser.getPositionDescription()+") ")
+               + (chain == null ? "" : "caused by: "+chain));
+
+        if (parser != null) {
+            this.row = parser.getLineNumber();
+            this.column = parser.getColumnNumber();
+        }
+        this.detail = chain;
+    }
+
+    public Throwable getDetail() { return detail; }
+    //    public void setDetail(Throwable cause) { this.detail = cause; }
+    public int getLineNumber() { return row; }
+    public int getColumnNumber() { return column; }
+
+    /*
+    public String getMessage() {
+        if(detail == null)
+            return super.getMessage();
+        else
+            return super.getMessage() + "; nested exception is: \n\t"
+                + detail.getMessage();
+    }
+    */
+
+    //NOTE: code that prints this and detail is difficult in J2ME
+    public void printStackTrace() {
+        if (detail == null) {
+            super.printStackTrace();
+        } else {
+            synchronized(System.err) {
+                System.err.println(super.getMessage() + "; nested exception is:");
+                detail.printStackTrace();
+            }
+        }
+    }
+
+}
+
diff --git a/xml/src/main/java/org/xmlpull/v1/XmlPullParserFactory.java b/xml/src/main/java/org/xmlpull/v1/XmlPullParserFactory.java
new file mode 100644
index 0000000..7b786f6
--- /dev/null
+++ b/xml/src/main/java/org/xmlpull/v1/XmlPullParserFactory.java
@@ -0,0 +1,349 @@
+/* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
+// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
+
+package org.xmlpull.v1;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * This class is used to create implementations of XML Pull Parser defined in XMPULL V1 API.
+ * The name of actual factory class will be determined based on several parameters.
+ * It works similar to JAXP but tailored to work in J2ME environments
+ * (no access to system properties or file system) so name of parser class factory to use
+ * and its class used for loading (no class loader - on J2ME no access to context class loaders)
+ * must be passed explicitly. If no name of parser factory was passed (or is null)
+ * it will try to find name by searching in CLASSPATH for
+ * META-INF/services/org.xmlpull.v1.XmlPullParserFactory resource that should contain
+ * a comma separated list of class names of factories or parsers to try (in order from
+ * left to the right). If none found, it will throw an exception.
+ *
+ * <br /><strong>NOTE:</strong>In J2SE or J2EE environments, you may want to use
+ * <code>newInstance(property, classLoaderCtx)</code>
+ * where first argument is
+ * <code>System.getProperty(XmlPullParserFactory.PROPERTY_NAME)</code>
+ * and second is <code>Thread.getContextClassLoader().getClass()</code> .
+ *
+ * @see XmlPullParser
+ *
+ * @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
+ * @author Stefan Haustein
+ */
+
+public class XmlPullParserFactory {
+    /** used as default class to server as context class in newInstance() */
+    final static Class referenceContextClass;
+
+    static {
+        XmlPullParserFactory f = new XmlPullParserFactory();
+        referenceContextClass = f.getClass();
+    }
+
+    /** Name of the system or midlet property that should be used for
+     a system property containing a comma separated list of factory
+     or parser class names (value:
+     org.xmlpull.v1.XmlPullParserFactory). */
+
+
+    public static final String PROPERTY_NAME =
+        "org.xmlpull.v1.XmlPullParserFactory";
+
+    private static final String RESOURCE_NAME =
+        "/META-INF/services/" + PROPERTY_NAME;
+
+
+    // public static final String DEFAULT_PROPERTY =
+    //    "org.xmlpull.xpp3.XmlPullParser,org.kxml2.io.KXmlParser";
+
+
+    protected ArrayList parserClasses;
+    protected String classNamesLocation;
+
+    protected ArrayList serializerClasses;
+
+
+    // features are kept there
+    protected HashMap features = new HashMap();
+
+
+    /**
+     * Protected constructor to be called by factory implementations.
+     */
+
+    protected XmlPullParserFactory() {
+    }
+
+
+
+    /**
+     * Set the features to be set when XML Pull Parser is created by this factory.
+     * <p><b>NOTE:</b> factory features are not used for XML Serializer.
+     *
+     * @param name string with URI identifying feature
+     * @param state if true feature will be set; if false will be ignored
+     */
+
+    public void setFeature(String name,
+                           boolean state) throws XmlPullParserException {
+
+        features.put(name, new Boolean(state));
+    }
+
+
+    /**
+     * Return the current value of the feature with given name.
+     * <p><b>NOTE:</b> factory features are not used for XML Serializer.
+     *
+     * @param name The name of feature to be retrieved.
+     * @return The value of named feature.
+     *     Unknown features are <string>always</strong> returned as false
+     */
+
+    public boolean getFeature (String name) {
+        Boolean value = (Boolean) features.get(name);
+        return value != null ? value.booleanValue() : false;
+    }
+
+    /**
+     * Specifies that the parser produced by this factory will provide
+     * support for XML namespaces.
+     * By default the value of this is set to false.
+     *
+     * @param awareness true if the parser produced by this code
+     *    will provide support for XML namespaces;  false otherwise.
+     */
+
+    public void setNamespaceAware(boolean awareness) {
+        features.put (XmlPullParser.FEATURE_PROCESS_NAMESPACES, new Boolean (awareness));
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce
+     * parsers which are namespace aware
+     * (it simply set feature XmlPullParser.FEATURE_PROCESS_NAMESPACES to true or false).
+     *
+     * @return  true if the factory is configured to produce parsers
+     *    which are namespace aware; false otherwise.
+     */
+
+    public boolean isNamespaceAware() {
+        return getFeature (XmlPullParser.FEATURE_PROCESS_NAMESPACES);
+    }
+
+
+    /**
+     * Specifies that the parser produced by this factory will be validating
+     * (it simply set feature XmlPullParser.FEATURE_VALIDATION to true or false).
+     *
+     * By default the value of this is set to false.
+     *
+     * @param validating - if true the parsers created by this factory  must be validating.
+     */
+
+    public void setValidating(boolean validating) {
+        features.put (XmlPullParser.FEATURE_VALIDATION, new Boolean (validating));
+    }
+
+    /**
+     * Indicates whether or not the factory is configured to produce parsers
+     * which validate the XML content during parse.
+     *
+     * @return   true if the factory is configured to produce parsers
+     * which validate the XML content during parse; false otherwise.
+     */
+
+    public boolean isValidating() {
+        return getFeature (XmlPullParser.FEATURE_VALIDATION);
+    }
+
+    /**
+     * Creates a new instance of a XML Pull Parser
+     * using the currently configured factory features.
+     *
+     * @return A new instance of a XML Pull Parser.
+     * @throws XmlPullParserException if a parser cannot be created which satisfies the
+     * requested configuration.
+     */
+
+    public XmlPullParser newPullParser() throws XmlPullParserException {
+
+        if (parserClasses == null) throw new XmlPullParserException
+                ("Factory initialization was incomplete - has not tried "+classNamesLocation);
+
+        if (parserClasses.size() == 0) throw new XmlPullParserException
+                ("No valid parser classes found in "+classNamesLocation);
+
+        final StringBuffer issues = new StringBuffer ();
+
+        for (int i = 0; i < parserClasses.size(); i++) {
+            final Class ppClass = (Class) parserClasses.get(i);
+            try {
+                final XmlPullParser pp = (XmlPullParser) ppClass.newInstance();
+
+                for (Iterator iter = features.keySet().iterator(); iter.hasNext(); ) {
+                    final String key = (String) iter.next();
+                    final Boolean value = (Boolean) features.get(key);
+                    if(value != null && value.booleanValue()) {
+                        pp.setFeature(key, true);
+                    }
+                }
+                return pp;
+
+            } catch(Exception ex) {
+                issues.append (ppClass.getName () + ": "+ ex.toString ()+"; ");
+            }
+        }
+
+        throw new XmlPullParserException ("could not create parser: "+issues);
+    }
+
+
+    /**
+     * Creates a new instance of a XML Serializer.
+     *
+     * <p><b>NOTE:</b> factory features are not used for XML Serializer.
+     *
+     * @return A new instance of a XML Serializer.
+     * @throws XmlPullParserException if a parser cannot be created which satisfies the
+     * requested configuration.
+     */
+
+    public XmlSerializer newSerializer() throws XmlPullParserException {
+
+        if (serializerClasses == null) {
+            throw new XmlPullParserException
+                ("Factory initialization incomplete - has not tried "+classNamesLocation);
+        }
+        if(serializerClasses.size() == 0) {
+            throw new XmlPullParserException
+                ("No valid serializer classes found in "+classNamesLocation);
+        }
+
+        final StringBuffer issues = new StringBuffer ();
+
+        for (int i = 0; i < serializerClasses.size (); i++) {
+            final Class ppClass = (Class) serializerClasses.get(i);
+            try {
+                final XmlSerializer ser = (XmlSerializer) ppClass.newInstance();
+
+                return ser;
+
+            } catch(Exception ex) {
+                issues.append (ppClass.getName () + ": "+ ex.toString ()+"; ");
+            }
+        }
+
+        throw new XmlPullParserException ("could not create serializer: "+issues);
+    }
+
+    /**
+     * Create a new instance of a PullParserFactory that can be used
+     * to create XML pull parsers (see class description for more
+     * details).
+     *
+     * @return a new instance of a PullParserFactory, as returned by newInstance (null, null); 
+     */
+    public static XmlPullParserFactory newInstance () throws XmlPullParserException {
+        return newInstance(null, null);
+    }
+
+    public static XmlPullParserFactory newInstance (String classNames, Class context)
+        throws XmlPullParserException {
+
+        if (context == null) {
+            //NOTE: make sure context uses the same class loader as API classes
+            //      this is the best we can do without having access to context classloader in J2ME
+            //      if API is in the same classloader as implementation then this will work
+            context = referenceContextClass;
+        }
+
+        /*
+        String  classNamesLocation = null;
+
+        if (classNames == null || classNames.length() == 0 || "DEFAULT".equals(classNames)) {
+            try {
+                InputStream is = context.getResourceAsStream (RESOURCE_NAME);
+
+                if (is == null) throw new XmlPullParserException
+                        ("resource not found: "+RESOURCE_NAME
+                             +" make sure that parser implementing XmlPull API is available");
+                final StringBuffer sb = new StringBuffer();
+
+                while (true) {
+                    final int ch = is.read();
+                    if (ch < 0) break;
+                    else if (ch > ' ')
+                        sb.append((char) ch);
+                }
+                is.close ();
+
+                classNames = sb.toString ();
+            }
+            catch (Exception e) {
+                throw new XmlPullParserException (null, null, e);
+            }
+            classNamesLocation = "resource "+RESOURCE_NAME+" that contained '"+classNames+"'";
+        } else {
+            classNamesLocation =
+                "parameter classNames to newInstance() that contained '"+classNames+"'";
+        }
+        */
+        classNames = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer";
+
+        XmlPullParserFactory factory = null;
+        final ArrayList parserClasses = new ArrayList();
+        final ArrayList serializerClasses = new ArrayList();
+        int pos = 0;
+
+        while (pos < classNames.length ()) {
+            int cut = classNames.indexOf (',', pos);
+
+            if (cut == -1) cut = classNames.length ();
+            final String name = classNames.substring (pos, cut);
+
+            Class candidate = null;
+            Object instance = null;
+
+            try {
+                candidate = Class.forName (name);
+                // necessary because of J2ME .class issue
+                instance = candidate.newInstance ();
+            }
+            catch (Exception e) {}
+
+            if (candidate != null) {
+                boolean recognized = false;
+                if (instance instanceof XmlPullParser) {
+                    parserClasses.add(candidate);
+                    recognized = true;
+                }
+                if (instance instanceof XmlSerializer) {
+                    serializerClasses.add(candidate);
+                    recognized = true;
+                }
+                if (instance instanceof XmlPullParserFactory) {
+                    if (factory == null) {
+                        factory = (XmlPullParserFactory) instance;
+                    }
+                    recognized = true;
+                }
+                if (!recognized) {
+                    throw new XmlPullParserException ("incompatible class: "+name);
+                }
+            }
+            pos = cut + 1;
+        }
+
+        if (factory == null) {
+            factory = new XmlPullParserFactory ();
+        }
+        factory.parserClasses = parserClasses;
+        factory.serializerClasses = serializerClasses;
+        factory.classNamesLocation = "org.kxml2.io.kXmlParser,org.kxml2.io.KXmlSerializer";
+        return factory;
+    }
+}
+
+
diff --git a/xml/src/main/java/org/xmlpull/v1/XmlSerializer.java b/xml/src/main/java/org/xmlpull/v1/XmlSerializer.java
new file mode 100644
index 0000000..8e85e2f
--- /dev/null
+++ b/xml/src/main/java/org/xmlpull/v1/XmlSerializer.java
@@ -0,0 +1,326 @@
+package org.xmlpull.v1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+/**
+ * Define an interface to serialziation of XML Infoset.
+ * This interface abstracts away if serialized XML is XML 1.0 comaptible text or
+ * other formats of XML 1.0 serializations (such as binary XML for example with WBXML).
+ *
+ * <p><b>PLEASE NOTE:</b> This interface will be part of XmlPull 1.2 API.
+ * It is included as basis for discussion. It may change in any way.
+ *
+ * <p>Exceptions that may be thrown are: IOException or runtime exception
+ * (more runtime exceptions can be thrown but are not declared and as such
+ * have no semantics defined for this interface):
+ * <ul>
+ * <li><em>IllegalArgumentException</em> - for almost all methods to signal that
+ *     argument is illegal
+ * <li><em>IllegalStateException</em> - to signal that call has good arguments but
+ *     is not expected here (violation of contract) and for features/properties
+ *    when requesting setting unimplemented feature/property
+ *    (UnsupportedOperationException would be better but it is not in MIDP)
+ *  </ul>
+ *
+ * <p><b>NOTE:</b> writing  CDSECT, ENTITY_REF, IGNORABLE_WHITESPACE,
+ *  PROCESSING_INSTRUCTION, COMMENT, and DOCDECL in some implementations
+ * may not be supported (for example when serializing to WBXML).
+ * In such case IllegalStateException will be thrown and it is recommened
+ * to use an optional feature to signal that implementation is not
+ * supporting this kind of output.
+ */
+
+public interface XmlSerializer {
+    
+    /**
+     * Set feature identified by name (recommended to be URI for uniqueness).
+     * Some well known optional features are defined in
+     * <a href="http://www.xmlpull.org/v1/doc/features.html">
+     * http://www.xmlpull.org/v1/doc/features.html</a>.
+     *
+     * If feature is not recocgnized or can not be set
+     * then IllegalStateException MUST be thrown.
+     *
+     * @exception IllegalStateException If the feature is not supported or can not be set
+     */
+    void setFeature(String name,
+                           boolean state)
+        throws IllegalArgumentException, IllegalStateException;
+    
+    
+    /**
+     * Return the current value of the feature with given name.
+     * <p><strong>NOTE:</strong> unknown properties are <strong>always</strong> returned as null
+     *
+     * @param name The name of feature to be retrieved.
+     * @return The value of named feature.
+     * @exception IllegalArgumentException if feature string is null
+     */
+    boolean getFeature(String name);
+    
+    
+    /**
+     * Set the value of a property.
+     * (the property name is recommened to be URI for uniqueness).
+     * Some well known optional properties are defined in
+     * <a href="http://www.xmlpull.org/v1/doc/properties.html">
+     * http://www.xmlpull.org/v1/doc/properties.html</a>.
+     *
+     * If property is not recocgnized or can not be set
+     * then IllegalStateException MUST be thrown.
+     *
+     * @exception IllegalStateException if the property is not supported or can not be set
+     */
+    void setProperty(String name,
+                            Object value)
+        throws IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Look up the value of a property.
+     *
+     * The property name is any fully-qualified URI. I
+     * <p><strong>NOTE:</strong> unknown properties are <string>always</strong> returned as null
+     *
+     * @param name The name of property to be retrieved.
+     * @return The value of named property.
+     */
+    Object getProperty(String name);
+    
+    /**
+     * Set to use binary output stream with given encoding.
+     */
+    void setOutput (OutputStream os, String encoding)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Set the output to the given writer.
+     * <p><b>WARNING</b> no information about encoding is available!
+     */
+    void setOutput (Writer writer)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Write &lt;&#63;xml declaration with encoding (if encoding not null)
+     * and standalone flag (if standalone not null)
+     * This method can only be called just after setOutput.
+     */
+    void startDocument (String encoding, Boolean standalone)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Finish writing. All unclosed start tags will be closed and output
+     * will be flushed. After calling this method no more output can be
+     * serialized until next call to setOutput()
+     */
+    void endDocument ()
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Binds the given prefix to the given namespace.
+     * This call is valid for the next element including child elements.
+     * The prefix and namespace MUST be always declared even if prefix
+     * is not used in element (startTag() or attribute()) - for XML 1.0
+     * it must result in declaring <code>xmlns:prefix='namespace'</code>
+     * (or <code>xmlns:prefix="namespace"</code> depending what character is used
+     * to quote attribute value).
+     *
+     * <p><b>NOTE:</b> this method MUST be called directly before startTag()
+     *   and if anything but startTag() or setPrefix() is called next there will be exception.
+     * <p><b>NOTE:</b> prefixes "xml" and "xmlns" are already bound
+     *   and can not be redefined see:
+     * <a href="http://www.w3.org/XML/xml-names-19990114-errata#NE05">Namespaces in XML Errata</a>.
+     * <p><b>NOTE:</b> to set default namespace use as prefix empty string.
+     *
+     * @param prefix must be not null (or IllegalArgumentException is thrown)
+     * @param namespace must be not null
+     */
+    void setPrefix (String prefix, String namespace)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Return namespace that corresponds to given prefix
+     * If there is no prefix bound to this namespace return null
+     * but if generatePrefix is false then return generated prefix.
+     *
+     * <p><b>NOTE:</b> if the prefix is empty string "" and defualt namespace is bound
+     * to this prefix then empty string ("") is returned.
+     *
+     * <p><b>NOTE:</b> prefixes "xml" and "xmlns" are already bound
+     *   will have values as defined
+     * <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces in XML specification</a>
+     */
+    String getPrefix (String namespace, boolean generatePrefix)
+        throws IllegalArgumentException;
+    
+    /**
+     * Returns the current depth of the element.
+     * Outside the root element, the depth is 0. The
+     * depth is incremented by 1 when startTag() is called.
+     * The depth is decremented after the call to endTag()
+     * event was observed.
+     *
+     * <pre>
+     * &lt;!-- outside --&gt;     0
+     * &lt;root&gt;               1
+     *   sometext                 1
+     *     &lt;foobar&gt;         2
+     *     &lt;/foobar&gt;        2
+     * &lt;/root&gt;              1
+     * &lt;!-- outside --&gt;     0
+     * </pre>
+     */
+    int getDepth();
+    
+    /**
+     * Returns the namespace URI of the current element as set by startTag().
+     *
+     * <p><b>NOTE:</b> that measn in particaulr that: <ul>
+     * <li>if there was startTag("", ...) then getNamespace() returns ""
+     * <li>if there was startTag(null, ...) then getNamespace() returns null
+     * </ul>
+     *
+     * @return namespace set by startTag() that is currently in scope
+     */
+    String getNamespace ();
+    
+    /**
+     * Returns the name of the current element as set by startTag().
+     * It can only be null before first call to startTag()
+     * or when last endTag() is called to close first startTag().
+     *
+     * @return namespace set by startTag() that is currently in scope
+     */
+    String getName();
+    
+    /**
+     * Writes a start tag with the given namespace and name.
+     * If there is no prefix defined for the given namespace,
+     * a prefix will be defined automatically.
+     * The explicit prefixes for namespaces can be established by calling setPrefix()
+     * immediately before this method.
+     * If namespace is null no namespace prefix is printed but just name.
+     * If namespace is empty string then serialzier will make sure that
+     * default empty namespace is declared (in XML 1.0 xmlns='')
+     * or throw IllegalStateException if default namespace is already bound
+     * to non-empty string.
+     */
+    XmlSerializer startTag (String namespace, String name)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Write an attribute. Calls to attribute() MUST follow a call to
+     * startTag() immediately. If there is no prefix defined for the
+     * given namespace, a prefix will be defined automatically.
+     * If namespace is null or empty string
+     * no namespace prefix is printed but just name.
+     */
+    XmlSerializer attribute (String namespace, String name, String value)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Write end tag. Repetition of namespace and name is just for avoiding errors.
+     * <p><b>Background:</b> in kXML endTag had no arguments, and non matching tags were
+     *  very difficult to find...
+     * If namespace is null no namespace prefix is printed but just name.
+     * If namespace is empty string then serialzier will make sure that
+     * default empty namespace is declared (in XML 1.0 xmlns='').
+     */
+    XmlSerializer endTag (String namespace, String name)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    
+    //    /**
+    //     * Writes a start tag with the given namespace and name.
+    //     * <br />If there is no prefix defined (prefix == null) for the given namespace,
+    //     * a prefix will be defined automatically.
+    //     * <br />If explicit prefixes is passed (prefix != null) then it will be used
+    //      *and namespace declared if not already declared or
+    //     * throw IllegalStateException the same prefix was already set on this
+    //     * element (setPrefix()) and was bound to different namespace.
+    //     * <br />If namespace is null then prefix must be null too or IllegalStateException is thrown.
+    //     * <br />If namespace is null then no namespace prefix is printed but just name.
+    //     * <br />If namespace is empty string then serializer will make sure that
+    //     * default empty namespace is declared (in XML 1.0 xmlns='')
+    //     * or throw IllegalStateException if default namespace is already bound
+    //     * to non-empty string.
+    //     */
+    //    XmlSerializer startTag (String prefix, String namespace, String name)
+    //        throws IOException, IllegalArgumentException, IllegalStateException;
+    //
+    //    /**
+    //     * Write an attribute. Calls to attribute() MUST follow a call to
+    //     * startTag() immediately.
+    //     * <br />If there is no prefix defined (prefix == null) for the given namespace,
+    //     * a prefix will be defined automatically.
+    //     * <br />If explicit prefixes is passed (prefix != null) then it will be used
+    //     * and namespace declared if not already declared or
+    //     * throw IllegalStateException the same prefix was already set on this
+    //     * element (setPrefix()) and was bound to different namespace.
+    //     * <br />If namespace is null then prefix must be null too or IllegalStateException is thrown.
+    //     * <br />If namespace is null then no namespace prefix is printed but just name.
+    //     * <br />If namespace is empty string then serializer will make sure that
+    //     * default empty namespace is declared (in XML 1.0 xmlns='')
+    //     * or throw IllegalStateException if default namespace is already bound
+    //     * to non-empty string.
+    //     */
+    //    XmlSerializer attribute (String prefix, String namespace, String name, String value)
+    //        throws IOException, IllegalArgumentException, IllegalStateException;
+    //
+    //    /**
+    //     * Write end tag. Repetition of namespace, prefix, and name is just for avoiding errors.
+    //     * <br />If namespace or name arguments are different from corresponding startTag call
+    //     * then IllegalArgumentException is thrown, if prefix argument is not null and is different
+    //     * from corresponding starTag then IllegalArgumentException is thrown.
+    //     * <br />If namespace is null then prefix must be null too or IllegalStateException is thrown.
+    //     * <br />If namespace is null then no namespace prefix is printed but just name.
+    //     * <br />If namespace is empty string then serializer will make sure that
+    //     * default empty namespace is declared (in XML 1.0 xmlns='').
+    //     * <p><b>Background:</b> in kXML endTag had no arguments, and non matching tags were
+    //     *  very difficult to find...</p>
+    //     */
+    // ALEK: This is really optional as prefix in end tag MUST correspond to start tag but good for error checking
+    //    XmlSerializer endTag (String prefix, String namespace, String name)
+    //        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Writes text, where special XML chars are escaped automatically
+     */
+    XmlSerializer text (String text)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Writes text, where special XML chars are escaped automatically
+     */
+    XmlSerializer text (char [] buf, int start, int len)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    void cdsect (String text)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    void entityRef (String text)  throws IOException,
+        IllegalArgumentException, IllegalStateException;
+    void processingInstruction (String text)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    void comment (String text)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    void docdecl (String text)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    void ignorableWhitespace (String text)
+        throws IOException, IllegalArgumentException, IllegalStateException;
+    
+    /**
+     * Write all pending output to the stream.
+     * If method startTag() or attribute() was called then start tag is closed (final &gt;)
+     * before flush() is called on underlying output stream.
+     *
+     * <p><b>NOTE:</b> if there is need to close start tag
+     * (so no more attribute() calls are allowed) but without flushinging output
+     * call method text() with empty string (text("")).
+     *
+     */
+    void flush ()
+        throws IOException;
+    
+}
+
diff --git a/xml/src/main/java/org/xmlpull/v1/sax2/Driver.java b/xml/src/main/java/org/xmlpull/v1/sax2/Driver.java
new file mode 100644
index 0000000..0bd2d4f
--- /dev/null
+++ b/xml/src/main/java/org/xmlpull/v1/sax2/Driver.java
@@ -0,0 +1,469 @@
+/* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
+// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
+
+package org.xmlpull.v1.sax2;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+
+// not J2ME classes -- remove if you want to run in MIDP devices
+import java.net.URL;
+import java.net.MalformedURLException;
+
+
+// not J2ME classes
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+/**
+ * SAX2 Driver that pulls events from XmlPullParser
+ * and comverts them into SAX2 callbacks.
+ *
+ * @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
+ */
+
+public class Driver implements Locator, XMLReader, Attributes
+{
+
+    protected static final String DECLARATION_HANDLER_PROPERTY =
+        "http://xml.org/sax/properties/declaration-handler";
+
+    protected static final String LEXICAL_HANDLER_PROPERTY =
+        "http://xml.org/sax/properties/lexical-handler";
+
+    protected static final String NAMESPACES_FEATURE =
+        "http://xml.org/sax/features/namespaces";
+
+    protected static final String NAMESPACE_PREFIXES_FEATURE =
+        "http://xml.org/sax/features/namespace-prefixes";
+
+    protected static final String VALIDATION_FEATURE =
+        "http://xml.org/sax/features/validation";
+
+    protected static final String APACHE_SCHEMA_VALIDATION_FEATURE =
+        "http://apache.org/xml/features/validation/schema";
+
+    protected static final String APACHE_DYNAMIC_VALIDATION_FEATURE =
+        "http://apache.org/xml/features/validation/dynamic";
+
+    protected ContentHandler contentHandler = new DefaultHandler();
+    protected ErrorHandler errorHandler = new DefaultHandler();;
+
+    protected String systemId;
+
+    protected XmlPullParser pp;
+
+    //private final static boolean DEBUG = false;
+
+    /**
+     */
+    public Driver() throws XmlPullParserException {
+        final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+        factory.setNamespaceAware(true);
+        pp = factory.newPullParser();
+    }
+
+    public Driver(XmlPullParser pp) throws XmlPullParserException {
+        this.pp = pp;
+    }
+
+    // -- Attributes interface
+
+    public int getLength() { return pp.getAttributeCount(); }
+    public String getURI(int index) { return pp.getAttributeNamespace(index); }
+    public String getLocalName(int index) { return pp.getAttributeName(index); }
+    public String getQName(int index) {
+        final String prefix = pp.getAttributePrefix(index);
+        if(prefix != null) {
+            return prefix+':'+pp.getAttributeName(index);
+        } else {
+            return pp.getAttributeName(index);
+        }
+    }
+    public String getType(int index) { return pp.getAttributeType(index); }
+    public String getValue(int index) { return pp.getAttributeValue(index); }
+
+    public int getIndex(String uri, String localName) {
+        for (int i = 0; i < pp.getAttributeCount(); i++)
+        {
+            if(pp.getAttributeNamespace(i).equals(uri)
+               && pp.getAttributeName(i).equals(localName))
+            {
+                return i;
+            }
+
+        }
+        return -1;
+    }
+
+    public int getIndex(String qName) {
+        for (int i = 0; i < pp.getAttributeCount(); i++)
+        {
+            if(pp.getAttributeName(i).equals(qName))
+            {
+                return i;
+            }
+
+        }
+        return -1;
+    }
+
+    public String getType(String uri, String localName) {
+        for (int i = 0; i < pp.getAttributeCount(); i++)
+        {
+            if(pp.getAttributeNamespace(i).equals(uri)
+               && pp.getAttributeName(i).equals(localName))
+            {
+                return pp.getAttributeType(i);
+            }
+
+        }
+        return null;
+    }
+    public String getType(String qName) {
+        for (int i = 0; i < pp.getAttributeCount(); i++)
+        {
+            if(pp.getAttributeName(i).equals(qName))
+            {
+                return pp.getAttributeType(i);
+            }
+
+        }
+        return null;
+    }
+    public String getValue(String uri, String localName) {
+        return pp.getAttributeValue(uri, localName);
+    }
+    public String getValue(String qName) {
+        return pp.getAttributeValue(null, qName);
+    }
+
+    // -- Locator interface
+
+    public String getPublicId() { return null; }
+    public String getSystemId() { return systemId; }
+    public int getLineNumber() { return pp.getLineNumber(); }
+    public int getColumnNumber() { return pp.getColumnNumber(); }
+
+    // --- XMLReader interface
+
+    public boolean getFeature(String name)
+        throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+        if(NAMESPACES_FEATURE.equals(name)) {
+            return pp.getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES);
+        } else if(NAMESPACE_PREFIXES_FEATURE.equals(name)) {
+            return pp.getFeature(XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES);
+        } else if(VALIDATION_FEATURE.equals(name)) {
+            return pp.getFeature(XmlPullParser.FEATURE_VALIDATION);
+            //        } else if(APACHE_SCHEMA_VALIDATION_FEATURE.equals(name)) {
+            //            return false;  //TODO
+            //        } else if(APACHE_DYNAMIC_VALIDATION_FEATURE.equals(name)) {
+            //            return false; //TODO
+        } else {
+            return pp.getFeature(name);
+            //throw new SAXNotRecognizedException("unrecognized feature "+name);
+        }
+    }
+
+    public void setFeature (String name, boolean value)
+        throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+        try {
+            if(NAMESPACES_FEATURE.equals(name)) {
+                pp.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, value);
+            } else if(NAMESPACE_PREFIXES_FEATURE.equals(name)) {
+                if(pp.getFeature(XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES) != value) {
+                    pp.setFeature(XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES, value);
+                }
+            } else if(VALIDATION_FEATURE.equals(name)) {
+                pp.setFeature(XmlPullParser.FEATURE_VALIDATION, value);
+                //          } else if(APACHE_SCHEMA_VALIDATION_FEATURE.equals(name)) {
+                //              // can ignore as validation must be false ...
+                //              //              if(true == value) {
+                //              //                  throw new SAXNotSupportedException("schema validation is not supported");
+                //              //              }
+                //          } else if(APACHE_DYNAMIC_VALIDATION_FEATURE.equals(name)) {
+                //              if(true == value) {
+                //                  throw new SAXNotSupportedException("dynamic validation is not supported");
+                //              }
+            } else {
+                pp.setFeature(name, value);
+                //throw new SAXNotRecognizedException("unrecognized feature "+name);
+            }
+        } catch(XmlPullParserException ex) {
+           // throw new SAXNotSupportedException("problem with setting feature "+name+": "+ex);
+        }
+    }
+
+    public Object getProperty (String name)
+        throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+        if(DECLARATION_HANDLER_PROPERTY.equals(name)) {
+            return null;
+        } else if(LEXICAL_HANDLER_PROPERTY.equals(name)) {
+            return null;
+        } else {
+            return pp.getProperty(name);
+            //throw new SAXNotRecognizedException("not recognized get property "+name);
+        }
+    }
+
+    public void setProperty (String name, Object value)
+        throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+        //
+        if(DECLARATION_HANDLER_PROPERTY.equals(name)) {
+            throw new SAXNotSupportedException("not supported setting property "+name);//+" to "+value);
+        } else if(LEXICAL_HANDLER_PROPERTY.equals(name)) {
+            throw new SAXNotSupportedException("not supported setting property "+name);//+" to "+value);
+        } else {
+            try {
+                pp.setProperty(name, value);
+            } catch(XmlPullParserException ex) {
+                throw new SAXNotSupportedException("not supported set property "+name+": "+ ex);
+            }
+            //throw new SAXNotRecognizedException("not recognized set property "+name);
+        }
+    }
+
+    public void setEntityResolver (EntityResolver resolver) {}
+
+    public EntityResolver getEntityResolver () { return null; }
+
+    public void setDTDHandler (DTDHandler handler) {}
+
+    public DTDHandler getDTDHandler () { return null; }
+
+    public void setContentHandler (ContentHandler handler)
+    {
+        this.contentHandler = handler;
+    }
+
+    public ContentHandler getContentHandler() { return contentHandler; }
+
+    public void setErrorHandler(ErrorHandler handler) {
+        this.errorHandler = handler;
+    }
+
+    public ErrorHandler getErrorHandler() { return errorHandler; }
+
+    public void parse(InputSource source) throws SAXException, IOException
+    {
+
+        systemId = source.getSystemId();
+        contentHandler.setDocumentLocator(this);
+
+        final Reader reader = source.getCharacterStream();
+        try {
+            if (reader == null) {
+                InputStream stream = source.getByteStream();
+                final String encoding = source.getEncoding();
+
+                if (stream == null) {
+                    systemId = source.getSystemId();
+                    if(systemId == null) {
+                        SAXParseException saxException = new SAXParseException(
+                            "null source systemId" , this);
+                        errorHandler.fatalError(saxException);
+                        return;
+                    }
+                    // NOTE: replace with Connection to run in J2ME environment
+                    try {
+                        final URL url = new URL(systemId);
+                        stream = url.openStream();
+                    } catch (MalformedURLException nue) {
+                        try {
+                            stream = new FileInputStream(systemId);
+                        } catch (FileNotFoundException fnfe) {
+                            final SAXParseException saxException = new SAXParseException(
+                                "could not open file with systemId "+systemId, this, fnfe);
+                            errorHandler.fatalError(saxException);
+                            return;
+                        }
+                    }
+                }
+                pp.setInput(stream, encoding);
+            } else {
+                pp.setInput(reader);
+            }
+        } catch (XmlPullParserException ex)  {
+            final SAXParseException saxException = new SAXParseException(
+                "parsing initialization error: "+ex, this, ex);
+            //if(DEBUG) ex.printStackTrace();
+            errorHandler.fatalError(saxException);
+            return;
+        }
+
+        // start parsing - move to first start tag
+        try {
+            contentHandler.startDocument();
+            // get first event
+            pp.next();
+            // it should be start tag...
+            if(pp.getEventType() != XmlPullParser.START_TAG) {
+                final SAXParseException saxException = new SAXParseException(
+                    "expected start tag not"+pp.getPositionDescription(), this);
+                //throw saxException;
+                errorHandler.fatalError(saxException);
+                return;
+            }
+        } catch (XmlPullParserException ex)  {
+            final SAXParseException saxException = new SAXParseException(
+                "parsing initialization error: "+ex, this, ex);
+            //ex.printStackTrace();
+            errorHandler.fatalError(saxException);
+            return;
+        }
+
+        // now real parsing can start!
+
+        parseSubTree(pp);
+
+        // and finished ...
+
+        contentHandler.endDocument();
+    }
+
+    public void parse(String systemId) throws SAXException, IOException {
+        parse(new InputSource(systemId));
+    }
+
+
+    public void parseSubTree(XmlPullParser pp) throws SAXException, IOException {
+        this.pp = pp;
+        final boolean namespaceAware = pp.getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES);
+        try {
+            if(pp.getEventType() != XmlPullParser.START_TAG) {
+                throw new SAXException(
+                    "start tag must be read before skiping subtree"+pp.getPositionDescription());
+            }
+            final int[] holderForStartAndLength = new int[2];
+            final StringBuffer rawName = new StringBuffer(16);
+            String prefix = null;
+            String name = null;
+            int level = pp.getDepth() - 1;
+            int type = XmlPullParser.START_TAG;
+
+            LOOP:
+            do {
+                switch(type) {
+                    case XmlPullParser.START_TAG:
+                        if(namespaceAware) {
+                            final int depth = pp.getDepth() - 1;
+                            final int countPrev =
+                                (level > depth) ? pp.getNamespaceCount(depth) : 0;
+                            //int countPrev = pp.getNamespaceCount(pp.getDepth() - 1);
+                            final int count = pp.getNamespaceCount(depth + 1);
+                            for (int i = countPrev; i < count; i++)
+                            {
+                                contentHandler.startPrefixMapping(
+                                    pp.getNamespacePrefix(i),
+                                    pp.getNamespaceUri(i)
+                                );
+                            }
+                            name = pp.getName();
+                            prefix = pp.getPrefix();
+                            if(prefix != null) {
+                                rawName.setLength(0);
+                                rawName.append(prefix);
+                                rawName.append(':');
+                                rawName.append(name);
+                            }
+                            startElement(pp.getNamespace(),
+                                         name,
+                                         // TODO Fixed this. Was "not equals".
+                                         prefix == null ? name : rawName.toString());
+                        } else {
+                            startElement(pp.getNamespace(),
+                                         pp.getName(),
+                                         pp.getName());
+                        }
+                        //++level;
+
+                        break;
+                    case XmlPullParser.TEXT:
+                        final char[] chars = pp.getTextCharacters(holderForStartAndLength);
+                        contentHandler.characters(chars,
+                                                  holderForStartAndLength[0], //start
+                                                  holderForStartAndLength[1] //len
+                                                 );
+                        break;
+                    case XmlPullParser.END_TAG:
+                        //--level;
+                        if(namespaceAware) {
+                            name = pp.getName();
+                            prefix = pp.getPrefix();
+                            if(prefix != null) {
+                                rawName.setLength(0);
+                                rawName.append(prefix);
+                                rawName.append(':');
+                                rawName.append(name);
+                            }
+                            contentHandler.endElement(pp.getNamespace(),
+                                                      name,
+                                                      prefix != null ? name : rawName.toString()
+                                                     );
+                            // when entering show prefixes for all levels!!!!
+                            final int depth = pp.getDepth();
+                            final int countPrev =
+                                (level > depth) ? pp.getNamespaceCount(pp.getDepth()) : 0;
+                            int count = pp.getNamespaceCount(pp.getDepth() - 1);
+                            // undeclare them in reverse order
+                            for (int i = count - 1; i >= countPrev; i--)
+                            {
+                                contentHandler.endPrefixMapping(
+                                    pp.getNamespacePrefix(i)
+                                );
+                            }
+                        } else {
+                            contentHandler.endElement(pp.getNamespace(),
+                                                      pp.getName(),
+                                                      pp.getName()
+                                                     );
+
+                        }
+                        break;
+                    case XmlPullParser.END_DOCUMENT:
+                        break LOOP;
+                }
+                type = pp.next();
+            } while(pp.getDepth() > level);
+        } catch (XmlPullParserException ex)  {
+            final SAXParseException saxException = new SAXParseException("parsing error: "+ex, this, ex);
+            ex.printStackTrace();
+            errorHandler.fatalError(saxException);
+        }
+    }
+
+    /**
+     * Calls {@link ContentHandler#startElement(String, String, String, Attributes) startElement}
+     * on the <code>ContentHandler</code> with <code>this</code> driver object as the
+     * {@link Attributes} implementation. In default implementation
+     * {@link Attributes} object is valid only during this method call and may not
+     * be stored. Sub-classes can overwrite this method to cache attributes.
+     */
+    protected void startElement(String namespace, String localName, String qName) throws SAXException {
+        contentHandler.startElement(namespace, localName, qName, this);
+    }
+
+}