summaryrefslogtreecommitdiffstats
path: root/xml/src/main/java/org/xmlpull
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
commitadc854b798c1cfe3bfd4c27d68d5cee38ca617da (patch)
tree6aed8b4923ca428942cbaa7e848d50237a3d31e0 /xml/src/main/java/org/xmlpull
parent1c0fed63c71ddb230f3b304aac12caffbedf2f21 (diff)
downloadlibcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.zip
libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.gz
libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'xml/src/main/java/org/xmlpull')
-rw-r--r--xml/src/main/java/org/xmlpull/v1/XmlPullParser.java1116
-rw-r--r--xml/src/main/java/org/xmlpull/v1/XmlPullParserException.java76
-rw-r--r--xml/src/main/java/org/xmlpull/v1/XmlPullParserFactory.java349
-rw-r--r--xml/src/main/java/org/xmlpull/v1/XmlSerializer.java326
-rw-r--r--xml/src/main/java/org/xmlpull/v1/sax2/Driver.java469
5 files changed, 2336 insertions, 0 deletions
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);
+ }
+
+}