diff options
5 files changed, 183 insertions, 116 deletions
diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java index fb9821288f..4c682494e3 100644 --- a/luni/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java +++ b/luni/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java @@ -43,35 +43,16 @@ public final class AttrImpl extends NodeImpl implements Attr { String prefix; String localName; - private String value; + private String value = ""; AttrImpl(DocumentImpl document, String namespaceURI, String qualifiedName) { super(document); - setNameNS(this, namespaceURI, qualifiedName); - value = ""; } AttrImpl(DocumentImpl document, String name) { super(document); - - this.namespaceAware = false; - - int prefixSeparator = name.lastIndexOf(":"); - if (prefixSeparator != -1) { - String prefix = name.substring(0, prefixSeparator); - String localName = name.substring(prefixSeparator + 1); - - if (!DocumentImpl.isXMLIdentifier(prefix) || !DocumentImpl.isXMLIdentifier(localName)) { - throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name); - } - } else { - if (!DocumentImpl.isXMLIdentifier(name)) { - throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name); - } - } - - this.localName = name; + setName(this, name); } @Override diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java index c5e4054066..75b247fa27 100644 --- a/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java +++ b/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java @@ -20,7 +20,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; -import org.w3c.dom.Attr; import org.w3c.dom.CharacterData; import org.w3c.dom.Comment; import org.w3c.dom.DOMConfiguration; @@ -129,67 +128,81 @@ public final class DocumentImpl extends InnerNodeImpl implements Document { */ private NodeImpl shallowCopy(short operation, Node node) { switch (node.getNodeType()) { - case Node.ATTRIBUTE_NODE: - Attr attr = (Attr) node; - AttrImpl attrCopy = createAttributeNS(attr.getNamespaceURI(), attr.getLocalName()); + case Node.ATTRIBUTE_NODE: + AttrImpl attr = (AttrImpl) node; + AttrImpl attrCopy; + if (attr.namespaceAware) { + attrCopy = createAttributeNS(attr.getNamespaceURI(), attr.getLocalName()); attrCopy.setPrefix(attr.getPrefix()); - attrCopy.setNodeValue(attr.getNodeValue()); - return attrCopy; + } else { + attrCopy = createAttribute(attr.getName()); + } + attrCopy.setNodeValue(attr.getValue()); + return attrCopy; - case Node.CDATA_SECTION_NODE: - return createCDATASection(((CharacterData) node).getData()); + case Node.CDATA_SECTION_NODE: + return createCDATASection(((CharacterData) node).getData()); - case Node.COMMENT_NODE: - return createComment(((Comment) node).getData()); + case Node.COMMENT_NODE: + return createComment(((Comment) node).getData()); - case Node.DOCUMENT_FRAGMENT_NODE: - return createDocumentFragment(); + case Node.DOCUMENT_FRAGMENT_NODE: + return createDocumentFragment(); - case Node.DOCUMENT_NODE: - case Node.DOCUMENT_TYPE_NODE: - throw new DOMException(DOMException.NOT_SUPPORTED_ERR, - "Cannot copy node of type " + node.getNodeType()); + case Node.DOCUMENT_NODE: + case Node.DOCUMENT_TYPE_NODE: + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Cannot copy node of type " + node.getNodeType()); - case Node.ELEMENT_NODE: - Element element = (Element) node; - ElementImpl elementCopy = createElementNS( - element.getNamespaceURI(), element.getLocalName()); + case Node.ELEMENT_NODE: + ElementImpl element = (ElementImpl) node; + ElementImpl elementCopy; + if (element.namespaceAware) { + elementCopy = createElementNS(element.getNamespaceURI(), element.getLocalName()); elementCopy.setPrefix(element.getPrefix()); - NamedNodeMap attributes = element.getAttributes(); - for (int i = 0; i < attributes.getLength(); i++) { - Node elementAttr = attributes.item(i); - AttrImpl elementAttrCopy = (AttrImpl) shallowCopy(operation, elementAttr); - notifyUserDataHandlers(operation, elementAttr, elementAttrCopy); + } else { + elementCopy = createElement(element.getTagName()); + } + + NamedNodeMap attributes = element.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + AttrImpl elementAttr = (AttrImpl) attributes.item(i); + AttrImpl elementAttrCopy = (AttrImpl) shallowCopy(operation, elementAttr); + notifyUserDataHandlers(operation, elementAttr, elementAttrCopy); + if (elementAttr.namespaceAware) { elementCopy.setAttributeNodeNS(elementAttrCopy); + } else { + elementCopy.setAttributeNode(elementAttrCopy); } - return elementCopy; - - case Node.ENTITY_NODE: - case Node.NOTATION_NODE: - // TODO: implement this when we support these node types - throw new UnsupportedOperationException(); - - case Node.ENTITY_REFERENCE_NODE: - /* - * When we support entities in the doctype, this will need to - * behave differently for clones vs. imports. Clones copy - * entities by value, copying the referenced subtree from the - * original document. Imports copy entities by reference, - * possibly referring to a different subtree in the new - * document. - */ - return createEntityReference(node.getNodeName()); - - case Node.PROCESSING_INSTRUCTION_NODE: - ProcessingInstruction pi = (ProcessingInstruction) node; - return createProcessingInstruction(pi.getTarget(), pi.getData()); - - case Node.TEXT_NODE: - return createTextNode(((Text) node).getData()); - - default: - throw new DOMException(DOMException.NOT_SUPPORTED_ERR, - "Unsupported node type " + node.getNodeType()); + } + return elementCopy; + + case Node.ENTITY_NODE: + case Node.NOTATION_NODE: + // TODO: implement this when we support these node types + throw new UnsupportedOperationException(); + + case Node.ENTITY_REFERENCE_NODE: + /* + * When we support entities in the doctype, this will need to + * behave differently for clones vs. imports. Clones copy + * entities by value, copying the referenced subtree from the + * original document. Imports copy entities by reference, + * possibly referring to a different subtree in the new + * document. + */ + return createEntityReference(node.getNodeName()); + + case Node.PROCESSING_INSTRUCTION_NODE: + ProcessingInstruction pi = (ProcessingInstruction) node; + return createProcessingInstruction(pi.getTarget(), pi.getData()); + + case Node.TEXT_NODE: + return createTextNode(((Text) node).getData()); + + default: + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Unsupported node type " + node.getNodeType()); } } diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java index eae527c9b8..370100be8c 100644 --- a/luni/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java +++ b/luni/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java @@ -53,24 +53,7 @@ public class ElementImpl extends InnerNodeImpl implements Element { ElementImpl(DocumentImpl document, String name) { super(document); - - this.namespaceAware = false; - - int p = name.lastIndexOf(":"); - if (p != -1) { - String prefix = name.substring(0, p); - String localName = name.substring(p + 1); - - if (!DocumentImpl.isXMLIdentifier(prefix) || !DocumentImpl.isXMLIdentifier(localName)) { - throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name); - } - } else { - if (!DocumentImpl.isXMLIdentifier(name)) { - throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name); - } - } - - this.localName = name; + setName(this, name); } private int indexOfAttribute(String name) { diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java index 7c26112e8d..647723de08 100644 --- a/luni/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java +++ b/luni/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java @@ -216,10 +216,10 @@ public abstract class NodeImpl implements Node { } /** - * Sets the element or attribute node to be namespace-aware and assign it - * the specified name and namespace URI. + * Sets {@code node} to be namespace-aware and assigns its namespace URI + * and qualified name. * - * @param node an AttrImpl or ElementImpl node. + * @param node an element or attribute node. * @param namespaceURI this node's namespace URI. May be null. * @param qualifiedName a possibly-prefixed name like "img" or "html:img". */ @@ -240,30 +240,66 @@ public abstract class NodeImpl implements Node { } switch (node.getNodeType()) { - case ATTRIBUTE_NODE: - if ("xmlns".equals(qualifiedName) - && !"http://www.w3.org/2000/xmlns/".equals(namespaceURI)) { - throw new DOMException(DOMException.NAMESPACE_ERR, qualifiedName); - } + case ATTRIBUTE_NODE: + if ("xmlns".equals(qualifiedName) + && !"http://www.w3.org/2000/xmlns/".equals(namespaceURI)) { + throw new DOMException(DOMException.NAMESPACE_ERR, qualifiedName); + } - AttrImpl attr = (AttrImpl) node; - attr.namespaceAware = true; - attr.namespaceURI = namespaceURI; - attr.prefix = prefix; - attr.localName = qualifiedName; - break; + AttrImpl attr = (AttrImpl) node; + attr.namespaceAware = true; + attr.namespaceURI = namespaceURI; + attr.prefix = prefix; + attr.localName = qualifiedName; + break; + + case ELEMENT_NODE: + ElementImpl element = (ElementImpl) node; + element.namespaceAware = true; + element.namespaceURI = namespaceURI; + element.prefix = prefix; + element.localName = qualifiedName; + break; + + default: + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Cannot rename nodes of type " + node.getNodeType()); + } + } - case ELEMENT_NODE: - ElementImpl element = (ElementImpl) node; - element.namespaceAware = true; - element.namespaceURI = namespaceURI; - element.prefix = prefix; - element.localName = qualifiedName; - break; + /** + * Sets {@code node} to be not namespace-aware and assigns its name. + * + * @param node an element or attribute node. + */ + static void setName(NodeImpl node, String name) { + int prefixSeparator = name.lastIndexOf(":"); + if (prefixSeparator != -1) { + String prefix = name.substring(0, prefixSeparator); + String localName = name.substring(prefixSeparator + 1); + if (!DocumentImpl.isXMLIdentifier(prefix) || !DocumentImpl.isXMLIdentifier(localName)) { + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name); + } + } else if (!DocumentImpl.isXMLIdentifier(name)) { + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name); + } - default: - throw new DOMException(DOMException.NOT_SUPPORTED_ERR, - "Cannot rename nodes of type " + node.getNodeType()); + switch (node.getNodeType()) { + case ATTRIBUTE_NODE: + AttrImpl attr = (AttrImpl) node; + attr.namespaceAware = false; + attr.localName = name; + break; + + case ELEMENT_NODE: + ElementImpl element = (ElementImpl) node; + element.namespaceAware = false; + element.localName = name; + break; + + default: + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Cannot rename nodes of type " + node.getNodeType()); } } diff --git a/luni/src/test/java/tests/xml/DomTest.java b/luni/src/test/java/tests/xml/DomTest.java index 8477676d0f..3f68d7c5be 100644 --- a/luni/src/test/java/tests/xml/DomTest.java +++ b/luni/src/test/java/tests/xml/DomTest.java @@ -805,6 +805,60 @@ public class DomTest extends TestCase { } } + public void testValueOfNewAttributesIsEmptyString() { + assertEquals("", document.createAttribute("bar").getValue()); + assertEquals("", document.createAttributeNS("http://foo", "bar").getValue()); + } + + public void testCloneNode() throws Exception { + document = builder.parse(new InputSource(new StringReader("<menu " + + "xmlns:f=\"http://food\" xmlns:a=\"http://addons\">" + + "<f:item a:standard=\"strawberry\" deluxe=\"yes\">Waffles</f:item></menu>"))); + name = (Element) document.getFirstChild().getFirstChild(); + + Element clonedName = (Element) name.cloneNode(true); + assertNull(clonedName.getParentNode()); + assertNull(clonedName.getNextSibling()); + assertNull(clonedName.getPreviousSibling()); + assertEquals("http://food", clonedName.getNamespaceURI()); + assertEquals("f:item", clonedName.getNodeName()); + assertEquals("item", clonedName.getLocalName()); + assertEquals("http://food", clonedName.getNamespaceURI()); + assertEquals("yes", clonedName.getAttribute("deluxe")); + assertEquals("strawberry", clonedName.getAttribute("a:standard")); + assertEquals("strawberry", clonedName.getAttributeNS("http://addons", "standard")); + assertEquals(1, name.getChildNodes().getLength()); + + Text clonedChild = (Text) clonedName.getFirstChild(); + assertSame(clonedName, clonedChild.getParentNode()); + assertNull(clonedChild.getNextSibling()); + assertNull(clonedChild.getPreviousSibling()); + assertEquals("Waffles", clonedChild.getTextContent()); + } + + /** + * We can't use the namespace-aware factory method for non-namespace-aware + * nodes. http://code.google.com/p/android/issues/detail?id=2735 + */ + public void testCloneNodeNotNamespaceAware() throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(false); + builder = factory.newDocumentBuilder(); + document = builder.parse(new InputSource(new StringReader("<menu " + + "xmlns:f=\"http://food\" xmlns:a=\"http://addons\">" + + "<f:item a:standard=\"strawberry\" deluxe=\"yes\">Waffles</f:item></menu>"))); + name = (Element) document.getFirstChild().getFirstChild(); + + Element clonedName = (Element) name.cloneNode(true); + assertNull(clonedName.getNamespaceURI()); + assertEquals("f:item", clonedName.getNodeName()); + assertNull(clonedName.getLocalName()); + assertNull(clonedName.getNamespaceURI()); + assertEquals("yes", clonedName.getAttribute("deluxe")); + assertEquals("strawberry", clonedName.getAttribute("a:standard")); + assertEquals("", clonedName.getAttributeNS("http://addons", "standard")); + } + /** * A shallow clone requires cloning the attributes but not the child nodes. */ |
