1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License.
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.xml.dom;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilsonimport java.net.URI;
20f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilsonimport java.net.URISyntaxException;
217365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.util.ArrayList;
227365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.util.List;
237365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.util.Map;
241ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilsonimport org.w3c.dom.Attr;
25ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilsonimport org.w3c.dom.CharacterData;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.DOMException;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Document;
2835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilsonimport org.w3c.dom.Element;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.NamedNodeMap;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Node;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.NodeList;
32ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilsonimport org.w3c.dom.ProcessingInstruction;
335b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilsonimport org.w3c.dom.TypeInfo;
34320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport org.w3c.dom.UserDataHandler;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
371ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson * A straightforward implementation of the corresponding W3C DOM node.
381ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson *
391ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson * <p>Some fields have package visibility so other classes can access them while
401ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson * maintaining the DOM structure.
411ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson *
421ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson * <p>This class represents a Node that has neither a parent nor children.
431ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson * Subclasses may have either.
441ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson *
451ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson * <p>Some code was adapted from Apache Xerces.
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class NodeImpl implements Node {
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final NodeList EMPTY_LIST = new NodeListImpl();
505b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson
515b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson    static final TypeInfo NULL_TYPE_INFO = new TypeInfo() {
525b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson        public String getTypeName() {
535b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson            return null;
545b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson        }
555b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson        public String getTypeNamespace() {
565b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson            return null;
575b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson        }
585b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson        public boolean isDerivedFrom(
595b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson                String typeNamespaceArg, String typeNameArg, int derivationMethod) {
605b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson            return false;
615b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson        }
625b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson    };
635b6729bd043431bc17f5684fe3b0f5c93b54f76bJesse Wilson
6409c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson    /**
6509c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson     * The containing document. This is non-null except for DocumentTypeImpl
6609c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson     * nodes created by the DOMImplementation.
6709c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson     */
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    DocumentImpl document;
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    NodeImpl(DocumentImpl document) {
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.document = document;
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node appendChild(Node newChild) throws DOMException {
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
78df138faff880612d97a8e6e3fa344a91ae9d96acJesse Wilson    public final Node cloneNode(boolean deep) {
79df138faff880612d97a8e6e3fa344a91ae9d96acJesse Wilson        return document.cloneOrImportNode(UserDataHandler.NODE_CLONED, this, deep);
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public NamedNodeMap getAttributes() {
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public NodeList getChildNodes() {
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return EMPTY_LIST;
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node getFirstChild() {
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node getLastChild() {
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getLocalName() {
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getNamespaceURI() {
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node getNextSibling() {
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getNodeName() {
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public abstract short getNodeType();
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getNodeValue() throws DOMException {
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1208b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson    public final Document getOwnerDocument() {
1218b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        return document == this ? null : document;
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node getParentNode() {
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getPrefix() {
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node getPreviousSibling() {
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean hasAttributes() {
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return false;
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean hasChildNodes() {
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return false;
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node insertBefore(Node newChild, Node refChild) throws DOMException {
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean isSupported(String feature, String version) {
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return DOMImplementationImpl.getInstance().hasFeature(feature, version);
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void normalize() {
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node removeChild(Node oldChild) throws DOMException {
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
163ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson    public final void setNodeValue(String nodeValue) throws DOMException {
164ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson        switch (getNodeType()) {
165ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case CDATA_SECTION_NODE:
166ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case COMMENT_NODE:
167ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case TEXT_NODE:
168ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson                ((CharacterData) this).setData(nodeValue);
169ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson                return;
170ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson
171ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case PROCESSING_INSTRUCTION_NODE:
172ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson                ((ProcessingInstruction) this).setData(nodeValue);
173ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson                return;
174ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson
175ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case ATTRIBUTE_NODE:
176ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson                ((Attr) this).setValue(nodeValue);
177ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson                return;
178ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson
179ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case ELEMENT_NODE:
180ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case ENTITY_REFERENCE_NODE:
181ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case ENTITY_NODE:
182ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case DOCUMENT_NODE:
183ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case DOCUMENT_TYPE_NODE:
184ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case DOCUMENT_FRAGMENT_NODE:
185ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            case NOTATION_NODE:
186ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson                return; // do nothing!
187ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson
188ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson            default:
189ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
190ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson                        "Unsupported node type " + getNodeType());
191ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson        }
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setPrefix(String prefix) throws DOMException {
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1981ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * Validates the element or attribute namespace prefix on this node.
1991ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     *
2001ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * @param namespaceAware whether this node is namespace aware
2011ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * @param namespaceURI this node's namespace URI
2021ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     */
203503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson    static String validatePrefix(String prefix, boolean namespaceAware, String namespaceURI) {
2041ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        if (!namespaceAware) {
2051ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
2061ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        }
2071ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
2081ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        if (prefix != null) {
2091ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            if (namespaceURI == null
2101ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    || !DocumentImpl.isXMLIdentifier(prefix)
2111ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    || "xml".equals(prefix) && !"http://www.w3.org/XML/1998/namespace".equals(namespaceURI)
2121ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    || "xmlns".equals(prefix) && !"http://www.w3.org/2000/xmlns/".equals(namespaceURI)) {
2131ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                throw new DOMException(DOMException.NAMESPACE_ERR, prefix);
2141ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            }
2151ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        }
2161ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
2171ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        return prefix;
2181ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    }
2191ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
2201ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    /**
2219c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson     * Sets {@code node} to be namespace-aware and assigns its namespace URI
2229c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson     * and qualified name.
223503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson     *
2249c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson     * @param node an element or attribute node.
225503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson     * @param namespaceURI this node's namespace URI. May be null.
226503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson     * @param qualifiedName a possibly-prefixed name like "img" or "html:img".
227503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson     */
228503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson    static void setNameNS(NodeImpl node, String namespaceURI, String qualifiedName) {
229503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        if (qualifiedName == null) {
230503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson            throw new DOMException(DOMException.NAMESPACE_ERR, qualifiedName);
231503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        }
232503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson
233503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        String prefix = null;
234503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        int p = qualifiedName.lastIndexOf(":");
235503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        if (p != -1) {
236503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson            prefix = validatePrefix(qualifiedName.substring(0, p), true, namespaceURI);
237503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson            qualifiedName = qualifiedName.substring(p + 1);
238503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        }
239503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson
240503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        if (!DocumentImpl.isXMLIdentifier(qualifiedName)) {
241503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, qualifiedName);
242503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        }
243503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson
244503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        switch (node.getNodeType()) {
2459c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        case ATTRIBUTE_NODE:
2469c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            if ("xmlns".equals(qualifiedName)
2479c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson                    && !"http://www.w3.org/2000/xmlns/".equals(namespaceURI)) {
2489c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson                throw new DOMException(DOMException.NAMESPACE_ERR, qualifiedName);
2499c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            }
250503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson
2519c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            AttrImpl attr = (AttrImpl) node;
2529c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            attr.namespaceAware = true;
2539c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            attr.namespaceURI = namespaceURI;
2549c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            attr.prefix = prefix;
2559c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            attr.localName = qualifiedName;
2569c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            break;
2579c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson
2589c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        case ELEMENT_NODE:
2599c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            ElementImpl element = (ElementImpl) node;
2609c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            element.namespaceAware = true;
2619c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            element.namespaceURI = namespaceURI;
2629c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            element.prefix = prefix;
2639c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            element.localName = qualifiedName;
2649c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            break;
2659c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson
2669c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        default:
2679c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
2689c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson                    "Cannot rename nodes of type " + node.getNodeType());
2699c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        }
2709c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson    }
271503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson
2729c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson    /**
2739c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson     * Sets {@code node} to be not namespace-aware and assigns its name.
2749c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson     *
2759c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson     * @param node an element or attribute node.
2769c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson     */
2779c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson    static void setName(NodeImpl node, String name) {
2789c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        int prefixSeparator = name.lastIndexOf(":");
2799c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        if (prefixSeparator != -1) {
2809c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            String prefix = name.substring(0, prefixSeparator);
2819c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            String localName = name.substring(prefixSeparator + 1);
2829c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            if (!DocumentImpl.isXMLIdentifier(prefix) || !DocumentImpl.isXMLIdentifier(localName)) {
2839c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson                throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
2849c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            }
2859c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        } else if (!DocumentImpl.isXMLIdentifier(name)) {
2869c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            throw new DOMException(DOMException.INVALID_CHARACTER_ERR, name);
2879c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        }
2889c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson
2899c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        switch (node.getNodeType()) {
2909c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        case ATTRIBUTE_NODE:
2919c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            AttrImpl attr = (AttrImpl) node;
2929c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            attr.namespaceAware = false;
2939c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            attr.localName = name;
2949c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            break;
2959c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson
2969c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        case ELEMENT_NODE:
2979c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            ElementImpl element = (ElementImpl) node;
2989c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            element.namespaceAware = false;
2999c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            element.localName = name;
3009c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            break;
3019c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson
3029c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson        default:
3039c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson            throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
3049c075bb3e84c6eaafd016cbc1bf69a6e989eedf3Jesse Wilson                    "Cannot rename nodes of type " + node.getNodeType());
305503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson        }
306503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson    }
307503917e646b5ebd3f23dfe0cb41270cfe484693aJesse Wilson
308302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson    public final String getBaseURI() {
309302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson        switch (getNodeType()) {
310302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case DOCUMENT_NODE:
311302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                return sanitizeUri(((Document) this).getDocumentURI());
312302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson
313302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case ELEMENT_NODE:
314302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                Element element = (Element) this;
315302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                String uri = element.getAttributeNS(
316302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                        "http://www.w3.org/XML/1998/namespace", "base"); // or "xml:base"
317302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson
318302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                try {
319f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    // if this node has no base URI, return the parent's.
320f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    if (uri == null || uri.isEmpty()) {
321f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                        return getParentBaseUri();
322f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    }
323f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson
324f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    // if this node's URI is absolute, return it
325f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    if (new URI(uri).isAbsolute()) {
326f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                        return uri;
327f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    }
328f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson
329f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    // this node has a relative URI. Try to resolve it against the
330f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    // parent, but if that doesn't work just give up and return null.
331f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    String parentUri = getParentBaseUri();
332f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    if (parentUri == null) {
333f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                        return null;
334f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    }
335f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson
336f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    return new URI(parentUri).resolve(uri).toString();
337f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                } catch (URISyntaxException e) {
338f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson                    return null;
339302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                }
340302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson
341302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case PROCESSING_INSTRUCTION_NODE:
342302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                return getParentBaseUri();
343302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson
344302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case NOTATION_NODE:
345302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case ENTITY_NODE:
346302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                // When we support these node types, the parser should
347302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                // initialize a base URI field on these nodes.
348302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                return null;
349302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson
350302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case ENTITY_REFERENCE_NODE:
351302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                // TODO: get this value from the parser, falling back to the
352302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                // referenced entity's baseURI if that doesn't exist
353302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                return null;
354302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson
355302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case DOCUMENT_TYPE_NODE:
356302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case DOCUMENT_FRAGMENT_NODE:
357302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case ATTRIBUTE_NODE:
358302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case TEXT_NODE:
359302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case CDATA_SECTION_NODE:
360302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            case COMMENT_NODE:
361302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                return null;
362302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson
363302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            default:
364302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
365302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson                        "Unsupported node type " + getNodeType());
366302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson        }
367302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson    }
368302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson
369302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson    private String getParentBaseUri() {
370302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson        Node parentNode = getParentNode();
371302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson        return parentNode != null ? parentNode.getBaseURI() : null;
372302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson    }
373302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson
374302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson    /**
375302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson     * Returns the sanitized input if it is a URI, or {@code null} otherwise.
376302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson     */
377302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson    private String sanitizeUri(String uri) {
378302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson        if (uri == null || uri.length() == 0) {
379302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            return null;
380302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson        }
381302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson        try {
382302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            return new URI(uri).toString();
383f029395dff382fc4dcba0689fd948ec06644e1f0Jesse Wilson        } catch (URISyntaxException e) {
384302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson            return null;
385302f069f38e7890594816ceab517c15bcd59a9b7Jesse Wilson        }
386320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
387320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
388320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public short compareDocumentPosition(Node other)
389320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throws DOMException {
390320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        throw new UnsupportedOperationException(); // TODO
391320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
392320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
393320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public String getTextContent() throws DOMException {
3942e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        return getNodeValue();
3952e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson    }
3962e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson
3972e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson    void getTextContent(StringBuilder buf) throws DOMException {
3982e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        String content = getNodeValue();
3992e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        if (content != null) {
4002e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson            buf.append(content);
4012e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        }
402320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
403320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
404ea5adee4813216359fda6529e7064c42ccdbc4cdJesse Wilson    public final void setTextContent(String textContent) throws DOMException {
4051ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        switch (getNodeType()) {
4061ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case DOCUMENT_TYPE_NODE:
4071ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case DOCUMENT_NODE:
4081ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return; // do nothing!
4091ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4101ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case ELEMENT_NODE:
4111ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case ENTITY_NODE:
4121ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case ENTITY_REFERENCE_NODE:
4131ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case DOCUMENT_FRAGMENT_NODE:
4141ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                // remove all existing children
4151ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                Node child;
4161ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                while ((child = getFirstChild()) != null) {
4171ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    removeChild(child);
4181ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                }
4191ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                // create a text node to hold the given content
420bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                if (textContent != null && textContent.length() != 0) {
4218b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson                    appendChild(document.createTextNode(textContent));
4221ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                }
4231ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return;
4241ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4251ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case ATTRIBUTE_NODE:
4261ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case TEXT_NODE:
4271ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case CDATA_SECTION_NODE:
4281ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case PROCESSING_INSTRUCTION_NODE:
4291ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case COMMENT_NODE:
4301ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case NOTATION_NODE:
4311ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                setNodeValue(textContent);
4321ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return;
4331ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4341ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            default:
4351ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
4361ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                        "Unsupported node type " + getNodeType());
4371ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        }
438320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
439320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
440320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public boolean isSameNode(Node other) {
4411ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        return this == other;
442320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
443320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
4441ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    /**
4451ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * Returns the element whose namespace definitions apply to this node. Use
4461ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * this element when mapping prefixes to URIs and vice versa.
4471ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     */
4481ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    private NodeImpl getNamespacingElement() {
4491ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        switch (this.getNodeType()) {
4501ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case ELEMENT_NODE:
4511ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return this;
4521ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4531ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case DOCUMENT_NODE:
4541ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return (NodeImpl) ((Document) this).getDocumentElement();
4551ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4561ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case ENTITY_NODE:
4571ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case NOTATION_NODE:
4581ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case DOCUMENT_FRAGMENT_NODE:
4591ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case DOCUMENT_TYPE_NODE:
4601ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return null;
4611ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4621ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case ATTRIBUTE_NODE:
4631ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return (NodeImpl) ((Attr) this).getOwnerElement();
4641ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4651ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case TEXT_NODE:
4661ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case CDATA_SECTION_NODE:
4671ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case ENTITY_REFERENCE_NODE:
4681ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case PROCESSING_INSTRUCTION_NODE:
4691ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            case COMMENT_NODE:
4701ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return getContainingElement();
4711ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4721ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            default:
4731ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
4741ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                        "Unsupported node type " + getNodeType());
4751ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        }
4761ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    }
4771ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4781ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    /**
4791ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * Returns the nearest ancestor element that contains this node.
4801ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     */
4811ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    private NodeImpl getContainingElement() {
4821ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        for (Node p = getParentNode(); p != null; p = p.getParentNode()) {
4831ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            if (p.getNodeType() == ELEMENT_NODE) {
4841ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return (NodeImpl) p;
4851ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            }
4861ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        }
4871ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        return null;
4881ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    }
4891ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4901ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    public final String lookupPrefix(String namespaceURI) {
4911ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        if (namespaceURI == null) {
4921ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            return null;
4931ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        }
4941ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4951ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        // the XML specs define some prefixes (like "xml" and "xmlns") but this
4961ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        // API is explicitly defined to ignore those.
4971ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
4981ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        NodeImpl target = getNamespacingElement();
4991ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        for (NodeImpl node = target; node != null; node = node.getContainingElement()) {
5001ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            // check this element's namespace first
5011ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            if (namespaceURI.equals(node.getNamespaceURI())
5021ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    && target.isPrefixMappedToUri(node.getPrefix(), namespaceURI)) {
5031ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                return node.getPrefix();
5041ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            }
5051ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
5061ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            // search this element for an attribute of this form:
5071ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            //   xmlns:foo="http://namespaceURI"
5081ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            if (!node.hasAttributes()) {
5091ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                continue;
5101ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            }
5111ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            NamedNodeMap attributes = node.getAttributes();
5121ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            for (int i = 0, length = attributes.getLength(); i < length; i++) {
5131ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                Node attr = attributes.item(i);
5141ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                if (!"http://www.w3.org/2000/xmlns/".equals(attr.getNamespaceURI())
5151ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                        || !"xmlns".equals(attr.getPrefix())
5161ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                        || !namespaceURI.equals(attr.getNodeValue())) {
5171ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    continue;
5181ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                }
5191ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                if (target.isPrefixMappedToUri(attr.getLocalName(), namespaceURI)) {
5201ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    return attr.getLocalName();
5211ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                }
5221ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            }
5231ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        }
5241ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
5251ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        return null;
5261ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    }
5271ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
5281ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    /**
5291ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * Returns true if the given prefix is mapped to the given URI on this
5301ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * element. Since child elements can redefine prefixes, this check is
5311ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * necessary: {@code
5321ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * <foo xmlns:a="http://good">
5331ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     *   <bar xmlns:a="http://evil">
5341ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     *     <a:baz />
5351ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     *   </bar>
5361ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * </foo>}
5371ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     *
5381ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * @param prefix the prefix to find. Nullable.
5391ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     * @param uri the URI to match. Non-null.
5401ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson     */
5411ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    boolean isPrefixMappedToUri(String prefix, String uri) {
5421ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        if (prefix == null) {
5431ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            return false;
5441ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        }
5451ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
5461ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        String actual = lookupNamespaceURI(prefix);
5471ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        return uri.equals(actual);
548320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
549320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
55035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson    public final boolean isDefaultNamespace(String namespaceURI) {
55135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        String actual = lookupNamespaceURI(null); // null yields the default namespace
55235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        return namespaceURI == null
55335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                ? actual == null
55435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                : namespaceURI.equals(actual);
555320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
556320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
5571ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson    public final String lookupNamespaceURI(String prefix) {
5581ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        NodeImpl target = getNamespacingElement();
5591ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        for (NodeImpl node = target; node != null; node = node.getContainingElement()) {
5601ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            // check this element's namespace first
5611ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            String nodePrefix = node.getPrefix();
5621ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            if (node.getNamespaceURI() != null) {
5631ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                if (prefix == null // null => default prefix
5641ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                        ? nodePrefix == null
5651ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                        : prefix.equals(nodePrefix)) {
5661ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    return node.getNamespaceURI();
5671ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                }
5681ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            }
5691ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
5701ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            // search this element for an attribute of the appropriate form.
5711ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            //    default namespace: xmlns="http://resultUri"
5721ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            //          non default: xmlns:specifiedPrefix="http://resultUri"
5731ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            if (!node.hasAttributes()) {
5741ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                continue;
5751ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            }
5761ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            NamedNodeMap attributes = node.getAttributes();
5771ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            for (int i = 0, length = attributes.getLength(); i < length; i++) {
5781ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                Node attr = attributes.item(i);
5791ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                if (!"http://www.w3.org/2000/xmlns/".equals(attr.getNamespaceURI())) {
5801ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    continue;
5811ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                }
5821ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                if (prefix == null // null => default prefix
5831ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                        ? "xmlns".equals(attr.getNodeName())
5841ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                        : "xmlns".equals(attr.getPrefix()) && prefix.equals(attr.getLocalName())) {
5851ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    String value = attr.getNodeValue();
5861ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                    return value.length() > 0 ? value : null;
5871ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson                }
5881ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson            }
5891ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        }
5901ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson
5911ec94feeb09591c30996c7c0834d6f131e204922Jesse Wilson        return null;
592320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
593320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
59435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson    /**
59535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson     * Returns a list of objects such that two nodes are equal if their lists
59635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson     * are equal. Be careful: the lists may contain NamedNodeMaps and Nodes,
59735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson     * neither of which override Object.equals(). Such values must be compared
59835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson     * manually.
59935d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson     */
60035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson    private static List<Object> createEqualityKey(Node node) {
60135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        List<Object> values = new ArrayList<Object>();
60235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        values.add(node.getNodeType());
60335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        values.add(node.getNodeName());
60435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        values.add(node.getLocalName());
60535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        values.add(node.getNamespaceURI());
60635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        values.add(node.getPrefix());
60735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        values.add(node.getNodeValue());
60835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
60935d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            values.add(child);
61035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        }
61135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
61235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        switch (node.getNodeType()) {
61335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            case DOCUMENT_TYPE_NODE:
61435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                DocumentTypeImpl doctype = (DocumentTypeImpl) node;
61535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                values.add(doctype.getPublicId());
61635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                values.add(doctype.getSystemId());
61735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                values.add(doctype.getInternalSubset());
61835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                values.add(doctype.getEntities());
61935d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                values.add(doctype.getNotations());
62035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                break;
62135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
62235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            case ELEMENT_NODE:
62335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                Element element = (Element) node;
62435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                values.add(element.getAttributes());
62535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                break;
62635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        }
62735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
62835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        return values;
629320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
630320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
63135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson    public final boolean isEqualNode(Node arg) {
63235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        if (arg == this) {
63335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            return true;
63435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        }
63535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
63635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        List<Object> listA = createEqualityKey(this);
63735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        List<Object> listB = createEqualityKey(arg);
63835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
63935d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        if (listA.size() != listB.size()) {
64035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            return false;
64135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        }
64235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
64335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        for (int i = 0; i < listA.size(); i++) {
64435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            Object a = listA.get(i);
64535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            Object b = listB.get(i);
64635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
64735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            if (a == b) {
64835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                continue;
64935d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
65035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            } else if (a == null || b == null) {
65135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                return false;
65235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
65335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            } else if (a instanceof String || a instanceof Short) {
65435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                if (!a.equals(b)) {
65535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                    return false;
65635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                }
65735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
65835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            } else if (a instanceof NamedNodeMap) {
65935d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                if (!(b instanceof NamedNodeMap)
66035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                        || !namedNodeMapsEqual((NamedNodeMap) a, (NamedNodeMap) b)) {
66135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                    return false;
66235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                }
66335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
66435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            } else if (a instanceof Node) {
66535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                if (!(b instanceof Node)
66635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                        || !((Node) a).isEqualNode((Node) b)) {
66735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                    return false;
66835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                }
66935d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
67035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            } else {
67135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                throw new AssertionError(); // unexpected type
67235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            }
67335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        }
674f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
67535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        return true;
67635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson    }
67735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
67835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson    private boolean namedNodeMapsEqual(NamedNodeMap a, NamedNodeMap b) {
67935d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        if (a.getLength() != b.getLength()) {
68035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            return false;
68135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        }
68235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        for (int i = 0; i < a.getLength(); i++) {
68335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            Node aNode = a.item(i);
68435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            Node bNode = aNode.getLocalName() == null
68535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                    ? b.getNamedItem(aNode.getNodeName())
68635d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                    : b.getNamedItemNS(aNode.getNamespaceURI(), aNode.getLocalName());
68735d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            if (bNode == null || !aNode.isEqualNode(bNode)) {
68835d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson                return false;
68935d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson            }
69035d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        }
69135d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        return true;
69235d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson    }
69335d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson
69435d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson    public final Object getFeature(String feature, String version) {
69535d7c089bd45f1030407b9b69b46e66f02c03043Jesse Wilson        return isSupported(feature, version) ? this : null;
696320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
697320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
6988b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson    public final Object setUserData(String key, Object data, UserDataHandler handler) {
6998b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        if (key == null) {
70086acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("key == null");
7018b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        }
7028b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        Map<String, UserData> map = document.getUserDataMap(this);
7038b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        UserData previous = data == null
7048b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson                ? map.remove(key)
7058b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson                : map.put(key, new UserData(data, handler));
7068b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        return previous != null ? previous.value : null;
707320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
708320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
7098b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson    public final Object getUserData(String key) {
7108b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        if (key == null) {
71186acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("key == null");
7128b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        }
7138b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        Map<String, UserData> map = document.getUserDataMapForRead(this);
7148b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        UserData userData = map.get(key);
7158b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        return userData != null ? userData.value : null;
7168b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson    }
7178b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson
7188b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson    static class UserData {
7198b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        final Object value;
7208b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        final UserDataHandler handler;
7218b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        UserData(Object value, UserDataHandler handler) {
7228b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson            this.value = value;
7238b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson            this.handler = handler;
7248b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        }
725320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
727