2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.xml.libxmlj.dom;
40 import java.util.HashMap;
41 import java.util.Iterator;
44 import org.w3c.dom.Document;
45 import org.w3c.dom.DocumentType;
46 import org.w3c.dom.DOMException;
47 import org.w3c.dom.NamedNodeMap;
48 import org.w3c.dom.Node;
49 import org.w3c.dom.NodeList;
50 import org.w3c.dom.Text;
51 import org.w3c.dom.UserDataHandler;
53 import gnu.xml.libxmlj.util.StandaloneDocumentType;
56 * A DOM node implemented in libxml2.
58 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
61 implements Node, Comparable
65 * Maps document pointers to a map of node pointers to node instances.
70 * Retrieves the node instance for the specified node pointer.
71 * This creates a new instance and adds it to the cache if required.
72 * @param doc the document pointer
73 * @param node the node pointer
74 * @param type the node type
76 static GnomeNode newInstance(final Object doc, final Object node,
81 throw new NullPointerException("doc");
85 throw new NullPointerException("node");
87 if (instances == null)
89 instances = new HashMap();
91 Map docNodes = (Map) instances.get(doc);
94 docNodes = new HashMap(1024); // TODO review optimal initial capacity
95 instances.put(doc, docNodes);
97 GnomeNode nodeInstance = (GnomeNode) docNodes.get(node);
98 if (nodeInstance != null)
100 return nodeInstance; // Return cached version
105 nodeInstance = new GnomeElement(node);
108 nodeInstance = new GnomeAttr(node);
111 nodeInstance = new GnomeText(node);
113 case CDATA_SECTION_NODE:
114 nodeInstance = new GnomeCDATASection(node);
116 case ENTITY_REFERENCE_NODE:
117 nodeInstance = new GnomeEntityReference(node);
120 nodeInstance = new GnomeEntity(node);
122 case PROCESSING_INSTRUCTION_NODE:
123 nodeInstance = new GnomeProcessingInstruction(node);
126 nodeInstance = new GnomeComment(node);
129 nodeInstance = new GnomeDocument(node);
131 case DOCUMENT_TYPE_NODE:
132 nodeInstance = new GnomeDocumentType(node);
134 case DOCUMENT_FRAGMENT_NODE:
135 nodeInstance = new GnomeDocumentFragment(node);
138 nodeInstance = new GnomeNotation(node);
141 throw new IllegalArgumentException("Unknown node type: " + type);
143 docNodes.put(node, nodeInstance);
148 * Frees the specified document.
149 * This removes all its nodes from the cache.
151 static void freeDocument(final Object doc)
153 if (instances == null || doc == null)
157 instances.remove(doc);
158 //System.out.println("Freed "+instances.remove(doc));
167 Map userDataHandlers;
169 GnomeNode(final Object id)
174 public native String getNodeName();
176 public native String getNodeValue()
179 public native void setNodeValue(String nodeValue)
182 public native short getNodeType();
184 public native Node getParentNode();
186 public NodeList getChildNodes()
188 return new GnomeNodeList(id);
191 public native Node getFirstChild();
193 public native Node getLastChild();
195 public native Node getPreviousSibling();
197 public native Node getNextSibling();
199 public NamedNodeMap getAttributes()
201 return new GnomeNamedNodeMap(id, 0);
204 public native Document getOwnerDocument();
206 public Node insertBefore(Node newChild, Node refChild)
209 if (newChild instanceof StandaloneDocumentType)
211 DocumentType dt = (DocumentType) newChild;
212 newChild = ((GnomeDocument) getOwnerDocument())
213 .createDocumentType(dt.getName(), dt.getPublicId(),
216 if (newChild == null)
218 throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null);
220 if (!(newChild instanceof GnomeNode))
222 throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null);
224 if (refChild == null || !(refChild instanceof GnomeNode))
226 throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null);
228 return xmljInsertBefore(newChild, refChild);
231 private native Node xmljInsertBefore(Node newChild, Node refChild)
234 public Node replaceChild(Node newChild, Node oldChild)
237 if (newChild instanceof StandaloneDocumentType)
239 DocumentType dt = (DocumentType) newChild;
240 newChild = ((GnomeDocument) getOwnerDocument())
241 .createDocumentType(dt.getName(), dt.getPublicId(),
244 if (newChild == null)
246 throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null);
248 if (!(newChild instanceof GnomeNode))
250 throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, newChild.toString());
252 if (oldChild == null || !(oldChild instanceof GnomeNode))
254 throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null);
256 return xmljReplaceChild(newChild, oldChild);
259 private native Node xmljReplaceChild(Node newChild, Node oldChild)
262 public Node removeChild(Node oldChild)
265 if (!(oldChild instanceof GnomeNode))
267 throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null);
269 return xmljRemoveChild(oldChild);
272 private native Node xmljRemoveChild(Node oldChild)
275 public Node appendChild(Node newChild)
278 if (newChild instanceof StandaloneDocumentType)
280 DocumentType dt = (DocumentType) newChild;
281 newChild = ((GnomeDocument) getOwnerDocument())
282 .createDocumentType(dt.getName(), dt.getPublicId(),
285 if (!(newChild instanceof GnomeNode))
287 throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null);
289 return xmljAppendChild(newChild);
292 private native Node xmljAppendChild(Node newChild)
295 public native boolean hasChildNodes();
297 public Node cloneNode(boolean deep)
299 Node ret = xmljCloneNode(deep);
300 notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, ret);
304 private native Node xmljCloneNode(boolean deep);
306 public native void normalize();
308 public boolean isSupported(String feature, String version)
310 return getOwnerDocument().getImplementation()
311 .hasFeature(feature, version);
314 public native String getNamespaceURI();
316 public native String getPrefix();
318 public native void setPrefix(String prefix)
321 public native String getLocalName();
323 public native boolean hasAttributes();
325 public int hashCode()
327 return id.hashCode();
330 public boolean equals(Object other)
336 return (other instanceof GnomeNode &&
337 ((GnomeNode) other).id == id);
340 // DOM Level 3 methods
342 public native String getBaseURI();
344 public short compareDocumentPosition(Node other)
347 return (short) compareTo(other);
350 public final int compareTo(Object other)
352 if (other instanceof GnomeNode)
354 return xmljCompareTo(other);
359 private native int xmljCompareTo(Object other);
361 public String getTextContent()
364 switch (getNodeType())
369 case ENTITY_REFERENCE_NODE:
370 case DOCUMENT_FRAGMENT_NODE:
371 StringBuffer buffer = new StringBuffer();
372 NodeList children = getChildNodes();
373 int len = children.getLength();
374 for (int i = 0; i < len; i++)
376 Node child = children.item(i);
377 String textContent = child.getTextContent();
378 if (textContent != null)
380 buffer.append(textContent);
383 return buffer.toString();
385 case CDATA_SECTION_NODE:
387 case PROCESSING_INSTRUCTION_NODE:
388 return getNodeValue();
394 public void setTextContent(String textContent)
397 switch (getNodeType())
399 case ENTITY_REFERENCE_NODE:
400 // entity references are read only
401 throw new GnomeDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
406 case DOCUMENT_FRAGMENT_NODE:
407 NodeList children = getChildNodes();
408 int len = children.getLength();
409 for (int i = 0; i < len; i++)
411 Node child = children.item(i);
414 if (textContent != null)
416 Text text = getOwnerDocument().createTextNode(textContent);
421 case CDATA_SECTION_NODE:
423 case PROCESSING_INSTRUCTION_NODE:
424 setNodeValue(textContent);
429 public boolean isSameNode(Node other)
431 return equals(other);
434 public native String lookupPrefix(String namespaceURI);
436 public native boolean isDefaultNamespace(String namespaceURI);
438 public native String lookupNamespaceURI(String prefix);
440 public native boolean isEqualNode(Node arg);
442 public Object getFeature(String feature, String version)
444 return getOwnerDocument().getImplementation()
445 .getFeature(feature, version);
448 public Object setUserData(String key, Object data, UserDataHandler handler)
451 if (userData == null)
453 userData = new HashMap();
457 if (userDataHandlers == null)
459 userDataHandlers = new HashMap();
461 userDataHandlers.put(key, handler);
463 return userData.put(key, data);
466 public Object getUserData(String key)
468 if (userData == null)
472 return userData.get(key);
475 void notifyUserDataHandlers(short op, Node src, Node dst)
477 if (userDataHandlers != null)
479 for (Iterator i = userDataHandlers.entrySet().iterator(); i.hasNext(); )
481 Map.Entry entry = (Map.Entry) i.next();
482 String key = (String) entry.getKey();
483 UserDataHandler handler = (UserDataHandler) entry.getValue();
484 Object data = userData.get(key);
485 handler.handle(op, key, data, src, dst);
490 public String toString()
492 StringBuffer buffer = new StringBuffer(getClass().getName());
493 buffer.append("[nodeName=");
494 buffer.append(getNodeName());
496 return buffer.toString();