DocumentImpl.java revision cacbb893cd1361e7c7a63aa49ae85c0232813b9c
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package org.apache.harmony.xml.dom; 18 19import org.w3c.dom.Attr; 20import org.w3c.dom.CDATASection; 21import org.w3c.dom.CharacterData; 22import org.w3c.dom.Comment; 23import org.w3c.dom.DOMConfiguration; 24import org.w3c.dom.DOMException; 25import org.w3c.dom.DOMImplementation; 26import org.w3c.dom.Document; 27import org.w3c.dom.DocumentFragment; 28import org.w3c.dom.DocumentType; 29import org.w3c.dom.Element; 30import org.w3c.dom.EntityReference; 31import org.w3c.dom.NamedNodeMap; 32import org.w3c.dom.Node; 33import org.w3c.dom.NodeList; 34import org.w3c.dom.ProcessingInstruction; 35import org.w3c.dom.Text; 36 37/** 38 * Provides a straightforward implementation of the corresponding W3C DOM 39 * interface. The class is used internally only, thus only notable members that 40 * are not in the original interface are documented (the W3C docs are quite 41 * extensive). Hope that's ok. 42 * <p> 43 * Some of the fields may have package visibility, so other classes belonging to 44 * the DOM implementation can easily access them while maintaining the DOM tree 45 * structure. 46 */ 47public class DocumentImpl extends InnerNodeImpl implements Document { 48 49 private DOMImplementation domImplementation; 50 51 DocumentImpl(DOMImplementationImpl impl, String namespaceURI, 52 String qualifiedName, DocumentType doctype) { 53 super(null); 54 55 this.domImplementation = impl; 56 // this.document = this; 57 58 if (doctype != null) { 59 appendChild(doctype); 60 } 61 62 if (qualifiedName != null) { 63 appendChild(createElementNS(namespaceURI, qualifiedName)); 64 } 65 } 66 67 private static boolean isXMLIdentifierStart(char c) { 68 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_'); 69 } 70 71 private static boolean isXMLIdentifierPart(char c) { 72 return isXMLIdentifierStart(c) || (c >= '0' && c <= '9') || (c == '-') || (c == '.'); 73 } 74 75 static boolean isXMLIdentifier(String s) { 76 if (s.length() == 0) { 77 return false; 78 } 79 80 if (!isXMLIdentifierStart(s.charAt(0))) { 81 return false; 82 } 83 84 for (int i = 1; i < s.length(); i++) { 85 if (!isXMLIdentifierPart(s.charAt(i))) { 86 return false; 87 } 88 } 89 90 return true; 91 } 92 93 /** 94 * Clones a node and (if requested) its children. The source node(s) may 95 * have been created by a different DocumentImpl or even DOM implementation. 96 * 97 * @param node The node to clone. 98 * @param deep If true, a deep copy is created (including all child nodes). 99 * 100 * @return The new node. 101 */ 102 Node cloneNode(Node node, boolean deep) throws DOMException { 103 // TODO: callback the UserDataHandler with a NODE_CLONED event 104 105 Node target; 106 107 switch (node.getNodeType()) { 108 case Node.ATTRIBUTE_NODE: { 109 Attr source = (Attr)node; 110 target = createAttributeNS(source.getNamespaceURI(), source.getLocalName()); 111 target.setPrefix(source.getPrefix()); 112 target.setNodeValue(source.getNodeValue()); 113 break; 114 } 115 case Node.CDATA_SECTION_NODE: { 116 CharacterData source = (CharacterData)node; 117 target = createCDATASection(source.getData()); 118 break; 119 } 120 case Node.COMMENT_NODE: { 121 Comment source = (Comment)node; 122 target = createComment(source.getData()); 123 break; 124 } 125 case Node.DOCUMENT_FRAGMENT_NODE: { 126 // Source is irrelevant in this case. 127 target = createDocumentFragment(); 128 break; 129 } 130 case Node.DOCUMENT_NODE: { 131 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a Document node"); 132 } 133 case Node.DOCUMENT_TYPE_NODE: { 134 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a DocumentType node"); 135 } 136 case Node.ELEMENT_NODE: { 137 Element source = (Element)node; 138 target = createElementNS(source.getNamespaceURI(), source.getLocalName()); 139 target.setPrefix(source.getPrefix()); 140 141 NamedNodeMap map = source.getAttributes(); 142 for (int i = 0; i < map.getLength(); i++) { 143 Attr attr = (Attr)map.item(i); 144 ((Element)target).setAttributeNodeNS((Attr)cloneNode(attr, deep)); 145 } 146 break; 147 } 148 case Node.ENTITY_NODE: { 149 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone an Entity node"); 150 } 151 case Node.ENTITY_REFERENCE_NODE: { 152 EntityReference source = (EntityReference)node; 153 target = createEntityReference(source.getNodeName()); 154 break; 155 } 156 case Node.NOTATION_NODE: { 157 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a Notation node"); 158 } 159 case Node.PROCESSING_INSTRUCTION_NODE: { 160 ProcessingInstruction source = (ProcessingInstruction)node; 161 target = createProcessingInstruction(source.getTarget(), source.getData()); 162 break; 163 } 164 case Node.TEXT_NODE: { 165 Text source = (Text)node; 166 target = createTextNode(source.getData()); 167 break; 168 } 169 default: { 170 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone unknown node type " + node.getNodeType() + " (" + node.getClass().getSimpleName() + ")"); 171 } 172 } 173 174 if (deep) { 175 NodeList list = node.getChildNodes(); 176 for (int i = 0; i < list.getLength(); i++) { 177 Node child = cloneNode(list.item(i), deep); 178 target.appendChild(child); 179 } 180 } 181 182 return target; 183 } 184 185 public AttrImpl createAttribute(String name) throws DOMException { 186 return new AttrImpl(this, name); 187 } 188 189 public Attr createAttributeNS(String namespaceURI, String qualifiedName) 190 throws DOMException { 191 return new AttrImpl(this, namespaceURI, qualifiedName); 192 } 193 194 public CDATASection createCDATASection(String data) throws DOMException { 195 return new CDATASectionImpl(this, data); 196 } 197 198 public Comment createComment(String data) { 199 return new CommentImpl(this, data); 200 } 201 202 public DocumentFragment createDocumentFragment() { 203 return new DocumentFragmentImpl(this); 204 } 205 206 public Element createElement(String tagName) throws DOMException { 207 return new ElementImpl(this, tagName); 208 } 209 210 public Element createElementNS(String namespaceURI, String qualifiedName) 211 throws DOMException { 212 return new ElementImpl(this, namespaceURI, qualifiedName); 213 } 214 215 public EntityReference createEntityReference(String name) 216 throws DOMException { 217 return new EntityReferenceImpl(this, name); 218 } 219 220 public ProcessingInstruction createProcessingInstruction(String target, 221 String data) throws DOMException { 222 return new ProcessingInstructionImpl(this, target, data); 223 } 224 225 public Text createTextNode(String data) { 226 return new TextImpl(this, data); 227 } 228 229 public DocumentType getDoctype() { 230 for (int i = 0; i < children.size(); i++) { 231 if (children.get(i) instanceof DocumentType) { 232 return (DocumentType) children.get(i); 233 } 234 } 235 236 return null; 237 } 238 239 public Element getDocumentElement() { 240 for (int i = 0; i < children.size(); i++) { 241 if (children.get(i) instanceof Element) { 242 return (Element) children.get(i); 243 } 244 } 245 246 return null; 247 } 248 249 public Element getElementById(String elementId) { 250 ElementImpl root = (ElementImpl) getDocumentElement(); 251 252 return (root == null ? null : root.getElementById(elementId)); 253 } 254 255 public NodeList getElementsByTagName(String tagname) { 256 ElementImpl root = (ElementImpl) getDocumentElement(); 257 258 return (root == null ? new NodeListImpl() 259 : root.getElementsByTagName(tagname)); 260 } 261 262 public NodeList getElementsByTagNameNS(String namespaceURI, String localName) { 263 ElementImpl root = (ElementImpl) getDocumentElement(); 264 265 return (root == null ? new NodeListImpl() : root.getElementsByTagNameNS( 266 namespaceURI, localName)); 267 } 268 269 public DOMImplementation getImplementation() { 270 return domImplementation; 271 } 272 273 @Override 274 public String getNodeName() { 275 return "#document"; 276 } 277 278 @Override 279 public short getNodeType() { 280 return Node.DOCUMENT_NODE; 281 } 282 283 public Node importNode(Node importedNode, boolean deep) throws DOMException { 284 // TODO: callback the UserDataHandler with a NODE_IMPORTED event 285 return cloneNode(importedNode, deep); 286 } 287 288 @Override 289 public Node insertChildAt(Node newChild, int index) throws DOMException { 290 // Make sure we have at most one root element and one DTD element. 291 if (newChild instanceof Element && getDocumentElement() != null) { 292 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 293 "Only one root element allowed"); 294 } else if (newChild instanceof DocumentType && getDoctype() != null) { 295 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 296 "Only one DOCTYPE element allowed"); 297 } 298 299 return super.insertChildAt(newChild, index); 300 } 301 302 @Override public String getTextContent() throws DOMException { 303 return null; 304 } 305 306 public String getInputEncoding() { 307 throw new UnsupportedOperationException(); // TODO 308 } 309 310 public String getXmlEncoding() { 311 throw new UnsupportedOperationException(); // TODO 312 } 313 314 public boolean getXmlStandalone() { 315 throw new UnsupportedOperationException(); // TODO 316 } 317 318 public void setXmlStandalone(boolean xmlStandalone) throws DOMException { 319 throw new UnsupportedOperationException(); // TODO 320 } 321 322 public String getXmlVersion() { 323 throw new UnsupportedOperationException(); // TODO 324 } 325 326 public void setXmlVersion(String xmlVersion) throws DOMException { 327 throw new UnsupportedOperationException(); // TODO 328 } 329 330 public boolean getStrictErrorChecking() { 331 throw new UnsupportedOperationException(); // TODO 332 } 333 334 public void setStrictErrorChecking(boolean strictErrorChecking) { 335 throw new UnsupportedOperationException(); // TODO 336 } 337 338 public String getDocumentURI() { 339 throw new UnsupportedOperationException(); // TODO 340 } 341 342 public void setDocumentURI(String documentURI) { 343 throw new UnsupportedOperationException(); // TODO 344 } 345 346 public Node adoptNode(Node source) throws DOMException { 347 // TODO: callback the UserDataHandler with a NODE_ADOPTED event 348 throw new UnsupportedOperationException(); // TODO 349 } 350 351 public DOMConfiguration getDomConfig() { 352 throw new UnsupportedOperationException(); // TODO 353 } 354 355 public void normalizeDocument() { 356 throw new UnsupportedOperationException(); // TODO 357 } 358 359 public Node renameNode(Node n, String namespaceURI, String qualifiedName) 360 throws DOMException { 361 // TODO: callback the UserDataHandler with a NODE_RENAMED event 362 throw new UnsupportedOperationException(); // TODO 363 } 364} 365