blob: a1d0307f838273c34007c588c49e63681d49563a [file] [log] [blame]
/*
* $Id$
*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Crimson" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Sun Microsystems, Inc.,
* http://www.sun.com. For more information on the Apache Software
* Foundation, please see <http://www.apache.org/>.
*/
package org.apache.xerces.tree;
import java.io.Writer;
import java.io.IOException;
import java.util.Locale;
import org.w3c.dom.*;
/**
* Base class for DOM parse tree nodes which may appear in XmlDocument nodes.
* This implements "parented by" and "owning document" relationships. If
* the parent is not null, this also supports sibling relationships through
* that parent. Children may be directly accessed through this class,
* although it is subclasses which implement that access.
*
* @author David Brownell
* @version $Revision$
*/
// not public ... javadoc looks a bit odd (hidden base class)
// but it's only subclassable within this package anyway
abstract class NodeBase
implements Node, NodeEx, NodeList, XmlWritable
{
private ParentNode parent;
private int parentIndex = -1; // cache
// package private for speed ...
XmlDocument ownerDocument;
boolean readonly;
/**
* Constructs a node which will later have its parent set
* by some other member of this package.
*/
// package private
NodeBase () { }
/* Returns the node's parent; typesafe convenience rtn. */
// package private ...
ParentNode getParentImpl () { return parent; }
/* not public yet ... */
// package private
public boolean isReadonly ()
{ return readonly; }
/* not public yet ... */
// package private
public void setReadonly (boolean deep)
{
readonly = true;
if (deep) {
TreeWalker walker = new TreeWalker (this);
Node next;
while ((next = walker.getNext ()) != null)
((NodeBase)next).setReadonly (false);
}
}
/**
* Returns the language id (value of <code>xml:lang</code>
* attribute) applicable to this node, if known. Traces up
* through ancestors as needed.
*/
public String getLanguage () {
return getInheritedAttribute ("xml:lang");
}
/**
* Returns the value of a given attribute, tracing up through
* ancestors if needed. In the XML standard, two attributes are
* inherited: <em>xml:lang</em> and <em>xml:space</em>. This
* mechanism can also be involved with Cascading Style Sheets (CSS).
* The current version of XML Namespaces also uses inheritance.
*
* @param name identifies the attribute; colons may be included,
* but namespace prefixes are not interpreted
* @return the value of the inherited attribute, or null if
* no value was inherited.
*/
public String getInheritedAttribute (String name)
{
NodeBase current = this;
Attr value = null;
do {
if (current instanceof ElementNode) {
ElementNode e = (ElementNode) current;
if ((value = e.getAttributeNode (name)) != null)
break;
}
current = current.getParentImpl ();
} while (current != null);
if (value != null)
return value.getValue ();
return null;
}
/**
* Returns the value of a given attribute, tracing up through
* ancestors if needed. This version accounts for namespaces,
* so that the prefix used to identify the namespace of any
* particular attribute is ignored when returning its value.
*
* @param namespace URI associated with the namespace, or null
* to indicate the default namespace
* @param name colon-free "local part" of the attribute name
* @return the value of the inherited attribute, or null if
* no value was inherited.
*/
public String getInheritedAttribute (String namespace, String name)
{
NodeBase current = this;
Attr value = null;
do {
if (current instanceof ElementNode) {
ElementNode e = (ElementNode) current;
if ((value = e.getAttributeNode (namespace, name)) != null)
break;
}
current = current.getParentImpl ();
} while (current != null);
if (value != null)
return value.getValue ();
return null;
}
/**
* Does nothing; this type of node has no children.
*/
public void writeChildrenXml (XmlWriteContext context) throws IOException
{
}
// DOM support from W3C recommendation
/**
* <b>DOM:</b> Returns the node's parent. This will be null in cases such
* as newly created or removed nodes, and for attributes, fragments,
* and documents.
*/
public Node getParentNode () {
return parent;
}
/*
* Assigns the node's parent, and remove it from its current parent.
* The caller is responsible for letting the new parent know about
* this child by inserting it into the set of children at the
* appropriate place, if it's not null.
*
* <P> Note that this method, of necessity, involves the DOM being in
* an internally inconsistent state, either with the new parent not yet
* knowing about its child-to-be after this call, or this node not
* knowing its true parent before the call. That's why it's not a
* public API, here or in DOM.
*/
void setParentNode (ParentNode arg, int index)
throws DOMException
{
if (parent != null && arg != null)
parent.removeChild (this);
parent = arg;
parentIndex = index;
}
// assigns the owner of this document
void setOwnerDocument (XmlDocument doc)
{
ownerDocument = doc;
}
/**
* <b>DOM:</b> Returns the document to which this node belongs.
*/
public Document getOwnerDocument ()
{
return ownerDocument;
}
/**
* <b>DOM:</b> Returns false.
* Overridden by subclasses which support children.
*/
public boolean hasChildNodes() { return false; }
/**
* <b>DOM:</b> does nothing; overridden by subclasses as needed.
*/
public void setNodeValue (String value)
{
if (readonly)
throw new DomEx (DomEx.NO_MODIFICATION_ALLOWED_ERR);
}
/**
* <b>DOM:</b> Returns null; overridden by subclasses as needed.
*/
public String getNodeValue ()
{ return null; }
/**
* <b>DOM:</b> Returns null.
* Overridden by subclasses which support children.
*/
public Node getFirstChild () { return null; }
/**
* <b>DOM:</b> Returns zero.
* Overridden by subclasses which support children.
*/
public int getLength () { return 0; }
/**
* <b>DOM:</b> Returns null.
* Overridden by subclasses which support children.
*/
public Node item (int i) { return null; }
/**
* <b>DOM:</b> Returns an object which permits "live" access to all
* this node's children.
*
* <P> In this implementation, nodes provide such access without
* needing another node as an intermediary; "this" is returned.
*/
public NodeList getChildNodes ()
{ return this; }
/**
* <b>DOM:</b> returns null.
* Overridden by subclasses which support children.
*/
public Node getLastChild ()
{ return null; }
/**
* <b>DOM:</b> Throws a HIERARCHY_REQUEST_ERR DOMException.
* Overridden by subclasses which support children.
* @exception DOMException thrown always.
*/
public Node appendChild (Node newChild)
throws DOMException
{ throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR); }
/**
* <b>DOM:</b> Throws a HIERARCHY_REQUEST_ERR DOMException.
* Overridden by subclasses which support children.
* @exception DOMException thrown always.
*/
public Node insertBefore (Node newChild, Node refChild)
throws DOMException
{ throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR); }
/**
* <b>DOM:</b> Throws a HIERARCHY_REQUEST_ERR DOMException.
* Overridden by subclasses which support children.
* @exception DOMException thrown always.
*/
public Node replaceChild (Node newChild, Node refChild)
throws DOMException
{ throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR); }
/**
* <b>DOM:</b> Throws a HIERARCHY_REQUEST_ERR DOMException.
* Overridden by subclasses which support children.
* @exception DOMException thrown always.
*/
public Node removeChild (Node oldChild)
throws DOMException
{ throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR); }
/**
* <b>DOM:</b> Returns the node immediately following this node in a
* breadth first traversal of the tree, or null if there is no
* such sibling. In this implementation, sibling access from a
* node is slower than indexed access from its parent.
*/
public Node getNextSibling ()
{
if (parent == null)
return null;
if (parentIndex < 0 || parent.item (parentIndex) != this)
parentIndex = parent.getIndexOf (this);
return parent.item (parentIndex + 1);
}
/**
* <b>DOM:</b> Returns the node immediately preceding this node in a
* breadth first traversal of the tree, or null if there is no
* such sibling. In this implementation, sibling access from a
* node is slower than indexed access from its parent.
*/
public Node getPreviousSibling ()
{
if (parent == null)
return null;
if (parentIndex < 0 || parent.item (parentIndex) != this)
parentIndex = parent.getIndexOf (this);
return parent.item (parentIndex - 1);
}
/**
* <b>DOM:</b> returns null.
* Overridden by the ElementNode subclass.
*/
public NamedNodeMap getAttributes ()
{ return null; }
/**
* <b>DOM2:</b> noop.
* @since DOM Level 2
* Overridden by subclasses that need to support normalization.
*/
public void normalize() {
}
/**
* <b>DOM2:</b>
* @since DOM Level 2
*/
public boolean supports(String feature, String version) {
return XmlDocument.hasFeature0(feature, version);
}
/**
* <b>DOM2:</b> returns null.
* Overridden by subclasses that support namespaces, ie. ElementNode and
* AttributeNode.
*/
public String getNamespaceURI() {
return null;
}
/**
* <b>DOM2:</b> returns null.
* Overridden by subclasses that support namespaces.
*/
public String getPrefix() {
return null;
}
/**
* <b>DOM2:</b> throws DOMException.NAMESPACE_ERR
* Overridden by subclasses that support namespaces.
*/
public void setPrefix(String prefix) throws DOMException {
throw new DomEx(DomEx.NAMESPACE_ERR);
}
/**
* <b>DOM2:</b> returns null.
* Overridden by subclasses that support namespaces.
*/
public String getLocalName() {
return null;
}
public int getIndexOf (Node maybeChild)
{ return -1; }
/*
* Gets the messages from the resource bundles for the given messageId.
*/
String getMessage (String messageId) {
return getMessage (messageId, null);
}
/*
* Gets the messages from the resource bundles for the given messageId
* after formatting it with the parameters passed to it.
*/
String getMessage (String messageId, Object[] parameters) {
Locale locale;
if (this instanceof XmlDocument)
locale = ((XmlDocument)this).getLocale ();
else if (ownerDocument == null)
locale = Locale.getDefault (); // sigh
else
locale = ownerDocument.getLocale ();
return XmlDocument.catalog.getMessage (locale, messageId, parameters);
}
}