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 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.DOMException; 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Node; 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Text; 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Provides a straightforward implementation of the corresponding W3C DOM 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * interface. The class is used internally only, thus only notable members that 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * are not in the original interface are documented (the W3C docs are quite 27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * extensive). Hope that's ok. 28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p> 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Some of the fields may have package visibility, so other classes belonging to 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the DOM implementation can easily access them while maintaining the DOM tree 31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * structure. 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class TextImpl extends CharacterDataImpl implements Text { 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 35bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson public TextImpl(DocumentImpl document, String data) { 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(document, data); 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public String getNodeName() { 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return "#text"; 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public short getNodeType() { 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return Node.TEXT_NODE; 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 49bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson public final Text splitText(int offset) throws DOMException { 508b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson Text newText = document.createTextNode( 51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project substringData(offset, getLength() - offset)); 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project deleteData(0, offset); 53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Node refNode = getNextSibling(); 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (refNode == null) { 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project getParentNode().appendChild(newText); 57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project getParentNode().insertBefore(newText, refNode); 59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return this; 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 64bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson public final boolean isElementContentWhitespace() { 65bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // Undefined because we don't validate. Whether whitespace characters 66bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // constitute "element content whitespace" is defined by the containing 67bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // element's declaration (DTD) and we don't parse that. 68bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // TODO: wire this up when we support document validation 69bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson return false; 70320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 71320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 72bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson public final String getWholeText() { 73bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // TODO: support entity references. This code should expand through 74bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // the child elements of entity references. 75bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // http://code.google.com/p/android/issues/detail?id=6807 76bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson 77bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson StringBuilder result = new StringBuilder(); 78bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson for (TextImpl n = firstTextNodeInCurrentRun(); n != null; n = n.nextTextNode()) { 79bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson n.appendDataTo(result); 80bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } 81bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson return result.toString(); 82320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 83320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson 84bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson public final Text replaceWholeText(String content) throws DOMException { 85bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // TODO: support entity references. This code should expand and replace 86bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // the child elements of entity references. 87bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // http://code.google.com/p/android/issues/detail?id=6807 88bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson 89bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson Node parent = getParentNode(); 90bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson Text result = null; 91bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson 92bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // delete all nodes in the current run of text... 93bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson for (TextImpl n = firstTextNodeInCurrentRun(); n != null; ) { 94bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson 95bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson // ...except the current node if we have content for it 96bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson if (n == this && content != null && content.length() > 0) { 97bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson setData(content); 98bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson result = this; 99bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson n = n.nextTextNode(); 100bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson 101bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } else { 102bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson Node toRemove = n; // because removeChild() detaches siblings 103bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson n = n.nextTextNode(); 104bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson parent.removeChild(toRemove); 105bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } 106bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } 107bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson 108bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson return result; 109bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } 110bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson 111bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson /** 112bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson * Returns the first text or CDATA node in the current sequence of text and 113bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson * CDATA nodes. 114bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson */ 115bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson private TextImpl firstTextNodeInCurrentRun() { 116bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson TextImpl firstTextInCurrentRun = this; 117bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson for (Node p = getPreviousSibling(); p != null; p = p.getPreviousSibling()) { 118bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson short nodeType = p.getNodeType(); 119bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) { 120bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson firstTextInCurrentRun = (TextImpl) p; 121bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } else { 122bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson break; 123bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } 124bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } 125bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson return firstTextInCurrentRun; 126bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } 127bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson 128bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson /** 129bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson * Returns the next sibling node if it exists and it is text or CDATA. 130bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson * Otherwise returns null. 131bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson */ 132bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson private TextImpl nextTextNode() { 133bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson Node nextSibling = getNextSibling(); 134bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson if (nextSibling == null) { 135bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson return null; 136bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson } 137bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson 138bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson short nodeType = nextSibling.getNodeType(); 139bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson return nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE 140bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson ? (TextImpl) nextSibling 141bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson : null; 142320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson } 1438092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson 1448092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson /** 1458092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * Tries to remove this node using itself and the previous node as context. 1468092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * If this node's text is empty, this node is removed and null is returned. 1478092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * If the previous node exists and is a text node, this node's text will be 1488092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * appended to that node's text and this node will be removed. 1498092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * 1508092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * <p>Although this method alters the structure of the DOM tree, it does 1518092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * not alter the document's semantics. 1528092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * 1538092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * @return the node holding this node's text and the end of the operation. 1548092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson * Can be null if this node contained the empty string. 1558092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson */ 1568092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson public final TextImpl minimize() { 1578092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson if (getLength() == 0) { 1588092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson parent.removeChild(this); 1598092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson return null; 1608092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson } 1618092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson 1628092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson Node previous = getPreviousSibling(); 1638092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson if (previous == null || previous.getNodeType() != Node.TEXT_NODE) { 1648092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson return this; 1658092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson } 1668092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson 1678092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson TextImpl previousText = (TextImpl) previous; 1688092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson previousText.buffer.append(buffer); 1698092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson parent.removeChild(this); 1708092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson return previousText; 1718092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson } 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 173