diff options
Diffstat (limited to 'libjava/gnu/xml/dom/DomNode.java')
-rw-r--r-- | libjava/gnu/xml/dom/DomNode.java | 2189 |
1 files changed, 0 insertions, 2189 deletions
diff --git a/libjava/gnu/xml/dom/DomNode.java b/libjava/gnu/xml/dom/DomNode.java deleted file mode 100644 index 761c8de494d..00000000000 --- a/libjava/gnu/xml/dom/DomNode.java +++ /dev/null @@ -1,2189 +0,0 @@ -/* DomNode.java -- - Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package gnu.xml.dom; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.w3c.dom.Document; -import org.w3c.dom.DOMException; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.Text; -import org.w3c.dom.UserDataHandler; -import org.w3c.dom.events.DocumentEvent; -import org.w3c.dom.events.Event; -import org.w3c.dom.events.EventException; -import org.w3c.dom.events.EventListener; -import org.w3c.dom.events.EventTarget; -import org.w3c.dom.events.MutationEvent; -import org.w3c.dom.traversal.NodeFilter; -import org.w3c.dom.traversal.NodeIterator; - -/** - * <p> "Node", "EventTarget", and "DocumentEvent" implementation. - * This provides most of the core DOM functionality; only more - * specialized features are provided by subclasses. Those subclasses may - * have some particular constraints they must implement, by overriding - * methods defined here. Such constraints are noted here in the method - * documentation. </p> - * - * <p> Note that you can create events with type names prefixed with "USER-", - * and pass them through this DOM. This lets you use the DOM event scheme - * for application specific purposes, although you must use a predefined event - * structure (such as MutationEvent) to pass data along with those events. - * Test for existence of this feature with the "USER-Events" DOM feature - * name.</p> - * - * <p> Other kinds of events you can send include the "html" events, - * like "load", "unload", "abort", "error", and "blur"; and the mutation - * events. If this DOM has been compiled with mutation event support - * enabled, it will send mutation events when you change parts of the - * tree; otherwise you may create and send such events yourself, but - * they won't be generated by the DOM itself. </p> - * - * <p> Note that there is a namespace-aware name comparison method, - * <em>nameAndTypeEquals</em>, which compares the names (and types) of - * two nodes in conformance with the "Namespaces in XML" specification. - * While mostly intended for use with elements and attributes, this should - * also be helpful for ProcessingInstruction nodes and some others which - * do not have namespace URIs. - * - * @author David Brownell - * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> - */ -public abstract class DomNode - implements Node, NodeList, EventTarget, DocumentEvent, Cloneable, Comparable -{ - - // package private - //final static String xmlNamespace = "http://www.w3.org/XML/1998/namespace"; - //final static String xmlnsURI = "http://www.w3.org/2000/xmlns/"; - - // tunable - // NKIDS_* affects arrays of children (which grow) - // (currently) fixed size: - // ANCESTORS_* is for event capture/bubbling, # ancestors - // NOTIFICATIONS_* is for per-node event delivery, # events - private static final int NKIDS_DELTA = 8; - private static final int ANCESTORS_INIT = 20; - private static final int NOTIFICATIONS_INIT = 10; - - // tunable: enable mutation events or not? Enabling it costs about - // 10-15% in DOM construction time, last time it was measured. - - // package private !!! - static final boolean reportMutations = true; - - // locking protocol changeable only within this class - private static final Object lockNode = new Object(); - - // NON-FINAL class data - - // Optimize event dispatch by not allocating memory each time - private static boolean dispatchDataLock; - private static DomNode[] ancestors = new DomNode[ANCESTORS_INIT]; - private static ListenerRecord[] notificationSet - = new ListenerRecord[NOTIFICATIONS_INIT]; - - // Ditto for the (most common) event object itself! - private static boolean eventDataLock; - private static DomEvent.DomMutationEvent mutationEvent - = new DomEvent.DomMutationEvent(null); - - // - // PER-INSTANCE DATA - // - - DomDocument owner; - DomNode parent; // parent node; - DomNode previous; // previous sibling node - DomNode next; // next sibling node - DomNode first; // first child node - DomNode last; // last child node - int index; // index of this node in its parent's children - int depth; // depth of the node in the document - int length; // number of children - final short nodeType; - - // Bleech ... "package private" so a builder can populate entity refs. - // writable during construction. DOM spec is nasty. - boolean readonly; - - // event registrations - private ListenerRecord[] listeners; - private int nListeners; - - // DOM Level 3 userData dictionary. - private HashMap userData; - private HashMap userDataHandlers; - - // - // Some of the methods here are declared 'final' because - // knowledge about their implementation is built into this - // class -- for both integrity and performance. - // - - /** - * Reduces space utilization for this node. - */ - public void compact() - { - if (listeners != null && listeners.length != nListeners) - { - if (nListeners == 0) - { - listeners = null; - } - else - { - ListenerRecord[] l = new ListenerRecord[nListeners]; - System.arraycopy(listeners, 0, l, 0, nListeners); - listeners = l; - } - } - } - - /** - * Constructs a node and associates it with its owner. Only - * Document and DocumentType nodes may be created with no owner, - * and DocumentType nodes get an owner as soon as they are - * associated with a document. - */ - protected DomNode(short nodeType, DomDocument owner) - { - this.nodeType = nodeType; - - if (owner == null) - { - // DOM calls never go down this path - if (nodeType != DOCUMENT_NODE && nodeType != DOCUMENT_TYPE_NODE) - { - throw new IllegalArgumentException ("no owner!"); - } - } - this.owner = owner; - } - - - /** - * <b>DOM L1</b> - * Returns null; Element subclasses must override this method. - */ - public NamedNodeMap getAttributes() - { - return null; - } - - /** - * <b>DOM L2></b> - * Returns true iff this is an element node with attributes. - */ - public boolean hasAttributes() - { - return false; - } - - /** - * <b>DOM L1</b> - * Returns a list, possibly empty, of the children of this node. - * In this implementation, to conserve memory, nodes are the same - * as their list of children. This can have ramifications for - * subclasses, which may need to provide their own getLength method - * for reasons unrelated to the NodeList method of the same name. - */ - public NodeList getChildNodes() - { - return this; - } - - /** - * <b>DOM L1</b> - * Returns the first child of this node, or null if there are none. - */ - public Node getFirstChild() - { - return first; - } - - /** - * <b>DOM L1</b> - * Returns the last child of this node, or null if there are none. - */ - public Node getLastChild() - { - return last; - } - - /** - * <b>DOM L1</b> - * Returns true if this node has children. - */ - public boolean hasChildNodes() - { - return length != 0; - } - - - /** - * Exposes the internal "readonly" flag. In DOM, children of - * entities and entity references are readonly, as are the - * objects associated with DocumentType objets. - */ - public final boolean isReadonly() - { - return readonly; - } - - /** - * Sets the internal "readonly" flag so this subtree can't be changed. - * Subclasses need to override this method for any associated content - * that's not a child node, such as an element's attributes or the - * (few) declarations associated with a DocumentType. - */ - public void makeReadonly() - { - readonly = true; - for (DomNode child = first; child != null; child = child.next) - { - child.makeReadonly(); - } - } - - /** - * Used to adopt a node to a new document. - */ - void setOwner(DomDocument doc) - { - this.owner = doc; - for (DomNode ctx = first; ctx != null; ctx = ctx.next) - { - ctx.setOwner(doc); - } - } - - // just checks the node for inclusion -- may be called many - // times (docfrag) before anything is allowed to change - private void checkMisc(DomNode child) - { - if (readonly && !owner.building) - { - throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, - null, this, 0); - } - for (DomNode ctx = this; ctx != null; ctx = ctx.parent) - { - if (child == ctx) - { - throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, - "can't make ancestor into a child", - this, 0); - } - } - - DomDocument owner = (nodeType == DOCUMENT_NODE) ? (DomDocument) this : - this.owner; - DomDocument childOwner = child.owner; - short childNodeType = child.nodeType; - - if (childOwner != owner) - { - // new in DOM L2, this case -- patch it up later, in reparent() - if (!(childNodeType == DOCUMENT_TYPE_NODE && childOwner == null)) - { - throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, - null, child, 0); - } - } - - // enforce various structural constraints - switch (nodeType) - { - case DOCUMENT_NODE: - switch (childNodeType) - { - case ELEMENT_NODE: - case PROCESSING_INSTRUCTION_NODE: - case COMMENT_NODE: - case DOCUMENT_TYPE_NODE: - return; - } - break; - - case ATTRIBUTE_NODE: - switch (childNodeType) - { - case TEXT_NODE: - case ENTITY_REFERENCE_NODE: - return; - } - break; - - case DOCUMENT_FRAGMENT_NODE: - case ENTITY_REFERENCE_NODE: - case ELEMENT_NODE: - case ENTITY_NODE: - switch (childNodeType) - { - case ELEMENT_NODE: - case TEXT_NODE: - case COMMENT_NODE: - case PROCESSING_INSTRUCTION_NODE: - case CDATA_SECTION_NODE: - case ENTITY_REFERENCE_NODE: - return; - } - break; - } - if (owner.checkingWellformedness) - { - throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, - "can't append " + - nodeTypeToString(childNodeType) + - " to node of type " + - nodeTypeToString(nodeType), - this, 0); - } - } - - // Here's hoping a good optimizer will detect the case when the - // next several methods are never called, and won't allocate - // object code space of any kind. (Case: not reporting any - // mutation events. We can also remove some static variables - // listed above.) - - private void insertionEvent(DomEvent.DomMutationEvent event, - DomNode target) - { - if (owner == null || owner.building) - { - return; - } - boolean doFree = false; - - if (event == null) - { - event = getMutationEvent(); - } - if (event != null) - { - doFree = true; - } - else - { - event = new DomEvent.DomMutationEvent(null); - } - event.initMutationEvent("DOMNodeInserted", - true /* bubbles */, false /* nocancel */, - this /* related */, null, null, null, (short) 0); - target.dispatchEvent(event); - - // XXX should really visit every descendant of 'target' - // and sent a DOMNodeInsertedIntoDocument event to it... - // bleech, there's no way to keep that acceptably fast. - - if (doFree) - { - event.target = null; - event.relatedNode = null; - event.currentNode = null; - eventDataLock = false; - } // else we created work for the GC - } - - private void removalEvent(DomEvent.DomMutationEvent event, - DomNode target) - { - if (owner == null || owner.building) - { - return; - } - boolean doFree = false; - - if (event == null) - { - event = getMutationEvent(); - } - if (event != null) - { - doFree = true; - } - else - { - event = new DomEvent.DomMutationEvent(null); - } - event.initMutationEvent("DOMNodeRemoved", - true /* bubbles */, false /* nocancel */, - this /* related */, null, null, null, (short) 0); - target.dispatchEvent(event); - - // XXX should really visit every descendant of 'target' - // and sent a DOMNodeRemovedFromDocument event to it... - // bleech, there's no way to keep that acceptably fast. - - event.target = null; - event.relatedNode = null; - event.currentNode = null; - if (doFree) - { - eventDataLock = false; - } - // else we created more work for the GC - } - - // - // Avoid creating lots of memory management work, by using a simple - // allocation strategy for the mutation event objects that get used - // at least once per tree modification. We can't use stack allocation, - // so we do the next simplest thing -- more or less, static allocation. - // Concurrent notifications should be rare, anyway. - // - // Returns the preallocated object, which needs to be carefully freed, - // or null to indicate the caller needs to allocate their own. - // - static private DomEvent.DomMutationEvent getMutationEvent() - { - synchronized (lockNode) - { - if (eventDataLock) - { - return null; - } - eventDataLock = true; - return mutationEvent; - } - } - - // NOTE: this is manually inlined in the insertion - // and removal event methods above; change in sync. - static private void freeMutationEvent() - { - // clear fields to enable GC - mutationEvent.clear(); - eventDataLock = false; - } - - void setDepth(int depth) - { - this.depth = depth; - for (DomNode ctx = first; ctx != null; ctx = ctx.next) - { - ctx.setDepth(depth + 1); - } - } - - /** - * <b>DOM L1</b> - * Appends the specified node to this node's list of children. - * Document subclasses must override this to enforce the restrictions - * that there be only one element and document type child. - * - * <p> Causes a DOMNodeInserted mutation event to be reported. - * Will first cause a DOMNodeRemoved event to be reported if the - * parameter already has a parent. If the new child is a document - * fragment node, both events will be reported for each child of - * the fragment; the order in which children are removed and - * inserted is implementation-specific. - * - * <p> If this DOM has been compiled without mutation event support, - * these events will not be reported. - */ - public Node appendChild(Node newChild) - { - try - { - DomNode child = (DomNode) newChild; - - if (child.nodeType == DOCUMENT_FRAGMENT_NODE) - { - // Append all nodes in the fragment to this node - for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) - { - checkMisc(ctx); - } - for (DomNode ctx = child.first; ctx != null; ) - { - DomNode ctxNext = ctx.next; - appendChild(ctx); - ctx = ctxNext; - } - } - else - { - checkMisc(child); - if (child.parent != null) - { - child.parent.removeChild(child); - } - child.parent = this; - child.index = length++; - child.setDepth(depth + 1); - child.next = null; - if (last == null) - { - first = child; - child.previous = null; - } - else - { - last.next = child; - child.previous = last; - } - last = child; - - if (reportMutations) - { - insertionEvent(null, child); - } - } - - return child; - } - catch (ClassCastException e) - { - throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, - null, newChild, 0); - } - } - - /** - * <b>DOM L1</b> - * Inserts the specified node in this node's list of children. - * Document subclasses must override this to enforce the restrictions - * that there be only one element and document type child. - * - * <p> Causes a DOMNodeInserted mutation event to be reported. Will - * first cause a DOMNodeRemoved event to be reported if the newChild - * parameter already has a parent. If the new child is a document - * fragment node, both events will be reported for each child of - * the fragment; the order in which children are removed and inserted - * is implementation-specific. - * - * <p> If this DOM has been compiled without mutation event support, - * these events will not be reported. - */ - public Node insertBefore(Node newChild, Node refChild) - { - if (refChild == null) - { - return appendChild(newChild); - } - - try - { - DomNode child = (DomNode) newChild; - DomNode ref = (DomNode) refChild; - - if (child.nodeType == DOCUMENT_FRAGMENT_NODE) - { - // Append all nodes in the fragment to this node - for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) - { - checkMisc(ctx); - } - for (DomNode ctx = child.first; ctx != null; ) - { - DomNode ctxNext = ctx.next; - insertBefore(ctx, ref); - ctx = ctxNext; - } - } - else - { - checkMisc(child); - if (ref == null || ref.parent != this) - { - throw new DomDOMException(DOMException.NOT_FOUND_ERR, - null, ref, 0); - } - if (ref == child) - { - throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, - "can't insert node before itself", - ref, 0); - } - - if (child.parent != null) - { - child.parent.removeChild(child); - } - child.parent = this; - int i = ref.index; - child.setDepth(depth + 1); - child.next = ref; - if (ref.previous != null) - { - ref.previous.next = child; - } - child.previous = ref.previous; - ref.previous = child; - if (first == ref) - { - first = child; - } - // index renumbering - for (DomNode ctx = child; ctx != null; ctx = ctx.next) - { - ctx.index = i++; - } - - if (reportMutations) - { - insertionEvent(null, child); - } - } - - return child; - } - catch (ClassCastException e) - { - throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, - null, newChild, 0); - } - } - - /** - * <b>DOM L1</b> - * Replaces the specified node in this node's list of children. - * Document subclasses must override this to test the restrictions - * that there be only one element and document type child. - * - * <p> Causes DOMNodeRemoved and DOMNodeInserted mutation event to be - * reported. Will cause another DOMNodeRemoved event to be reported if - * the newChild parameter already has a parent. These events may be - * delivered in any order, except that the event reporting removal - * from such an existing parent will always be delivered before the - * event reporting its re-insertion as a child of some other node. - * The order in which children are removed and inserted is implementation - * specific. - * - * <p> If your application needs to depend on the in which those removal - * and insertion events are delivered, don't use this API. Instead, - * invoke the removeChild and insertBefore methods directly, to guarantee - * a specific delivery order. Similarly, don't use document fragments, - * Otherwise your application code may not work on a DOM which implements - * this method differently. - * - * <p> If this DOM has been compiled without mutation event support, - * these events will not be reported. - */ - public Node replaceChild(Node newChild, Node refChild) - { - try - { - DomNode child = (DomNode) newChild; - DomNode ref = (DomNode) refChild; - - DomEvent.DomMutationEvent event = getMutationEvent(); - boolean doFree = (event != null); - - if (child.nodeType == DOCUMENT_FRAGMENT_NODE) - { - // Append all nodes in the fragment to this node - for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) - { - checkMisc(ctx); - } - if (ref == null || ref.parent != this) - { - throw new DomDOMException(DOMException.NOT_FOUND_ERR, - null, ref, 0); - } - - if (reportMutations) - { - removalEvent(event, ref); - } - length--; - length += child.length; - - if (child.length == 0) - { - // Removal - if (ref.previous != null) - { - ref.previous.next = ref.next; - } - if (ref.next != null) - { - ref.next.previous = ref.previous; - } - if (first == ref) - { - first = ref.next; - } - if (last == ref) - { - last = ref.previous; - } - } - else - { - int i = ref.index; - for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) - { - // Insertion - ctx.parent = this; - ctx.index = i++; - ctx.setDepth(ref.depth); - if (ctx == child.first) - { - ctx.previous = ref.previous; - } - if (ctx == child.last) - { - ctx.next = ref.next; - } - } - if (first == ref) - { - first = child.first; - } - if (last == ref) - { - last = child.last; - } - } - } - else - { - checkMisc(child); - if (ref == null || ref.parent != this) - { - throw new DomDOMException(DOMException.NOT_FOUND_ERR, - null, ref, 0); - } - - if (reportMutations) - { - removalEvent(event, ref); - } - - if (child.parent != null) - { - child.parent.removeChild(child); - } - child.parent = this; - child.index = ref.index; - child.setDepth(ref.depth); - if (ref.previous != null) - { - ref.previous.next = child; - } - child.previous = ref.previous; - if (ref.next != null) - { - ref.next.previous = child; - } - child.next = ref.next; - if (first == ref) - { - first = child; - } - if (last == ref) - { - last = child; - } - - if (reportMutations) - { - insertionEvent(event, child); - } - if (doFree) - { - freeMutationEvent(); - } - } - ref.parent = null; - ref.index = 0; - ref.setDepth(0); - ref.previous = null; - ref.next = null; - - return ref; - } - catch (ClassCastException e) - { - throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, - null, newChild, 0); - } - } - - /** - * <b>DOM L1</b> - * Removes the specified child from this node's list of children, - * or else reports an exception. - * - * <p> Causes a DOMNodeRemoved mutation event to be reported. - * - * <p> If this DOM has been compiled without mutation event support, - * these events will not be reported. - */ - public Node removeChild(Node refChild) - { - try - { - DomNode ref = (DomNode) refChild; - - if (ref == null || ref.parent != this) - { - throw new DomDOMException(DOMException.NOT_FOUND_ERR, - null, ref, 0); - } - if (readonly && !owner.building) - { - throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, - null, this, 0); - } - - for (DomNode child = first; child != null; child = child.next) - { - if (child == ref) - { - if (reportMutations) - { - removalEvent(null, child); - } - - length--; - if (ref.previous != null) - { - ref.previous.next = ref.next; - } - if (ref.next != null) - { - ref.next.previous = ref.previous; - } - if (first == ref) - { - first = ref.next; - } - if (last == ref) - { - last = ref.previous; - } - // renumber indices - int i = 0; - for (DomNode ctx = first; ctx != null; ctx = ctx.next) - { - ctx.index = i++; - } - ref.parent = null; - ref.setDepth(0); - ref.index = 0; - ref.previous = null; - ref.next = null; - - return ref; - } - } - throw new DomDOMException(DOMException.NOT_FOUND_ERR, - "that's no child of mine", refChild, 0); - } - catch (ClassCastException e) - { - throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, - null, refChild, 0); - } - } - - /** - * <b>DOM L1 (NodeList)</b> - * Returns the item with the specified index in this NodeList, - * else null. - */ - public Node item(int index) - { - DomNode child = first; - int count = 0; - while (child != null && count < index) - { - child = child.next; - count++; - } - return child; - } - - /** - * <b>DOM L1 (NodeList)</b> - * Returns the number of elements in this NodeList. - * (Note that many interfaces have a "Length" property, not just - * NodeList, and if a node subtype must implement one of those, - * it will also need to override getChildNodes.) - */ - public int getLength() - { - return length; - } - - /** - * Minimize extra space consumed by this node to hold children and event - * listeners. - */ - public void trimToSize() - { - if (listeners != null && listeners.length != nListeners) - { - ListenerRecord[] newKids = new ListenerRecord[length]; - System.arraycopy(listeners, 0, newKids, 0, nListeners); - listeners = newKids; - } - } - - /** - * <b>DOM L1</b> - * Returns the previous sibling, if one is known. - */ - public Node getNextSibling() - { - return next; - } - - /** - * <b>DOM L1</b> - * Returns the previous sibling, if one is known. - */ - public Node getPreviousSibling() - { - return previous; - } - - /** - * <b>DOM L1</b> - * Returns the parent node, if one is known. - */ - public Node getParentNode() - { - return parent; - } - - /** - * <b>DOM L2</b> - * Consults the DOM implementation to determine if the requested - * feature is supported. DocumentType subclasses must override - * this method, and associate themselves directly with the - * DOMImplementation node used. (This method relies on being able - * to access the DOMImplementation from the owner document, but - * DocumentType nodes can be created without an owner.) - */ - public boolean isSupported(String feature, String version) - { - Document doc = owner; - DOMImplementation impl = null; - - if (doc == null && nodeType == DOCUMENT_NODE) - { - doc = (Document) this; - } - - if (doc == null) - { - // possible for DocumentType - throw new IllegalStateException ("unbound ownerDocument"); - } - - impl = doc.getImplementation(); - return impl.hasFeature(feature, version); - } - - /** - * <b>DOM L1 (modified in L2)</b> - * Returns the owner document. This is only null for Document nodes, - * and (new in L2) for DocumentType nodes which have not yet been - * associated with the rest of their document. - */ - final public Document getOwnerDocument() - { - return owner; - } - - /** - * <b>DOM L1</b> - * Does nothing; this must be overridden (along with the - * getNodeValue method) for nodes with a non-null defined value. - */ - public void setNodeValue(String value) - { - } - - /** - * <b>DOM L1</b> - * Returns null; this must be overridden for nodes types with - * a defined value, along with the setNodeValue method. - */ - public String getNodeValue() - { - return null; - } - - /** This forces GCJ compatibility. - * Without this method GCJ is unable to compile to byte code. - */ - public final short getNodeType() - { - return nodeType; - } - - /** This forces GCJ compatibility. - * Without this method GCJ seems unable to natively compile GNUJAXP. - */ - public abstract String getNodeName(); - - /** - * <b>DOM L2</b> - * Does nothing; this must be overridden (along with the - * getPrefix method) for element and attribute nodes. - */ - public void setPrefix(String prefix) - { - } - - /** - * <b>DOM L2</b> - * Returns null; this must be overridden for element and - * attribute nodes. - */ - public String getPrefix() - { - return null; - } - - /** - * <b>DOM L2</b> - * Returns null; this must be overridden for element and - * attribute nodes. - */ - public String getNamespaceURI() - { - return null; - } - - /** - * <b>DOM L2</b> - * Returns the node name; this must be overridden for element and - * attribute nodes. - */ - public String getLocalName() - { - return null; - } - - /** - * <b>DOM L1</b> - * Returns a clone of this node which optionally includes cloned - * versions of child nodes. Clones are always mutable, except for - * entity reference nodes. - */ - public Node cloneNode(boolean deep) - { - DomNode node = (DomNode) clone(); - - if (deep) - { - DomDocument doc = (nodeType == DOCUMENT_NODE) ? - (DomDocument) node : node.owner; - for (DomNode ctx = first; ctx != null; ctx = ctx.next) - { - DomNode newChild = (DomNode) ctx.cloneNode(deep); - newChild.setOwner(doc); - node.appendChild(newChild); - } - } - - if (nodeType == ENTITY_REFERENCE_NODE) - { - node.makeReadonly(); - } - notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, node); - return node; - } - - void notifyUserDataHandlers(short op, Node src, Node dst) - { - if (userDataHandlers != null) - { - for (Iterator i = userDataHandlers.entrySet().iterator(); i.hasNext(); ) - { - Map.Entry entry = (Map.Entry) i.next(); - String key = (String) entry.getKey(); - UserDataHandler handler = (UserDataHandler) entry.getValue(); - Object data = userData.get(key); - handler.handle(op, key, data, src, dst); - } - } - } - - /** - * Clones this node; roughly equivalent to cloneNode(false). - * Element subclasses must provide a new implementation which - * invokes this method to handle the basics, and then arranges - * to clone any element attributes directly. Attribute subclasses - * must make similar arrangements, ensuring that existing ties to - * elements are broken by cloning. - */ - public Object clone() - { - try - { - DomNode node = (DomNode) super.clone(); - - node.parent = null; - node.depth = 0; - node.index = 0; - node.length = 0; - node.first = null; - node.last = null; - node.previous = null; - node.next = null; - - node.readonly = false; - node.listeners = null; - node.nListeners = 0; - return node; - - } - catch (CloneNotSupportedException x) - { - throw new Error("clone didn't work"); - } - } - - // the elements-by-tagname stuff is needed for both - // elements and documents ... this is in lieu of a - // common base class between Node and NodeNS. - - /** - * <b>DOM L1</b> - * Creates a NodeList giving array-style access to elements with - * the specified name. Access is fastest if indices change by - * small values, and the DOM is not modified. - */ - public NodeList getElementsByTagName(String tag) - { - return new ShadowList(null, tag); - } - - /** - * <b>DOM L2</b> - * Creates a NodeList giving array-style access to elements with - * the specified namespace and local name. Access is fastest if - * indices change by small values, and the DOM is not modified. - */ - public NodeList getElementsByTagNameNS(String namespace, String local) - { - return new ShadowList(namespace, local); - } - - - // - // This shadow class is GC-able even when the live list it shadows - // can't be, because of event registration hookups. Its finalizer - // makes that live list become GC-able. - // - final class ShadowList - implements NodeList - { - - private LiveNodeList liveList; - - ShadowList(String ns, String local) - { - liveList = new LiveNodeList(ns, local); - } - - public void finalize() - { - liveList.detach(); - liveList = null; - } - - public Node item(int index) - { - return liveList.item(index); - } - - public int getLength() - { - return liveList.getLength(); - } - } - - final class LiveNodeList - implements NodeList, EventListener, NodeFilter - { - - private final boolean matchAnyURI; - private final boolean matchAnyName; - private final String elementURI; - private final String elementName; - - private DomIterator current; - private int lastIndex; - - LiveNodeList(String uri, String name) - { - elementURI = uri; - elementName = name; - matchAnyURI = "*".equals(uri); - matchAnyName = "*".equals(name); - - DomNode.this.addEventListener("DOMNodeInserted", this, true); - DomNode.this.addEventListener("DOMNodeRemoved", this, true); - } - - void detach() - { - current.detach(); - current = null; - - DomNode.this.removeEventListener("DOMNodeInserted", this, true); - DomNode.this.removeEventListener("DOMNodeRemoved", this, true); - } - - public short acceptNode(Node element) - { - if (element == DomNode.this) - { - return FILTER_SKIP; - } - - // use namespace-aware matching ... - if (elementURI != null) - { - if (!(matchAnyURI - || elementURI.equals(element.getNamespaceURI()))) - { - return FILTER_SKIP; - } - if (!(matchAnyName - || elementName.equals(element.getLocalName()))) - { - return FILTER_SKIP; - } - - // ... or qName-based kind. - } - else - { - if (!(matchAnyName - || elementName.equals(element.getNodeName()))) - { - return FILTER_SKIP; - } - } - return FILTER_ACCEPT; - } - - private DomIterator createIterator() - { - return new DomIterator(DomNode.this, - NodeFilter.SHOW_ELEMENT, - this, /* filter */ - true /* expand entity refs */ - ); - } - - public void handleEvent(Event e) - { - MutationEvent mutation = (MutationEvent) e; - Node related = mutation.getRelatedNode(); - - // XXX if it's got children ... check all kids too, they - // will invalidate our saved index - - if (related.getNodeType() != Node.ELEMENT_NODE || - related.getNodeName() != elementName || - related.getNamespaceURI() != elementURI) - { - return; - } - - current = null; - } - - public Node item(int index) - { - if (current == null) - { - current = createIterator(); - lastIndex = -1; - } - - // last node or before? go backwards - if (index <= lastIndex) { - while (index != lastIndex) { - current.previousNode (); - lastIndex--; - } - Node ret = current.previousNode (); - current = null; - return ret; - } - - // somewhere after last node - while (++lastIndex != index) - current.nextNode (); - Node ret = current.nextNode (); - current = null; - return ret; - } - - public int getLength() - { - int retval = 0; - NodeIterator iter = createIterator(); - - while (iter.nextNode() != null) - { - retval++; - } - current = null; - return retval; - } - - } - - // - // EventTarget support - // - static final class ListenerRecord - { - - String type; - EventListener listener; - boolean useCapture; - - // XXX use JDK 1.2 java.lang.ref.WeakReference to listener, - // and we can both get rid of "shadow" classes and remove - // the need for applications to apply similar trix ... but - // JDK 1.2 support isn't generally available yet - - ListenerRecord(String type, EventListener listener, boolean useCapture) - { - this.type = type.intern(); - this.listener = listener; - this.useCapture = useCapture; - } - - boolean equals(ListenerRecord rec) - { - return listener == rec.listener - && useCapture == rec.useCapture - && type == rec.type; - } - - } - - /** - * <b>DOM L2 (Events)</b> - * Returns an instance of the specified type of event object. - * Understands about DOM Mutation, HTML, and UI events. - * - * <p>If the name of the event type begins with "USER-", then an object - * implementing the "Event" class will be returned; this provides a - * limited facility for application-defined events to use the DOM event - * infrastructure. Alternatively, use one of the standard DOM event - * classes and initialize it using use such a "USER-" event type name; - * or defin, instantiate, and initialize an application-specific subclass - * of DomEvent and pass that to dispatchEvent(). - * - * @param eventType Identifies the particular DOM feature module - * defining the type of event, such as "MutationEvents". - * <em>The event "name" is a different kind of "type".</em> - */ - public Event createEvent(String eventType) - { - eventType = eventType.toLowerCase(); - - if ("mutationevents".equals(eventType)) - { - return new DomEvent.DomMutationEvent(null); - } - - if ("htmlevents".equals(eventType) - || "events".equals(eventType) - || "user-events".equals(eventType)) - { - return new DomEvent(null); - } - - if ("uievents".equals(eventType)) - { - return new DomEvent.DomUIEvent(null); - } - - // mouse events - - throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, - eventType, null, 0); - } - - /** - * <b>DOM L2 (Events)</b> - * Registers an event listener's interest in a class of events. - */ - public final void addEventListener(String type, - EventListener listener, - boolean useCapture) - { - if (listeners == null) - { - listeners = new ListenerRecord[1]; - } - else if (nListeners == listeners.length) - { - ListenerRecord[] newListeners = - new ListenerRecord[listeners.length + NKIDS_DELTA]; - System.arraycopy(listeners, 0, newListeners, 0, nListeners); - listeners = newListeners; - } - - // prune duplicates - ListenerRecord record; - - record = new ListenerRecord(type, listener, useCapture); - for (int i = 0; i < nListeners; i++) - { - if (record.equals(listeners[i])) - { - return; - } - } - listeners [nListeners++] = record; - } - - // XXX this exception should be discarded from DOM - - // this class can be instantiated, unlike the one in the spec - static final class DomEventException - extends EventException - { - - DomEventException() - { - super(UNSPECIFIED_EVENT_TYPE_ERR, "unspecified event type"); - } - - } - - /** - * <b>DOM L2 (Events)</b> - * Delivers an event to all relevant listeners, returning true if the - * caller should perform their default action. Note that the event - * must have been provided by the createEvent() method on this - * class, else it can't be dispatched. - * - * @see #createEvent - * - * @exception NullPointerException When a null event is passed. - * @exception ClassCastException When the event wasn't provided by - * the createEvent method, or otherwise isn't a DomEvent. - * @exception EventException If the event type wasn't specified - */ - public final boolean dispatchEvent(Event event) - throws EventException - { - DomEvent e = (DomEvent) event; - DomNode[] ancestors = null; - int ancestorMax = 0; - boolean haveDispatchDataLock = false; - - if (e.type == null) - { - throw new DomEventException(); - } - - e.doDefault = true; - e.target = this; - - // - // Typical case: one nonrecursive dispatchEvent call at a time - // for this class. If that's our case, we can avoid allocating - // garbage, which is overall a big win. Even with advanced GCs - // that deal well with short-lived garbage, and wayfast allocators, - // it still helps. - // - // Remember -- EVERY mutation goes though here at least once. - // - // When populating a DOM tree, trying to send mutation events is - // the primary cost; this dominates the critical path. - // - try - { - DomNode current; - int index; - boolean haveAncestorRegistrations = false; - ListenerRecord[] notificationSet; - int ancestorLen; - - synchronized (lockNode) - { - if (!dispatchDataLock) - { - haveDispatchDataLock = dispatchDataLock = true; - notificationSet = DomNode.notificationSet; - ancestors = DomNode.ancestors; - } - else - { - notificationSet = new ListenerRecord[NOTIFICATIONS_INIT]; - ancestors = new DomNode[ANCESTORS_INIT]; - } - ancestorLen = ancestors.length; - } - - // XXX autogrow ancestors ... based on statistics - - // Climb to the top of this subtree and handle capture, letting - // each node (from the top down) capture until one stops it or - // until we get to this one. - - for (index = 0, current = parent; - current != null && index < ancestorLen; - index++, current = current.parent) - { - if (current.nListeners != 0) - { - haveAncestorRegistrations = true; - } - ancestors [index] = current; - } - if (current != null) - { - throw new RuntimeException("dispatchEvent capture stack size"); - } - - ancestorMax = index; - e.stop = false; - - if (haveAncestorRegistrations) - { - e.eventPhase = Event.CAPTURING_PHASE; - while (!e.stop && index-- > 0) - { - current = ancestors [index]; - if (current.nListeners != 0) - { - notifyNode(e, current, true, notificationSet); - } - } - } - - // Always deliver events to the target node (this) - // unless stopPropagation was called. If we saw - // no registrations yet (typical!), we never will. - if (!e.stop && nListeners != 0) - { - e.eventPhase = Event.AT_TARGET; - notifyNode (e, this, false, notificationSet); - } - else if (!haveAncestorRegistrations) - { - e.stop = true; - } - - // If the event bubbles and propagation wasn't halted, - // walk back up the ancestor list. Stop bubbling when - // any bubbled event handler stops it. - - if (!e.stop && e.bubbles) - { - e.eventPhase = Event.BUBBLING_PHASE; - for (index = 0; - !e.stop - && index < ancestorMax - && (current = ancestors[index]) != null; - index++) - { - if (current.nListeners != 0) - { - notifyNode(e, current, false, notificationSet); - } - } - } - e.eventPhase = 0; - - // Caller chooses whether to perform the default - // action based on return from this method. - return e.doDefault; - - } - finally - { - if (haveDispatchDataLock) - { - // synchronize to force write ordering - synchronized (lockNode) - { - // null out refs to ensure they'll be GC'd - for (int i = 0; i < ancestorMax; i++) - { - ancestors [i] = null; - } - // notificationSet handled by notifyNode - - dispatchDataLock = false; - } - } - } - } - - private void notifyNode(DomEvent e, - DomNode current, - boolean capture, - ListenerRecord[] notificationSet) - { - int count = 0; - - // do any of this set of listeners get notified? - for (int i = 0; i < current.nListeners; i++) - { - ListenerRecord rec = current.listeners[i]; - - if (rec.useCapture != capture) - { - continue; - } - if (!e.type.equals (rec.type)) - { - continue; - } - if (count >= notificationSet.length) - { - // very simple growth algorithm - int len = Math.max(notificationSet.length, 1); - ListenerRecord[] tmp = new ListenerRecord[len * 2]; - System.arraycopy(notificationSet, 0, tmp, 0, - notificationSet.length); - notificationSet = tmp; - } - notificationSet[count++] = rec; - } - - // Notify just those listeners - e.currentNode = current; - for (int i = 0; i < count; i++) - { - try - { - // Late in the DOM CR process (3rd or 4th CR?) the - // removeEventListener spec became asymmetric with respect - // to addEventListener ... effect is now immediate. - for (int j = 0; j < current.nListeners; j++) - { - if (current.listeners[j].equals(notificationSet[i])) - { - notificationSet[i].listener.handleEvent(e); - break; - } - } - - } - catch (Exception x) - { - // ignore all exceptions - } - notificationSet[i] = null; // free for GC - } - } - - /** - * <b>DOM L2 (Events)</b> - * Unregisters an event listener. - */ - public final void removeEventListener(String type, - EventListener listener, - boolean useCapture) - { - for (int i = 0; i < nListeners; i++) - { - if (listeners[i].listener != listener) - { - continue; - } - if (listeners[i].useCapture != useCapture) - { - continue; - } - if (!listeners[i].type.equals(type)) - { - continue; - } - - if (nListeners == 1) - { - listeners = null; - nListeners = 0; - } - else - { - for (int j = i + 1; j < nListeners; j++) - { - listeners[i++] = listeners[j++]; - } - listeners[--nListeners] = null; - } - break; - } - // no exceptions reported - } - - /** - * <b>DOM L1 (relocated in DOM L2)</b> - * In this node and all contained nodes (including attributes if - * relevant) merge adjacent text nodes. This is done while ignoring - * text which happens to use CDATA delimiters). - */ - public final void normalize() - { - // Suspend readonly status - boolean saved = readonly; - readonly = false; - for (DomNode ctx = first; ctx != null; ctx = ctx.next) - { - switch (ctx.nodeType) - { - case TEXT_NODE: - while (ctx.next != null && ctx.next.nodeType == TEXT_NODE) - { - Text text = (Text) ctx; - text.appendData(ctx.next.getNodeValue()); - removeChild(ctx.next); - } - break; - case ELEMENT_NODE: - NamedNodeMap attrs = ctx.getAttributes(); - int len = attrs.getLength(); - for (int i = 0; i < len; i++) - { - attrs.item(i).normalize(); - } - // Fall through - case DOCUMENT_NODE: - case DOCUMENT_FRAGMENT_NODE: - case ATTRIBUTE_NODE: - case ENTITY_REFERENCE_NODE: - ctx.normalize(); - break; - } - } - readonly = saved; - } - - /** - * Returns true iff node types match, and either (a) both nodes have no - * namespace and their getNodeName() values are the same, or (b) both - * nodes have the same getNamespaceURI() and same getLocalName() values. - * - * <p>Note that notion of a "Per-Element-Type" attribute name scope, as - * found in a non-normative appendix of the XML Namespaces specification, - * is not supported here. Your application must implement that notion, - * typically by not bothering to check nameAndTypeEquals for attributes - * without namespace URIs unless you already know their elements are - * nameAndTypeEquals. - */ - public boolean nameAndTypeEquals(Node other) - { - if (other == this) - { - return true; - } - // node types must match - if (nodeType != other.getNodeType()) - { - return false; - } - - // if both have namespaces, do a "full" comparision - // this is a "global" partition - String ns1 = this.getNamespaceURI(); - String ns2 = other.getNamespaceURI(); - - if (ns1 != null && ns2 != null) - { - return ns1.equals(ns2) && - getLocalName().equals(other.getLocalName()); - } - - // if neither has a namespace, this is a "no-namespace" name. - if (ns1 == null && ns2 == null) - { - if (!getNodeName().equals(other.getNodeName())) - { - return false; - } - // can test the non-normative "per-element-type" scope here. - // if this is an attribute node and both nodes have been bound - // to elements (!!), then return the nameAndTypeEquals() - // comparison of those elements. - return true; - } - - // otherwise they're unequal: one scoped, one not. - return false; - } - - // DOM Level 3 methods - - public String getBaseURI() - { - return (parent != null) ? parent.getBaseURI() : null; - } - - public short compareDocumentPosition(Node other) - throws DOMException - { - return (short) compareTo(other); - } - - /** - * DOM nodes have a natural ordering: document order. - */ - public final int compareTo(Object other) - { - if (other instanceof DomNode) - { - DomNode n1 = this; - DomNode n2 = (DomNode) other; - if (n1.owner != n2.owner) - { - return 0; - } - int d1 = n1.depth, d2 = n2.depth; - int delta = d1 - d2; - while (d1 > d2) - { - n1 = n1.parent; - d1--; - } - while (d2 > d1) - { - n2 = n2.parent; - d2--; - } - int c = compareTo2(n1, n2); - return (c != 0) ? c : delta; - } - return 0; - } - - /** - * Compare two nodes at the same depth. - */ - final int compareTo2(DomNode n1, DomNode n2) - { - if (n1 == n2 || n1.depth == 0 || n2.depth == 0) - { - return 0; - } - int c = compareTo2(n1.parent, n2.parent); - return (c != 0) ? c : n1.index - n2.index; - } - - public final String getTextContent() - throws DOMException - { - return getTextContent(true); - } - - final String getTextContent(boolean topLevel) - throws DOMException - { - switch (nodeType) - { - case ELEMENT_NODE: - case ENTITY_NODE: - case ENTITY_REFERENCE_NODE: - case DOCUMENT_FRAGMENT_NODE: - StringBuffer buffer = new StringBuffer(); - for (DomNode ctx = first; ctx != null; ctx = ctx.next) - { - String textContent = ctx.getTextContent(false); - if (textContent != null) - { - buffer.append(textContent); - } - } - return buffer.toString(); - case TEXT_NODE: - case CDATA_SECTION_NODE: - if (((Text) this).isElementContentWhitespace()) - { - return ""; - } - return getNodeValue(); - case ATTRIBUTE_NODE: - return getNodeValue(); - case COMMENT_NODE: - case PROCESSING_INSTRUCTION_NODE: - return topLevel ? getNodeValue() : ""; - default: - return null; - } - } - - public void setTextContent(String textContent) - throws DOMException - { - switch (nodeType) - { - case ELEMENT_NODE: - case ATTRIBUTE_NODE: - case ENTITY_NODE: - case ENTITY_REFERENCE_NODE: - case DOCUMENT_FRAGMENT_NODE: - for (DomNode ctx = first; ctx != null; ) - { - DomNode n = ctx.next; - removeChild(ctx); - ctx = n; - } - if (textContent != null) - { - Text text = owner.createTextNode(textContent); - appendChild(text); - } - break; - case TEXT_NODE: - case CDATA_SECTION_NODE: - case COMMENT_NODE: - case PROCESSING_INSTRUCTION_NODE: - setNodeValue(textContent); - break; - } - } - - public boolean isSameNode(Node other) - { - return this == other; - } - - public String lookupPrefix(String namespaceURI) - { - return (parent == null || parent == owner) ? null : - parent.lookupPrefix(namespaceURI); - } - - public boolean isDefaultNamespace(String namespaceURI) - { - return (parent == null || parent == owner) ? false : - parent.isDefaultNamespace(namespaceURI); - } - - public String lookupNamespaceURI(String prefix) - { - return (parent == null || parent == owner) ? null : - parent.lookupNamespaceURI(prefix); - } - - public boolean isEqualNode(Node arg) - { - if (this == arg) - { - return true; - } - if (arg == null) - { - return false; - } - if (nodeType != arg.getNodeType() || - !equal(getNodeName(), arg.getNodeName()) || - !equal(getLocalName(), arg.getLocalName()) || - !equal(getNamespaceURI(), arg.getNamespaceURI()) || - !equal(getPrefix(), arg.getPrefix()) || - !equal(getNodeValue(), arg.getNodeValue())) - { - return false; - } - // Children - Node argCtx = arg.getFirstChild(); - getFirstChild(); // because of DomAttr lazy children - for (DomNode ctx = first; ctx != null; ctx = ctx.next) - { - if (!ctx.isEqualNode(argCtx)) - { - return false; - } - argCtx = argCtx.getNextSibling(); - } - if (argCtx != null) - { - return false; - } - - // TODO Attr NamedNodeMap - // TODO DocumentType - return true; - } - - boolean equal(String arg1, String arg2) - { - return ((arg1 == null && arg2 == null) || - (arg1 != null && arg1.equals(arg2))); - } - - public Object getFeature(String feature, String version) - { - DOMImplementation impl = (nodeType == DOCUMENT_NODE) ? - ((Document) this).getImplementation() : owner.getImplementation(); - if (impl.hasFeature(feature, version)) - { - return this; - } - return null; - } - - public Object setUserData(String key, Object data, UserDataHandler handler) - { - if (userData == null) - { - userData = new HashMap(); - } - if (handler != null) - { - if (userDataHandlers == null) - { - userDataHandlers = new HashMap(); - } - userDataHandlers.put(key, handler); - } - return userData.put(key, data); - } - - public Object getUserData(String key) - { - if (userData == null) - { - return null; - } - return userData.get(key); - } - - public String toString() - { - String nodeName = getNodeName(); - String nodeValue = getNodeValue(); - StringBuffer buf = new StringBuffer(getClass().getName()); - buf.append('['); - if (nodeName != null) - { - buf.append(nodeName); - } - if (nodeValue != null) - { - if (nodeName != null) - { - buf.append('='); - } - buf.append('\''); - buf.append(encode(nodeValue)); - buf.append('\''); - } - buf.append(']'); - return buf.toString(); - } - - String encode(String value) - { - StringBuffer buf = null; - int len = value.length(); - for (int i = 0; i < len; i++) - { - char c = value.charAt(i); - if (c == '\n') - { - if (buf == null) - { - buf = new StringBuffer(value.substring(0, i)); - } - buf.append("\\n"); - } - else if (c == '\r') - { - if (buf == null) - { - buf = new StringBuffer(value.substring(0, i)); - } - buf.append("\\r"); - } - else if (buf != null) - { - buf.append(c); - } - } - return (buf != null) ? buf.toString() : value; - } - - String nodeTypeToString(short nodeType) - { - switch (nodeType) - { - case ELEMENT_NODE: - return "ELEMENT_NODE"; - case ATTRIBUTE_NODE: - return "ATTRIBUTE_NODE"; - case TEXT_NODE: - return "TEXT_NODE"; - case CDATA_SECTION_NODE: - return "CDATA_SECTION_NODE"; - case DOCUMENT_NODE: - return "DOCUMENT_NODE"; - case DOCUMENT_TYPE_NODE: - return "DOCUMENT_TYPE_NODE"; - case COMMENT_NODE: - return "COMMENT_NODE"; - case PROCESSING_INSTRUCTION_NODE: - return "PROCESSING_INSTRUCTION_NODE"; - case DOCUMENT_FRAGMENT_NODE: - return "DOCUMENT_FRAGMENT_NODE"; - case ENTITY_NODE: - return "ENTITY_NODE"; - case ENTITY_REFERENCE_NODE: - return "ENTITY_REFERENCE_NODE"; - case NOTATION_NODE: - return "NOTATION_NODE"; - default: - return "UNKNOWN"; - } - } - -} - |