All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jidesoft.plaf.aqua.XMLElement Maven / Gradle / Ivy

There is a newer version: 3.6.18
Show newest version
/* 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 com.jidesoft.plaf.aqua;


import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;


/**
 * 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(String) getStringAttribute}. The following example shows how to list the attributes of an * element:
    XMLElement element = ...;
    Iterator iter = element.getAttributeNames();
    while * (iter.hasNext()) {
        String key = (String) iter.next();
        String * value = element.getStringAttribute(key);
        System.out.println(key + " = " + value);
    } *
Retrieving Child Elements
You can enumerate the children of an * element using {@link #iterateChildren() iterateChildren}. The number of child iterator can be retrieved using {@link * #countChildren() countChildren}.
Elements Containing Character Data
If an * iterator 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.
*

* * @author Marc De Scheemaecker <[email protected]> * @version 2005-06-18 Werner Randelshofer: Adapted for Java 2 Collections API.
$Name: RELEASE_2_2_1 $, $Revision: * 1.4 $ * @see XMLParseException */ @SuppressWarnings({"CommentsWithMistakes"}) 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 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 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 keySet().iterator and the values are strings.
*/ private HashMap attributes; /** * Child iterator of the element. *

*

Invariants:
  • The field can be empty.
  • The field is never null. *
  • The iterator are instances of XMLElement or a subclass of XMLElement. *
*/ private ArrayList 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 keySet().iterator 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 keySet().iterator * are strings
  • The values are char arrays
*/ private HashMap 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 HashMap(), false, true)
*

*

Postconditions:
  • countChildren() => 0
  • iterateChildren() => empty enumeration *
  • enumeratePropertyNames() => empty enumeration
  • getChildren() => empty vector
  • getContent() => "" *
  • getLineNr() => 0
  • getName() => null
* * @see XMLElement#XMLElement(java.util.HashMap) XMLElement(HashMap) * @see XMLElement#XMLElement(boolean) * @see XMLElement#XMLElement(java.util.HashMap,boolean) XMLElement(HashMap, boolean) */ public XMLElement() { this(new HashMap(), 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
  • iterateChildren() => * empty enumeration
  • enumeratePropertyNames() => empty enumeration
  • getChildren() => empty * vector
  • getContent() => ""
  • getLineNr() => 0
  • getName() => null
* @see XMLElement#XMLElement() * @see XMLElement#XMLElement(boolean) * @see XMLElement#XMLElement(java.util.HashMap,boolean) XMLElement(HashMap, boolean) */ public XMLElement(HashMap entities) { this(entities, false, true, true); } /** * Creates and initializes a new XML element. Calling the construction is equivalent to:
    new * XMLElement(new HashMap(), skipLeadingWhitespace, true)
* * @param skipLeadingWhitespace true if leading and trailing whitespace in PCDATA content has to be * removed. *

*

Postconditions:
  • countChildren() => 0 *
  • iterateChildren() => empty enumeration
  • enumeratePropertyNames() => empty * enumeration
  • getChildren() => empty vector
  • getContent() => ""
  • getLineNr() * => 0
  • getName() => null
* @see XMLElement#XMLElement() * @see XMLElement#XMLElement(java.util.HashMap) XMLElement(HashMap) * @see XMLElement#XMLElement(java.util.HashMap,boolean) XMLElement(HashMap, boolean) */ public XMLElement(boolean skipLeadingWhitespace) { this(new HashMap(), 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 *
  • iterateChildren() => empty enumeration
  • enumeratePropertyNames() => empty * enumeration
  • getChildren() => empty vector
  • getContent() => ""
  • getLineNr() * => 0
  • getName() => null
* @see XMLElement#XMLElement() * @see XMLElement#XMLElement(boolean) * @see XMLElement#XMLElement(java.util.HashMap) XMLElement(HashMap) */ public XMLElement(HashMap 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 *
  • iterateChildren() => empty enumeration
  • enumeratePropertyNames() => empty * enumeration
  • getChildren() => empty vector
  • getContent() => ""
  • getLineNr() * => 0
  • getName() => null
