From 35d7c089bd45f1030407b9b69b46e66f02c03043 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sat, 20 Feb 2010 10:20:55 -0800 Subject: More XML DOM v3 APIs. This adds the following APIs and tests: - Node.isDefaultNamespace - DomImplementation.hasFeature - Node.isSupported - Node.getFeature - Node.isEqualNode --- .../harmony/xml/dom/DOMImplementationImpl.java | 23 +++-- .../org/apache/harmony/xml/dom/DocumentImpl.java | 5 + .../java/org/apache/harmony/xml/dom/NodeImpl.java | 115 +++++++++++++++++++-- 3 files changed, 129 insertions(+), 14 deletions(-) (limited to 'xml/src/main/java/org') diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java index 861f0a3..834cc47 100644 --- a/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java @@ -50,17 +50,24 @@ public class DOMImplementationImpl implements DOMImplementation { } public boolean hasFeature(String feature, String version) { - // We claim to support DOM Core Level 1 & 2, nothing else. + boolean anyVersion = version == null || version.length() == 0; + if (feature.startsWith("+")) { + feature = feature.substring(1); + } - // TODO + // TODO: fully implement these APIs: + // "LS" (org.w3c.dom.ls) versions "3.0" + // "ElementTraversal" (org.w3c.dom.traversal) versions "1.0" - if ("Core".equalsIgnoreCase(feature) || "XML".equalsIgnoreCase(feature)) { - if (version == null || "".equals(version) || "1.0".equals(version) || "2.0".equals(version)) { - return true; - } + if (feature.equalsIgnoreCase("Core")) { + return anyVersion || version.equals("1.0") || version.equals("2.0") || version.equals("3.0"); + } else if (feature.equalsIgnoreCase("XML")) { + return anyVersion || version.equals("1.0") || version.equals("2.0") || version.equals("3.0"); + } else if (feature.equalsIgnoreCase("XMLVersion")) { + return anyVersion || version.equals("1.0") || version.equals("1.1"); + } else { + return false; } - - return false; } /** diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java index d6d412b..c8819cb 100644 --- a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java @@ -100,6 +100,8 @@ public class DocumentImpl extends InnerNodeImpl implements Document { * @return The new node. */ Node cloneNode(Node node, boolean deep) throws DOMException { + // TODO: callback the UserDataHandler with a NODE_CLONED event + Node target; switch (node.getNodeType()) { @@ -279,6 +281,7 @@ public class DocumentImpl extends InnerNodeImpl implements Document { } public Node importNode(Node importedNode, boolean deep) throws DOMException { + // TODO: callback the UserDataHandler with a NODE_IMPORTED event return cloneNode(importedNode, deep); } @@ -341,6 +344,7 @@ public class DocumentImpl extends InnerNodeImpl implements Document { } public Node adoptNode(Node source) throws DOMException { + // TODO: callback the UserDataHandler with a NODE_ADOPTED event throw new UnsupportedOperationException(); // TODO } @@ -354,6 +358,7 @@ public class DocumentImpl extends InnerNodeImpl implements Document { public Node renameNode(Node n, String namespaceURI, String qualifiedName) throws DOMException { + // TODO: callback the UserDataHandler with a NODE_RENAMED event throw new UnsupportedOperationException(); // TODO } } diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java index 13e6c9f..ebfdd52 100644 --- a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java +++ b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java @@ -20,12 +20,16 @@ import org.w3c.dom.Attr; import org.w3c.dom.CharacterData; import org.w3c.dom.DOMException; import org.w3c.dom.Document; +import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.UserDataHandler; +import java.util.ArrayList; +import java.util.List; + /** * A straightforward implementation of the corresponding W3C DOM node. * @@ -435,8 +439,11 @@ public abstract class NodeImpl implements Node { return uri.equals(actual); } - public boolean isDefaultNamespace(String namespaceURI) { - throw new UnsupportedOperationException(); // TODO + public final boolean isDefaultNamespace(String namespaceURI) { + String actual = lookupNamespaceURI(null); // null yields the default namespace + return namespaceURI == null + ? actual == null + : namespaceURI.equals(actual); } public final String lookupNamespaceURI(String prefix) { @@ -476,12 +483,108 @@ public abstract class NodeImpl implements Node { return null; } - public boolean isEqualNode(Node arg) { - throw new UnsupportedOperationException(); // TODO + /** + * Returns a list of objects such that two nodes are equal if their lists + * are equal. Be careful: the lists may contain NamedNodeMaps and Nodes, + * neither of which override Object.equals(). Such values must be compared + * manually. + */ + private static List createEqualityKey(Node node) { + List values = new ArrayList(); + values.add(node.getNodeType()); + values.add(node.getNodeName()); + values.add(node.getLocalName()); + values.add(node.getNamespaceURI()); + values.add(node.getPrefix()); + values.add(node.getNodeValue()); + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + values.add(child); + } + + switch (node.getNodeType()) { + case DOCUMENT_TYPE_NODE: + DocumentTypeImpl doctype = (DocumentTypeImpl) node; + values.add(doctype.getPublicId()); + values.add(doctype.getSystemId()); + values.add(doctype.getInternalSubset()); + values.add(doctype.getEntities()); + values.add(doctype.getNotations()); + break; + + case ELEMENT_NODE: + Element element = (Element) node; + values.add(element.getAttributes()); + break; + } + + return values; } - public Object getFeature(String feature, String version) { - throw new UnsupportedOperationException(); // TODO + public final boolean isEqualNode(Node arg) { + if (arg == this) { + return true; + } + + List listA = createEqualityKey(this); + List listB = createEqualityKey(arg); + + if (listA.size() != listB.size()) { + return false; + } + + for (int i = 0; i < listA.size(); i++) { + Object a = listA.get(i); + Object b = listB.get(i); + + if (a == b) { + continue; + + } else if (a == null || b == null) { + return false; + + } else if (a instanceof String || a instanceof Short) { + if (!a.equals(b)) { + return false; + } + + } else if (a instanceof NamedNodeMap) { + if (!(b instanceof NamedNodeMap) + || !namedNodeMapsEqual((NamedNodeMap) a, (NamedNodeMap) b)) { + return false; + } + + } else if (a instanceof Node) { + if (!(b instanceof Node) + || !((Node) a).isEqualNode((Node) b)) { + return false; + } + + } else { + throw new AssertionError(); // unexpected type + } + } + + return true; + } + + private boolean namedNodeMapsEqual(NamedNodeMap a, NamedNodeMap b) { + if (a.getLength() != b.getLength()) { + return false; + } + for (int i = 0; i < a.getLength(); i++) { + Node aNode = a.item(i); + Node bNode = aNode.getLocalName() == null + ? b.getNamedItem(aNode.getNodeName()) + : b.getNamedItemNS(aNode.getNamespaceURI(), aNode.getLocalName()); + if (bNode == null || !aNode.isEqualNode(bNode)) { + return false; + } + } + return true; + } + + public final Object getFeature(String feature, String version) { + return isSupported(feature, version) ? this : null; } public Object setUserData(String key, Object data, -- cgit v1.1