/*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.ukit.dom;
import org.w3c.dom.Node;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.UserDataHandler;
import org.w3c.dom.DOMException;
import java.util.Hashtable;
import java.util.Enumeration;
/**
* Base DOM node functionality implementation.
*
* @see org.w3c.dom.Node
*/
public abstract class XBase
implements Node, NodeList
{
/** XML namespace URI. */
public final static String URI_XML = "http://www.w3.org/XML/1998/namespace";
/** XML namespace definition namespace URI. */
public final static String URI_XMLNS = "http://www.w3.org/2000/xmlns/";
/** Owner document */
private XDoc owner;
/** Parent node */
private XParent parent;
/** Qualified name. */
private String qname;
/** Local name. */
private String lname;
/** Namespace URI. */
private String nsuri;
/** User data. */
private Hashtable usrdat;
/**
* XML name character type array.
* This array maps an ASCII (7 bit) character to the character type.<br />
* Defined character types are:<br />
* - 0 for underscore ('_') or any lower and upper case alphabetical character value;<br />
* - 1 for colon (':') character;<br />
* - 2 for dash ('-') and dot ('.') or any decimal digit character value;<br />
* - 3 for any kind of white space character<br />
* An ASCII (7 bit) character which does not fall in any category listed
* above is mapped to 0xff.
*/
private static final byte chtyp[];
/**
* Static constructor.
*
* Sets up the XML name character type array which is used by
* {@link #_chekName _chekName} method.
*/
static {
short i = 0;
chtyp = new byte[0x80];
for (i = 0; i < '0'; i++)
chtyp[i] = (byte)0xff;
while (i <= '9')
chtyp[i++] = (byte)2; // digits
while (i < 'A')
chtyp[i++] = (byte)0xff;
// skipped upper case alphabetical character are already 0
for (i = '['; i < 'a'; i++)
chtyp[i] = (byte)0xff;
// skipped lower case alphabetical character are already 0
for (i = '{'; i < 0x80; i++)
chtyp[i] = (byte)0xff;
chtyp['_'] = 0;
chtyp[':'] = 1;
chtyp['.'] = 2;
chtyp['-'] = 2;
chtyp[' '] = 3;
chtyp['\t'] = 3;
chtyp['\r'] = 3;
chtyp['\n'] = 3;
}
/**
* Constructs node object from its owner document.
*/
protected XBase(XDoc ownerDocument)
{
owner = (XDoc)ownerDocument;
}
/**
* Constructs node object from other node.
*/
protected XBase(XNode node, boolean deep)
{
owner = ((XBase)node).owner;
qname = ((XBase)node).qname;
lname = ((XBase)node).lname;
nsuri = ((XBase)node).nsuri;
}
/**
* Constructs node object from its qualified name and namespace URI and
* its owner document.
*/
protected XBase(String namespaceURI, String qName, XDoc ownerDocument)
{
owner = (XDoc)ownerDocument;
qname = (owner != null)? owner._intern(qName): qName;
if (namespaceURI != null && qname.charAt(0) != '#') {
nsuri = owner._intern(namespaceURI);
lname = owner._intern(XNode._getLocalName(qname));
} else {
nsuri = null;
lname = null;
}
}
/**
* A code representing the type of the underlying object, as defined above.
*/
public abstract short getNodeType();
/**
* The namespace URI of this node, or <code>null</code> if it is
* unspecified.
* <br>This is not a computed value that is the result of a namespace
* lookup based on an examination of the namespace declarations in
* scope. It is merely the namespace URI given at creation time.
* <br>For nodes of any type other than <code>ELEMENT_NODE</code> and
* <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1
* method, such as <code>createElement</code> from the
* <code>Document</code> interface, this is always <code>null</code>.Per
* the Namespaces in XML Specification an attribute does not inherit
* its namespace from the element it is attached to. If an attribute is
* not explicitly given a namespace, it simply has no namespace.
*
* @since DOM Level 2
*/
public String getNamespaceURI()
{
return (nsuri != null && nsuri.length() == 0)? null: nsuri;
}
/**
* The namespace prefix of this node, or <code>null</code> if it is
* unspecified. When it is defined to be <code>null</code>, setting it
* has no effect, including if the node is read-only.
* <br>Note that setting this attribute, when permitted, changes the
* <code>nodeName</code> attribute, which holds the qualified name, as
* well as the <code>tagName</code> and <code>name</code> attributes of
* the <code>Element</code> and <code>Attr</code> interfaces, when
* applicable.
* <br>Setting the prefix to <code>null</code> makes it unspecified,
* setting it to an empty string is implementation dependent.
* <br>Note also that changing the prefix of an attribute that is known to
* have a default value, does not make a new attribute with the default
* value and the original prefix appear, since the
* <code>namespaceURI</code> and <code>localName</code> do not change.
* <br>For nodes of any type other than <code>ELEMENT_NODE</code> and
* <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1
* method, such as <code>createElement</code> from the
* <code>Document</code> interface, this is always <code>null</code>.
* @return The namespace prefix of this node, or <code>null</code>
*
* @since DOM Level 2
*/
public String getPrefix()
{
return (nsuri != null && qname.length() != lname.length())?
qname.substring(0, qname.length() - lname.length() - 1): null;
}
/**
* Sets the namespace prefix of this node.
* <br>Note that setting this attribute, when permitted, changes the
* <code>nodeName</code> attribute, which holds the qualified name, as
* well as the <code>tagName</code> and <code>name</code> attributes of
* the <code>Element</code> and <code>Attr</code> interfaces, when
* applicable.
* <br>Note also that changing the prefix of an attribute that is known to
* have a default value, does not make a new attribute with the default
* value and the original prefix appear, since the
* <code>namespaceURI</code> and <code>localName</code> do not change.
*
* @param prefix This node namespace prefix.
* @exception DOMException
* INVALID_CHARACTER_ERR: Raised if the specified prefix contains an
* illegal character.
* <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
* <br>NAMESPACE_ERR: Raised if the specified <code>prefix</code> is
* malformed, if the <code>namespaceURI</code> of this node is
* <code>null</code>, if the specified prefix is "xml" and the
* <code>namespaceURI</code> of this node is different from "
* http://www.w3.org/XML/1998/namespace", if this node is an attribute
* and the specified prefix is "xmlns" and the
* <code>namespaceURI</code> of this node is different from "
* http://www.w3.org/2000/xmlns/", or if this node is an attribute and
* the <code>qualifiedName</code> of this node is "xmlns" .
*
* @since DOM Level 2
*/
public void setPrefix(String prefix)
throws DOMException
{
// This method is implemented on Element and Attr only.
return;
}
/**
* Returns the local part of the qualified name of this node.
* <br>For nodes of any type other than <code>ELEMENT_NODE</code> and
* <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1
* method, such as <code>createElement</code> from the
* <code>Document</code> interface, this is always <code>null</code>.
*
* @since DOM Level 2
*/
public String getLocalName()
{
return (nsuri != null)? lname: null;
}
/**
* The name of this node, depending on its type; see the table above.
*/
public String getNodeName()
{
return qname;
}
/**
* The value of this node, depending on its type.
* When it is defined to be <code>null</code>, setting it has no effect.
*
* @exception DOMException
* NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
* @exception DOMException
* DOMSTRING_SIZE_ERR: Raised when it would return more characters than
* fit in a <code>DOMString</code> variable on the implementation
* platform.
*/
public String getNodeValue()
throws DOMException
{
return null;
}
/**
* The value of this node, depending on its type.
* When it is defined to be <code>null</code>, setting it has no effect.
*
* @exception DOMException
* NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
* @exception DOMException
* DOMSTRING_SIZE_ERR: Raised when it would return more characters than
* fit in a <code>DOMString</code> variable on the implementation
* platform.
*/
public void setNodeValue(String nodeValue)
throws DOMException
{
}
/**
* The parent of this node. All nodes, except <code>Attr</code>,
* <code>Document</code>, <code>DocumentFragment</code>,
* <code>Entity</code>, and <code>Notation</code> may have a parent.
* However, if a node has just been created and not yet added to the
* tree, or if it has been removed from the tree, this is
* <code>null</code>.
*/
public Node getParentNode()
{
return parent;
}
/**
* A <code>NodeList</code> that contains all children of this node. If
* there are no children, this is a <code>NodeList</code> containing no
* nodes.
*/
public NodeList getChildNodes()
{
return this;
}
/**
* The first child of this node. If there is no such node, this returns
* <code>null</code>.
*/
public Node getFirstChild()
{
return null;
}
/**
* The last child of this node. If there is no such node, this returns
* <code>null</code>.
*/
public Node getLastChild()
{
return null;
}
/**
* The node immediately preceding this node. If there is no such node,
* this returns <code>null</code>.
*/
public Node getPreviousSibling()
{
return (parent != null)?
parent.item(parent._childIdx(this) - 1): null;
}
/**
* The node immediately following this node. If there is no such node,
* this returns <code>null</code>.
*/
public Node getNextSibling()
{
return (parent != null)?
parent.item(parent._childIdx(this) + 1): null;
}
/**
* A <code>NamedNodeMap</code> containing the attributes of this node (if
* it is an <code>Element</code>) or <code>null</code> otherwise.
*/
public NamedNodeMap getAttributes()
{
return null;
}
/**
* The <code>Document</code> object associated with this node. This is
* also the <code>Document</code> object used to create new nodes. When
* this node is a <code>Document</code> or a <code>DocumentType</code>
* which is not used with any <code>Document</code> yet, this is
* <code>null</code>.
*
* @since DOM Level 2
*/
public Document getOwnerDocument()
{
return owner;
}
/**
* Inserts the node <code>newChild</code> before the existing child node
* <code>refChild</code>. If <code>refChild</code> is <code>null</code>,
* insert <code>newChild</code> at the end of the list of children.
* <br>If <code>newChild</code> is a <code>DocumentFragment</code> object,
* all of its children are inserted, in the same order, before
* <code>refChild</code>. If the <code>newChild</code> is already in the
* tree, it is first removed.
*
* @param newChild The node to insert.
* @param refChild The reference node, i.e., the node before which the new
* node must be inserted.
* @return The node being inserted.
* @exception DOMException
* HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not
* allow children of the type of the <code>newChild</code> node, or if
* the node to insert is one of this node's ancestors.
* <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created
* from a different document than the one that created this node.
* <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or
* if the parent of the node being inserted is readonly.
* <br>NOT_FOUND_ERR: Raised if <code>refChild</code> is not a child of
* this node.
*/
public Node insertBefore(Node newChild, Node refChild)
throws DOMException
{
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "");
}
/**
* Replaces the child node <code>oldChild</code> with <code>newChild</code>
* in the list of children, and returns the <code>oldChild</code> node.
* <br>If <code>newChild</code> is a <code>DocumentFragment</code> object,
* <code>oldChild</code> is replaced by all of the
* <code>DocumentFragment</code> children, which are inserted in the
* same order. If the <code>newChild</code> is already in the tree, it
* is first removed.
*
* @param newChild The new node to put in the child list.
* @param oldChild The node being replaced in the list.
* @return The node replaced.
* @exception DOMException
* HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not
* allow children of the type of the <code>newChild</code> node, or if
* the node to put in is one of this node's ancestors.
* <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created
* from a different document than the one that created this node.
* <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node or the parent of
* the new node is readonly.
* <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of
* this node.
*/
public Node replaceChild(Node newChild, Node oldChild)
throws DOMException
{
throw new DOMException(DOMException.NOT_FOUND_ERR, "");
}
/**
* Removes the child node indicated by <code>oldChild</code> from the list
* of children, and returns it.
*
* @param oldChild The node being removed.
* @return The node removed.
* @exception DOMException
* NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
* <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of
* this node.
*/
public Node removeChild(Node oldChild)
throws DOMException
{
throw new DOMException(DOMException.NOT_FOUND_ERR, "");
}
/**
* Adds the node <code>newChild</code> to the end of the list of children
* of this node. If the <code>newChild</code> is already in the tree, it
* is first removed.
*
* @param newChild The node to add.If it is a <code>DocumentFragment</code>
* object, the entire contents of the document fragment are moved
* into the child list of this node
* @return The node added.
* @exception DOMException
* HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not
* allow children of the type of the <code>newChild</code> node, or if
* the node to append is one of this node's ancestors.
* <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created
* from a different document than the one that created this node.
* <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
*/
public Node appendChild(Node newChild)
throws DOMException
{
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "");
}
/**
* Returns whether this node has any children.
*
* @return <code>true</code> if this node has any children,
* <code>false</code> otherwise.
*/
public boolean hasChildNodes()
{
return false;
}
/**
* Returns a duplicate of this node, i.e., serves as a generic copy
* constructor for nodes. The duplicate node has no parent; (
* <code>parentNode</code> is <code>null</code>.).
* <br>Cloning an <code>Element</code> copies all attributes and their
* values, including those generated by the XML processor to represent
* defaulted attributes, but this method does not copy any text it
* contains unless it is a deep clone, since the text is contained in a
* child <code>Text</code> node. Cloning an <code>Attribute</code>
* directly, as opposed to be cloned as part of an <code>Element</code>
* cloning operation, returns a specified attribute (
* <code>specified</code> is <code>true</code>). Cloning any other type
* of node simply returns a copy of this node.
* <br>Note that cloning an immutable subtree results in a mutable copy,
* but the children of an <code>EntityReference</code> clone are readonly
* . In addition, clones of unspecified <code>Attr</code> nodes are
* specified. And, cloning <code>Document</code>,
* <code>DocumentType</code>, <code>Entity</code>, and
* <code>Notation</code> nodes is implementation dependent.
*
* @param deep If <code>true</code>, recursively clone the subtree under
* the specified node; if <code>false</code>, clone only the node
* itself (and its attributes, if it is an <code>Element</code>).
* @return The duplicate node.
*/
public Node cloneNode(boolean deep)
{
XNode node = owner._clone(this, deep);
_notifyUDH(UserDataHandler.NODE_CLONED, node);
return node;
}
/**
* Puts all <code>Text</code> nodes in the full depth of the sub-tree
* underneath this <code>Node</code>, including attribute nodes, into a
* "normal" form where only structure (e.g., elements, comments,
* processing instructions, CDATA sections, and entity references)
* separates <code>Text</code> nodes, i.e., there are neither adjacent
* <code>Text</code> nodes nor empty <code>Text</code> nodes. This can
* be used to ensure that the DOM view of a document is the same as if
* it were saved and re-loaded, and is useful when operations (such as
* XPointer lookups) that depend on a particular document tree
* structure are to be used.In cases where the document contains
* <code>CDATASections</code>, the normalize operation alone may not be
* sufficient, since XPointers do not differentiate between
* <code>Text</code> nodes and <code>CDATASection</code> nodes.
*
* @since DOM Level 2
*/
public void normalize()
{
}
/**
* Tests whether the DOM implementation implements a specific feature and
* that feature is supported by this node.
*
* @param feature The name of the feature to test. This is the same name
* which can be passed to the method <code>hasFeature</code> on
* <code>DOMImplementation</code>.
* @param version This is the version number of the feature to test. In
* Level 2, version 1, this is the string "2.0". If the version is not
* specified, supporting any version of the feature will cause the
* method to return <code>true</code>.
* @return Returns <code>true</code> if the specified feature is
* supported on this node, <code>false</code> otherwise.
*
* @since DOM Level 2
*/
public boolean isSupported(String feature, String version)
{
return _getDoc()._isSupported(feature, version);
}
/**
* Returns whether this node (if it is an element) has any attributes.
*
* @return <code>true</code> if this node has any attributes,
* <code>false</code> otherwise.
*
* @since DOM Level 2
*/
public boolean hasAttributes()
{
return false;
}
/**
* This attribute returns the text content of this node and its
* descendants. When it is defined to be <code>null</code>, setting it
* has no effect.
* <br> On getting, no serialization is performed, the returned string
* does not contain any markup. No whitespace normalization is performed
* and the returned string does not contain the white spaces in element
* content.
* <br>The string returned is made of the text content of this node
* depending on its type, as defined below:
* <table border='1' cellpadding='3'>
* <tr>
* <th>Node type</th>
* <th>Content</th>
* </tr>
* <tr>
* <td valign='top' rowspan='1' colspan='1'>
* ELEMENT_NODE, ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
* DOCUMENT_FRAGMENT_NODE</td>
* <td valign='top' rowspan='1' colspan='1'>concatenation of the <code>textContent</code>
* attribute value of every child node, excluding COMMENT_NODE and
* PROCESSING_INSTRUCTION_NODE nodes. This is the empty string if the
* node has no children.</td>
* </tr>
* <tr>
* <td valign='top' rowspan='1' colspan='1'>TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE,
* PROCESSING_INSTRUCTION_NODE</td>
* <td valign='top' rowspan='1' colspan='1'><code>nodeValue</code></td>
* </tr>
* <tr>
* <td valign='top' rowspan='1' colspan='1'>DOCUMENT_NODE,
* DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
* <td valign='top' rowspan='1' colspan='1'><em>null</em></td>
* </tr>
* </table>
*
* @exception DOMException
* DOMSTRING_SIZE_ERR: Raised when it would return more characters than
* fit in a <code>DOMString</code> variable on the implementation
* platform.
*
* @since DOM Level 3
*/
public String getTextContent()
throws DOMException
{
switch(getNodeType()) {
case TEXT_NODE:
case CDATA_SECTION_NODE:
case COMMENT_NODE:
case PROCESSING_INSTRUCTION_NODE:
case ATTRIBUTE_NODE:
return getNodeValue();
case DOCUMENT_NODE:
case DOCUMENT_TYPE_NODE:
case NOTATION_NODE:
break;
default:
}
return null;
}
/**
* On setting, any possible children this node may have
* are removed and, if it the new string is not empty or
* <code>null</code>, replaced by a single <code>Text</code> node
* containing the string this attribute is set to.
* <br>No parsing is performed, the input string is taken as pure
* textual content.
*
* @exception DOMException
* NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
*
* @since DOM Level 3
*/
public void setTextContent(String textContent)
throws DOMException
{
switch(getNodeType()) {
case TEXT_NODE:
case CDATA_SECTION_NODE:
case COMMENT_NODE:
case PROCESSING_INSTRUCTION_NODE:
case ATTRIBUTE_NODE:
if (_isRO())
throw new DOMException(
DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
setNodeValue((textContent != null)? textContent: "");
break;
case DOCUMENT_NODE:
case DOCUMENT_TYPE_NODE:
case NOTATION_NODE:
break;
default:
}
}
/**
* This method returns a specialized object which implements the
* specialized APIs of the specified feature and version, as specified
* in . The specialized object may also be obtained by using
* binding-specific casting methods but is not necessarily expected to,
* as discussed in <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#Embedded-DOM">
* Mixed DOM Implementations</a>. This method also allow the implementation
* to provide specialized objects which do not support the <code>Node</code>
* interface.
*
* @param feature The name of the feature requested. Note that any plus
* sign "+" prepended to the name of the feature will be ignored since
* it is not significant in the context of this method.
* @param version This is the version number of the feature to test.
* @return Returns an object which implements the specialized APIs of
* the specified feature and version, if any, or <code>null</code> if
* there is no object which implements interfaces associated with that
* feature. If the <code>DOMObject</code> returned by this method
* implements the <code>Node</code> interface, it must delegate to the
* primary core <code>Node</code> and not return results inconsistent
* with the primary core <code>Node</code> such as attributes,
* childNodes, etc.
*
* @since DOM Level 3
*/
public Object getFeature(String feature, String version)
{
return (_getDoc()._isSupported(feature, version))? this: null;
}
/**
* Associate an object to a key on this node. The object can later be
* retrieved from this node by calling <code>getUserData</code> with the
* same key.
*
* @param key The key to associate the object to.
* @param data The object to associate to the given key, or
* <code>null</code> to remove any existing association to that key.
* @param handler The handler to associate to that key, or
* <code>null</code>.
* @return Returns the <code>DOMUserData</code> previously associated to
* the given key on this node, or <code>null</code> if there was none.
*
* @since DOM Level 3
*/
public final Object setUserData(
String key, Object data, UserDataHandler handler)
{
Object[] olddat = null;
if (data == null && usrdat == null)
return null;
if (usrdat != null)
olddat = (Object[])usrdat.get(key);
else
usrdat = new Hashtable(4);
if (data != null) {
Object[] kdh = new Object[3];
kdh[0] = key;
kdh[1] = data;
kdh[2] = handler;
usrdat.put(key, kdh);
} else {
usrdat.remove(key);
}
return (olddat != null)? olddat[1]: null;
}
/**
* Retrieves the object associated to a key on a this node. The object
* must first have been set to this node by calling
* <code>setUserData</code> with the same key.
*
* @param key The key the object is associated to.
* @return Returns the <code>DOMUserData</code> associated to the given
* key on this node, or <code>null</code> if there was none.
*
* @since DOM Level 3
*/
public final Object getUserData(String key)
{
if (usrdat == null)
return null;
Object[] pair = (Object[])usrdat.get(key);
return (pair != null)? pair[1]: null;
}
/**
* Returns the <code>index</code>th item in the collection. If
* <code>index</code> is greater than or equal to the number of nodes in
* the list, this returns <code>null</code>.
*
* @param index Index into the collection.
* @return The node at the <code>index</code>th position in the
* <code>NodeList</code>, or <code>null</code> if that is not a valid
* index.
*/
public Node item(int index)
{
return null;
}
/**
* The number of nodes in the list. The range of valid child node indices
* is 0 to <code>length - 1</code> inclusive.
*/
public int getLength()
{
return 0;
}
/**
* Sets node's name attributes.
*/
protected final void _set(
String namespaceURI, String qName, String localName)
{
nsuri = namespaceURI;
qname = qName;
lname = localName;
}
/**
* Sets node's name prefix.
*/
protected final void _setPrefix(String prefix)
throws DOMException
{
if (_isRO())
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
String name = (prefix != null)? (prefix + ':' + lname): lname;
XBase._checkNameNS(nsuri, name);
qname = owner._intern(name);
}
/**
* Sets node's value attributes.
*/
protected void _setValue(String value)
{
}
/**
* Updates node's value attributes.
*/
protected void _updateValue(String value)
{
}
/**
* Cleans up node.
*/
protected void _clear()
{
_set(null, null, null);
}
/**
* Retrieves node's parent node. Note, for an attribute node this method
* retrieves element owner.
*/
protected final XParent _getParent()
{
return parent;
}
/**
* Sets node's parent node.
*/
protected void _setParent(XParent parentNode)
{
parent = parentNode;
}
/**
* Retrieves node's owner document.
*/
protected final XDoc _getDoc()
{
return (getNodeType() != DOCUMENT_NODE)? owner: (XDoc)this;
}
/**
* Sets node's owner document.
*
* @param ownerDoc New owner document.
*/
protected void _setDoc(XDoc ownerDoc)
{
if (owner == ownerDoc)
return;
if (getNodeType() != DOCUMENT_NODE)
owner = ownerDoc;
if (owner != null) {
qname = owner._intern(qname);
nsuri = owner._intern(nsuri);
lname = owner._intern(lname);
}
}
/**
* Return true if node or one of its parents is read only.
*/
protected boolean _isRO()
{
return (parent != null)? parent._isRO(): false;
}
/**
* Return true if node created by namespace-aware methods.
*/
protected final boolean _isNS()
{
return (nsuri != null);
}
/**
* Returns <code>true</code> if node is one of ancestors of this node.
*/
protected final boolean _isAncestor(Node node)
{
if (parent == null)
return false;
if (parent == node)
return true;
return parent._isAncestor(node);
}
/**
* Notifies all user data handlers on this node.
*/
protected void _notifyUDH(short action, XNode node)
{
if (usrdat == null)
return;
Enumeration elms = usrdat.elements();
while (elms.hasMoreElements()) {
Object[] data = (Object[])elms.nextElement();
UserDataHandler udh = (UserDataHandler)data[2];
if (udh != null)
udh.handle(action, (String)data[0], data[1], this, node);
}
}
/**
* Lets filter to process each child node.
*/
protected void _procEachChild(XList filter)
{
filter._proc((XNode)this);
}
/**
* Appends textual content of the node to the buffer.
*/
protected void _appendText(StringBuffer buffer)
{
switch(getNodeType()) {
case TEXT_NODE:
case CDATA_SECTION_NODE:
buffer.append(getNodeValue());
break;
case COMMENT_NODE:
case PROCESSING_INSTRUCTION_NODE:
default:
}
}
/**
* Checks qualified name.
*
* @param qName The XML name to check.
* @param ns The true value turns namespace conformance on.
* @return an index to colon (prefix separator) or -1
*
* @exception DOMException
* INVALID_CHARACTER_ERR: Raised when qName is invalid XML name or
* an empty string.
* @exception NullPointerException Raised when qName is <code>null</code>.
*/
protected final static int _checkName(String qName, boolean ns)
throws DOMException
{
char ch;
char type;
int colon = -1;
int st = (ns == true)? 0: 2;
int idx = 0;
chloop: while (idx < qName.length()) {
// Read next character
ch = qName.charAt(idx++);
type = (char)0; // any char above 0x7f
if (ch < 0x80)
type = (char)chtyp[ch];
// Parse QName
switch (st) {
case 0: // read the first char of the prefix
case 2: // read the first char of the suffix
switch (type) {
case 0: // [aA_X]
st++; // (st == 0)? 1: 3;
break;
case 1: // [:]
if (st == 2) { // read the first char of the suffix
idx--;
st = 3; // read the suffix
break;
}
default:
idx = -1;
break chloop; // invalid character
}
break;
case 1: // read the prefix
case 3: // read the suffix
switch (type) {
case 0: // [aA_X]
case 2: // [.-d]
break;
case 1: // [:]
if (ns == true) {
// It must be only one colon and it may not be
// the last character of qName
if ((colon >= 0) || (idx >= qName.length()))
throw new DOMException(
DOMException.NAMESPACE_ERR, qName);
colon = idx - 1;
if (st == 1)
st = 2;
}
break;
default:
idx = -1;
break chloop; // invalid character
}
break;
default:
idx = -1;
break chloop; // invalid character
}
}
if (idx <= 0)
throw new DOMException(DOMException.INVALID_CHARACTER_ERR, qName);
return colon;
}
/**
* Checks qualified name and namespace URI.
*/
protected final static int _checkNameNS(String uri, String qName)
throws DOMException
{
int idx = XBase._checkName(qName, true);
// There is a prefix but there is no NS URI
if (idx >= 0 && (uri == null || (uri != null && uri.length() == 0)))
throw new DOMException(DOMException.NAMESPACE_ERR, "");
// Identify 'xml' and 'xmlns' prefixes
int xmlns = 0;
if (qName.charAt(0) == 'x' &&
qName.charAt(1) == 'm' &&
qName.charAt(2) == 'l') {
xmlns = (idx == 3)? 1: 0; // 'xml'
if (qName.charAt(3) == 'n' &&
qName.charAt(4) == 's') {
if (idx == 5 || qName.length() == 5)
xmlns = 2; // 'xmlns' prefix or qName
}
}
// There is 'xml' prefix and namespace URI is not URI_XML
if (xmlns == 1 && uri != null && !uri.equals(URI_XML))
throw new DOMException(DOMException.NAMESPACE_ERR, URI_XML);
if (URI_XMLNS.equals(uri) == true) {
// NS URI is URI_XMLNS but qName or prefix is not 'xmlns'
if (xmlns != 2)
throw new DOMException(DOMException.NAMESPACE_ERR, URI_XMLNS);
} else {
// There is 'xmlns' qName or prefix and NS URI is not URI_XMLNS
if (xmlns == 2)
throw new DOMException(DOMException.NAMESPACE_ERR, URI_XMLNS);
}
return idx;
}
/**
* Returns local name substring of qualified name string.
*/
protected final static String _getLocalName(String qName)
{
int idx = qName.indexOf(':');
return (idx >= 0)? qName.substring(idx + 1): qName;
}
}