* @see XMLElement#XMLElement() * @see XMLElement#XMLElement(boolean) * @see XMLElement#XMLElement(java.util.HashMap) XMLElement(HashMap) * @see XMLElement#XMLElement(java.util.HashMap,boolean) XMLElement(HashMap, boolean) */ public XMLElement(HashMap 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 iterator. * * @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 *
  • iterateChildren() => empty enumeration
  • enumeratePropertyNames() => empty * enumeration
  • getChildren() => empty vector
  • getContent() => "" *
  • getLineNr() => 0
  • getName() => null
* @see XMLElement#createAnotherElement() */ protected XMLElement(HashMap entities, boolean skipLeadingWhitespace, boolean fillBasicConversionTable, boolean ignoreCase) { this.ignoreWhitespace = skipLeadingWhitespace; this.ignoreCase = ignoreCase; this.name = null; this.contents = ""; this.attributes = new HashMap(); this.children = new ArrayList(); this.entities = entities; this.lineNr = 0; Iterator iter = this.entities.keySet().iterator(); while (iter.hasNext()) { Object key = iter.next(); 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 *
  • iterateChildren() => old.iterateChildren() + child
  • getChildren() => old.iterateChildren() + * child
* @see XMLElement#countChildren() * @see XMLElement#iterateChildren() * @see XMLElement#getChildren() * @see XMLElement#removeChild(XMLElement) removeChild(XMLElement) */ public void addChild(XMLElement child) { this.children.add(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 XMLElement#setDoubleAttribute(String,double) setDoubleAttribute(String, double) * @see XMLElement#setIntAttribute(String,int) setIntAttribute(String, int) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getAttribute(String) getAttribute(String) * @see XMLElement#getAttribute(String,Object) getAttribute(String, Object) * @see XMLElement#getAttribute(String, java.util.HashMap, String,boolean) getAttribute(String, HashMap, String, * boolean) * @see XMLElement#getStringAttribute(String) getStringAttribute(String) * @see XMLElement#getStringAttribute(String, String) getStringAttribute(String, String) * @see XMLElement#getStringAttribute(String, java.util.HashMap, String,boolean) getStringAttribute(String, HashMap, * 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(String,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 XMLElement#setDoubleAttribute(String,double) setDoubleAttribute(String, double) * @see XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getIntAttribute(String) getIntAttribute(String) * @see XMLElement#getIntAttribute(String,int) getIntAttribute(String, int) * @see XMLElement#getIntAttribute(String, java.util.HashMap, String,boolean) getIntAttribute(String, HashMap, * 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 key The name of the attribute. * @param value The value of the attribute. * @deprecated Use {@link #setIntAttribute(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 XMLElement#setIntAttribute(String,int) setIntAttribute(String, int) * @see XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getDoubleAttribute(String) getDoubleAttribute(String) * @see XMLElement#getDoubleAttribute(String,double) getDoubleAttribute(String, double) * @see XMLElement#getDoubleAttribute(String, java.util.HashMap, String,boolean) getDoubleAttribute(String, HashMap, * 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(String,double) setDoubleAttribute} instead. */ public void addProperty(String name, double value) { this.setDoubleAttribute(name, value); } /** * Returns the number of child iterator of the element. *

*

Postconditions:
  • result >= 0
* * @see XMLElement#addChild(XMLElement) addChild(XMLElement) * @see XMLElement#iterateChildren() * @see XMLElement#getChildren() * @see XMLElement#removeChild(XMLElement) removeChild(XMLElement) */ public int countChildren() { return this.children.size(); } /** * Enumerates the attribute names. *

*

Postconditions:
  • result != null
* * @see XMLElement#setDoubleAttribute(String,double) setDoubleAttribute(String, double) * @see XMLElement#setIntAttribute(String,int) setIntAttribute(String, int) * @see XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see XMLElement#getAttribute(String) getAttribute(String) * @see XMLElement#getAttribute(String,Object) getAttribute(String, String) * @see XMLElement#getAttribute(String, java.util.HashMap, String,boolean) getAttribute(String, HashMap, String, * boolean) * @see XMLElement#getStringAttribute(String) getStringAttribute(String) * @see XMLElement#getStringAttribute(String, String) getStringAttribute(String, String) * @see XMLElement#getStringAttribute(String, java.util.HashMap, String,boolean) getStringAttribute(String, HashMap, * String, boolean) * @see XMLElement#getIntAttribute(String) getIntAttribute(String) * @see XMLElement#getIntAttribute(String,int) getIntAttribute(String, int) * @see XMLElement#getIntAttribute(String, java.util.HashMap, String,boolean) getIntAttribute(String, HashMap, * String, boolean) * @see XMLElement#getDoubleAttribute(String) getDoubleAttribute(String) * @see XMLElement#getDoubleAttribute(String,double) getDoubleAttribute(String, double) * @see XMLElement#getDoubleAttribute(String, java.util.HashMap, String,boolean) getDoubleAttribute(String, HashMap, * String, boolean) * @see XMLElement#getBooleanAttribute(String, String, String,boolean) getBooleanAttribute(String, String, String, * boolean) */ public Iterator enumerateAttributeNames() { return this.attributes.keySet().iterator(); } /** * Enumerates the attribute names. * * @deprecated Use {@link #enumerateAttributeNames() enumerateAttributeNames} instead. */ public Iterator enumeratePropertyNames() { return this.enumerateAttributeNames(); } /** * Enumerates the child iterator. *

