# HG changeset patch # User Jaroslav Tulach # Date 1245854304 -7200 # Node ID 52864f10883d0cd9d638a9428db8256586ae9729 # Parent 29f4f9b451b8def2c9c9194c4d2b264884fa42c2 By default (when no XML SAX and DOM 2 present) parsing the properties stream with simple nanoXML parser diff -r 29f4f9b451b8 -r 52864f10883d build.xml --- a/build.xml Wed Jun 24 14:53:01 2009 +0200 +++ b/build.xml Wed Jun 24 16:38:24 2009 +0200 @@ -16,7 +16,7 @@ - + @@ -63,7 +63,13 @@ - + + + + + + + - - - - - - - - + @@ -402,6 +404,8 @@ includejavaruntime="false" includeantruntime="false" classpath="${module.cp}:${plugs}/jre/lib/rt-closed.jar" + debug="true" + debuglevel="lines,vars,source" > diff -r 29f4f9b451b8 -r 52864f10883d src/share/classes/sun/util/xml/DefaultPropertiesXMLUtils.java --- a/src/share/classes/sun/util/xml/DefaultPropertiesXMLUtils.java Wed Jun 24 14:53:01 2009 +0200 +++ b/src/share/classes/sun/util/xml/DefaultPropertiesXMLUtils.java Wed Jun 24 16:38:24 2009 +0200 @@ -40,7 +40,14 @@ public class DefaultPropertiesXMLUtils extends PropertiesXMLUtils { public void load(Properties props, InputStream in) throws IOException, InvalidPropertiesFormatException { - throw new IOException("Not implemented yet"); + XMLElement e = new XMLElement(); + e.parseFromReader(new InputStreamReader(in, "UTF-8")); + for (Object o : e.getChildren()) { + XMLElement ch = (XMLElement)o; + if (ch.getName().equals("entry")) { + props.put(ch.getAttribute("key"), ch.getContent()); + } + } } public void save(Properties props, OutputStream out, String comment, String encoding) throws IOException { diff -r 29f4f9b451b8 -r 52864f10883d src/share/classes/sun/util/xml/XMLElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/util/xml/XMLElement.java Wed Jun 24 16:38:24 2009 +0200 @@ -0,0 +1,2874 @@ +/* XMLElement.java + * + * $Revision: 1.4 $ + * $Date: 2002/03/24 10:27:59 $ + * $Name: RELEASE_2_2_1 $ + * + * This file is part of NanoXML 2 Lite. + * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved. + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the + * use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source distribution. + *****************************************************************************/ + + +package sun.util.xml; + + +import java.io.ByteArrayOutputStream; +import java.io.CharArrayReader; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.Writer; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + + +/** + * XMLElement is a representation of an XML object. The object is able to parse + * XML code. + *

+ *
Parsing XML Data
+ *
+ * You can parse XML data using the following code: + *
    + * XMLElement xml = new XMLElement();
    + * FileReader reader = new FileReader("filename.xml");
    + * xml.parseFromReader(reader); + *
