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
197365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.util.ArrayList;
207365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.util.List;
216186821cb13f4ac7ff50950c813394367e021eaeJesse Wilsonimport libcore.util.Objects;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.DOMException;
235c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilsonimport org.w3c.dom.DocumentFragment;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Node;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.NodeList;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Provides a straightforward implementation of the corresponding W3C DOM
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * interface. The class is used internally only, thus only notable members that
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * are not in the original interface are documented (the W3C docs are quite
312f4bbf1068869f45783608450731f83c523ded30Jesse Wilson * extensive).
322f4bbf1068869f45783608450731f83c523ded30Jesse Wilson *
332f4bbf1068869f45783608450731f83c523ded30Jesse Wilson * <p>Some of the fields may have package visibility, so other classes belonging
342f4bbf1068869f45783608450731f83c523ded30Jesse Wilson * to the DOM implementation can easily access them while maintaining the DOM
352f4bbf1068869f45783608450731f83c523ded30Jesse Wilson * tree structure.
362f4bbf1068869f45783608450731f83c523ded30Jesse Wilson *
372f4bbf1068869f45783608450731f83c523ded30Jesse Wilson * <p>This class represents a Node that has a parent Node as well as
382f4bbf1068869f45783608450731f83c523ded30Jesse Wilson * (potentially) a number of children.
392f4bbf1068869f45783608450731f83c523ded30Jesse Wilson *
402f4bbf1068869f45783608450731f83c523ded30Jesse Wilson * <p>Some code was adapted from Apache Xerces.
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class InnerNodeImpl extends LeafNodeImpl {
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Maintained by LeafNodeImpl and ElementImpl.
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    List<LeafNodeImpl> children = new ArrayList<LeafNodeImpl>();
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
478b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson    protected InnerNodeImpl(DocumentImpl document) {
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(document);
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node appendChild(Node newChild) throws DOMException {
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return insertChildAt(newChild, children.size());
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public NodeList getChildNodes() {
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        NodeListImpl list = new NodeListImpl();
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (NodeImpl node : children) {
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            list.add(node);
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return list;
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node getFirstChild() {
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return (!children.isEmpty() ? children.get(0) : null);
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node getLastChild() {
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return (!children.isEmpty() ? children.get(children.size() - 1) : null);
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node getNextSibling() {
74ab3721103266c7c9f58d5a9d32521a00a2c478d7Elliott Hughes        if (parent == null || index + 1 >= parent.children.size()) {
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return parent.children.get(index + 1);
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean hasChildNodes() {
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return children.size() != 0;
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node insertBefore(Node newChild, Node refChild) throws DOMException {
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        LeafNodeImpl refChildImpl = (LeafNodeImpl) refChild;
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8881341fd8822d545037fca9d9820a7814e6d64da7Elliott Hughes        if (refChildImpl == null) {
8981341fd8822d545037fca9d9820a7814e6d64da7Elliott Hughes            return appendChild(newChild);
9081341fd8822d545037fca9d9820a7814e6d64da7Elliott Hughes        }
9181341fd8822d545037fca9d9820a7814e6d64da7Elliott Hughes
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (refChildImpl.document != document) {
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (refChildImpl.parent != this) {
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return insertChildAt(newChild, refChildImpl.index);
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1045c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson     * Inserts {@code newChild} at {@code index}. If it is already child of
1055c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson     * another node, it is removed from there.
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1075c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson    Node insertChildAt(Node newChild, int index) throws DOMException {
1085c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        if (newChild instanceof DocumentFragment) {
1095c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson            NodeList toAdd = newChild.getChildNodes();
1105c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson            for (int i = 0; i < toAdd.getLength(); i++) {
1115c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson                insertChildAt(toAdd.item(i), index + i);
1125c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson            }
1135c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson            return newChild;
1145c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        }
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1165c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        LeafNodeImpl toInsert = (LeafNodeImpl) newChild;
11709c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson        if (toInsert.document != null && document != null && toInsert.document != document) {
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1205c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        if (toInsert.isParentOf(this)) {
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1245c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        if (toInsert.parent != null) {
1255c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson            int oldIndex = toInsert.index;
1265c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson            toInsert.parent.children.remove(oldIndex);
1275c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson            toInsert.parent.refreshIndices(oldIndex);
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1305c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        children.add(index, toInsert);
1315c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        toInsert.parent = this;
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        refreshIndices(index);
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return newChild;
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean isParentOf(Node node) {
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        LeafNodeImpl nodeImpl = (LeafNodeImpl) node;
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (nodeImpl != null) {
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (nodeImpl == this) {
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return true;
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            nodeImpl = nodeImpl.parent;
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return false;
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
15181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    /**
15281ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson     * Normalize the text nodes within this subtree. Although named similarly,
15381ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson     * this method is unrelated to Document.normalize.
15481ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson     */
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
15681ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson    public final void normalize() {
1578092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        Node next;
1588092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        for (Node node = getFirstChild(); node != null; node = next) {
1598092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            next = node.getNextSibling();
16081ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson            node.normalize();
16181ca3dd430f9c038b4257e1124f45a07d0e6b543Jesse Wilson
1628092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            if (node.getNodeType() == Node.TEXT_NODE) {
1638092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson                ((TextImpl) node).minimize();
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void refreshIndices(int fromIndex) {
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = fromIndex; i < children.size(); i++) {
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            children.get(i).index = i;
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node removeChild(Node oldChild) throws DOMException {
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        LeafNodeImpl oldChildImpl = (LeafNodeImpl) oldChild;
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (oldChildImpl.document != document) {
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, null);
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (oldChildImpl.parent != this) {
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int index = oldChildImpl.index;
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        children.remove(index);
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        oldChildImpl.parent = null;
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        refreshIndices(index);
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return oldChild;
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1925c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson    /**
1935c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson     * Removes {@code oldChild} and adds {@code newChild} in its place. This
1945c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson     * is not atomic.
1955c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson     */
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
1975c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        int index = ((LeafNodeImpl) oldChild).index;
1985c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        removeChild(oldChild);
1995c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        insertChildAt(newChild, index);
2005c0408af32a2b1c78b2d5a93cca60b0fffddd7daJesse Wilson        return oldChild;
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2032e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson    public String getTextContent() throws DOMException {
2042e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        Node child = getFirstChild();
2052e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        if (child == null) {
2062e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson            return "";
2072e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        }
2082e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson
2092e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        Node next = child.getNextSibling();
2102e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        if (next == null) {
2112e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson            return hasTextContent(child) ? child.getTextContent() : "";
2122e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        }
2132e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson
2142e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        StringBuilder buf = new StringBuilder();
2152e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        getTextContent(buf);
2162e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        return buf.toString();
2172e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson    }
2182e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson
2192e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson    void getTextContent(StringBuilder buf) throws DOMException {
2202e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        Node child = getFirstChild();
2212e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        while (child != null) {
2222e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson            if (hasTextContent(child)) {
2232e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson                ((NodeImpl) child).getTextContent(buf);
2242e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson            }
2252e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson            child = child.getNextSibling();
2262e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        }
2272e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson    }
2282e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson
2292e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson    final boolean hasTextContent(Node child) {
2302e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        // TODO: skip text nodes with ignorable whitespace?
2312e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson        return child.getNodeType() != Node.COMMENT_NODE
2322e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson                && child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE;
2332e4c40c282464cb5435b3078b8d375634355dbc1Jesse Wilson    }
23409c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson
23509c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson    void getElementsByTagName(NodeListImpl out, String name) {
23609c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson        for (NodeImpl node : children) {
23709c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson            if (node.getNodeType() == Node.ELEMENT_NODE) {
23809c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                ElementImpl element = (ElementImpl) node;
23909c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                if (matchesNameOrWildcard(name, element.getNodeName())) {
24009c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                    out.add(element);
24109c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                }
24209c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                element.getElementsByTagName(out, name);
24309c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson            }
24409c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson        }
24509c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson    }
24609c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson
24709c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson    void getElementsByTagNameNS(NodeListImpl out, String namespaceURI, String localName) {
24809c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson        for (NodeImpl node : children) {
24909c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson            if (node.getNodeType() == Node.ELEMENT_NODE) {
25009c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                ElementImpl element = (ElementImpl) node;
25109c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                if (matchesNameOrWildcard(namespaceURI, element.getNamespaceURI())
25209c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                        && matchesNameOrWildcard(localName, element.getLocalName())) {
25309c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                    out.add(element);
25409c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                }
25509c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson                element.getElementsByTagNameNS(out, namespaceURI, localName);
25609c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson            }
25709c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson        }
25809c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson    }
25909c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson
26009c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson    /**
26109c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson     * Returns true if {@code pattern} equals either "*" or {@code s}. Pattern
26209c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson     * may be {@code null}.
26309c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson     */
26409c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson    private static boolean matchesNameOrWildcard(String pattern, String s) {
26509c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson        return "*".equals(pattern) || Objects.equal(pattern, s);
26609c4640423dbe85c606c5b46312cd5c0e5c94eebJesse Wilson    }
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
268