*

Postconditions:
  • result != null
* * @see XMLElement#addChild(XMLElement) addChild(XMLElement) * @see XMLElement#countChildren() * @see XMLElement#getChildren() * @see XMLElement#removeChild(XMLElement) removeChild(XMLElement) */ public Iterator iterateChildren() { return this.children.iterator(); } /** * Returns the child iterator as a ArrayList. It is safe to modify this ArrayList. *

*

Postconditions:
  • result != null
* * @see XMLElement#addChild(XMLElement) addChild(XMLElement) * @see XMLElement#countChildren() * @see XMLElement#iterateChildren() * @see XMLElement#removeChild(XMLElement) removeChild(XMLElement) */ public ArrayList getChildren() { try { return (ArrayList) 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 XMLElement#setContent(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 XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getAttribute(String,Object) getAttribute(String, Object) * @see XMLElement#getAttribute(String, java.util.HashMap, String,boolean) getAttribute(String, HashMap, 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 XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getAttribute(String) getAttribute(String) * @see XMLElement#getAttribute(String, java.util.HashMap, String,boolean) getAttribute(String, HashMap, 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 HashMap mapping keySet().iterator 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 * keySet().iterator of valueSet are strings
* @see XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getAttribute(String) getAttribute(String) * @see XMLElement#getAttribute(String,Object) getAttribute(String, Object) */ public Object getAttribute(String name, HashMap 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 XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getStringAttribute(String, String) getStringAttribute(String, String) * @see XMLElement#getStringAttribute(String, java.util.HashMap, String,boolean) getStringAttribute(String, HashMap, * 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 XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getStringAttribute(String) getStringAttribute(String) * @see XMLElement#getStringAttribute(String, java.util.HashMap, String,boolean) getStringAttribute(String, HashMap, * 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 HashMap mapping keySet().iterator 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 * keySet().iterator of valueSet are strings
  • the values of * valueSet are strings
* @see XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getStringAttribute(String) getStringAttribute(String) * @see XMLElement#getStringAttribute(String, String) getStringAttribute(String, String) */ public String getStringAttribute(String name, HashMap 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 XMLElement#setIntAttribute(String,int) setIntAttribute(String, int) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getIntAttribute(String,int) getIntAttribute(String, int) * @see XMLElement#getIntAttribute(String, java.util.HashMap, String,boolean) getIntAttribute(String, HashMap, * 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 XMLElement#setIntAttribute(String,int) setIntAttribute(String, int) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getIntAttribute(String) getIntAttribute(String) * @see XMLElement#getIntAttribute(String, java.util.HashMap, String,boolean) getIntAttribute(String, HashMap, * 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 HashMap mapping keySet().iterator 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 keySet().iterator of valueSet are strings
  • the values of * valueSet are Integer objects
  • defaultKey is either * null, a key in valueSet or an integer.
* @see XMLElement#setIntAttribute(String,int) setIntAttribute(String, int) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getIntAttribute(String) getIntAttribute(String) * @see XMLElement#getIntAttribute(String,int) getIntAttribute(String, int) */ public int getIntAttribute(String name, HashMap 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; } /** * 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 XMLElement#setDoubleAttribute(String,double) setDoubleAttribute(String, double) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getDoubleAttribute(String,double) getDoubleAttribute(String, double) * @see XMLElement#getDoubleAttribute(String, java.util.HashMap, String,boolean) getDoubleAttribute(String, HashMap, * 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 XMLElement#setDoubleAttribute(String,double) setDoubleAttribute(String, double) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getDoubleAttribute(String) getDoubleAttribute(String) * @see XMLElement#getDoubleAttribute(String, java.util.HashMap, String,boolean) getDoubleAttribute(String, HashMap, * 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); } 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 HashMap mapping keySet().iterator 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 keySet().iterator of valueSet are strings
  • the values of * valueSet are Double objects
  • defaultKey is either * null, a key in valueSet or a double.
