summaryrefslogtreecommitdiffstats
path: root/xml
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2010-02-20 11:11:40 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-02-20 11:11:40 -0800
commit5266a158422ee13eefc577f82b50fa0e4f36e381 (patch)
tree7c5a73feba8848b33b14140b6d6da48d3fc99e10 /xml
parent67cc34b75c18ae7d02c90282cb8616b82e1d8fcb (diff)
parent35d7c089bd45f1030407b9b69b46e66f02c03043 (diff)
downloadlibcore-5266a158422ee13eefc577f82b50fa0e4f36e381.zip
libcore-5266a158422ee13eefc577f82b50fa0e4f36e381.tar.gz
libcore-5266a158422ee13eefc577f82b50fa0e4f36e381.tar.bz2
Merge "More XML DOM v3 APIs."
Diffstat (limited to 'xml')
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java23
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java5
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java115
-rw-r--r--xml/src/test/java/tests/xml/DomTest.java195
4 files changed, 324 insertions, 14 deletions
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<Object> createEqualityKey(Node node) {
+ List<Object> values = new ArrayList<Object>();
+ 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<Object> listA = createEqualityKey(this);
+ List<Object> 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,
diff --git a/xml/src/test/java/tests/xml/DomTest.java b/xml/src/test/java/tests/xml/DomTest.java
index 566b1f0..5f0a19a 100644
--- a/xml/src/test/java/tests/xml/DomTest.java
+++ b/xml/src/test/java/tests/xml/DomTest.java
@@ -21,6 +21,7 @@ import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
@@ -52,6 +53,7 @@ public class DomTest extends TestCase {
private Transformer transformer;
private DocumentBuilder builder;
+ private DOMImplementation domImplementation;
private final String xml
= "<!DOCTYPE menu ["
@@ -106,6 +108,7 @@ public class DomTest extends TestCase {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
builder = factory.newDocumentBuilder();
+ domImplementation = builder.getDOMImplementation();
document = builder.parse(new InputSource(new StringReader(xml)));
@@ -319,6 +322,79 @@ public class DomTest extends TestCase {
assertEquals("a", vitamincText.lookupPrefix("http://usda"));
}
+ public void testIsDefaultNamespace() {
+ assertFalse(document.isDefaultNamespace("http://food"));
+ assertFalse(doctype.isDefaultNamespace("http://food"));
+ if (sp != null) {
+ assertFalse(sp.isDefaultNamespace("http://food"));
+ }
+ if (png != null) {
+ assertFalse(png.isDefaultNamespace("http://food"));
+ }
+ assertFalse(menu.isDefaultNamespace("http://food"));
+ assertTrue(item.isDefaultNamespace("http://food"));
+ assertTrue(itemXmlns.isDefaultNamespace("http://food"));
+ assertTrue(itemXmlnsA.isDefaultNamespace("http://food"));
+ assertTrue(name.isDefaultNamespace("http://food"));
+ assertTrue(standard.isDefaultNamespace("http://food"));
+ assertTrue(deluxe.isDefaultNamespace("http://food"));
+ assertFalse(description.isDefaultNamespace("http://food"));
+ assertFalse(descriptionText1.isDefaultNamespace("http://food"));
+ assertFalse(descriptionText2.isDefaultNamespace("http://food"));
+ assertFalse(descriptionText3.isDefaultNamespace("http://food"));
+ assertTrue(option1.isDefaultNamespace("http://food"));
+ assertTrue(option2.isDefaultNamespace("http://food"));
+ assertTrue(option2Reference.isDefaultNamespace("http://food"));
+ assertTrue(wafflemaker.isDefaultNamespace("http://food"));
+ assertTrue(nutrition.isDefaultNamespace("http://food"));
+ assertTrue(vitamins.isDefaultNamespace("http://food"));
+ assertTrue(vitaminsXmlnsA.isDefaultNamespace("http://food"));
+ assertTrue(comment.isDefaultNamespace("http://food"));
+ assertTrue(vitaminc.isDefaultNamespace("http://food"));
+ assertTrue(vitamincText.isDefaultNamespace("http://food"));
+ }
+
+ /**
+ * Xerces fails this test. It returns false always for entity, notation,
+ * document fragment and document type nodes. This contradicts its own
+ * behaviour on lookupNamespaceURI(null).
+ */
+ public void testIsDefaultNamespaceNull_XercesBugs() {
+ String message = "isDefaultNamespace() should be consistent with lookupNamespaceURI(null)";
+ assertTrue(message, doctype.isDefaultNamespace(null));
+ if (sp != null) {
+ assertTrue(message, sp.isDefaultNamespace(null));
+ }
+ if (png != null) {
+ assertTrue(message, png.isDefaultNamespace(null));
+ }
+ }
+
+ public void testIsDefaultNamespaceNull() {
+ assertTrue(document.isDefaultNamespace(null));
+ assertTrue(menu.isDefaultNamespace(null));
+ assertFalse(item.isDefaultNamespace(null));
+ assertFalse(itemXmlns.isDefaultNamespace(null));
+ assertFalse(itemXmlnsA.isDefaultNamespace(null));
+ assertFalse(name.isDefaultNamespace(null));
+ assertFalse(standard.isDefaultNamespace(null));
+ assertFalse(deluxe.isDefaultNamespace(null));
+ assertFalse(description.isDefaultNamespace(null));
+ assertFalse(descriptionText1.isDefaultNamespace(null));
+ assertFalse(descriptionText2.isDefaultNamespace(null));
+ assertFalse(descriptionText3.isDefaultNamespace(null));
+ assertFalse(option1.isDefaultNamespace(null));
+ assertFalse(option2.isDefaultNamespace(null));
+ assertFalse(option2Reference.isDefaultNamespace(null));
+ assertFalse(wafflemaker.isDefaultNamespace(null));
+ assertFalse(nutrition.isDefaultNamespace(null));
+ assertFalse(vitamins.isDefaultNamespace(null));
+ assertFalse(vitaminsXmlnsA.isDefaultNamespace(null));
+ assertFalse(comment.isDefaultNamespace(null));
+ assertFalse(vitaminc.isDefaultNamespace(null));
+ assertFalse(vitamincText.isDefaultNamespace(null));
+ }
+
public void testDoctypeSetTextContent() throws TransformerException {
String original = domToString(document);
doctype.setTextContent("foobar"); // strangely, this is specified to no-op
@@ -419,6 +495,125 @@ public class DomTest extends TestCase {
assertEquals(expected, domToString(document));
}
+ public void testCoreFeature() {
+ assertTrue(domImplementation.hasFeature("Core", null));
+ assertTrue(domImplementation.hasFeature("Core", ""));
+ assertTrue(domImplementation.hasFeature("Core", "1.0"));
+ assertTrue(domImplementation.hasFeature("Core", "2.0"));
+ assertTrue(domImplementation.hasFeature("Core", "3.0"));
+ assertTrue(domImplementation.hasFeature("CORE", "3.0"));
+ assertTrue(domImplementation.hasFeature("+Core", "3.0"));
+ assertFalse(domImplementation.hasFeature("Core", "4.0"));
+ }
+
+ public void testXmlFeature() {
+ assertTrue(domImplementation.hasFeature("XML", null));
+ assertTrue(domImplementation.hasFeature("XML", ""));
+ assertTrue(domImplementation.hasFeature("XML", "1.0"));
+ assertTrue(domImplementation.hasFeature("XML", "2.0"));
+ assertTrue(domImplementation.hasFeature("XML", "3.0"));
+ assertTrue(domImplementation.hasFeature("Xml", "3.0"));
+ assertTrue(domImplementation.hasFeature("+XML", "3.0"));
+ assertFalse(domImplementation.hasFeature("XML", "4.0"));
+ }
+
+ /**
+ * The RI fails this test.
+ * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Document3-version
+ */
+ public void testXmlVersionFeature() {
+ String message = "This implementation does not support the XMLVersion feature";
+ assertTrue(message, domImplementation.hasFeature("XMLVersion", null));
+ assertTrue(message, domImplementation.hasFeature("XMLVersion", ""));
+ assertTrue(message, domImplementation.hasFeature("XMLVersion", "1.0"));
+ assertTrue(message, domImplementation.hasFeature("XMLVersion", "1.1"));
+ assertTrue(message, domImplementation.hasFeature("XMLVERSION", "1.1"));
+ assertTrue(message, domImplementation.hasFeature("+XMLVersion", "1.1"));
+ assertFalse(domImplementation.hasFeature("XMLVersion", "1.2"));
+ assertFalse(domImplementation.hasFeature("XMLVersion", "2.0"));
+ assertFalse(domImplementation.hasFeature("XMLVersion", "2.0"));
+ }
+
+ public void testLsFeature() {
+ assertTrue("This implementation does not support the LS feature",
+ domImplementation.hasFeature("LS", "3.0"));
+ }
+
+ public void testElementTraversalFeature() {
+ assertTrue("This implementation does not support the ElementTraversal feature",
+ domImplementation.hasFeature("ElementTraversal", "1.0"));
+ }
+
+ public void testIsSupported() {
+ // we don't independently test the features; instead just assume the
+ // implementation calls through to hasFeature (as tested above)
+ for (Node node : allNodes) {
+ assertTrue(node.isSupported("XML", null));
+ assertTrue(node.isSupported("XML", "3.0"));
+ assertFalse(node.isSupported("foo", null));
+ assertFalse(node.isSupported("foo", "bar"));
+ }
+ }
+
+ public void testGetFeature() {
+ // we don't independently test the features; instead just assume the
+ // implementation calls through to hasFeature (as tested above)
+ for (Node node : allNodes) {
+ assertSame(node, node.getFeature("XML", null));
+ assertSame(node, node.getFeature("XML", "3.0"));
+ assertNull(node.getFeature("foo", null));
+ assertNull(node.getFeature("foo", "bar"));
+ }
+ }
+
+ public void testNodeEqualsPositive() throws Exception {
+ DomTest copy = new DomTest();
+ copy.setUp();
+
+ for (int i = 0; i < allNodes.size(); i++) {
+ Node a = allNodes.get(i);
+ Node b = copy.allNodes.get(i);
+ assertTrue(a.isEqualNode(b));
+ }
+ }
+
+ public void testNodeEqualsNegative() throws Exception {
+ for (Node a : allNodes) {
+ for (Node b : allNodes) {
+ assertEquals(a == b, a.isEqualNode(b));
+ }
+ }
+ }
+
+ public void testNodeEqualsNegativeRecursive() throws Exception {
+ DomTest copy = new DomTest();
+ copy.setUp();
+ copy.vitaminc.setTextContent("55%");
+
+ // changing anything about a node should break equality for all parents
+ assertFalse(document.isEqualNode(copy.document));
+ assertFalse(menu.isEqualNode(copy.menu));
+ assertFalse(item.isEqualNode(copy.item));
+ assertFalse(nutrition.isEqualNode(copy.nutrition));
+ assertFalse(vitamins.isEqualNode(copy.vitamins));
+ assertFalse(vitaminc.isEqualNode(copy.vitaminc));
+
+ // but not siblings
+ assertTrue(doctype.isEqualNode(copy.doctype));
+ assertTrue(description.isEqualNode(copy.description));
+ assertTrue(option1.isEqualNode(copy.option1));
+ }
+
+ public void testNodeEqualsNull() {
+ for (Node node : allNodes) {
+ try {
+ node.isEqualNode(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ }
+ }
+
private String domToString(Document document)
throws TransformerException {
StringWriter writer = new StringWriter();