+ *
Retrieving Attributes
+ *
+ * You can enumerate the attributes of an element using the method + * {@link #enumerateAttributeNames() enumerateAttributeNames}. + * The attribute values can be retrieved using the method + * {@link #getStringAttribute(java.lang.String) getStringAttribute}. + * The following example shows how to list the attributes of an element: + *
    + * XMLElement element = ...;
    + * Enumeration enumV = element.getAttributeNames();
    + * while (enumV.hasMoreElements()) {
    + *     String key = (String) enumV.nextElement();
    + *     String value = element.getStringAttribute(key);
    + *     System.out.println(key + " = " + value);
    + * } + *
+ *
Retrieving Child Elements
+ *
+ * You can enumerate the children of an element using + * {@link #enumerateChildren() enumerateChildren}. + * The number of child elements can be retrieved using + * {@link #countChildren() countChildren}. + *
+ *
Elements Containing Character Data
+ *
+ * If an elements contains character data, like in the following example: + *
    + * <title>The Title</title> + *
+ * you can retrieve that data using the method + * {@link #getContent() getContent}. + *
+ *
Subclassing XMLElement
+ *
+ * When subclassing XMLElement, you need to override the method + * {@link #createAnotherElement() createAnotherElement} + * which has to return a new copy of the receiver. + *
+ *

+ * + * @see nanoxml.XMLParseException + * + * @author Marc De Scheemaecker + * <cyberelf@mac.com> + * @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $ + */ +class XMLElement { + + /** + * Serialization serial version ID. + */ + static final long serialVersionUID = 6685035139346394777L; + + + /** + * Major version of NanoXML. Classes with the same major and minor + * version are binary compatible. Classes with the same major version + * are source compatible. If the major version is different, you may + * need to modify the client source code. + * + * @see nanoxml.XMLElement#NANOXML_MINOR_VERSION + */ + public static final int NANOXML_MAJOR_VERSION = 2; + + + /** + * Minor version of NanoXML. Classes with the same major and minor + * version are binary compatible. Classes with the same major version + * are source compatible. If the major version is different, you may + * need to modify the client source code. + * + * @see nanoxml.XMLElement#NANOXML_MAJOR_VERSION + */ + public static final int NANOXML_MINOR_VERSION = 2; + + + /** + * The attributes given to the element. + * + *

Invariants:
+ *
  • The field can be empty. + *
  • The field is never null. + *
  • The keys and the values are strings. + *
+ */ + private Hashtable attributes; + + + /** + * Child elements of the element. + * + *
Invariants:
+ *
  • The field can be empty. + *
  • The field is never null. + *
  • The elements are instances of XMLElement + * or a subclass of XMLElement. + *
+ */ + private Vector children; + + + /** + * The name of the element. + * + *
Invariants:
+ *
  • The field is null iff the element is not + * initialized by either parse or setName. + *
  • If the field is not null, it's not empty. + *
  • If the field is not null, it contains a valid + * XML identifier. + *
+ */ + private String name; + + + /** + * The #PCDATA content of the object. + * + *
Invariants:
+ *
  • The field is null iff the element is not a + * #PCDATA element. + *
  • The field can be any string, including the empty string. + *
+ */ + private String contents; + + + /** + * Conversion table for &...; entities. The keys are the entity names + * without the & and ; delimiters. + * + *
Invariants:
+ *
  • The field is never null. + *
  • The field always contains the following associations: + * "lt" => "<", "gt" => ">", + * "quot" => "\"", "apos" => "'", + * "amp" => "&" + *
  • The keys are strings + *
  • The values are char arrays + *
+ */ + private Hashtable entities; + + + /** + * The line number where the element starts. + * + *
Invariants:
+ *
  • lineNr >= 0 + *
+ */ + private int lineNr; + + + /** + * true if the case of the element and attribute names + * are case insensitive. + */ + private boolean ignoreCase; + + + /** + * true if the leading and trailing whitespace of #PCDATA + * sections have to be ignored. + */ + private boolean ignoreWhitespace; + + + /** + * Character read too much. + * This character provides push-back functionality to the input reader + * without having to use a PushbackReader. + * If there is no such character, this field is '\0'. + */ + private char charReadTooMuch; + + + /** + * The reader provided by the caller of the parse method. + * + *
Invariants:
+ *
  • The field is not null while the parse method + * is running. + *
+ */ + private Reader reader; + + + /** + * The current line number in the source content. + * + *
Invariants:
+ *
  • parserLineNr > 0 while the parse method is running. + *
+ */ + private int parserLineNr; + + + /** + * Creates and initializes a new XML element. + * Calling the construction is equivalent to: + *
    new XMLElement(new Hashtable(), false, true) + *
+ * + *
Postconditions:
+ *
  • countChildren() => 0 + *
  • enumerateChildren() => empty enumeration + *
  • enumeratePropertyNames() => empty enumeration + *
  • getChildren() => empty vector + *
  • getContent() => "" + *
  • getLineNr() => 0 + *
  • getName() => null + *
+ * + * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable) + * XMLElement(Hashtable) + * @see nanoxml.XMLElement#XMLElement(boolean) + * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable,boolean) + * XMLElement(Hashtable, boolean) + */ + public XMLElement() + { + this(new Hashtable(), false, true, true); + } + + + /** + * Creates and initializes a new XML element. + * Calling the construction is equivalent to: + *
    new XMLElement(entities, false, true) + *
+ * + * @param entities + * The entity conversion table. + * + *
Preconditions:
+ *
  • entities != null + *
+ * + *
Postconditions:
+ *
  • countChildren() => 0 + *
  • enumerateChildren() => empty enumeration + *
  • enumeratePropertyNames() => empty enumeration + *
  • getChildren() => empty vector + *
  • getContent() => "" + *
  • getLineNr() => 0 + *
  • getName() => null + *
+ * + * @see nanoxml.XMLElement#XMLElement() + * @see nanoxml.XMLElement#XMLElement(boolean) + * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable,boolean) + * XMLElement(Hashtable, boolean) + */ + public XMLElement(Hashtable entities) + { + this(entities, false, true, true); + } + + + /** + * Creates and initializes a new XML element. + * Calling the construction is equivalent to: + *
    new XMLElement(new Hashtable(), skipLeadingWhitespace, true) + *
+ * + * @param skipLeadingWhitespace + * true if leading and trailing whitespace in PCDATA + * content has to be removed. + * + *
Postconditions:
+ *
  • countChildren() => 0 + *
  • enumerateChildren() => empty enumeration + *
  • enumeratePropertyNames() => empty enumeration + *
  • getChildren() => empty vector + *
  • getContent() => "" + *
  • getLineNr() => 0 + *
  • getName() => null + *
+ * + * @see nanoxml.XMLElement#XMLElement() + * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable) + * XMLElement(Hashtable) + * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable,boolean) + * XMLElement(Hashtable, boolean) + */ + public XMLElement(boolean skipLeadingWhitespace) + { + this(new Hashtable(), skipLeadingWhitespace, true, true); + } + + + /** + * Creates and initializes a new XML element. + * Calling the construction is equivalent to: + *
    new XMLElement(entities, skipLeadingWhitespace, true) + *
+ * + * @param entities + * The entity conversion table. + * @param skipLeadingWhitespace + * true if leading and trailing whitespace in PCDATA + * content has to be removed. + * + *
Preconditions:
+ *
  • entities != null + *
+ * + *
Postconditions:
+ *
  • countChildren() => 0 + *
  • enumerateChildren() => empty enumeration + *
  • enumeratePropertyNames() => empty enumeration + *
  • getChildren() => empty vector + *
  • getContent() => "" + *
  • getLineNr() => 0 + *
  • getName() => null + *
+ * + * @see nanoxml.XMLElement#XMLElement() + * @see nanoxml.XMLElement#XMLElement(boolean) + * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable) + * XMLElement(Hashtable) + */ + public XMLElement(Hashtable entities, + boolean skipLeadingWhitespace) + { + this(entities, skipLeadingWhitespace, true, true); + } + + + /** + * Creates and initializes a new XML element. + * + * @param entities + * The entity conversion table. + * @param skipLeadingWhitespace + * true if leading and trailing whitespace in PCDATA + * content has to be removed. + * @param ignoreCase + * true if the case of element and attribute names have + * to be ignored. + * + *
Preconditions:
+ *
  • entities != null + *
+ * + *
Postconditions:
+ *
  • countChildren() => 0 + *
  • enumerateChildren() => empty enumeration + *
  • enumeratePropertyNames() => empty enumeration + *
  • getChildren() => empty vector + *
  • getContent() => "" + *
  • getLineNr() => 0 + *
  • getName() => null + *
+ * + * @see nanoxml.XMLElement#XMLElement() + * @see nanoxml.XMLElement#XMLElement(boolean) + * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable) + * XMLElement(Hashtable) + * @see nanoxml.XMLElement#XMLElement(java.util.Hashtable,boolean) + * XMLElement(Hashtable, boolean) + */ + public XMLElement(Hashtable entities, + boolean skipLeadingWhitespace, + boolean ignoreCase) + { + this(entities, skipLeadingWhitespace, true, ignoreCase); + } + + + /** + * Creates and initializes a new XML element. + *

+ * This constructor should only be called from + * {@link #createAnotherElement() createAnotherElement} + * to create child elements. + * + * @param entities + * The entity conversion table. + * @param skipLeadingWhitespace + * true if leading and trailing whitespace in PCDATA + * content has to be removed. + * @param fillBasicConversionTable + * true if the basic entities need to be added to + * the entity list. + * @param ignoreCase + * true if the case of element and attribute names have + * to be ignored. + * + *

Preconditions:
+ *
  • entities != null + *
  • if fillBasicConversionTable == false + * then entities contains at least the following + * entries: amp, lt, gt, + * apos and quot + *
+ * + *
Postconditions:
+ *
  • countChildren() => 0 + *
  • enumerateChildren() => empty enumeration + *
  • enumeratePropertyNames() => empty enumeration + *
  • getChildren() => empty vector + *
  • getContent() => "" + *
  • getLineNr() => 0 + *
  • getName() => null + *
+ * + * @see nanoxml.XMLElement#createAnotherElement() + */ + protected XMLElement(Hashtable entities, + boolean skipLeadingWhitespace, + boolean fillBasicConversionTable, + boolean ignoreCase) + { + this.ignoreWhitespace = skipLeadingWhitespace; + this.ignoreCase = ignoreCase; + this.name = null; + this.contents = ""; + this.attributes = new Hashtable(); + this.children = new Vector(); + this.entities = entities; + this.lineNr = 0; + Enumeration enumV = this.entities.keys(); + while (enumV.hasMoreElements()) { + Object key = enumV.nextElement(); + Object value = this.entities.get(key); + if (value instanceof String) { + value = ((String) value).toCharArray(); + this.entities.put(key, value); + } + } + if (fillBasicConversionTable) { + this.entities.put("amp", new char[] { '&' }); + this.entities.put("quot", new char[] { '"' }); + this.entities.put("apos", new char[] { '\'' }); + this.entities.put("lt", new char[] { '<' }); + this.entities.put("gt", new char[] { '>' }); + } + } + + + /** + * Adds a child element. + * + * @param child + * The child element to add. + * + *
Preconditions:
+ *
  • child != null + *
  • child.getName() != null + *
  • child does not have a parent element + *
+ * + *
Postconditions:
+ *
  • countChildren() => old.countChildren() + 1 + *
  • enumerateChildren() => old.enumerateChildren() + child + *
  • getChildren() => old.enumerateChildren() + child + *
+ * + * @see nanoxml.XMLElement#countChildren() + * @see nanoxml.XMLElement#enumerateChildren() + * @see nanoxml.XMLElement#getChildren() + * @see nanoxml.XMLElement#removeChild(nanoxml.XMLElement) + * removeChild(XMLElement) + */ + public void addChild(XMLElement child) + { + this.children.addElement(child); + } + + + /** + * Adds or modifies an attribute. + * + * @param name + * The name of the attribute. + * @param value + * The value of the attribute. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
  • value != null + *
+ * + *
Postconditions:
+ *
  • enumerateAttributeNames() + * => old.enumerateAttributeNames() + name + *
  • getAttribute(name) => value + *
+ * + * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double) + * setDoubleAttribute(String, double) + * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int) + * setIntAttribute(String, int) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getAttribute(java.lang.String) + * getAttribute(String) + * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object) + * getAttribute(String, Object) + * @see nanoxml.XMLElement#getAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getAttribute(String, Hashtable, String, boolean) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String) + * getStringAttribute(String) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.lang.String) + * getStringAttribute(String, String) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getStringAttribute(String, Hashtable, String, boolean) + */ + public void setAttribute(String name, + Object value) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + this.attributes.put(name, value.toString()); + } + + + /** + * Adds or modifies an attribute. + * + * @param name + * The name of the attribute. + * @param value + * The value of the attribute. + * + * @deprecated Use {@link #setAttribute(java.lang.String, java.lang.Object) + * setAttribute} instead. + */ + public void addProperty(String name, + Object value) + { + this.setAttribute(name, value); + } + + + /** + * Adds or modifies an attribute. + * + * @param name + * The name of the attribute. + * @param value + * The value of the attribute. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + *
Postconditions:
+ *
  • enumerateAttributeNames() + * => old.enumerateAttributeNames() + name + *
  • getIntAttribute(name) => value + *
+ * + * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double) + * setDoubleAttribute(String, double) + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String) + * getIntAttribute(String) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int) + * getIntAttribute(String, int) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getIntAttribute(String, Hashtable, String, boolean) + */ + public void setIntAttribute(String name, + int value) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + this.attributes.put(name, Integer.toString(value)); + } + + + /** + * Adds or modifies an attribute. + * + * @param name + * The name of the attribute. + * @param value + * The value of the attribute. + * + * @deprecated Use {@link #setIntAttribute(java.lang.String, int) + * setIntAttribute} instead. + */ + public void addProperty(String key, + int value) + { + this.setIntAttribute(key, value); + } + + + /** + * Adds or modifies an attribute. + * + * @param name + * The name of the attribute. + * @param value + * The value of the attribute. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + *
Postconditions:
+ *
  • enumerateAttributeNames() + * => old.enumerateAttributeNames() + name + *
  • getDoubleAttribute(name) => value + *
+ * + * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int) + * setIntAttribute(String, int) + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String) + * getDoubleAttribute(String) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double) + * getDoubleAttribute(String, double) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getDoubleAttribute(String, Hashtable, String, boolean) + */ + public void setDoubleAttribute(String name, + double value) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + this.attributes.put(name, Double.toString(value)); + } + + + /** + * Adds or modifies an attribute. + * + * @param name + * The name of the attribute. + * @param value + * The value of the attribute. + * + * @deprecated Use {@link #setDoubleAttribute(java.lang.String, double) + * setDoubleAttribute} instead. + */ + public void addProperty(String name, + double value) + { + this.setDoubleAttribute(name, value); + } + + + /** + * Returns the number of child elements of the element. + * + *
Postconditions:
+ *
  • result >= 0 + *
+ * + * @see nanoxml.XMLElement#addChild(nanoxml.XMLElement) + * addChild(XMLElement) + * @see nanoxml.XMLElement#enumerateChildren() + * @see nanoxml.XMLElement#getChildren() + * @see nanoxml.XMLElement#removeChild(nanoxml.XMLElement) + * removeChild(XMLElement) + */ + public int countChildren() + { + return this.children.size(); + } + + + /** + * Enumerates the attribute names. + * + *
Postconditions:
+ *
  • result != null + *
+ * + * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double) + * setDoubleAttribute(String, double) + * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int) + * setIntAttribute(String, int) + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#getAttribute(java.lang.String) + * getAttribute(String) + * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object) + * getAttribute(String, String) + * @see nanoxml.XMLElement#getAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getAttribute(String, Hashtable, String, boolean) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String) + * getStringAttribute(String) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.lang.String) + * getStringAttribute(String, String) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getStringAttribute(String, Hashtable, String, boolean) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String) + * getIntAttribute(String) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int) + * getIntAttribute(String, int) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getIntAttribute(String, Hashtable, String, boolean) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String) + * getDoubleAttribute(String) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double) + * getDoubleAttribute(String, double) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getDoubleAttribute(String, Hashtable, String, boolean) + * @see nanoxml.XMLElement#getBooleanAttribute(java.lang.String, + * java.lang.String, + * java.lang.String, boolean) + * getBooleanAttribute(String, String, String, boolean) + */ + public Enumeration enumerateAttributeNames() + { + return this.attributes.keys(); + } + + + /** + * Enumerates the attribute names. + * + * @deprecated Use {@link #enumerateAttributeNames() + * enumerateAttributeNames} instead. + */ + public Enumeration enumeratePropertyNames() + { + return this.enumerateAttributeNames(); + } + + + /** + * Enumerates the child elements. + * + *
Postconditions:
+ *
  • result != null + *
+ * + * @see nanoxml.XMLElement#addChild(nanoxml.XMLElement) + * addChild(XMLElement) + * @see nanoxml.XMLElement#countChildren() + * @see nanoxml.XMLElement#getChildren() + * @see nanoxml.XMLElement#removeChild(nanoxml.XMLElement) + * removeChild(XMLElement) + */ + public Enumeration enumerateChildren() + { + return this.children.elements(); + } + + + /** + * Returns the child elements as a Vector. It is safe to modify this + * Vector. + * + *
Postconditions:
+ *
  • result != null + *
+ * + * @see nanoxml.XMLElement#addChild(nanoxml.XMLElement) + * addChild(XMLElement) + * @see nanoxml.XMLElement#countChildren() + * @see nanoxml.XMLElement#enumerateChildren() + * @see nanoxml.XMLElement#removeChild(nanoxml.XMLElement) + * removeChild(XMLElement) + */ + public Vector getChildren() + { + try { + return (Vector) this.children.clone(); + } catch (Exception e) { + // this never happens, however, some Java compilers are so + // braindead that they require this exception clause + return null; + } + } + + + /** + * Returns the PCDATA content of the object. If there is no such content, + * null is returned. + * + * @deprecated Use {@link #getContent() getContent} instead. + */ + public String getContents() + { + return this.getContent(); + } + + + /** + * Returns the PCDATA content of the object. If there is no such content, + * null is returned. + * + * @see nanoxml.XMLElement#setContent(java.lang.String) + * setContent(String) + */ + public String getContent() + { + return this.contents; + } + + + /** + * Returns the line nr in the source data on which the element is found. + * This method returns 0 there is no associated source data. + * + *
Postconditions:
+ *
  • result >= 0 + *
+ */ + public int getLineNr() + { + return this.lineNr; + } + + + /** + * Returns an attribute of the element. + * If the attribute doesn't exist, null is returned. + * + * @param name The name of the attribute. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object) + * getAttribute(String, Object) + * @see nanoxml.XMLElement#getAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getAttribute(String, Hashtable, String, boolean) + */ + public Object getAttribute(String name) + { + return this.getAttribute(name, null); + } + + + /** + * Returns an attribute of the element. + * If the attribute doesn't exist, defaultValue is returned. + * + * @param name The name of the attribute. + * @param defaultValue Key to use if the attribute is missing. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getAttribute(java.lang.String) + * getAttribute(String) + * @see nanoxml.XMLElement#getAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getAttribute(String, Hashtable, String, boolean) + */ + public Object getAttribute(String name, + Object defaultValue) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + Object value = this.attributes.get(name); + if (value == null) { + value = defaultValue; + } + return value; + } + + + /** + * Returns an attribute by looking up a key in a hashtable. + * If the attribute doesn't exist, the value corresponding to defaultKey + * is returned. + *

+ * As an example, if valueSet contains the mapping "one" => + * "1" + * and the element contains the attribute attr="one", then + * getAttribute("attr", mapping, defaultKey, false) returns + * "1". + * + * @param name + * The name of the attribute. + * @param valueSet + * Hashtable mapping keys to values. + * @param defaultKey + * Key to use if the attribute is missing. + * @param allowLiterals + * true if literals are valid. + * + *

Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
  • valueSet != null + *
  • the keys of valueSet are strings + *
+ * + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getAttribute(java.lang.String) + * getAttribute(String) + * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object) + * getAttribute(String, Object) + */ + public Object getAttribute(String name, + Hashtable valueSet, + String defaultKey, + boolean allowLiterals) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + Object key = this.attributes.get(name); + Object result; + if (key == null) { + key = defaultKey; + } + result = valueSet.get(key); + if (result == null) { + if (allowLiterals) { + result = key; + } else { + throw this.invalidValue(name, (String) key); + } + } + return result; + } + + + /** + * Returns an attribute of the element. + * If the attribute doesn't exist, null is returned. + * + * @param name The name of the attribute. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.lang.String) + * getStringAttribute(String, String) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getStringAttribute(String, Hashtable, String, boolean) + */ + public String getStringAttribute(String name) + { + return this.getStringAttribute(name, null); + } + + + /** + * Returns an attribute of the element. + * If the attribute doesn't exist, defaultValue is returned. + * + * @param name The name of the attribute. + * @param defaultValue Key to use if the attribute is missing. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String) + * getStringAttribute(String) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getStringAttribute(String, Hashtable, String, boolean) + */ + public String getStringAttribute(String name, + String defaultValue) + { + return (String) this.getAttribute(name, defaultValue); + } + + + /** + * Returns an attribute by looking up a key in a hashtable. + * If the attribute doesn't exist, the value corresponding to defaultKey + * is returned. + *

+ * As an example, if valueSet contains the mapping "one" => + * "1" + * and the element contains the attribute attr="one", then + * getAttribute("attr", mapping, defaultKey, false) returns + * "1". + * + * @param name + * The name of the attribute. + * @param valueSet + * Hashtable mapping keys to values. + * @param defaultKey + * Key to use if the attribute is missing. + * @param allowLiterals + * true if literals are valid. + * + *

Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
  • valueSet != null + *
  • the keys of valueSet are strings + *
  • the values of valueSet are strings + *
+ * + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String) + * getStringAttribute(String) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.lang.String) + * getStringAttribute(String, String) + */ + public String getStringAttribute(String name, + Hashtable valueSet, + String defaultKey, + boolean allowLiterals) + { + return (String) this.getAttribute(name, valueSet, defaultKey, + allowLiterals); + } + + + /** + * Returns an attribute of the element. + * If the attribute doesn't exist, 0 is returned. + * + * @param name The name of the attribute. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int) + * setIntAttribute(String, int) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int) + * getIntAttribute(String, int) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getIntAttribute(String, Hashtable, String, boolean) + */ + public int getIntAttribute(String name) + { + return this.getIntAttribute(name, 0); + } + + + /** + * Returns an attribute of the element. + * If the attribute doesn't exist, defaultValue is returned. + * + * @param name The name of the attribute. + * @param defaultValue Key to use if the attribute is missing. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int) + * setIntAttribute(String, int) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String) + * getIntAttribute(String) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getIntAttribute(String, Hashtable, String, boolean) + */ + public int getIntAttribute(String name, + int defaultValue) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + String value = (String) this.attributes.get(name); + if (value == null) { + return defaultValue; + } else { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw this.invalidValue(name, value); + } + } + } + + + /** + * Returns an attribute by looking up a key in a hashtable. + * If the attribute doesn't exist, the value corresponding to defaultKey + * is returned. + *

+ * As an example, if valueSet contains the mapping "one" => 1 + * and the element contains the attribute attr="one", then + * getIntAttribute("attr", mapping, defaultKey, false) returns + * 1. + * + * @param name + * The name of the attribute. + * @param valueSet + * Hashtable mapping keys to values. + * @param defaultKey + * Key to use if the attribute is missing. + * @param allowLiteralNumbers + * true if literal numbers are valid. + * + *

Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
  • valueSet != null + *
  • the keys of valueSet are strings + *
  • the values of valueSet are Integer objects + *
  • defaultKey is either null, a + * key in valueSet or an integer. + *
+ * + * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int) + * setIntAttribute(String, int) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String) + * getIntAttribute(String) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int) + * getIntAttribute(String, int) + */ + public int getIntAttribute(String name, + Hashtable valueSet, + String defaultKey, + boolean allowLiteralNumbers) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + Object key = this.attributes.get(name); + Integer result; + if (key == null) { + key = defaultKey; + } + try { + result = (Integer) valueSet.get(key); + } catch (ClassCastException e) { + throw this.invalidValueSet(name); + } + if (result == null) { + if (! allowLiteralNumbers) { + throw this.invalidValue(name, (String) key); + } + try { + result = Integer.valueOf((String) key); + } catch (NumberFormatException e) { + throw this.invalidValue(name, (String) key); + } + } + return result.intValue(); + } + + + /** + * Returns an attribute of the element. + * If the attribute doesn't exist, 0.0 is returned. + * + * @param name The name of the attribute. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double) + * setDoubleAttribute(String, double) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double) + * getDoubleAttribute(String, double) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getDoubleAttribute(String, Hashtable, String, boolean) + */ + public double getDoubleAttribute(String name) + { + return this.getDoubleAttribute(name, 0.); + } + + + /** + * Returns an attribute of the element. + * If the attribute doesn't exist, defaultValue is returned. + * + * @param name The name of the attribute. + * @param defaultValue Key to use if the attribute is missing. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double) + * setDoubleAttribute(String, double) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String) + * getDoubleAttribute(String) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getDoubleAttribute(String, Hashtable, String, boolean) + */ + public double getDoubleAttribute(String name, + double defaultValue) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + String value = (String) this.attributes.get(name); + if (value == null) { + return defaultValue; + } else { + try { + return Double.valueOf(value).doubleValue(); + } catch (NumberFormatException e) { + throw this.invalidValue(name, value); + } + } + } + + + /** + * Returns an attribute by looking up a key in a hashtable. + * If the attribute doesn't exist, the value corresponding to defaultKey + * is returned. + *

+ * As an example, if valueSet contains the mapping "one" => + * 1.0 + * and the element contains the attribute attr="one", then + * getDoubleAttribute("attr", mapping, defaultKey, false) + * returns 1.0. + * + * @param name + * The name of the attribute. + * @param valueSet + * Hashtable mapping keys to values. + * @param defaultKey + * Key to use if the attribute is missing. + * @param allowLiteralNumbers + * true if literal numbers are valid. + * + *

Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
  • valueSet != null + *
  • the keys of valueSet are strings + *
  • the values of valueSet are Double objects + *
  • defaultKey is either null, a + * key in valueSet or a double. + *
+ * + * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double) + * setDoubleAttribute(String, double) + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String) + * getDoubleAttribute(String) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double) + * getDoubleAttribute(String, double) + */ + public double getDoubleAttribute(String name, + Hashtable valueSet, + String defaultKey, + boolean allowLiteralNumbers) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + Object key = this.attributes.get(name); + Double result; + if (key == null) { + key = defaultKey; + } + try { + result = (Double) valueSet.get(key); + } catch (ClassCastException e) { + throw this.invalidValueSet(name); + } + if (result == null) { + if (! allowLiteralNumbers) { + throw this.invalidValue(name, (String) key); + } + try { + result = Double.valueOf((String) key); + } catch (NumberFormatException e) { + throw this.invalidValue(name, (String) key); + } + } + return result.doubleValue(); + } + + + /** + * Returns an attribute of the element. + * If the attribute doesn't exist, defaultValue is returned. + * If the value of the attribute is equal to trueValue, + * true is returned. + * If the value of the attribute is equal to falseValue, + * false is returned. + * If the value doesn't match trueValue or + * falseValue, an exception is thrown. + * + * @param name The name of the attribute. + * @param trueValue The value associated with true. + * @param falseValue The value associated with true. + * @param defaultValue Value to use if the attribute is missing. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
  • trueValue and falseValue + * are different strings. + *
+ * + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#removeAttribute(java.lang.String) + * removeAttribute(String) + * @see nanoxml.XMLElement#enumerateAttributeNames() + */ + public boolean getBooleanAttribute(String name, + String trueValue, + String falseValue, + boolean defaultValue) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + Object value = this.attributes.get(name); + if (value == null) { + return defaultValue; + } else if (value.equals(trueValue)) { + return true; + } else if (value.equals(falseValue)) { + return false; + } else { + throw this.invalidValue(name, (String) value); + } + } + + + /** + * Returns an attribute by looking up a key in a hashtable. + * + * @deprecated Use {@link #getIntAttribute(java.lang.String, + * java.util.Hashtable, java.lang.String, boolean) + * getIntAttribute} instead. + */ + public int getIntProperty(String name, + Hashtable valueSet, + String defaultKey) + { + return this.getIntAttribute(name, valueSet, defaultKey, false); + } + + + /** + * Returns an attribute. + * + * @deprecated Use {@link #getStringAttribute(java.lang.String) + * getStringAttribute} instead. + */ + public String getProperty(String name) + { + return this.getStringAttribute(name); + } + + + /** + * Returns an attribute. + * + * @deprecated Use {@link #getStringAttribute(java.lang.String, + * java.lang.String) getStringAttribute} instead. + */ + public String getProperty(String name, + String defaultValue) + { + return this.getStringAttribute(name, defaultValue); + } + + + /** + * Returns an attribute. + * + * @deprecated Use {@link #getIntAttribute(java.lang.String, int) + * getIntAttribute} instead. + */ + public int getProperty(String name, + int defaultValue) + { + return this.getIntAttribute(name, defaultValue); + } + + + /** + * Returns an attribute. + * + * @deprecated Use {@link #getDoubleAttribute(java.lang.String, double) + * getDoubleAttribute} instead. + */ + public double getProperty(String name, + double defaultValue) + { + return this.getDoubleAttribute(name, defaultValue); + } + + + /** + * Returns an attribute. + * + * @deprecated Use {@link #getBooleanAttribute(java.lang.String, + * java.lang.String, java.lang.String, boolean) + * getBooleanAttribute} instead. + */ + public boolean getProperty(String key, + String trueValue, + String falseValue, + boolean defaultValue) + { + return this.getBooleanAttribute(key, trueValue, falseValue, + defaultValue); + } + + + /** + * Returns an attribute by looking up a key in a hashtable. + * + * @deprecated Use {@link #getAttribute(java.lang.String, + * java.util.Hashtable, java.lang.String, boolean) + * getAttribute} instead. + */ + public Object getProperty(String name, + Hashtable valueSet, + String defaultKey) + { + return this.getAttribute(name, valueSet, defaultKey, false); + } + + + /** + * Returns an attribute by looking up a key in a hashtable. + * + * @deprecated Use {@link #getStringAttribute(java.lang.String, + * java.util.Hashtable, java.lang.String, boolean) + * getStringAttribute} instead. + */ + public String getStringProperty(String name, + Hashtable valueSet, + String defaultKey) + { + return this.getStringAttribute(name, valueSet, defaultKey, false); + } + + + /** + * Returns an attribute by looking up a key in a hashtable. + * + * @deprecated Use {@link #getIntAttribute(java.lang.String, + * java.util.Hashtable, java.lang.String, boolean) + * getIntAttribute} instead. + */ + public int getSpecialIntProperty(String name, + Hashtable valueSet, + String defaultKey) + { + return this.getIntAttribute(name, valueSet, defaultKey, true); + } + + + /** + * Returns an attribute by looking up a key in a hashtable. + * + * @deprecated Use {@link #getDoubleAttribute(java.lang.String, + * java.util.Hashtable, java.lang.String, boolean) + * getDoubleAttribute} instead. + */ + public double getSpecialDoubleProperty(String name, + Hashtable valueSet, + String defaultKey) + { + return this.getDoubleAttribute(name, valueSet, defaultKey, true); + } + + + /** + * Returns the name of the element. + * + * @see nanoxml.XMLElement#setName(java.lang.String) setName(String) + */ + public String getName() + { + return this.name; + } + + + /** + * Returns the name of the element. + * + * @deprecated Use {@link #getName() getName} instead. + */ + public String getTagName() + { + return this.getName(); + } + + + /** + * Reads one XML element from a java.io.Reader and parses it. + * + * @param reader + * The reader from which to retrieve the XML data. + * + *
Preconditions:
+ *
  • reader != null + *
  • reader is not closed + *
+ * + *
Postconditions:
+ *
  • the state of the receiver is updated to reflect the XML element + * parsed from the reader + *
  • the reader points to the first character following the last + * '>' character of the XML element + *
+ * + * @throws java.io.IOException + * If an error occured while reading the input. + * @throws nanoxml.XMLParseException + * If an error occured while parsing the read data. + */ + public void parseFromReader(Reader reader) + throws IOException, XMLParseException + { + this.parseFromReader(reader, /*startingLineNr*/ 1); + } + + + /** + * Reads one XML element from a java.io.Reader and parses it. + * + * @param reader + * The reader from which to retrieve the XML data. + * @param startingLineNr + * The line number of the first line in the data. + * + *
Preconditions:
+ *
  • reader != null + *
  • reader is not closed + *
+ * + *
Postconditions:
+ *
  • the state of the receiver is updated to reflect the XML element + * parsed from the reader + *
  • the reader points to the first character following the last + * '>' character of the XML element + *
+ * + * @throws java.io.IOException + * If an error occured while reading the input. + * @throws nanoxml.XMLParseException + * If an error occured while parsing the read data. + */ + public void parseFromReader(Reader reader, + int startingLineNr) + throws IOException, XMLParseException + { + this.name = null; + this.contents = ""; + this.attributes = new Hashtable(); + this.children = new Vector(); + this.charReadTooMuch = '\0'; + this.reader = reader; + this.parserLineNr = startingLineNr; + + for (;;) { + char ch = this.scanWhitespace(); + + if (ch != '<') { + throw this.expectedInput("<"); + } + + ch = this.readChar(); + + if ((ch == '!') || (ch == '?')) { + this.skipSpecialTag(0); + } else { + this.unreadChar(ch); + this.scanElement(this); + return; + } + } + } + + + /** + * Reads one XML element from a String and parses it. + * + * @param reader + * The reader from which to retrieve the XML data. + * + *
Preconditions:
+ *
  • string != null + *
  • string.length() > 0 + *
+ * + *
Postconditions:
+ *
  • the state of the receiver is updated to reflect the XML element + * parsed from the reader + *
+ * + * @throws nanoxml.XMLParseException + * If an error occured while parsing the string. + */ + public void parseString(String string) + throws XMLParseException + { + try { + this.parseFromReader(new StringReader(string), + /*startingLineNr*/ 1); + } catch (IOException e) { + // Java exception handling suxx + } + } + + + /** + * Reads one XML element from a String and parses it. + * + * @param reader + * The reader from which to retrieve the XML data. + * @param offset + * The first character in string to scan. + * + *
Preconditions:
+ *
  • string != null + *
  • offset < string.length() + *
  • offset >= 0 + *
+ * + *
Postconditions:
+ *
  • the state of the receiver is updated to reflect the XML element + * parsed from the reader + *
+ * + * @throws nanoxml.XMLParseException + * If an error occured while parsing the string. + */ + public void parseString(String string, + int offset) + throws XMLParseException + { + this.parseString(string.substring(offset)); + } + + + /** + * Reads one XML element from a String and parses it. + * + * @param reader + * The reader from which to retrieve the XML data. + * @param offset + * The first character in string to scan. + * @param end + * The character where to stop scanning. + * This character is not scanned. + * + *
Preconditions:
+ *
  • string != null + *
  • end <= string.length() + *
  • offset < end + *
  • offset >= 0 + *
+ * + *
Postconditions:
+ *
  • the state of the receiver is updated to reflect the XML element + * parsed from the reader + *
+ * + * @throws nanoxml.XMLParseException + * If an error occured while parsing the string. + */ + public void parseString(String string, + int offset, + int end) + throws XMLParseException + { + this.parseString(string.substring(offset, end)); + } + + + /** + * Reads one XML element from a String and parses it. + * + * @param reader + * The reader from which to retrieve the XML data. + * @param offset + * The first character in string to scan. + * @param end + * The character where to stop scanning. + * This character is not scanned. + * @param startingLineNr + * The line number of the first line in the data. + * + *
Preconditions:
+ *
  • string != null + *
  • end <= string.length() + *
  • offset < end + *
  • offset >= 0 + *
+ * + *
Postconditions:
+ *
  • the state of the receiver is updated to reflect the XML element + * parsed from the reader + *
+ * + * @throws nanoxml.XMLParseException + * If an error occured while parsing the string. + */ + public void parseString(String string, + int offset, + int end, + int startingLineNr) + throws XMLParseException + { + string = string.substring(offset, end); + try { + this.parseFromReader(new StringReader(string), startingLineNr); + } catch (IOException e) { + // Java exception handling suxx + } + } + + + /** + * Reads one XML element from a char array and parses it. + * + * @param reader + * The reader from which to retrieve the XML data. + * @param offset + * The first character in string to scan. + * @param end + * The character where to stop scanning. + * This character is not scanned. + * + *
Preconditions:
+ *
  • input != null + *
  • end <= input.length + *
  • offset < end + *
  • offset >= 0 + *
+ * + *
Postconditions:
+ *
  • the state of the receiver is updated to reflect the XML element + * parsed from the reader + *
+ * + * @throws nanoxml.XMLParseException + * If an error occured while parsing the string. + */ + public void parseCharArray(char[] input, + int offset, + int end) + throws XMLParseException + { + this.parseCharArray(input, offset, end, /*startingLineNr*/ 1); + } + + + /** + * Reads one XML element from a char array and parses it. + * + * @param reader + * The reader from which to retrieve the XML data. + * @param offset + * The first character in string to scan. + * @param end + * The character where to stop scanning. + * This character is not scanned. + * @param startingLineNr + * The line number of the first line in the data. + * + *
Preconditions:
+ *
  • input != null + *
  • end <= input.length + *
  • offset < end + *
  • offset >= 0 + *
+ * + *
Postconditions:
+ *
  • the state of the receiver is updated to reflect the XML element + * parsed from the reader + *
+ * + * @throws nanoxml.XMLParseException + * If an error occured while parsing the string. + */ + public void parseCharArray(char[] input, + int offset, + int end, + int startingLineNr) + throws XMLParseException + { + try { + Reader reader = new CharArrayReader(input, offset, end); + this.parseFromReader(reader, startingLineNr); + } catch (IOException e) { + // This exception will never happen. + } + } + + + /** + * Removes a child element. + * + * @param child + * The child element to remove. + * + *
Preconditions:
+ *
  • child != null + *
  • child is a child element of the receiver + *
+ * + *
Postconditions:
+ *
  • countChildren() => old.countChildren() - 1 + *
  • enumerateChildren() => old.enumerateChildren() - child + *
  • getChildren() => old.enumerateChildren() - child + *
+ * + * @see nanoxml.XMLElement#addChild(nanoxml.XMLElement) + * addChild(XMLElement) + * @see nanoxml.XMLElement#countChildren() + * @see nanoxml.XMLElement#enumerateChildren() + * @see nanoxml.XMLElement#getChildren() + */ + public void removeChild(XMLElement child) + { + this.children.removeElement(child); + } + + + /** + * Removes an attribute. + * + * @param name + * The name of the attribute. + * + *
Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + *
Postconditions:
+ *
  • enumerateAttributeNames() + * => old.enumerateAttributeNames() - name + *
  • getAttribute(name) => null + *
+ * + * @see nanoxml.XMLElement#enumerateAttributeNames() + * @see nanoxml.XMLElement#setDoubleAttribute(java.lang.String, double) + * setDoubleAttribute(String, double) + * @see nanoxml.XMLElement#setIntAttribute(java.lang.String, int) + * setIntAttribute(String, int) + * @see nanoxml.XMLElement#setAttribute(java.lang.String, java.lang.Object) + * setAttribute(String, Object) + * @see nanoxml.XMLElement#getAttribute(java.lang.String) + * getAttribute(String) + * @see nanoxml.XMLElement#getAttribute(java.lang.String, java.lang.Object) + * getAttribute(String, Object) + * @see nanoxml.XMLElement#getAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getAttribute(String, Hashtable, String, boolean) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String) + * getStringAttribute(String) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.lang.String) + * getStringAttribute(String, String) + * @see nanoxml.XMLElement#getStringAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getStringAttribute(String, Hashtable, String, boolean) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String) + * getIntAttribute(String) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, int) + * getIntAttribute(String, int) + * @see nanoxml.XMLElement#getIntAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getIntAttribute(String, Hashtable, String, boolean) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String) + * getDoubleAttribute(String) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, double) + * getDoubleAttribute(String, double) + * @see nanoxml.XMLElement#getDoubleAttribute(java.lang.String, + * java.util.Hashtable, + * java.lang.String, boolean) + * getDoubleAttribute(String, Hashtable, String, boolean) + * @see nanoxml.XMLElement#getBooleanAttribute(java.lang.String, + * java.lang.String, + * java.lang.String, boolean) + * getBooleanAttribute(String, String, String, boolean) + */ + public void removeAttribute(String name) + { + if (this.ignoreCase) { + name = name.toUpperCase(); + } + this.attributes.remove(name); + } + + + /** + * Removes an attribute. + * + * @param name + * The name of the attribute. + * + * @deprecated Use {@link #removeAttribute(java.lang.String) + * removeAttribute} instead. + */ + public void removeProperty(String name) + { + this.removeAttribute(name); + } + + + /** + * Removes an attribute. + * + * @param name + * The name of the attribute. + * + * @deprecated Use {@link #removeAttribute(java.lang.String) + * removeAttribute} instead. + */ + public void removeChild(String name) + { + this.removeAttribute(name); + } + + + /** + * Creates a new similar XML element. + *

+ * You should override this method when subclassing XMLElement. + */ + protected XMLElement createAnotherElement() + { + return new XMLElement(this.entities, + this.ignoreWhitespace, + false, + this.ignoreCase); + } + + + /** + * Changes the content string. + * + * @param content + * The new content string. + */ + public void setContent(String content) + { + this.contents = content; + } + + + /** + * Changes the name of the element. + * + * @param name + * The new name. + * + * @deprecated Use {@link #setName(java.lang.String) setName} instead. + */ + public void setTagName(String name) + { + this.setName(name); + } + + + /** + * Changes the name of the element. + * + * @param name + * The new name. + * + *

Preconditions:
+ *
  • name != null + *
  • name is a valid XML identifier + *
+ * + * @see nanoxml.XMLElement#getName() + */ + public void setName(String name) + { + this.name = name; + } + + + /** + * Writes the XML element to a string. + * + * @see nanoxml.XMLElement#write(java.io.Writer) write(Writer) + */ + public String toString() + { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + OutputStreamWriter writer = new OutputStreamWriter(out); + this.write(writer); + writer.flush(); + return new String(out.toByteArray()); + } catch (IOException e) { + // Java exception handling suxx + return super.toString(); + } + } + + + /** + * Writes the XML element to a writer. + * + * @param writer + * The writer to write the XML data to. + * + *
Preconditions:
+ *
  • writer != null + *
  • writer is not closed + *
+ * + * @throws java.io.IOException + * If the data could not be written to the writer. + * + * @see nanoxml.XMLElement#toString() + */ + public void write(Writer writer) + throws IOException + { + if (this.name == null) { + this.writeEncoded(writer, this.contents); + return; + } + writer.write('<'); + writer.write(this.name); + if (! this.attributes.isEmpty()) { + Enumeration enumV = this.attributes.keys(); + while (enumV.hasMoreElements()) { + writer.write(' '); + String key = (String) enumV.nextElement(); + String value = (String) this.attributes.get(key); + writer.write(key); + writer.write('='); writer.write('"'); + this.writeEncoded(writer, value); + writer.write('"'); + } + } + if ((this.contents != null) && (this.contents.length() > 0)) { + writer.write('>'); + this.writeEncoded(writer, this.contents); + writer.write('<'); writer.write('/'); + writer.write(this.name); + writer.write('>'); + } else if (this.children.isEmpty()) { + writer.write('/'); writer.write('>'); + } else { + writer.write('>'); + Enumeration enumV = this.enumerateChildren(); + while (enumV.hasMoreElements()) { + XMLElement child = (XMLElement) enumV.nextElement(); + child.write(writer); + } + writer.write('<'); writer.write('/'); + writer.write(this.name); + writer.write('>'); + } + } + + + /** + * Writes a string encoded to a writer. + * + * @param writer + * The writer to write the XML data to. + * @param str + * The string to write encoded. + * + *
Preconditions:
+ *
  • writer != null + *
  • writer is not closed + *
  • str != null + *
+ */ + protected void writeEncoded(Writer writer, + String str) + throws IOException + { + for (int i = 0; i < str.length(); i += 1) { + char ch = str.charAt(i); + switch (ch) { + case '<': + writer.write('&'); writer.write('l'); writer.write('t'); + writer.write(';'); + break; + case '>': + writer.write('&'); writer.write('g'); writer.write('t'); + writer.write(';'); + break; + case '&': + writer.write('&'); writer.write('a'); writer.write('m'); + writer.write('p'); writer.write(';'); + break; + case '"': + writer.write('&'); writer.write('q'); writer.write('u'); + writer.write('o'); writer.write('t'); writer.write(';'); + break; + case '\'': + writer.write('&'); writer.write('a'); writer.write('p'); + writer.write('o'); writer.write('s'); writer.write(';'); + break; + default: + int unicode = (int) ch; + if ((unicode < 32) || (unicode > 126)) { + writer.write('&'); writer.write('#'); + writer.write('x'); + writer.write(Integer.toString(unicode, 16)); + writer.write(';'); + } else { + writer.write(ch); + } + } + } + } + + + /** + * Scans an identifier from the current reader. + * The scanned identifier is appended to result. + * + * @param result + * The buffer in which the scanned identifier will be put. + * + *
Preconditions:
+ *
  • result != null + *
  • The next character read from the reader is a valid first + * character of an XML identifier. + *
+ * + *
Postconditions:
+ *
  • The next character read from the reader won't be an identifier + * character. + *
+ */ + protected void scanIdentifier(StringBuffer result) + throws IOException + { + for (;;) { + char ch = this.readChar(); + if (((ch < 'A') || (ch > 'Z')) && ((ch < 'a') || (ch > 'z')) + && ((ch < '0') || (ch > '9')) && (ch != '_') && (ch != '.') + && (ch != ':') && (ch != '-') && (ch <= '\u007E')) { + this.unreadChar(ch); + return; + } + result.append(ch); + } + } + + + /** + * This method scans an identifier from the current reader. + * + * @return the next character following the whitespace. + */ + protected char scanWhitespace() + throws IOException + { + for (;;) { + char ch = this.readChar(); + switch (ch) { + case ' ': + case '\t': + case '\n': + case '\r': + break; + default: + return ch; + } + } + } + + + /** + * This method scans an identifier from the current reader. + * The scanned whitespace is appended to result. + * + * @return the next character following the whitespace. + * + *
Preconditions:
+ *
  • result != null + *
+ */ + protected char scanWhitespace(StringBuffer result) + throws IOException + { + for (;;) { + char ch = this.readChar(); + switch (ch) { + case ' ': + case '\t': + case '\n': + result.append(ch); + case '\r': + break; + default: + return ch; + } + } + } + + + /** + * This method scans a delimited string from the current reader. + * The scanned string without delimiters is appended to + * string. + * + *
Preconditions:
+ *
  • string != null + *
  • the next char read is the string delimiter + *
+ */ + protected void scanString(StringBuffer string) + throws IOException + { + char delimiter = this.readChar(); + if ((delimiter != '\'') && (delimiter != '"')) { + throw this.expectedInput("' or \""); + } + for (;;) { + char ch = this.readChar(); + if (ch == delimiter) { + return; + } else if (ch == '&') { + this.resolveEntity(string); + } else { + string.append(ch); + } + } + } + + + /** + * Scans a #PCDATA element. CDATA sections and entities are resolved. + * The next < char is skipped. + * The scanned data is appended to data. + * + *
Preconditions:
+ *
  • data != null + *
+ */ + protected void scanPCData(StringBuffer data) + throws IOException + { + for (;;) { + char ch = this.readChar(); + if (ch == '<') { + ch = this.readChar(); + if (ch == '!') { + this.checkCDATA(data); + } else { + this.unreadChar(ch); + return; + } + } else if (ch == '&') { + this.resolveEntity(data); + } else { + data.append(ch); + } + } + } + + + /** + * Scans a special tag and if the tag is a CDATA section, append its + * content to buf. + * + *
Preconditions:
+ *
  • buf != null + *
  • The first < has already been read. + *
+ */ + protected boolean checkCDATA(StringBuffer buf) + throws IOException + { + char ch = this.readChar(); + if (ch != '[') { + this.unreadChar(ch); + this.skipSpecialTag(0); + return false; + } else if (! this.checkLiteral("CDATA[")) { + this.skipSpecialTag(1); // one [ has already been read + return false; + } else { + int delimiterCharsSkipped = 0; + while (delimiterCharsSkipped < 3) { + ch = this.readChar(); + switch (ch) { + case ']': + if (delimiterCharsSkipped < 2) { + delimiterCharsSkipped += 1; + } else { + buf.append(']'); + buf.append(']'); + delimiterCharsSkipped = 0; + } + break; + case '>': + if (delimiterCharsSkipped < 2) { + for (int i = 0; i < delimiterCharsSkipped; i++) { + buf.append(']'); + } + delimiterCharsSkipped = 0; + buf.append('>'); + } else { + delimiterCharsSkipped = 3; + } + break; + default: + for (int i = 0; i < delimiterCharsSkipped; i += 1) { + buf.append(']'); + } + buf.append(ch); + delimiterCharsSkipped = 0; + } + } + return true; + } + } + + + /** + * Skips a comment. + * + *
Preconditions:
+ *
  • The first <!-- has already been read. + *
+ */ + protected void skipComment() + throws IOException + { + int dashesToRead = 2; + while (dashesToRead > 0) { + char ch = this.readChar(); + if (ch == '-') { + dashesToRead -= 1; + } else { + dashesToRead = 2; + } + } + if (this.readChar() != '>') { + throw this.expectedInput(">"); + } + } + + + /** + * Skips a special tag or comment. + * + * @param bracketLevel The number of open square brackets ([) that have + * already been read. + * + *
Preconditions:
+ *
  • The first <! has already been read. + *
  • bracketLevel >= 0 + *
+ */ + protected void skipSpecialTag(int bracketLevel) + throws IOException + { + int tagLevel = 1; // < + char stringDelimiter = '\0'; + if (bracketLevel == 0) { + char ch = this.readChar(); + if (ch == '[') { + bracketLevel += 1; + } else if (ch == '-') { + ch = this.readChar(); + if (ch == '[') { + bracketLevel += 1; + } else if (ch == ']') { + bracketLevel -= 1; + } else if (ch == '-') { + this.skipComment(); + return; + } + } + } + while (tagLevel > 0) { + char ch = this.readChar(); + if (stringDelimiter == '\0') { + if ((ch == '"') || (ch == '\'')) { + stringDelimiter = ch; + } else if (bracketLevel <= 0) { + if (ch == '<') { + tagLevel += 1; + } else if (ch == '>') { + tagLevel -= 1; + } + } + if (ch == '[') { + bracketLevel += 1; + } else if (ch == ']') { + bracketLevel -= 1; + } + } else { + if (ch == stringDelimiter) { + stringDelimiter = '\0'; + } + } + } + } + + + /** + * Scans the data for literal text. + * Scanning stops when a character does not match or after the complete + * text has been checked, whichever comes first. + * + * @param literal the literal to check. + * + *
Preconditions:
+ *
  • literal != null + *
+ */ + protected boolean checkLiteral(String literal) + throws IOException + { + int length = literal.length(); + for (int i = 0; i < length; i += 1) { + if (this.readChar() != literal.charAt(i)) { + return false; + } + } + return true; + } + + + /** + * Reads a character from a reader. + */ + protected char readChar() + throws IOException + { + if (this.charReadTooMuch != '\0') { + char ch = this.charReadTooMuch; + this.charReadTooMuch = '\0'; + return ch; + } else { + int i = this.reader.read(); + if (i < 0) { + throw this.unexpectedEndOfData(); + } else if (i == 10) { + this.parserLineNr += 1; + return '\n'; + } else { + return (char) i; + } + } + } + + + /** + * Scans an XML element. + * + * @param elt The element that will contain the result. + * + *
Preconditions:
+ *
  • The first < has already been read. + *
  • elt != null + *
+ */ + protected void scanElement(XMLElement elt) + throws IOException + { + StringBuffer buf = new StringBuffer(); + this.scanIdentifier(buf); + String name = buf.toString(); + elt.setName(name); + char ch = this.scanWhitespace(); + while ((ch != '>') && (ch != '/')) { + buf.setLength(0); + this.unreadChar(ch); + this.scanIdentifier(buf); + String key = buf.toString(); + ch = this.scanWhitespace(); + if (ch != '=') { + throw this.expectedInput("="); + } + this.unreadChar(this.scanWhitespace()); + buf.setLength(0); + this.scanString(buf); + elt.setAttribute(key, buf); + ch = this.scanWhitespace(); + } + if (ch == '/') { + ch = this.readChar(); + if (ch != '>') { + throw this.expectedInput(">"); + } + return; + } + buf.setLength(0); + ch = this.scanWhitespace(buf); + if (ch != '<') { + this.unreadChar(ch); + this.scanPCData(buf); + } else { + for (;;) { + ch = this.readChar(); + if (ch == '!') { + if (this.checkCDATA(buf)) { + this.scanPCData(buf); + break; + } else { + ch = this.scanWhitespace(buf); + if (ch != '<') { + this.unreadChar(ch); + this.scanPCData(buf); + break; + } + } + } else { + if ((ch != '/') || this.ignoreWhitespace) { + buf.setLength(0); + } + if (ch == '/') { + this.unreadChar(ch); + } + break; + } + } + } + if (buf.length() == 0) { + while (ch != '/') { + if (ch == '!') { + ch = this.readChar(); + if (ch != '-') { + throw this.expectedInput("Comment or Element"); + } + ch = this.readChar(); + if (ch != '-') { + throw this.expectedInput("Comment or Element"); + } + this.skipComment(); + } else { + this.unreadChar(ch); + XMLElement child = this.createAnotherElement(); + this.scanElement(child); + elt.addChild(child); + } + ch = this.scanWhitespace(); + if (ch != '<') { + throw this.expectedInput("<"); + } + ch = this.readChar(); + } + this.unreadChar(ch); + } else { + if (this.ignoreWhitespace) { + elt.setContent(buf.toString().trim()); + } else { + elt.setContent(buf.toString()); + } + } + ch = this.readChar(); + if (ch != '/') { + throw this.expectedInput("/"); + } + this.unreadChar(this.scanWhitespace()); + if (! this.checkLiteral(name)) { + throw this.expectedInput(name); + } + if (this.scanWhitespace() != '>') { + throw this.expectedInput(">"); + } + } + + + /** + * Resolves an entity. The name of the entity is read from the reader. + * The value of the entity is appended to buf. + * + * @param buf Where to put the entity value. + * + *
Preconditions:
+ *
  • The first & has already been read. + *
  • buf != null + *
+ */ + protected void resolveEntity(StringBuffer buf) + throws IOException + { + char ch = '\0'; + StringBuffer keyBuf = new StringBuffer(); + for (;;) { + ch = this.readChar(); + if (ch == ';') { + break; + } + keyBuf.append(ch); + } + String key = keyBuf.toString(); + if (key.charAt(0) == '#') { + try { + if (key.charAt(1) == 'x') { + ch = (char) Integer.parseInt(key.substring(2), 16); + } else { + ch = (char) Integer.parseInt(key.substring(1), 10); + } + } catch (NumberFormatException e) { + throw this.unknownEntity(key); + } + buf.append(ch); + } else { + char[] value = (char[]) this.entities.get(key); + if (value == null) { + throw this.unknownEntity(key); + } + buf.append(value); + } + } + + + /** + * Pushes a character back to the read-back buffer. + * + * @param ch The character to push back. + * + *
Preconditions:
+ *
  • The read-back buffer is empty. + *
  • ch != '\0' + *
+ */ + protected void unreadChar(char ch) + { + this.charReadTooMuch = ch; + } + + + /** + * Creates a parse exception for when an invalid valueset is given to + * a method. + * + * @param name The name of the entity. + * + *
Preconditions:
+ *
  • name != null + *
+ */ + protected XMLParseException invalidValueSet(String name) + { + String msg = "Invalid value set (entity name = \"" + name + "\")"; + return new XMLParseException(this.getName(), this.parserLineNr, msg); + } + + + /** + * Creates a parse exception for when an invalid value is given to a + * method. + * + * @param name The name of the entity. + * @param value The value of the entity. + * + *
Preconditions:
+ *
  • name != null + *
  • value != null + *
+ */ + protected XMLParseException invalidValue(String name, + String value) + { + String msg = "Attribute \"" + name + "\" does not contain a valid " + + "value (\"" + value + "\")"; + return new XMLParseException(this.getName(), this.parserLineNr, msg); + } + + + /** + * Creates a parse exception for when the end of the data input has been + * reached. + */ + protected XMLParseException unexpectedEndOfData() + { + String msg = "Unexpected end of data reached"; + return new XMLParseException(this.getName(), this.parserLineNr, msg); + } + + + /** + * Creates a parse exception for when a syntax error occured. + * + * @param context The context in which the error occured. + * + *
Preconditions:
+ *
  • context != null + *
  • context.length() > 0 + *
+ */ + protected XMLParseException syntaxError(String context) + { + String msg = "Syntax error while parsing " + context; + return new XMLParseException(this.getName(), this.parserLineNr, msg); + } + + + /** + * Creates a parse exception for when the next character read is not + * the character that was expected. + * + * @param charSet The set of characters (in human readable form) that was + * expected. + * + *
Preconditions:
+ *
  • charSet != null + *
  • charSet.length() > 0 + *
+ */ + protected XMLParseException expectedInput(String charSet) + { + String msg = "Expected: " + charSet; + return new XMLParseException(this.getName(), this.parserLineNr, msg); + } + + + /** + * Creates a parse exception for when an entity could not be resolved. + * + * @param name The name of the entity. + * + *
Preconditions:
+ *
  • name != null + *
  • name.length() > 0 + *
+ */ + protected XMLParseException unknownEntity(String name) + { + String msg = "Unknown or invalid entity: &" + name + ";"; + return new XMLParseException(this.getName(), this.parserLineNr, msg); + } + +} diff -r 29f4f9b451b8 -r 52864f10883d src/share/classes/sun/util/xml/XMLParseException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/util/xml/XMLParseException.java Wed Jun 24 16:38:24 2009 +0200 @@ -0,0 +1,129 @@ +/* XMLParseException.java + * + * $Revision: 1.4 $ + * $Date: 2002/03/24 10:27:59 $ + * $Name: RELEASE_2_2_1 $ + * + * This file is part of NanoXML 2 Lite. + * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved. + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the + * use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source distribution. + *****************************************************************************/ + + + package sun.util.xml; + + +/** + * An XMLParseException is thrown when an error occures while parsing an XML + * string. + *

+ * $Revision: 1.4 $
+ * $Date: 2002/03/24 10:27:59 $

+ * + * @see nanoxml.XMLElement + * + * @author Marc De Scheemaecker + * @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $ + */ +class XMLParseException extends RuntimeException +{ + + /** + * Indicates that no line number has been associated with this exception. + */ + public static final int NO_LINE = -1; + + + /** + * The line number in the source code where the error occurred, or + * NO_LINE if the line number is unknown. + * + *

Invariants:
+ *
  • lineNr > 0 || lineNr == NO_LINE + *
+ */ + private int lineNr; + + + /** + * Creates an exception. + * + * @param name The name of the element where the error is located. + * @param message A message describing what went wrong. + * + *
Preconditions:
+ *
  • message != null + *
+ * + *
Postconditions:
+ *
  • getLineNr() => NO_LINE + *
+ */ + public XMLParseException(String name, + String message) + { + super("XML Parse Exception during parsing of " + + ((name == null) ? "the XML definition" + : ("a " + name + " element")) + + ": " + message); + this.lineNr = XMLParseException.NO_LINE; + } + + + /** + * Creates an exception. + * + * @param name The name of the element where the error is located. + * @param lineNr The number of the line in the input. + * @param message A message describing what went wrong. + * + *
Preconditions:
+ *
  • message != null + *
  • lineNr > 0 + *
+ * + *
Postconditions:
+ *
  • getLineNr() => lineNr + *
+ */ + public XMLParseException(String name, + int lineNr, + String message) + { + super("XML Parse Exception during parsing of " + + ((name == null) ? "the XML definition" + : ("a " + name + " element")) + + " at line " + lineNr + ": " + message); + this.lineNr = lineNr; + } + + + /** + * Where the error occurred, or NO_LINE if the line number is + * unknown. + * + * @see nanoxml.XMLParseException#NO_LINE + */ + public int getLineNr() + { + return this.lineNr; + } + +} diff -r 29f4f9b451b8 -r 52864f10883d test/java/util/Properties/XMLReadAndWriteTest.java --- a/test/java/util/Properties/XMLReadAndWriteTest.java Wed Jun 24 14:53:01 2009 +0200 +++ b/test/java/util/Properties/XMLReadAndWriteTest.java Wed Jun 24 16:38:24 2009 +0200 @@ -3,6 +3,7 @@ * and open the template in the editor. */ +import java.io.ByteArrayInputStream; import sun.util.xml.PropertiesXMLUtils; import java.io.ByteArrayOutputStream; @@ -22,6 +23,7 @@ public static void main(String[] args) throws Exception { XMLReadAndWriteTest test = new XMLReadAndWriteTest(); test.testCompareOutput(); + test.testCompareInput(); } @@ -48,4 +50,34 @@ } } + public void testCompareInput() throws IOException { + String text = "" + + " " + + "\n" + + "my commment on beginging\n" + + "and on the second line" + + "" + + "simple\n" + + " buk" + + " one\n" + + "two\n" + + "three\n" + + "four\n"; + + Properties p1 = new Properties(); + { + ByteArrayInputStream is = new ByteArrayInputStream(text.getBytes("UTF-8")); + FULL.load(p1, is); + } + + Properties p2 = new Properties(); + { + ByteArrayInputStream is = new ByteArrayInputStream(text.getBytes("UTF-8")); + SIMPLE.load(p2, is); + } + + assert p1.equals(p2) : "P1: " + p1 + "\nP2: " + p2; + System.err.println("OK: testCompareInput"); + } + } \ No newline at end of file