* @see XMLElement#setDoubleAttribute(String,double) setDoubleAttribute(String, double) * @see XMLElement#enumerateAttributeNames() * @see XMLElement#getDoubleAttribute(String) getDoubleAttribute(String) * @see XMLElement#getDoubleAttribute(String,double) getDoubleAttribute(String, double) */ public double getDoubleAttribute(String name, HashMap 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; } /** * 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 XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#removeAttribute(String) removeAttribute(String) * @see 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.HashMap,java.lang.String,boolean) * getIntAttribute} instead. */ public int getIntProperty(String name, HashMap 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.HashMap,java.lang.String,boolean) getAttribute} * instead. */ public Object getProperty(String name, HashMap 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.HashMap,java.lang.String,boolean) * getStringAttribute} instead. */ public String getStringProperty(String name, HashMap 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.HashMap,java.lang.String,boolean) * getIntAttribute} instead. */ public int getSpecialIntProperty(String name, HashMap 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.HashMap,java.lang.String,boolean) * getDoubleAttribute} instead. */ public double getSpecialDoubleProperty(String name, HashMap valueSet, String defaultKey) { return this.getDoubleAttribute(name, valueSet, defaultKey, true); } /** * Returns the name of the element. * * @see 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 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 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 HashMap(); this.children = new ArrayList(); 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 string 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 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 string 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 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 string 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 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 string 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 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 input 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 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 input 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 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 *
  • iterateChildren() => old.iterateChildren() - child
  • getChildren() => old.iterateChildren() - * child
* @see XMLElement#addChild(XMLElement) addChild(XMLElement) * @see XMLElement#countChildren() * @see XMLElement#iterateChildren() * @see XMLElement#getChildren() */ public void removeChild(XMLElement child) { this.children.remove(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 XMLElement#enumerateAttributeNames() * @see XMLElement#setDoubleAttribute(String,double) setDoubleAttribute(String, double) * @see XMLElement#setIntAttribute(String,int) setIntAttribute(String, int) * @see XMLElement#setAttribute(String,Object) setAttribute(String, Object) * @see XMLElement#getAttribute(String) getAttribute(String) * @see XMLElement#getAttribute(String,Object) getAttribute(String, Object) * @see XMLElement#getAttribute(String, java.util.HashMap, String,boolean) getAttribute(String, HashMap, String, * boolean) * @see XMLElement#getStringAttribute(String) getStringAttribute(String) * @see XMLElement#getStringAttribute(String, String) getStringAttribute(String, String) * @see XMLElement#getStringAttribute(String, java.util.HashMap, String,boolean) getStringAttribute(String, HashMap, * String, boolean) * @see XMLElement#getIntAttribute(String) getIntAttribute(String) * @see XMLElement#getIntAttribute(String,int) getIntAttribute(String, int) * @see XMLElement#getIntAttribute(String, java.util.HashMap, String,boolean) getIntAttribute(String, HashMap, * String, boolean) * @see XMLElement#getDoubleAttribute(String) getDoubleAttribute(String) * @see XMLElement#getDoubleAttribute(String,double) getDoubleAttribute(String, double) * @see XMLElement#getDoubleAttribute(String, java.util.HashMap, String,boolean) getDoubleAttribute(String, HashMap, * String, boolean) * @see XMLElement#getBooleanAttribute(String, String, 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(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(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. */ public 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(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 XMLElement#getName() */ public void setName(String name) { this.name = name; } /** * Writes the XML element to a string. * * @see XMLElement#write(java.io.Writer) write(Writer) */ @Override 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 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()) { Iterator iter = this.attributes.keySet().iterator(); while (iter.hasNext()) { writer.write(' '); String key = (String) iter.next(); 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('>'); Iterator iter = this.iterateChildren(); while (iter.hasNext()) { XMLElement child = (XMLElement) iter.next(); 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); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy