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;
public abstract class DomNode
implements Node, NodeList, EventTarget, DocumentEvent, Cloneable, Comparable
{
private static final int NKIDS_DELTA = 8;
private static final int ANCESTORS_INIT = 20;
private static final int NOTIFICATIONS_INIT = 10;
static final boolean reportMutations = true;
private static final Object lockNode = new Object();
private static boolean dispatchDataLock;
private static DomNode[] ancestors = new DomNode[ANCESTORS_INIT];
private static ListenerRecord[] notificationSet
= new ListenerRecord[NOTIFICATIONS_INIT];
private static boolean eventDataLock;
private static DomEvent.DomMutationEvent mutationEvent
= new DomEvent.DomMutationEvent(null);
DomDocument owner;
DomNode parent; DomNode previous; DomNode next; DomNode first; DomNode last; int index; int depth; int length; final short nodeType;
boolean readonly;
private ListenerRecord[] listeners;
private int nListeners;
private HashMap userData;
private HashMap userDataHandlers;
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;
}
}
}
protected DomNode(short nodeType, DomDocument owner)
{
this.nodeType = nodeType;
if (owner == null)
{
if (nodeType != DOCUMENT_NODE && nodeType != DOCUMENT_TYPE_NODE)
{
throw new IllegalArgumentException ("no owner!");
}
}
this.owner = owner;
}
public NamedNodeMap getAttributes()
{
return null;
}
public boolean hasAttributes()
{
return false;
}
public NodeList getChildNodes()
{
return this;
}
public Node getFirstChild()
{
return first;
}
public Node getLastChild()
{
return last;
}
public boolean hasChildNodes()
{
return length != 0;
}
public final boolean isReadonly()
{
return readonly;
}
public void makeReadonly()
{
readonly = true;
for (DomNode child = first; child != null; child = child.next)
{
child.makeReadonly();
}
}
void setOwner(DomDocument doc)
{
this.owner = doc;
for (DomNode ctx = first; ctx != null; ctx = ctx.next)
{
ctx.setOwner(doc);
}
}
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)
{
if (!(childNodeType == DOCUMENT_TYPE_NODE && childOwner == null))
{
throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR,
null, child, 0);
}
}
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);
}
}
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 , false ,
this , null, null, null, (short) 0);
target.dispatchEvent(event);
if (doFree)
{
event.target = null;
event.relatedNode = null;
event.currentNode = null;
eventDataLock = false;
} }
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 , false ,
this , null, null, null, (short) 0);
target.dispatchEvent(event);
event.target = null;
event.relatedNode = null;
event.currentNode = null;
if (doFree)
{
eventDataLock = false;
}
}
static private DomEvent.DomMutationEvent getMutationEvent()
{
synchronized (lockNode)
{
if (eventDataLock)
{
return null;
}
eventDataLock = true;
return mutationEvent;
}
}
static private void freeMutationEvent()
{
mutationEvent.clear();
eventDataLock = false;
}
void setDepth(int depth)
{
this.depth = depth;
for (DomNode ctx = first; ctx != null; ctx = ctx.next)
{
ctx.setDepth(depth + 1);
}
}
public Node appendChild(Node newChild)
{
try
{
DomNode child = (DomNode) newChild;
if (child.nodeType == DOCUMENT_FRAGMENT_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);
}
}
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)
{
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;
}
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);
}
}
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)
{
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)
{
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)
{
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);
}
}
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;
}
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);
}
}
public Node item(int index)
{
DomNode child = first;
int count = 0;
while (child != null && count < index)
{
child = child.next;
count++;
}
return child;
}
public int getLength()
{
return length;
}
public void trimToSize()
{
if (listeners != null && listeners.length != nListeners)
{
ListenerRecord[] newKids = new ListenerRecord[length];
System.arraycopy(listeners, 0, newKids, 0, nListeners);
listeners = newKids;
}
}
public Node getNextSibling()
{
return next;
}
public Node getPreviousSibling()
{
return previous;
}
public Node getParentNode()
{
return parent;
}
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)
{
throw new IllegalStateException ("unbound ownerDocument");
}
impl = doc.getImplementation();
return impl.hasFeature(feature, version);
}
final public Document getOwnerDocument()
{
return owner;
}
public void setNodeValue(String value)
{
}
public String getNodeValue()
{
return null;
}
public final short getNodeType()
{
return nodeType;
}
public abstract String getNodeName();
public void setPrefix(String prefix)
{
}
public String getPrefix()
{
return null;
}
public String getNamespaceURI()
{
return null;
}
public String getLocalName()
{
return null;
}
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);
}
}
}
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");
}
}
public NodeList getElementsByTagName(String tag)
{
return new ShadowList(null, tag);
}
public NodeList getElementsByTagNameNS(String namespace, String local)
{
return new ShadowList(namespace, local);
}
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;
}
if (elementURI != null)
{
if (!(matchAnyURI
|| elementURI.equals(element.getNamespaceURI())))
{
return FILTER_SKIP;
}
if (!(matchAnyName
|| elementName.equals(element.getLocalName())))
{
return FILTER_SKIP;
}
}
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,
true
);
}
public void handleEvent(Event e)
{
MutationEvent mutation = (MutationEvent) e;
Node related = mutation.getRelatedNode();
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;
}
if (index <= lastIndex) {
while (index != lastIndex) {
current.previousNode ();
lastIndex--;
}
Node ret = current.previousNode ();
current = null;
return ret;
}
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;
}
}
static final class ListenerRecord
{
String type;
EventListener listener;
boolean useCapture;
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;
}
}
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);
}
throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR,
eventType, null, 0);
}
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;
}
ListenerRecord record;
record = new ListenerRecord(type, listener, useCapture);
for (int i = 0; i < nListeners; i++)
{
if (record.equals(listeners[i]))
{
return;
}
}
listeners [nListeners++] = record;
}
static final class DomEventException
extends EventException
{
DomEventException()
{
super(UNSPECIFIED_EVENT_TYPE_ERR, "unspecified event type");
}
}
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;
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;
}
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);
}
}
}
if (!e.stop && nListeners != 0)
{
e.eventPhase = Event.AT_TARGET;
notifyNode (e, this, false, notificationSet);
}
else if (!haveAncestorRegistrations)
{
e.stop = true;
}
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;
return e.doDefault;
}
finally
{
if (haveDispatchDataLock)
{
synchronized (lockNode)
{
for (int i = 0; i < ancestorMax; i++)
{
ancestors [i] = null;
}
dispatchDataLock = false;
}
}
}
}
private void notifyNode(DomEvent e,
DomNode current,
boolean capture,
ListenerRecord[] notificationSet)
{
int count = 0;
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)
{
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;
}
e.currentNode = current;
for (int i = 0; i < count; i++)
{
try
{
for (int j = 0; j < current.nListeners; j++)
{
if (current.listeners[j].equals(notificationSet[i]))
{
notificationSet[i].listener.handleEvent(e);
break;
}
}
}
catch (Exception x)
{
}
notificationSet[i] = null; }
}
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;
}
}
public final void normalize()
{
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();
}
case DOCUMENT_NODE:
case DOCUMENT_FRAGMENT_NODE:
case ATTRIBUTE_NODE:
case ENTITY_REFERENCE_NODE:
ctx.normalize();
break;
}
}
readonly = saved;
}
public boolean nameAndTypeEquals(Node other)
{
if (other == this)
{
return true;
}
if (nodeType != other.getNodeType())
{
return false;
}
String ns1 = this.getNamespaceURI();
String ns2 = other.getNamespaceURI();
if (ns1 != null && ns2 != null)
{
return ns1.equals(ns2) &&
getLocalName().equals(other.getLocalName());
}
if (ns1 == null && ns2 == null)
{
if (!getNodeName().equals(other.getNodeName()))
{
return false;
}
return true;
}
return false;
}
public String getBaseURI()
{
return (parent != null) ? parent.getBaseURI() : null;
}
public short compareDocumentPosition(Node other)
throws DOMException
{
return (short) compareTo(other);
}
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;
}
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;
}
Node argCtx = arg.getFirstChild();
getFirstChild(); for (DomNode ctx = first; ctx != null; ctx = ctx.next)
{
if (!ctx.isEqualNode(argCtx))
{
return false;
}
argCtx = argCtx.getNextSibling();
}
if (argCtx != null)
{
return false;
}
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";
}
}
}