1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License. 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License. 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.apache.harmony.xml.dom; 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.w3c.dom.DOMException; 20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.w3c.dom.Node; 21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.w3c.dom.Text; 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** 24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Provides a straightforward implementation of the corresponding W3C DOM 25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * interface. The class is used internally only, thus only notable members that 26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * are not in the original interface are documented (the W3C docs are quite 27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * extensive). Hope that's ok. 28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p> 29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Some of the fields may have package visibility, so other classes belonging to 30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the DOM implementation can easily access them while maintaining the DOM tree 31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * structure. 32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class TextImpl extends CharacterDataImpl implements Text { 34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 35606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson public TextImpl(DocumentImpl document, String data) { 36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project super(document, data); 37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public String getNodeName() { 41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return "#text"; 42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public short getNodeType() { 46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return Node.TEXT_NODE; 47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 49606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson public final Text splitText(int offset) throws DOMException { 50e14d736a739d6523fd13d98f13e9d51167197a34Jesse Wilson Text newText = document.createTextNode( 51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project substringData(offset, getLength() - offset)); 52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project deleteData(0, offset); 53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Node refNode = getNextSibling(); 55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (refNode == null) { 56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project getParentNode().appendChild(newText); 57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project getParentNode().insertBefore(newText, refNode); 59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return this; 62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 64606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson public final boolean isElementContentWhitespace() { 65606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // Undefined because we don't validate. Whether whitespace characters 66606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // constitute "element content whitespace" is defined by the containing 67606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // element's declaration (DTD) and we don't parse that. 68606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // TODO: wire this up when we support document validation 69606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson return false; 704c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson } 714c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson 72606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson public final String getWholeText() { 73606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // TODO: support entity references. This code should expand through 74606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // the child elements of entity references. 75606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // http://code.google.com/p/android/issues/detail?id=6807 76606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson 77606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson StringBuilder result = new StringBuilder(); 78606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson for (TextImpl n = firstTextNodeInCurrentRun(); n != null; n = n.nextTextNode()) { 79606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson n.appendDataTo(result); 80606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } 81606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson return result.toString(); 824c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson } 834c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson 84606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson public final Text replaceWholeText(String content) throws DOMException { 85606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // TODO: support entity references. This code should expand and replace 86606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // the child elements of entity references. 87606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // http://code.google.com/p/android/issues/detail?id=6807 88606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson 89606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson Node parent = getParentNode(); 90606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson Text result = null; 91606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson 92606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // delete all nodes in the current run of text... 93606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson for (TextImpl n = firstTextNodeInCurrentRun(); n != null; ) { 94606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson 95606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson // ...except the current node if we have content for it 96606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson if (n == this && content != null && content.length() > 0) { 97606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson setData(content); 98606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson result = this; 99606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson n = n.nextTextNode(); 100606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson 101606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } else { 102606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson Node toRemove = n; // because removeChild() detaches siblings 103606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson n = n.nextTextNode(); 104606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson parent.removeChild(toRemove); 105606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } 106606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } 107606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson 108606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson return result; 109606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } 110606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson 111606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson /** 112606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson * Returns the first text or CDATA node in the current sequence of text and 113606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson * CDATA nodes. 114606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson */ 115606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson private TextImpl firstTextNodeInCurrentRun() { 116606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson TextImpl firstTextInCurrentRun = this; 117606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson for (Node p = getPreviousSibling(); p != null; p = p.getPreviousSibling()) { 118606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson short nodeType = p.getNodeType(); 119606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { 120606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson firstTextInCurrentRun = (TextImpl) p; 121606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } else { 122606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson break; 123606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } 124606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } 125606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson return firstTextInCurrentRun; 126606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } 127606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson 128606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson /** 129606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson * Returns the next sibling node if it exists and it is text or CDATA. 130606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson * Otherwise returns null. 131606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson */ 132606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson private TextImpl nextTextNode() { 133606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson Node nextSibling = getNextSibling(); 134606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson if (nextSibling == null) { 135606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson return null; 136606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson } 137606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson 138606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson short nodeType = nextSibling.getNodeType(); 139606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson return nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE 140606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson ? (TextImpl) nextSibling 141606d8d2d12b615f58bc7614c490f9c48cf923e95Jesse Wilson : null; 1424c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson } 143e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson 144e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson /** 145e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * Tries to remove this node using itself and the previous node as context. 146e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * If this node's text is empty, this node is removed and null is returned. 147e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * If the previous node exists and is a text node, this node's text will be 148e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * appended to that node's text and this node will be removed. 149e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * 150e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * <p>Although this method alters the structure of the DOM tree, it does 151e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * not alter the document's semantics. 152e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * 153e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * @return the node holding this node's text and the end of the operation. 154e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson * Can be null if this node contained the empty string. 155e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson */ 156e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson public final TextImpl minimize() { 157e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson if (getLength() == 0) { 158e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson parent.removeChild(this); 159e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson return null; 160e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson } 161e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson 162e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson Node previous = getPreviousSibling(); 163e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson if (previous == null || previous.getNodeType() != Node.TEXT_NODE) { 164e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson return this; 165e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson } 166e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson 167e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson TextImpl previousText = (TextImpl) previous; 168e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson previousText.buffer.append(buffer); 169e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson parent.removeChild(this); 170e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson return previousText; 171e5aa5453769a682192ead8b1203e4096879ecacdJesse Wilson } 172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 173