1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xerces" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, International
  53. * Business Machines, Inc., http://www.apache.org. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package com.sun.org.apache.xerces.internal.dom;
  58. import java.io.Serializable;
  59. import java.util.Enumeration;
  60. import java.util.Hashtable;
  61. import org.w3c.dom.DOMConfiguration;
  62. import org.w3c.dom.UserDataHandler;
  63. import com.sun.org.apache.xerces.internal.util.XMLChar;
  64. import com.sun.org.apache.xerces.internal.util.XML11Char;
  65. import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  66. import org.w3c.dom.Attr;
  67. import org.w3c.dom.CDATASection;
  68. import org.w3c.dom.Comment;
  69. import org.w3c.dom.DOMException;
  70. import org.w3c.dom.DOMImplementation;
  71. import org.w3c.dom.Document;
  72. import org.w3c.dom.DocumentFragment;
  73. import org.w3c.dom.DocumentType;
  74. import org.w3c.dom.Element;
  75. import org.w3c.dom.Entity;
  76. import org.w3c.dom.EntityReference;
  77. import org.w3c.dom.NamedNodeMap;
  78. import org.w3c.dom.Node;
  79. import org.w3c.dom.NodeList;
  80. import org.w3c.dom.Notation;
  81. import org.w3c.dom.ProcessingInstruction;
  82. import org.w3c.dom.Text;
  83. import org.w3c.dom.events.Event;
  84. import org.w3c.dom.events.EventListener;
  85. import org.w3c.dom.ls.DOMImplementationLS;
  86. import org.w3c.dom.ls.LSSerializer;
  87. /**
  88. * The Document interface represents the entire HTML or XML document.
  89. * Conceptually, it is the root of the document tree, and provides the
  90. * primary access to the document's data.
  91. * <P>
  92. * Since elements, text nodes, comments, processing instructions,
  93. * etc. cannot exist outside the context of a Document, the Document
  94. * interface also contains the factory methods needed to create these
  95. * objects. The Node objects created have a ownerDocument attribute
  96. * which associates them with the Document within whose context they
  97. * were created.
  98. * <p>
  99. * The CoreDocumentImpl class only implements the DOM Core. Additional modules
  100. * are supported by the more complete DocumentImpl subclass.
  101. * <p>
  102. * <b>Note:</b> When any node in the document is serialized, the
  103. * entire document is serialized along with it.
  104. *
  105. * @author Arnaud Le Hors, IBM
  106. * @author Joe Kesselman, IBM
  107. * @author Andy Clark, IBM
  108. * @author Ralf Pfeiffer, IBM
  109. * @version $Id: CoreDocumentImpl.java,v 1.71 2004/04/26 14:44:56 venu Exp $
  110. * @since PR-DOM-Level-1-19980818.
  111. */
  112. public class CoreDocumentImpl
  113. extends ParentNode implements Document {
  114. /**TODO::
  115. * 1. Change XML11Char method names similar to XMLChar. That will prevent lot
  116. * of dirty version checking code.
  117. *
  118. * 2. IMO during cloneNode qname/isXMLName check should not be made.
  119. */
  120. //
  121. // Constants
  122. //
  123. /** Serialization version. */
  124. static final long serialVersionUID = 0;
  125. //
  126. // Data
  127. //
  128. // document information
  129. /** Document type. */
  130. protected DocumentTypeImpl docType;
  131. /** Document element. */
  132. protected ElementImpl docElement;
  133. /** NodeListCache free list */
  134. transient NodeListCache fFreeNLCache;
  135. /**Experimental DOM Level 3 feature: Document encoding */
  136. protected String encoding;
  137. /**Experimental DOM Level 3 feature: Document actualEncoding */
  138. protected String actualEncoding;
  139. /**Experimental DOM Level 3 feature: Document version */
  140. protected String version;
  141. /**Experimental DOM Level 3 feature: Document standalone */
  142. protected boolean standalone;
  143. /**Experimental DOM Level 3 feature: documentURI */
  144. protected String fDocumentURI;
  145. //Revisit :: change to a better data structure.
  146. /** Table for user data attached to this document nodes. */
  147. protected Hashtable userData;
  148. /** Identifiers. */
  149. protected Hashtable identifiers;
  150. // DOM Level 3: normalizeDocument
  151. transient DOMNormalizer domNormalizer = null;
  152. transient DOMConfigurationImpl fConfiguration= null;
  153. // support of XPath API
  154. transient Object fXPathEvaluator = null;
  155. /** Table for quick check of child insertion. */
  156. private final static int[] kidOK;
  157. /**
  158. * Number of alterations made to this document since its creation.
  159. * Serves as a "dirty bit" so that live objects such as NodeList can
  160. * recognize when an alteration has been made and discard its cached
  161. * state information.
  162. * <p>
  163. * Any method that alters the tree structure MUST cause or be
  164. * accompanied by a call to changed(), to inform it that any outstanding
  165. * NodeLists may have to be updated.
  166. * <p>
  167. * (Required because NodeList is simultaneously "live" and integer-
  168. * indexed -- a bad decision in the DOM's design.)
  169. * <p>
  170. * Note that changes which do not affect the tree's structure -- changing
  171. * the node's name, for example -- do _not_ have to call changed().
  172. * <p>
  173. * Alternative implementation would be to use a cryptographic
  174. * Digest value rather than a count. This would have the advantage that
  175. * "harmless" changes (those producing equal() trees) would not force
  176. * NodeList to resynchronize. Disadvantage is that it's slightly more prone
  177. * to "false negatives", though that's the difference between "wildly
  178. * unlikely" and "absurdly unlikely". IF we start maintaining digests,
  179. * we should consider taking advantage of them.
  180. *
  181. * Note: This used to be done a node basis, so that we knew what
  182. * subtree changed. But since only DeepNodeList really use this today,
  183. * the gain appears to be really small compared to the cost of having
  184. * an int on every (parent) node plus having to walk up the tree all the
  185. * way to the root to mark the branch as changed everytime a node is
  186. * changed.
  187. * So we now have a single counter global to the document. It means that
  188. * some objects may flush their cache more often than necessary, but this
  189. * makes nodes smaller and only the document needs to be marked as changed.
  190. */
  191. protected int changes = 0;
  192. // experimental
  193. /** Allow grammar access. */
  194. protected boolean allowGrammarAccess;
  195. /** Bypass error checking. */
  196. protected boolean errorChecking = true;
  197. //Did version change at any point when the document was created ?
  198. //this field helps us to optimize when normalizingDocument.
  199. protected boolean xmlVersionChanged = false ;
  200. /** The following are required for compareDocumentPosition
  201. */
  202. // Document number. Documents are ordered across the implementation using
  203. // positive integer values. Documents are assigned numbers on demand.
  204. private int documentNumber=0;
  205. // Node counter and table. Used to assign numbers to nodes for this
  206. // document. Node number values are negative integers. Nodes are
  207. // assigned numbers on demand.
  208. private int nodeCounter = 0;
  209. private Hashtable nodeTable;
  210. private boolean xml11Version = false; //by default 1.0
  211. //
  212. // Static initialization
  213. //
  214. static {
  215. kidOK = new int[13];
  216. kidOK[DOCUMENT_NODE] =
  217. 1 << ELEMENT_NODE | 1 << PROCESSING_INSTRUCTION_NODE |
  218. 1 << COMMENT_NODE | 1 << DOCUMENT_TYPE_NODE;
  219. kidOK[DOCUMENT_FRAGMENT_NODE] =
  220. kidOK[ENTITY_NODE] =
  221. kidOK[ENTITY_REFERENCE_NODE] =
  222. kidOK[ELEMENT_NODE] =
  223. 1 << ELEMENT_NODE | 1 << PROCESSING_INSTRUCTION_NODE |
  224. 1 << COMMENT_NODE | 1 << TEXT_NODE |
  225. 1 << CDATA_SECTION_NODE | 1 << ENTITY_REFERENCE_NODE ;
  226. kidOK[ATTRIBUTE_NODE] =
  227. 1 << TEXT_NODE | 1 << ENTITY_REFERENCE_NODE;
  228. kidOK[DOCUMENT_TYPE_NODE] =
  229. kidOK[PROCESSING_INSTRUCTION_NODE] =
  230. kidOK[COMMENT_NODE] =
  231. kidOK[TEXT_NODE] =
  232. kidOK[CDATA_SECTION_NODE] =
  233. kidOK[NOTATION_NODE] =
  234. 0;
  235. } // static
  236. //
  237. // Constructors
  238. //
  239. /**
  240. * NON-DOM: Actually creating a Document is outside the DOM's spec,
  241. * since it has to operate in terms of a particular implementation.
  242. */
  243. public CoreDocumentImpl() {
  244. this(false);
  245. }
  246. /** Constructor. */
  247. public CoreDocumentImpl(boolean grammarAccess) {
  248. super(null);
  249. ownerDocument = this;
  250. allowGrammarAccess = grammarAccess;
  251. }
  252. /**
  253. * For DOM2 support.
  254. * The createDocument factory method is in DOMImplementation.
  255. */
  256. public CoreDocumentImpl(DocumentType doctype) {
  257. this(doctype, false);
  258. }
  259. /** For DOM2 support. */
  260. public CoreDocumentImpl(DocumentType doctype, boolean grammarAccess) {
  261. this(grammarAccess);
  262. if (doctype != null) {
  263. DocumentTypeImpl doctypeImpl;
  264. try {
  265. doctypeImpl = (DocumentTypeImpl) doctype;
  266. } catch (ClassCastException e) {
  267. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
  268. throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
  269. }
  270. doctypeImpl.ownerDocument = this;
  271. appendChild(doctype);
  272. }
  273. }
  274. //
  275. // Node methods
  276. //
  277. // even though ownerDocument refers to this in this implementation
  278. // the DOM Level 2 spec says it must be null, so make it appear so
  279. final public Document getOwnerDocument() {
  280. return null;
  281. }
  282. /** Returns the node type. */
  283. public short getNodeType() {
  284. return Node.DOCUMENT_NODE;
  285. }
  286. /** Returns the node name. */
  287. public String getNodeName() {
  288. return "#document";
  289. }
  290. /**
  291. * Deep-clone a document, including fixing ownerDoc for the cloned
  292. * children. Note that this requires bypassing the WRONG_DOCUMENT_ERR
  293. * protection. I've chosen to implement it by calling importNode
  294. * which is DOM Level 2.
  295. *
  296. * @return org.w3c.dom.Node
  297. * @param deep boolean, iff true replicate children
  298. */
  299. public Node cloneNode(boolean deep) {
  300. CoreDocumentImpl newdoc = new CoreDocumentImpl();
  301. callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED);
  302. cloneNode(newdoc, deep);
  303. return newdoc;
  304. } // cloneNode(boolean):Node
  305. /**
  306. * internal method to share code with subclass
  307. **/
  308. protected void cloneNode(CoreDocumentImpl newdoc, boolean deep) {
  309. // clone the children by importing them
  310. if (needsSyncChildren()) {
  311. synchronizeChildren();
  312. }
  313. if (deep) {
  314. Hashtable reversedIdentifiers = null;
  315. if (identifiers != null) {
  316. // Build a reverse mapping from element to identifier.
  317. reversedIdentifiers = new Hashtable();
  318. Enumeration elementIds = identifiers.keys();
  319. while (elementIds.hasMoreElements()) {
  320. Object elementId = elementIds.nextElement();
  321. reversedIdentifiers.put(identifiers.get(elementId),
  322. elementId);
  323. }
  324. }
  325. // Copy children into new document.
  326. for (ChildNode kid = firstChild; kid != null;
  327. kid = kid.nextSibling) {
  328. newdoc.appendChild(newdoc.importNode(kid, true, true,
  329. reversedIdentifiers));
  330. }
  331. }
  332. // experimental
  333. newdoc.allowGrammarAccess = allowGrammarAccess;
  334. newdoc.errorChecking = errorChecking;
  335. } // cloneNode(CoreDocumentImpl,boolean):void
  336. /**
  337. * Since a Document may contain at most one top-level Element child,
  338. * and at most one DocumentType declaraction, we need to subclass our
  339. * add-children methods to implement this constraint.
  340. * Since appendChild() is implemented as insertBefore(,null),
  341. * altering the latter fixes both.
  342. * <p>
  343. * While I'm doing so, I've taken advantage of the opportunity to
  344. * cache documentElement and docType so we don't have to
  345. * search for them.
  346. *
  347. * REVISIT: According to the spec it is not allowed to alter neither the
  348. * document element nor the document type in any way
  349. */
  350. public Node insertBefore(Node newChild, Node refChild)
  351. throws DOMException {
  352. // Only one such child permitted
  353. int type = newChild.getNodeType();
  354. if (errorChecking) {
  355. if((type == Node.ELEMENT_NODE && docElement != null) ||
  356. (type == Node.DOCUMENT_TYPE_NODE && docType != null)) {
  357. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
  358. throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg);
  359. }
  360. }
  361. // Adopt orphan doctypes
  362. if (newChild.getOwnerDocument() == null &&
  363. newChild instanceof DocumentTypeImpl) {
  364. ((DocumentTypeImpl) newChild).ownerDocument = this;
  365. }
  366. super.insertBefore(newChild,refChild);
  367. // If insert succeeded, cache the kid appropriately
  368. if (type == Node.ELEMENT_NODE) {
  369. docElement = (ElementImpl)newChild;
  370. }
  371. else if (type == Node.DOCUMENT_TYPE_NODE) {
  372. docType = (DocumentTypeImpl)newChild;
  373. }
  374. return newChild;
  375. } // insertBefore(Node,Node):Node
  376. /**
  377. * Since insertBefore caches the docElement (and, currently, docType),
  378. * removeChild has to know how to undo the cache
  379. *
  380. * REVISIT: According to the spec it is not allowed to alter neither the
  381. * document element nor the document type in any way
  382. */
  383. public Node removeChild(Node oldChild) throws DOMException {
  384. super.removeChild(oldChild);
  385. // If remove succeeded, un-cache the kid appropriately
  386. int type = oldChild.getNodeType();
  387. if(type == Node.ELEMENT_NODE) {
  388. docElement = null;
  389. }
  390. else if (type == Node.DOCUMENT_TYPE_NODE) {
  391. docType = null;
  392. }
  393. return oldChild;
  394. } // removeChild(Node):Node
  395. /**
  396. * Since we cache the docElement (and, currently, docType),
  397. * replaceChild has to update the cache
  398. *
  399. * REVISIT: According to the spec it is not allowed to alter neither the
  400. * document element nor the document type in any way
  401. */
  402. public Node replaceChild(Node newChild, Node oldChild)
  403. throws DOMException {
  404. // Adopt orphan doctypes
  405. if (newChild.getOwnerDocument() == null &&
  406. newChild instanceof DocumentTypeImpl) {
  407. ((DocumentTypeImpl) newChild).ownerDocument = this;
  408. }
  409. int type = oldChild.getNodeType();
  410. int newType = newChild.getNodeType();
  411. if (errorChecking &&((docType != null &&
  412. oldChild.getNodeType() != Node.DOCUMENT_TYPE_NODE &&
  413. newChild.getNodeType() == Node.DOCUMENT_TYPE_NODE)
  414. || (docElement != null &&
  415. oldChild.getNodeType() != Node.ELEMENT_NODE &&
  416. newChild.getNodeType() == Node.ELEMENT_NODE))) {
  417. throw new DOMException(
  418. DOMException.HIERARCHY_REQUEST_ERR,
  419. DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null));
  420. }
  421. super.replaceChild(newChild, oldChild);
  422. if(type == Node.ELEMENT_NODE) {
  423. docElement = (ElementImpl)newChild;
  424. }
  425. else if (type == Node.DOCUMENT_TYPE_NODE) {
  426. docType = (DocumentTypeImpl)newChild;
  427. }
  428. return oldChild;
  429. } // replaceChild(Node,Node):Node
  430. /*
  431. * Get Node text content
  432. * @since DOM Level 3
  433. */
  434. public String getTextContent() throws DOMException {
  435. return null;
  436. }
  437. /*
  438. * Set Node text content
  439. * @since DOM Level 3
  440. */
  441. public void setTextContent(String textContent)
  442. throws DOMException {
  443. // no-op
  444. }
  445. /**
  446. * @since DOM Level 3
  447. */
  448. public Object getFeature(String feature, String version) {
  449. boolean anyVersion = version == null || version.length() == 0;
  450. if ((feature.equalsIgnoreCase("XPath")
  451. || feature.equalsIgnoreCase("+XPath")) &&
  452. (anyVersion || version.equals("3.0"))) {
  453. try {
  454. Class xpathClass = ObjectFactory.findProviderClass(
  455. "com.sun.org.apache.xpath.internal.domapi.XPathEvaluatorImpl",
  456. ObjectFactory.findClassLoader(), true);
  457. fXPathEvaluator = xpathClass.newInstance();
  458. java.lang.reflect.Method setDocument = xpathClass.getMethod("setDoc", new Class[]{Document.class});
  459. setDocument.invoke(fXPathEvaluator, new Object[]{this});
  460. return fXPathEvaluator;
  461. }
  462. catch (Exception e){
  463. return null;
  464. }
  465. }
  466. return super.getFeature(feature, version);
  467. }
  468. //
  469. // Document methods
  470. //
  471. // factory methods
  472. /**
  473. * Factory method; creates an Attribute having this Document as its
  474. * OwnerDoc.
  475. *
  476. * @param name The name of the attribute. Note that the attribute's value
  477. * is _not_ established at the factory; remember to set it!
  478. *
  479. * @throws DOMException(INVALID_NAME_ERR) if the attribute name is not
  480. * acceptable.
  481. */
  482. public Attr createAttribute(String name)
  483. throws DOMException {
  484. if (errorChecking && !isXMLName(name,xml11Version)) {
  485. String msg =
  486. DOMMessageFormatter.formatMessage(
  487. DOMMessageFormatter.DOM_DOMAIN,
  488. "INVALID_CHARACTER_ERR",
  489. null);
  490. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  491. }
  492. return new AttrImpl(this, name);
  493. } // createAttribute(String):Attr
  494. /**
  495. * Factory method; creates a CDATASection having this Document as
  496. * its OwnerDoc.
  497. *
  498. * @param data The initial contents of the CDATA
  499. *
  500. * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents. (HTML
  501. * not yet implemented.)
  502. */
  503. public CDATASection createCDATASection(String data)
  504. throws DOMException {
  505. return new CDATASectionImpl(this, data);
  506. }
  507. /**
  508. * Factory method; creates a Comment having this Document as its
  509. * OwnerDoc.
  510. *
  511. * @param data The initial contents of the Comment. */
  512. public Comment createComment(String data) {
  513. return new CommentImpl(this, data);
  514. }
  515. /**
  516. * Factory method; creates a DocumentFragment having this Document
  517. * as its OwnerDoc.
  518. */
  519. public DocumentFragment createDocumentFragment() {
  520. return new DocumentFragmentImpl(this);
  521. }
  522. /**
  523. * Factory method; creates an Element having this Document
  524. * as its OwnerDoc.
  525. *
  526. * @param tagName The name of the element type to instantiate. For
  527. * XML, this is case-sensitive. For HTML, the tagName parameter may
  528. * be provided in any case, but it must be mapped to the canonical
  529. * uppercase form by the DOM implementation.
  530. *
  531. * @throws DOMException(INVALID_NAME_ERR) if the tag name is not
  532. * acceptable.
  533. */
  534. public Element createElement(String tagName)
  535. throws DOMException {
  536. if (errorChecking && !isXMLName(tagName,xml11Version)) {
  537. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
  538. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  539. }
  540. return new ElementImpl(this, tagName);
  541. } // createElement(String):Element
  542. /**
  543. * Factory method; creates an EntityReference having this Document
  544. * as its OwnerDoc.
  545. *
  546. * @param name The name of the Entity we wish to refer to
  547. *
  548. * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
  549. * nonstandard entities are not permitted. (HTML not yet
  550. * implemented.)
  551. */
  552. public EntityReference createEntityReference(String name)
  553. throws DOMException {
  554. if (errorChecking && !isXMLName(name,xml11Version)) {
  555. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
  556. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  557. }
  558. return new EntityReferenceImpl(this, name);
  559. } // createEntityReference(String):EntityReference
  560. /**
  561. * Factory method; creates a ProcessingInstruction having this Document
  562. * as its OwnerDoc.
  563. *
  564. * @param target The target "processor channel"
  565. * @param data Parameter string to be passed to the target.
  566. *
  567. * @throws DOMException(INVALID_NAME_ERR) if the target name is not
  568. * acceptable.
  569. *
  570. * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents. (HTML
  571. * not yet implemented.)
  572. */
  573. public ProcessingInstruction createProcessingInstruction(String target,
  574. String data)
  575. throws DOMException {
  576. if (errorChecking && !isXMLName(target,xml11Version)) {
  577. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
  578. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  579. }
  580. return new ProcessingInstructionImpl(this, target, data);
  581. } // createProcessingInstruction(String,String):ProcessingInstruction
  582. /**
  583. * Factory method; creates a Text node having this Document as its
  584. * OwnerDoc.
  585. *
  586. * @param data The initial contents of the Text.
  587. */
  588. public Text createTextNode(String data) {
  589. return new TextImpl(this, data);
  590. }
  591. // other document methods
  592. /**
  593. * For XML, this provides access to the Document Type Definition.
  594. * For HTML documents, and XML documents which don't specify a DTD,
  595. * it will be null.
  596. */
  597. public DocumentType getDoctype() {
  598. if (needsSyncChildren()) {
  599. synchronizeChildren();
  600. }
  601. return docType;
  602. }
  603. /**
  604. * Convenience method, allowing direct access to the child node
  605. * which is considered the root of the actual document content. For
  606. * HTML, where it is legal to have more than one Element at the top
  607. * level of the document, we pick the one with the tagName
  608. * "HTML". For XML there should be only one top-level
  609. *
  610. * (HTML not yet supported.)
  611. */
  612. public Element getDocumentElement() {
  613. if (needsSyncChildren()) {
  614. synchronizeChildren();
  615. }
  616. return docElement;
  617. }
  618. /**
  619. * Return a <em>live</em> collection of all descendent Elements (not just
  620. * immediate children) having the specified tag name.
  621. *
  622. * @param tagname The type of Element we want to gather. "*" will be
  623. * taken as a wildcard, meaning "all elements in the document."
  624. *
  625. * @see DeepNodeListImpl
  626. */
  627. public NodeList getElementsByTagName(String tagname) {
  628. return new DeepNodeListImpl(this,tagname);
  629. }
  630. /**
  631. * Retrieve information describing the abilities of this particular
  632. * DOM implementation. Intended to support applications that may be
  633. * using DOMs retrieved from several different sources, potentially
  634. * with different underlying representations.
  635. */
  636. public DOMImplementation getImplementation() {
  637. // Currently implemented as a singleton, since it's hardcoded
  638. // information anyway.
  639. return CoreDOMImplementationImpl.getDOMImplementation();
  640. }
  641. //
  642. // Public methods
  643. //
  644. // properties
  645. /**
  646. * Sets whether the DOM implementation performs error checking
  647. * upon operations. Turning off error checking only affects
  648. * the following DOM checks:
  649. * <ul>
  650. * <li>Checking strings to make sure that all characters are
  651. * legal XML characters
  652. * <li>Hierarchy checking such as allowed children, checks for
  653. * cycles, etc.
  654. * </ul>
  655. * <p>
  656. * Turning off error checking does <em>not</em> turn off the
  657. * following checks:
  658. * <ul>
  659. * <li>Read only checks
  660. * <li>Checks related to DOM events
  661. * </ul>
  662. */
  663. public void setErrorChecking(boolean check) {
  664. errorChecking = check;
  665. }
  666. /*
  667. * DOM Level 3 WD - Experimental.
  668. */
  669. public void setStrictErrorChecking(boolean check) {
  670. errorChecking = check;
  671. }
  672. /**
  673. * Returns true if the DOM implementation performs error checking.
  674. */
  675. public boolean getErrorChecking() {
  676. return errorChecking;
  677. }
  678. /*
  679. * DOM Level 3 WD - Experimental.
  680. */
  681. public boolean getStrictErrorChecking() {
  682. return errorChecking;
  683. }
  684. /**
  685. * DOM Level 3 CR - Experimental. (Was getActualEncoding)
  686. *
  687. * An attribute specifying the encoding used for this document
  688. * at the time of the parsing. This is <code>null</code> when
  689. * it is not known, such as when the <code>Document</code> was
  690. * created in memory.
  691. * @since DOM Level 3
  692. */
  693. public String getInputEncoding() {
  694. return actualEncoding;
  695. }
  696. /**
  697. * DOM Internal
  698. * (Was a DOM L3 Core WD public interface method setActualEncoding )
  699. *
  700. * An attribute specifying the actual encoding of this document. This is
  701. * <code>null</code> otherwise.
  702. * <br> This attribute represents the property [character encoding scheme]
  703. * defined in .
  704. */
  705. public void setInputEncoding(String value) {
  706. actualEncoding = value;
  707. }
  708. /**
  709. * DOM Internal
  710. * (Was a DOM L3 Core WD public interface method setXMLEncoding )
  711. *
  712. * An attribute specifying, as part of the XML declaration,
  713. * the encoding of this document. This is null when unspecified.
  714. */
  715. public void setXmlEncoding(String value) {
  716. encoding = value;
  717. }
  718. /**
  719. * DOM Level 3 WD - Experimental.
  720. * The encoding of this document (part of XML Declaration)
  721. */
  722. public String getXmlEncoding() {
  723. return encoding;
  724. }
  725. /**
  726. * DOM Level 3 CR - Experimental.
  727. * version - An attribute specifying, as part of the XML declaration,
  728. * the version number of this document.
  729. */
  730. public void setXmlVersion(String value) {
  731. if(value.equals("1.0") || value.equals("1.1")){
  732. //we need to change the flag value only --
  733. // when the version set is different than already set.
  734. if(!getXmlVersion().equals(value)){
  735. xmlVersionChanged = true ;
  736. //change the normalization value back to false
  737. isNormalized(false);
  738. version = value;
  739. }
  740. }
  741. else{
  742. //NOT_SUPPORTED_ERR: Raised if the vesion is set to a value that is not supported by
  743. //this document
  744. //we dont support any other XML version
  745. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
  746. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  747. }
  748. if((getXmlVersion()).equals("1.1")){
  749. xml11Version = true;
  750. }
  751. else{
  752. xml11Version = false;
  753. }
  754. }
  755. /**
  756. * DOM Level 3 WD - Experimental.
  757. * The version of this document (part of XML Declaration)
  758. */
  759. public String getXmlVersion() {
  760. return (version == null)?"1.0":version;
  761. }
  762. /**
  763. * DOM Level 3 CR - Experimental.
  764. *
  765. * Xmlstandalone - An attribute specifying, as part of the XML declaration,
  766. * whether this document is standalone
  767. * @exception DOMException
  768. * NOT_SUPPORTED_ERR: Raised if this document does not support the
  769. * "XML" feature.
  770. * @since DOM Level 3
  771. */
  772. public void setXmlStandalone(boolean value)
  773. throws DOMException {
  774. standalone = value;
  775. }
  776. /**
  777. * DOM Level 3 WD - Experimental.
  778. * standalone that specifies whether this document is standalone
  779. * (part of XML Declaration)
  780. */
  781. public boolean getXmlStandalone() {
  782. return standalone;
  783. }
  784. /**
  785. * DOM Level 3 WD - Experimental.
  786. * The location of the document or <code>null</code> if undefined.
  787. * <br>Beware that when the <code>Document</code> supports the feature
  788. * "HTML" , the href attribute of the HTML BASE element takes precedence
  789. * over this attribute.
  790. * @since DOM Level 3
  791. */
  792. public String getDocumentURI(){
  793. return fDocumentURI;
  794. }
  795. /**
  796. * DOM Level 3 WD - Experimental.
  797. * Renaming node
  798. */
  799. public Node renameNode(Node n,String namespaceURI,String name)
  800. throws DOMException{
  801. if (n.getOwnerDocument() != this && n != this) {
  802. String msg = DOMMessageFormatter.formatMessage(
  803. DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
  804. throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
  805. }
  806. switch (n.getNodeType()) {
  807. case ELEMENT_NODE: {
  808. ElementImpl el = (ElementImpl) n;
  809. if (el instanceof ElementNSImpl) {
  810. ((ElementNSImpl) el).rename(namespaceURI, name);
  811. // fire user data NODE_RENAMED event
  812. callUserDataHandlers(el, null,
  813. UserDataHandler.NODE_RENAMED);
  814. }
  815. else {
  816. if (namespaceURI == null) {
  817. int colon1 = name.indexOf(':');
  818. if(colon1 != -1){
  819. String msg =
  820. DOMMessageFormatter.formatMessage(
  821. DOMMessageFormatter.DOM_DOMAIN,
  822. "NAMESPACE_ERR",
  823. null);
  824. throw new DOMException(DOMException.NAMESPACE_ERR, msg);
  825. }
  826. if (errorChecking && !isXMLName(name,xml11Version)) {
  827. String msg = DOMMessageFormatter.formatMessage(
  828. DOMMessageFormatter.DOM_DOMAIN,
  829. "INVALID_CHARACTER_ERR", null);
  830. throw new DOMException(DOMException.INVALID_CHARACTER_ERR,
  831. msg);
  832. }
  833. el.rename(name);
  834. // fire user data NODE_RENAMED event
  835. callUserDataHandlers(el, null,
  836. UserDataHandler.NODE_RENAMED);
  837. }
  838. else {
  839. // we need to create a new object
  840. ElementNSImpl nel =
  841. new ElementNSImpl(this, namespaceURI, name);
  842. // register event listeners on new node
  843. copyEventListeners(el, nel);
  844. // remove user data from old node
  845. Hashtable data = removeUserDataTable(el);
  846. // remove old node from parent if any
  847. Node parent = el.getParentNode();
  848. Node nextSib = el.getNextSibling();
  849. if (parent != null) {
  850. parent.removeChild(el);
  851. }
  852. // move children to new node
  853. Node child = el.getFirstChild();
  854. while (child != null) {
  855. el.removeChild(child);
  856. nel.appendChild(child);
  857. child = el.getFirstChild();
  858. }
  859. // move specified attributes to new node
  860. nel.moveSpecifiedAttributes(el);
  861. // attach user data to new node
  862. setUserDataTable(nel, data);
  863. // and fire user data NODE_RENAMED event
  864. callUserDataHandlers(el, nel,
  865. UserDataHandler.NODE_RENAMED);
  866. // insert new node where old one was
  867. if (parent != null) {
  868. parent.insertBefore(nel, nextSib);
  869. }
  870. el = nel;
  871. }
  872. }
  873. // fire ElementNameChanged event
  874. renamedElement((Element) n, el);
  875. return el;
  876. }
  877. case ATTRIBUTE_NODE: {
  878. AttrImpl at = (AttrImpl) n;
  879. // dettach attr from element
  880. Element el = at.getOwnerElement();
  881. if (el != null) {
  882. el.removeAttributeNode(at);
  883. }
  884. if (n instanceof AttrNSImpl) {
  885. ((AttrNSImpl) at).rename(namespaceURI, name);
  886. // reattach attr to element
  887. if (el != null) {
  888. el.setAttributeNodeNS(at);
  889. }
  890. // fire user data NODE_RENAMED event
  891. callUserDataHandlers(at, null,
  892. UserDataHandler.NODE_RENAMED);
  893. }
  894. else {
  895. if (namespaceURI == null) {
  896. at.rename(name);
  897. // reattach attr to element
  898. if (el != null) {
  899. el.setAttributeNode(at);
  900. }
  901. // fire user data NODE_RENAMED event
  902. callUserDataHandlers(at, null,
  903. UserDataHandler.NODE_RENAMED);
  904. }
  905. else {
  906. // we need to create a new object
  907. AttrNSImpl nat =
  908. new AttrNSImpl(this, namespaceURI, name);
  909. // register event listeners on new node
  910. copyEventListeners(at, nat);
  911. // remove user data from old node
  912. Hashtable data = removeUserDataTable(at);
  913. // move children to new node
  914. Node child = at.getFirstChild();
  915. while (child != null) {
  916. at.removeChild(child);
  917. nat.appendChild(child);
  918. child = at.getFirstChild();
  919. }
  920. // attach user data to new node
  921. setUserDataTable(nat, data);
  922. // and fire user data NODE_RENAMED event
  923. callUserDataHandlers(at, nat,
  924. UserDataHandler.NODE_RENAMED);
  925. // reattach attr to element
  926. if (el != null) {
  927. el.setAttributeNode(nat);
  928. }
  929. at = nat;
  930. }
  931. }
  932. // fire AttributeNameChanged event
  933. renamedAttrNode((Attr) n, at);
  934. return at;
  935. }
  936. default: {
  937. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
  938. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  939. }
  940. }
  941. }
  942. /**
  943. * DOM Level 3 WD - Experimental
  944. * Normalize document.
  945. */
  946. public void normalizeDocument(){
  947. // No need to normalize if already normalized.
  948. if (isNormalized() && !isNormalizeDocRequired()) {
  949. return;
  950. }
  951. if (needsSyncChildren()) {
  952. synchronizeChildren();
  953. }
  954. if (domNormalizer == null) {
  955. domNormalizer = new DOMNormalizer();
  956. }
  957. if (fConfiguration == null) {
  958. fConfiguration = new DOMConfigurationImpl();
  959. }
  960. else {
  961. fConfiguration.reset();
  962. }
  963. domNormalizer.normalizeDocument(this, fConfiguration);
  964. isNormalized(true);
  965. //set the XMLversion changed value to false -- once we have finished
  966. //doing normalization
  967. xmlVersionChanged = false ;
  968. }
  969. /**
  970. * DOM Level 3 CR - Experimental
  971. *
  972. * The configuration used when <code>Document.normalizeDocument</code> is
  973. * invoked.
  974. * @since DOM Level 3
  975. */
  976. public DOMConfiguration getDomConfig(){
  977. if (fConfiguration == null) {
  978. fConfiguration = new DOMConfigurationImpl();
  979. }
  980. return fConfiguration;
  981. }
  982. /**
  983. * DOM Level 3 WD - Experimental.
  984. * Retrieve baseURI
  985. */
  986. public String getBaseURI() {
  987. return fDocumentURI;
  988. }
  989. /**
  990. * DOM Level 3 WD - Experimental.
  991. */
  992. public void setDocumentURI(String documentURI){
  993. fDocumentURI = documentURI;
  994. }
  995. //
  996. // DOM L3 LS
  997. //
  998. /**
  999. * DOM Level 3 WD - Experimental.
  1000. * Indicates whether the method load should be synchronous or
  1001. * asynchronous. When the async attribute is set to <code>true</code>
  1002. * the load method returns control to the caller before the document has
  1003. * completed loading. The default value of this property is
  1004. * <code>false</code>.
  1005. * <br>Setting the value of this attribute might throw NOT_SUPPORTED_ERR
  1006. * if the implementation doesn't support the mode the attribute is being
  1007. * set to. Should the DOM spec define the default value of this
  1008. * property? What if implementing both async and sync IO is impractical
  1009. * in some systems? 2001-09-14. default is <code>false</code> but we
  1010. * need to check with Mozilla and IE.
  1011. */
  1012. public boolean getAsync() {
  1013. return false;
  1014. }
  1015. /**
  1016. * DOM Level 3 WD - Experimental.
  1017. * Indicates whether the method load should be synchronous or
  1018. * asynchronous. When the async attribute is set to <code>true</code>
  1019. * the load method returns control to the caller before the document has
  1020. * completed loading. The default value of this property is
  1021. * <code>false</code>.
  1022. * <br>Setting the value of this attribute might throw NOT_SUPPORTED_ERR
  1023. * if the implementation doesn't support the mode the attribute is being
  1024. * set to. Should the DOM spec define the default value of this
  1025. * property? What if implementing both async and sync IO is impractical
  1026. * in some systems? 2001-09-14. default is <code>false</code> but we
  1027. * need to check with Mozilla and IE.
  1028. */
  1029. public void setAsync(boolean async) {
  1030. if (async) {
  1031. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
  1032. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  1033. }
  1034. }
  1035. /**
  1036. * DOM Level 3 WD - Experimental.
  1037. * If the document is currently being loaded as a result of the method
  1038. * <code>load</code> being invoked the loading and parsing is
  1039. * immediately aborted. The possibly partial result of parsing the
  1040. * document is discarded and the document is cleared.
  1041. */
  1042. public void abort() {
  1043. }
  1044. /**
  1045. * DOM Level 3 WD - Experimental.
  1046. *
  1047. * Replaces the content of the document with the result of parsing the
  1048. * given URI. Invoking this method will either block the caller or
  1049. * return to the caller immediately depending on the value of the async
  1050. * attribute. Once the document is fully loaded a "load" event (as
  1051. * defined in [<a href='http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331'>DOM Level 3 Events</a>]
  1052. * , except that the <code>Event.targetNode</code> will be the document,
  1053. * not an element) will be dispatched on the document. If an error
  1054. * occurs, an implementation dependent "error" event will be dispatched
  1055. * on the document. If this method is called on a document that is
  1056. * currently loading, the current load is interrupted and the new URI
  1057. * load is initiated.
  1058. * <br> When invoking this method the parameters used in the
  1059. * <code>DOMParser</code> interface are assumed to have their default
  1060. * values with the exception that the parameters <code>"entities"</code>
  1061. * , <code>"normalize-characters"</code>,
  1062. * <code>"check-character-normalization"</code> are set to
  1063. * <code>"false"</code>.
  1064. * <br> The result of a call to this method is the same the result of a
  1065. * call to <code>DOMParser.parseWithContext</code> with an input stream
  1066. * referencing the URI that was passed to this call, the document as the
  1067. * context node, and the action <code>ACTION_REPLACE_CHILDREN</code>.
  1068. * @param uri The URI reference for the XML file to be loaded. If this is
  1069. * a relative URI, the base URI used by the implementation is
  1070. * implementation dependent.
  1071. * @return If async is set to <code>true</code> <code>load</code> returns
  1072. * <code>true</code> if the document load was successfully initiated.
  1073. * If an error occurred when initiating the document load,
  1074. * <code>load</code> returns <code>false</code>.If async is set to
  1075. * <code>false</code> <code>load</code> returns <code>true</code> if
  1076. * the document was successfully loaded and parsed. If an error
  1077. * occurred when either loading or parsing the URI, <code>load</code>
  1078. * returns <code>false</code>.
  1079. */
  1080. public boolean load(String uri) {
  1081. return false;
  1082. }
  1083. /**
  1084. * DOM Level 3 WD - Experimental.
  1085. * Replace the content of the document with the result of parsing the
  1086. * input string, this method is always synchronous.
  1087. * @param source A string containing an XML document.
  1088. * @return <code>true</code> if parsing the input string succeeded
  1089. * without errors, otherwise <code>false</code>.
  1090. */
  1091. public boolean loadXML(String source) {
  1092. return false;
  1093. }
  1094. /**
  1095. * DOM Level 3 WD - Experimental.
  1096. * Save the document or the given node and all its descendants to a string
  1097. * (i.e. serialize the document or node).
  1098. * <br>The parameters used in the <code>LSSerializer</code> interface are
  1099. * assumed to have their default values when invoking this method.
  1100. * <br> The result of a call to this method is the same the result of a
  1101. * call to <code>LSSerializer.writeToString</code> with the document as
  1102. * the node to write.
  1103. * @param node Specifies what to serialize, if this parameter is
  1104. * <code>null</code> the whole document is serialized, if it's
  1105. * non-null the given node is serialized.
  1106. * @return The serialized document or <code>null</code> in case an error
  1107. * occurred.
  1108. * @exception DOMException
  1109. * WRONG_DOCUMENT_ERR: Raised if the node passed in as the node
  1110. * parameter is from an other document.
  1111. */
  1112. public String saveXML(Node node)
  1113. throws DOMException {
  1114. if ( node != null &&
  1115. this != node.getOwnerDocument() ) {
  1116. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
  1117. throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
  1118. }
  1119. DOMImplementationLS domImplLS = (DOMImplementationLS)DOMImplementationImpl.getDOMImplementation();
  1120. LSSerializer xmlWriter = domImplLS.createLSSerializer();
  1121. if (node == null) {
  1122. node = this;
  1123. }
  1124. return xmlWriter.writeToString(node);
  1125. }
  1126. /**
  1127. * Sets whether the DOM implementation generates mutation events
  1128. * upon operations.
  1129. */
  1130. void setMutationEvents(boolean set) {
  1131. // does nothing by default - overidden in subclass
  1132. }
  1133. /**
  1134. * Returns true if the DOM implementation generates mutation events.
  1135. */
  1136. boolean getMutationEvents() {
  1137. // does nothing by default - overriden in subclass
  1138. return false;
  1139. }
  1140. // non-DOM factory methods
  1141. /**
  1142. * NON-DOM
  1143. * Factory method; creates a DocumentType having this Document
  1144. * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building
  1145. * DTD information unspecified.)
  1146. *
  1147. * @param name The name of the Entity we wish to provide a value for.
  1148. *
  1149. * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
  1150. * DTDs are not permitted. (HTML not yet implemented.)
  1151. */
  1152. public DocumentType createDocumentType(String qualifiedName,
  1153. String publicID,
  1154. String systemID)
  1155. throws DOMException {
  1156. return new DocumentTypeImpl(this, qualifiedName, publicID, systemID);
  1157. } // createDocumentType(String):DocumentType
  1158. /**
  1159. * NON-DOM
  1160. * Factory method; creates an Entity having this Document
  1161. * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building
  1162. * DTD information unspecified.)
  1163. *
  1164. * @param name The name of the Entity we wish to provide a value for.
  1165. *
  1166. * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
  1167. * nonstandard entities are not permitted. (HTML not yet
  1168. * implemented.)
  1169. */
  1170. public Entity createEntity(String name)
  1171. throws DOMException {
  1172. if (errorChecking && !isXMLName(name,xml11Version)) {
  1173. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
  1174. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  1175. }
  1176. return new EntityImpl(this, name);
  1177. } // createEntity(String):Entity
  1178. /**
  1179. * NON-DOM
  1180. * Factory method; creates a Notation having this Document
  1181. * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building
  1182. * DTD information unspecified.)
  1183. *
  1184. * @param name The name of the Notation we wish to describe
  1185. *
  1186. * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
  1187. * notations are not permitted. (HTML not yet
  1188. * implemented.)
  1189. */
  1190. public Notation createNotation(String name)
  1191. throws DOMException {
  1192. if (errorChecking && !isXMLName(name,xml11Version)) {
  1193. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
  1194. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  1195. }
  1196. return new NotationImpl(this, name);
  1197. } // createNotation(String):Notation
  1198. /**
  1199. * NON-DOM Factory method: creates an element definition. Element
  1200. * definitions hold default attribute values.
  1201. */
  1202. public ElementDefinitionImpl createElementDefinition(String name)
  1203. throws DOMException {
  1204. if (errorChecking && !isXMLName(name,xml11Version)) {
  1205. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
  1206. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  1207. }
  1208. return new ElementDefinitionImpl(this, name);
  1209. } // createElementDefinition(String):ElementDefinitionImpl
  1210. // other non-DOM methods
  1211. /** NON-DOM: Get the number associated with this document. Used to
  1212. * order documents in the implementation.
  1213. */
  1214. protected int getNodeNumber() {
  1215. if (documentNumber==0) {
  1216. CoreDOMImplementationImpl cd = (CoreDOMImplementationImpl)CoreDOMImplementationImpl.getDOMImplementation();
  1217. documentNumber = cd.assignDocumentNumber();
  1218. }
  1219. return documentNumber;
  1220. }
  1221. /** NON-DOM: Get a number associated with a node created with respect
  1222. * to this document. Needed for compareDocumentPosition when nodes
  1223. * are disconnected. This is only used on demand.
  1224. */
  1225. protected int getNodeNumber(Node node) {
  1226. // Check if the node is already in the hash
  1227. // If so, retrieve the node number
  1228. // If not, assign a number to the node
  1229. // Node numbers are negative, from -1 to -n
  1230. int num;
  1231. if (nodeTable == null) {
  1232. nodeTable = new Hashtable();
  1233. num = --nodeCounter;
  1234. nodeTable.put(node, new Integer(num));
  1235. }
  1236. else {
  1237. Integer n = (Integer)nodeTable.get(node);
  1238. if (n== null) {
  1239. num = --nodeCounter;
  1240. nodeTable.put(node, new Integer(num));
  1241. }
  1242. else
  1243. num = n.intValue();
  1244. }
  1245. return num;
  1246. }
  1247. /**
  1248. * Copies a node from another document to this document. The new nodes are
  1249. * created using this document's factory methods and are populated with the
  1250. * data from the source's accessor methods defined by the DOM interfaces.
  1251. * Its behavior is otherwise similar to that of cloneNode.
  1252. * <p>
  1253. * According to the DOM specifications, document nodes cannot be imported
  1254. * and a NOT_SUPPORTED_ERR exception is thrown if attempted.
  1255. */
  1256. public Node importNode(Node source, boolean deep)
  1257. throws DOMException {
  1258. return importNode(source, deep, false, null);
  1259. } // importNode(Node,boolean):Node
  1260. /**
  1261. * Overloaded implementation of DOM's importNode method. This method
  1262. * provides the core functionality for the public importNode and cloneNode
  1263. * methods.
  1264. *
  1265. * The reversedIdentifiers parameter is provided for cloneNode to
  1266. * preserve the document's identifiers. The Hashtable has Elements as the
  1267. * keys and their identifiers as the values. When an element is being
  1268. * imported, a check is done for an associated identifier. If one exists,
  1269. * the identifier is registered with the new, imported element. If
  1270. * reversedIdentifiers is null, the parameter is not applied.
  1271. */
  1272. private Node importNode(Node source, boolean deep, boolean cloningDoc,
  1273. Hashtable reversedIdentifiers)
  1274. throws DOMException {
  1275. Node newnode=null;
  1276. Hashtable userData = null;
  1277. // Sigh. This doesn't work; too many nodes have private data that
  1278. // would have to be manually tweaked. May be able to add local
  1279. // shortcuts to each nodetype. Consider ?????
  1280. // if(source instanceof NodeImpl &&
  1281. // !(source instanceof DocumentImpl))
  1282. // {
  1283. // // Can't clone DocumentImpl since it invokes us...
  1284. // newnode=(NodeImpl)source.cloneNode(false);
  1285. // newnode.ownerDocument=this;
  1286. // }
  1287. // else
  1288. if(source instanceof NodeImpl)
  1289. userData = ((NodeImpl)source).getUserDataRecord();
  1290. int type = source.getNodeType();
  1291. switch (type) {
  1292. case ELEMENT_NODE: {
  1293. Element newElement;
  1294. boolean domLevel20 = source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0");
  1295. // Create element according to namespace support/qualification.
  1296. if(domLevel20 == false || source.getLocalName() == null)
  1297. newElement = createElement(source.getNodeName());
  1298. else
  1299. newElement = createElementNS(source.getNamespaceURI(),
  1300. source.getNodeName());
  1301. // Copy element's attributes, if any.
  1302. NamedNodeMap sourceAttrs = source.getAttributes();
  1303. if (sourceAttrs != null) {
  1304. int length = sourceAttrs.getLength();
  1305. for (int index = 0; index < length; index++) {
  1306. Attr attr = (Attr)sourceAttrs.item(index);
  1307. // NOTE: this methods is used for both importingNode
  1308. // and cloning the document node. In case of the
  1309. // clonning default attributes should be copied.
  1310. // But for importNode defaults should be ignored.
  1311. if (attr.getSpecified() || cloningDoc) {
  1312. Attr newAttr = (Attr)importNode(attr, true, cloningDoc,
  1313. reversedIdentifiers);
  1314. // Attach attribute according to namespace
  1315. // support/qualification.
  1316. if (domLevel20 == false ||
  1317. attr.getLocalName() == null)
  1318. newElement.setAttributeNode(newAttr);
  1319. else
  1320. newElement.setAttributeNodeNS(newAttr);
  1321. }
  1322. }
  1323. }
  1324. // Register element identifier.
  1325. if (reversedIdentifiers != null) {
  1326. // Does element have an associated identifier?
  1327. Object elementId = reversedIdentifiers.get(source);
  1328. if (elementId != null) {
  1329. if (identifiers == null)
  1330. identifiers = new Hashtable();
  1331. identifiers.put(elementId, newElement);
  1332. }
  1333. }
  1334. newnode = newElement;
  1335. break;
  1336. }
  1337. case ATTRIBUTE_NODE: {
  1338. if( source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0") ){
  1339. if (source.getLocalName() == null) {
  1340. newnode = createAttribute(source.getNodeName());
  1341. } else {
  1342. newnode = createAttributeNS(source.getNamespaceURI(),
  1343. source.getNodeName());
  1344. }
  1345. }
  1346. else {
  1347. newnode = createAttribute(source.getNodeName());
  1348. }
  1349. // if source is an AttrImpl from this very same implementation
  1350. // avoid creating the child nodes if possible
  1351. if (source instanceof AttrImpl) {
  1352. AttrImpl attr = (AttrImpl) source;
  1353. if (attr.hasStringValue()) {
  1354. AttrImpl newattr = (AttrImpl) newnode;
  1355. newattr.setValue(attr.getValue());
  1356. deep = false;
  1357. }
  1358. else {
  1359. deep = true;
  1360. }
  1361. }
  1362. else {
  1363. // According to the DOM spec the kids carry the value.
  1364. // However, there are non compliant implementations out
  1365. // there that fail to do so. To avoid ending up with no
  1366. // value at all, in this case we simply copy the text value
  1367. // directly.
  1368. if (source.getFirstChild() == null) {
  1369. newnode.setNodeValue(source.getNodeValue());
  1370. deep = false;
  1371. } else {
  1372. deep = true;
  1373. }
  1374. }
  1375. break;
  1376. }
  1377. case TEXT_NODE: {
  1378. newnode = createTextNode(source.getNodeValue());
  1379. break;
  1380. }
  1381. case CDATA_SECTION_NODE: {
  1382. newnode = createCDATASection(source.getNodeValue());
  1383. break;
  1384. }
  1385. case ENTITY_REFERENCE_NODE: {
  1386. newnode = createEntityReference(source.getNodeName());
  1387. // the subtree is created according to this doc by the method
  1388. // above, so avoid carrying over original subtree
  1389. deep = false;
  1390. break;
  1391. }
  1392. case ENTITY_NODE: {
  1393. Entity srcentity = (Entity)source;
  1394. EntityImpl newentity =
  1395. (EntityImpl)createEntity(source.getNodeName());
  1396. newentity.setPublicId(srcentity.getPublicId());
  1397. newentity.setSystemId(srcentity.getSystemId());
  1398. newentity.setNotationName(srcentity.getNotationName());
  1399. // Kids carry additional value,
  1400. // allow deep import temporarily
  1401. newentity.isReadOnly(false);
  1402. newnode = newentity;
  1403. break;
  1404. }
  1405. case PROCESSING_INSTRUCTION_NODE: {
  1406. newnode = createProcessingInstruction(source.getNodeName(),
  1407. source.getNodeValue());
  1408. break;
  1409. }
  1410. case COMMENT_NODE: {
  1411. newnode = createComment(source.getNodeValue());
  1412. break;
  1413. }
  1414. case DOCUMENT_TYPE_NODE: {
  1415. // unless this is used as part of cloning a Document
  1416. // forbid it for the sake of being compliant to the DOM spec
  1417. if (!cloningDoc) {
  1418. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
  1419. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  1420. }
  1421. DocumentType srcdoctype = (DocumentType)source;
  1422. DocumentTypeImpl newdoctype = (DocumentTypeImpl)
  1423. createDocumentType(srcdoctype.getNodeName(),
  1424. srcdoctype.getPublicId(),
  1425. srcdoctype.getSystemId());
  1426. // Values are on NamedNodeMaps
  1427. NamedNodeMap smap = srcdoctype.getEntities();
  1428. NamedNodeMap tmap = newdoctype.getEntities();
  1429. if(smap != null) {
  1430. for(int i = 0; i < smap.getLength(); i++) {
  1431. tmap.setNamedItem(importNode(smap.item(i), true, true,
  1432. reversedIdentifiers));
  1433. }
  1434. }
  1435. smap = srcdoctype.getNotations();
  1436. tmap = newdoctype.getNotations();
  1437. if (smap != null) {
  1438. for(int i = 0; i < smap.getLength(); i++) {
  1439. tmap.setNamedItem(importNode(smap.item(i), true, true,
  1440. reversedIdentifiers));
  1441. }
  1442. }
  1443. // NOTE: At this time, the DOM definition of DocumentType
  1444. // doesn't cover Elements and their Attributes. domimpl's
  1445. // extentions in that area will not be preserved, even if
  1446. // copying from domimpl to domimpl. We could special-case
  1447. // that here. Arguably we should. Consider. ?????
  1448. newnode = newdoctype;
  1449. break;
  1450. }
  1451. case DOCUMENT_FRAGMENT_NODE: {
  1452. newnode = createDocumentFragment();
  1453. // No name, kids carry value
  1454. break;
  1455. }
  1456. case NOTATION_NODE: {
  1457. Notation srcnotation = (Notation)source;
  1458. NotationImpl newnotation =
  1459. (NotationImpl)createNotation(source.getNodeName());
  1460. newnotation.setPublicId(srcnotation.getPublicId());
  1461. newnotation.setSystemId(srcnotation.getSystemId());
  1462. // Kids carry additional value
  1463. newnode = newnotation;
  1464. // No name, no value
  1465. break;
  1466. }
  1467. case DOCUMENT_NODE : // Can't import document nodes
  1468. default: { // Unknown node type
  1469. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
  1470. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  1471. }
  1472. }
  1473. if(userData != null)
  1474. callUserDataHandlers(source, newnode, UserDataHandler.NODE_IMPORTED,userData);
  1475. // If deep, replicate and attach the kids.
  1476. if (deep) {
  1477. for (Node srckid = source.getFirstChild();
  1478. srckid != null;
  1479. srckid = srckid.getNextSibling()) {
  1480. newnode.appendChild(importNode(srckid, true, cloningDoc,
  1481. reversedIdentifiers));
  1482. }
  1483. }
  1484. if (newnode.getNodeType() == Node.ENTITY_NODE) {
  1485. ((NodeImpl)newnode).setReadOnly(true, true);
  1486. }
  1487. return newnode;
  1488. } // importNode(Node,boolean,boolean,Hashtable):Node
  1489. /**
  1490. * DOM Level 3 WD - Experimental
  1491. * Change the node's ownerDocument, and its subtree, to this Document
  1492. *
  1493. * @param source The node to adopt.
  1494. * @see #importNode
  1495. **/
  1496. public Node adoptNode(Node source) {
  1497. NodeImpl node;
  1498. Hashtable userData = null;
  1499. try {
  1500. node = (NodeImpl) source;
  1501. } catch (ClassCastException e) {
  1502. // source node comes from a different DOMImplementation
  1503. return null;
  1504. }
  1505. switch (node.getNodeType()) {
  1506. case ATTRIBUTE_NODE: {
  1507. AttrImpl attr = (AttrImpl) node;
  1508. // remove node from wherever it is
  1509. if( attr.getOwnerElement() != null){
  1510. //1. owner element attribute is set to null
  1511. attr.getOwnerElement().removeAttributeNode(attr);
  1512. }
  1513. //2. specified flag is set to true
  1514. attr.isSpecified(true);
  1515. userData = node.getUserDataRecord();
  1516. //3. change ownership
  1517. attr.setOwnerDocument(this);
  1518. if(userData != null )
  1519. setUserDataTable(node,userData);
  1520. break;
  1521. }
  1522. //entity, notation nodes are read only nodes.. so they can't be adopted.
  1523. //runtime will fall through to NOTATION_NODE
  1524. case ENTITY_NODE:
  1525. case NOTATION_NODE:{
  1526. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
  1527. throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
  1528. }
  1529. //document, documentype nodes can't be adopted.
  1530. //runtime will fall through to DocumentTypeNode
  1531. case DOCUMENT_NODE:
  1532. case DOCUMENT_TYPE_NODE: {
  1533. String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
  1534. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
  1535. }
  1536. case ENTITY_REFERENCE_NODE: {
  1537. userData = node.getUserDataRecord();
  1538. Node parent = node.getParentNode();
  1539. if (parent != null) {
  1540. parent.removeChild(source);
  1541. }
  1542. // discard its replacement value
  1543. Node child;
  1544. while ((child = node.getFirstChild()) != null) {
  1545. node.removeChild(child);
  1546. }
  1547. // change ownership
  1548. node.setOwnerDocument(this);
  1549. if(userData != null)
  1550. setUserDataTable(node,userData);
  1551. // set its new replacement value if any
  1552. if (docType == null) {
  1553. break;
  1554. }
  1555. NamedNodeMap entities = docType.getEntities();
  1556. Node entityNode = entities.getNamedItem(node.getNodeName());
  1557. if (entityNode == null) {
  1558. break;
  1559. }
  1560. EntityImpl entity = (EntityImpl) entityNode;
  1561. for (child = entityNode.getFirstChild();
  1562. child != null; child = child.getNextSibling()) {
  1563. Node childClone = child.cloneNode(true);
  1564. node.appendChild(childClone);
  1565. }
  1566. break;
  1567. }
  1568. case ELEMENT_NODE: {
  1569. userData = node.getUserDataRecord();
  1570. // remove node from wherever it is
  1571. Node parent = node.getParentNode();
  1572. if (parent != null) {
  1573. parent.removeChild(source);
  1574. }
  1575. // change ownership
  1576. if(userData != null)
  1577. setUserDataTable(node,userData);
  1578. node.setOwnerDocument(this);
  1579. // reconcile default attributes
  1580. ((ElementImpl)node).reconcileDefaultAttributes();
  1581. break;
  1582. }
  1583. default: {
  1584. // remove node from wherever it is
  1585. userData = node.getUserDataRecord();
  1586. Node parent = node.getParentNode();
  1587. if (parent != null) {
  1588. parent.removeChild(source);
  1589. }
  1590. if(userData != null)
  1591. setUserDataTable(node,userData);
  1592. // change ownership
  1593. node.setOwnerDocument(this);
  1594. if(userData != null)
  1595. setUserDataTable(node,userData);
  1596. }
  1597. }
  1598. //DOM L3 Core CR
  1599. //http://www.w3.org/TR/2003/CR-DOM-Level-3-Core-20031107/core.html#UserDataHandler-ADOPTED
  1600. if(userData != null)
  1601. callUserDataHandlers(source, null, UserDataHandler.NODE_ADOPTED,userData);
  1602. return node;
  1603. }
  1604. // identifier maintenence
  1605. /**
  1606. * Introduced in DOM Level 2
  1607. * Returns the Element whose ID is given by elementId. If no such element
  1608. * exists, returns null. Behavior is not defined if more than one element
  1609. * has this ID.
  1610. * <p>
  1611. * Note: The DOM implementation must have information that says which
  1612. * attributes are of type ID. Attributes with the name "ID" are not of type
  1613. * ID unless so defined. Implementations that do not know whether
  1614. * attributes are of type ID or not are expected to return null.
  1615. * @see #getIdentifier
  1616. */
  1617. public Element getElementById(String elementId) {
  1618. return getIdentifier(elementId);
  1619. }
  1620. /**
  1621. * Remove all identifiers from the ID table
  1622. */
  1623. protected final void clearIdentifiers(){
  1624. if (identifiers != null){
  1625. identifiers.clear();
  1626. }
  1627. }
  1628. /**
  1629. * Registers an identifier name with a specified element node.
  1630. * If the identifier is already registered, the new element
  1631. * node replaces the previous node. If the specified element
  1632. * node is null, removeIdentifier() is called.
  1633. *
  1634. * @see #getIdentifier
  1635. * @see #removeIdentifier
  1636. */
  1637. public void putIdentifier(String idName, Element element) {
  1638. if (element == null) {
  1639. removeIdentifier(idName);
  1640. return;
  1641. }
  1642. if (needsSyncData()) {
  1643. synchronizeData();
  1644. }
  1645. if (identifiers == null) {
  1646. identifiers = new Hashtable();
  1647. }
  1648. identifiers.put(idName, element);
  1649. } // putIdentifier(String,Element)
  1650. /**
  1651. * Returns a previously registered element with the specified
  1652. * identifier name, or null if no element is registered.
  1653. *
  1654. * @see #putIdentifier
  1655. * @see #removeIdentifier
  1656. */
  1657. public Element getIdentifier(String idName) {
  1658. if (needsSyncData()) {
  1659. synchronizeData();
  1660. }
  1661. if (identifiers == null) {
  1662. return null;
  1663. }
  1664. Element elem = (Element) identifiers.get(idName);
  1665. if (elem != null) {
  1666. // check that the element is in the tree
  1667. Node parent = elem.getParentNode();
  1668. while (parent != null) {
  1669. if (parent == this) {
  1670. return elem;
  1671. }
  1672. parent = parent.getParentNode();
  1673. }
  1674. }
  1675. return null;
  1676. } // getIdentifier(String):Element
  1677. /**
  1678. * Removes a previously registered element with the specified
  1679. * identifier name.
  1680. *
  1681. * @see #putIdentifier
  1682. * @see #getIdentifier
  1683. */
  1684. public void removeIdentifier(String idName) {
  1685. if (needsSyncData()) {
  1686. synchronizeData();
  1687. }
  1688. if (identifiers == null) {
  1689. return;
  1690. }
  1691. identifiers.remove(idName);
  1692. } // removeIdentifier(String)
  1693. /** Returns an enumeration registered of identifier names. */
  1694. public Enumeration getIdentifiers() {
  1695. if (needsSyncData()) {
  1696. synchronizeData();
  1697. }
  1698. if (identifiers == null) {
  1699. identifiers = new Hashtable();
  1700. }
  1701. return identifiers.keys();
  1702. } // getIdentifiers():Enumeration
  1703. //
  1704. // DOM2: Namespace methods
  1705. //
  1706. /**
  1707. * Introduced in DOM Level 2. <p>
  1708. * Creates an element of the given qualified name and namespace URI.
  1709. * If the given namespaceURI is null or an empty string and the
  1710. * qualifiedName has a prefix that is "xml", the created element
  1711. * is bound to the predefined namespace
  1712. * "http://www.w3.org/XML/1998/namespace" [Namespaces].
  1713. * @param namespaceURI The namespace URI of the element to
  1714. * create.
  1715. * @param qualifiedName The qualified name of the element type to
  1716. * instantiate.
  1717. * @return Element A new Element object with the following attributes:
  1718. * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified
  1719. * name contains an invalid character.
  1720. * @throws DOMException NAMESPACE_ERR: Raised if the qualifiedName has a
  1721. * prefix that is "xml" and the namespaceURI is
  1722. * neither null nor an empty string nor
  1723. * "http://www.w3.org/XML/1998/namespace", or
  1724. * if the qualifiedName has a prefix different
  1725. * from "xml" and the namespaceURI is null or an
  1726. * empty string.
  1727. * @since WD-DOM-Level-2-19990923
  1728. */
  1729. public Element createElementNS(String namespaceURI, String qualifiedName)
  1730. throws DOMException {
  1731. return new ElementNSImpl(this, namespaceURI, qualifiedName);
  1732. }
  1733. /**
  1734. * NON-DOM: a factory method used by the Xerces DOM parser
  1735. * to create an element.
  1736. *
  1737. * @param namespaceURI The namespace URI of the element to
  1738. * create.
  1739. * @param qualifiedName The qualified name of the element type to
  1740. * instantiate.
  1741. * @param localpart The local name of the attribute to instantiate.
  1742. *
  1743. * @return Element A new Element object with the following attributes:
  1744. * @exception DOMException INVALID_CHARACTER_ERR: Raised if the specified
  1745. * name contains an invalid character.
  1746. */
  1747. public Element createElementNS(String namespaceURI, String qualifiedName,
  1748. String localpart)
  1749. throws DOMException {
  1750. return new ElementNSImpl(this, namespaceURI, qualifiedName, localpart);
  1751. }
  1752. /**
  1753. * Introduced in DOM Level 2. <p>
  1754. * Creates an attribute of the given qualified name and namespace URI.
  1755. * If the given namespaceURI is null or an empty string and the
  1756. * qualifiedName has a prefix that is "xml", the created element
  1757. * is bound to the predefined namespace
  1758. * "http://www.w3.org/XML/1998/namespace" [Namespaces].
  1759. *
  1760. * @param namespaceURI The namespace URI of the attribute to
  1761. * create. When it is null or an empty string,
  1762. * this method behaves like createAttribute.
  1763. * @param qualifiedName The qualified name of the attribute to
  1764. * instantiate.
  1765. * @return Attr A new Attr object.
  1766. * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified
  1767. * name contains an invalid character.
  1768. * @since WD-DOM-Level-2-19990923
  1769. */
  1770. public Attr createAttributeNS(String namespaceURI, String qualifiedName)
  1771. throws DOMException {
  1772. return new AttrNSImpl(this, namespaceURI, qualifiedName);
  1773. }
  1774. /**
  1775. * NON-DOM: a factory method used by the Xerces DOM parser
  1776. * to create an element.
  1777. *
  1778. * @param namespaceURI The namespace URI of the attribute to
  1779. * create. When it is null or an empty string,
  1780. * this method behaves like createAttribute.
  1781. * @param qualifiedName The qualified name of the attribute to
  1782. * instantiate.
  1783. * @param localpart The local name of the attribute to instantiate.
  1784. *
  1785. * @return Attr A new Attr object.
  1786. * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified
  1787. * name contains an invalid character.
  1788. */
  1789. public Attr createAttributeNS(String namespaceURI, String qualifiedName,
  1790. String localpart)
  1791. throws DOMException {
  1792. return new AttrNSImpl(this, namespaceURI, qualifiedName, localpart);
  1793. }
  1794. /**
  1795. * Introduced in DOM Level 2. <p>
  1796. * Returns a NodeList of all the Elements with a given local name and
  1797. * namespace URI in the order in which they would be encountered in a
  1798. * preorder traversal of the Document tree.
  1799. * @param namespaceURI The namespace URI of the elements to match
  1800. * on. The special value "*" matches all
  1801. * namespaces. When it is null or an empty
  1802. * string, this method behaves like
  1803. * getElementsByTagName.
  1804. * @param localName The local name of the elements to match on.
  1805. * The special value "*" matches all local names.
  1806. * @return NodeList A new NodeList object containing all the matched
  1807. * Elements.
  1808. * @since WD-DOM-Level-2-19990923
  1809. */
  1810. public NodeList getElementsByTagNameNS(String namespaceURI,
  1811. String localName) {
  1812. return new DeepNodeListImpl(this, namespaceURI, localName);
  1813. }
  1814. //
  1815. // Object methods
  1816. //
  1817. /** Clone. */
  1818. public Object clone() throws CloneNotSupportedException {
  1819. CoreDocumentImpl newdoc = (CoreDocumentImpl) super.clone();
  1820. newdoc.docType = null;
  1821. newdoc.docElement = null;
  1822. return newdoc;
  1823. }
  1824. //
  1825. // Public static methods
  1826. //
  1827. /**
  1828. * Check the string against XML's definition of acceptable names for
  1829. * elements and attributes and so on using the XMLCharacterProperties
  1830. * utility class
  1831. */
  1832. public static final boolean isXMLName(String s, boolean xml11Version) {
  1833. if (s == null) {
  1834. return false;
  1835. }
  1836. if(!xml11Version)
  1837. return XMLChar.isValidName(s);
  1838. else
  1839. return XML11Char.isXML11ValidName(s);
  1840. } // isXMLName(String):boolean
  1841. /**
  1842. * Checks if the given qualified name is legal with respect
  1843. * to the version of XML to which this document must conform.
  1844. *
  1845. * @param prefix prefix of qualified name
  1846. * @param local local part of qualified name
  1847. */
  1848. public static final boolean isValidQName(String prefix, String local, boolean xml11Version) {
  1849. // check that both prefix and local part match NCName
  1850. if (local == null) return false;
  1851. boolean validNCName = false;
  1852. if (!xml11Version) {
  1853. validNCName = (prefix == null || XMLChar.isValidNCName(prefix))
  1854. && XMLChar.isValidNCName(local);
  1855. }
  1856. else {
  1857. validNCName = (prefix == null || XML11Char.isXML11ValidNCName(prefix))
  1858. && XML11Char.isXML11ValidNCName(local);
  1859. }
  1860. return validNCName;
  1861. }
  1862. //
  1863. // Protected methods
  1864. //
  1865. /**
  1866. * Uses the kidOK lookup table to check whether the proposed
  1867. * tree structure is legal.
  1868. */
  1869. protected boolean isKidOK(Node parent, Node child) {
  1870. if (allowGrammarAccess &&
  1871. parent.getNodeType() == Node.DOCUMENT_TYPE_NODE) {
  1872. return child.getNodeType() == Node.ELEMENT_NODE;
  1873. }
  1874. return 0 != (kidOK[parent.getNodeType()] & 1 << child.getNodeType());
  1875. }
  1876. /**
  1877. * Denotes that this node has changed.
  1878. */
  1879. protected void changed() {
  1880. changes++;
  1881. }
  1882. /**
  1883. * Returns the number of changes to this node.
  1884. */
  1885. protected int changes() {
  1886. return changes;
  1887. }
  1888. // NodeListCache pool
  1889. /**
  1890. * Returns a NodeListCache for the given node.
  1891. */
  1892. NodeListCache getNodeListCache(ParentNode owner) {
  1893. if (fFreeNLCache == null) {
  1894. return new NodeListCache(owner);
  1895. }
  1896. NodeListCache c = fFreeNLCache;
  1897. fFreeNLCache = fFreeNLCache.next;
  1898. c.fChild = null;
  1899. c.fChildIndex = -1;
  1900. c.fLength = -1;
  1901. // revoke previous ownership
  1902. if (c.fOwner != null) {
  1903. c.fOwner.fNodeListCache = null;
  1904. }
  1905. c.fOwner = owner;
  1906. // c.next = null; not necessary, except for confused people...
  1907. return c;
  1908. }
  1909. /**
  1910. * Puts the given NodeListCache in the free list.
  1911. * Note: The owner node can keep using it until we reuse it
  1912. */
  1913. void freeNodeListCache(NodeListCache c) {
  1914. c.next = fFreeNLCache;
  1915. fFreeNLCache = c;
  1916. }
  1917. /**
  1918. * Associate an object to a key on this node. The object can later be
  1919. * retrieved from this node by calling <code>getUserData</code> with the
  1920. * same key.
  1921. * @param n The node to associate the object to.
  1922. * @param key The key to associate the object to.
  1923. * @param data The object to associate to the given key, or
  1924. * <code>null</code> to remove any existing association to that key.
  1925. * @param handler The handler to associate to that key, or
  1926. * <code>null</code>.
  1927. * @return Returns the <code>DOMObject</code> previously associated to
  1928. * the given key on this node, or <code>null</code> if there was none.
  1929. * @since DOM Level 3
  1930. *
  1931. * REVISIT: we could use a free list of UserDataRecord here
  1932. */
  1933. public Object setUserData(Node n, String key,
  1934. Object data, UserDataHandler handler) {
  1935. if (data == null) {
  1936. if (userData != null) {
  1937. Hashtable t = (Hashtable) userData.get(n);
  1938. if (t != null) {
  1939. Object o = t.remove(key);
  1940. if (o != null) {
  1941. UserDataRecord r = (UserDataRecord) o;
  1942. return r.fData;
  1943. }
  1944. }
  1945. }
  1946. return null;
  1947. }
  1948. else {
  1949. Hashtable t;
  1950. if (userData == null) {
  1951. userData = new Hashtable();
  1952. t = new Hashtable();
  1953. userData.put(n, t);
  1954. }
  1955. else {
  1956. t = (Hashtable) userData.get(n);
  1957. if (t == null) {
  1958. t = new Hashtable();
  1959. userData.put(n, t);
  1960. }
  1961. }
  1962. Object o = t.put(key, new UserDataRecord(data, handler));
  1963. if (o != null) {
  1964. UserDataRecord r = (UserDataRecord) o;
  1965. return r.fData;
  1966. }
  1967. return null;
  1968. }
  1969. }
  1970. /**
  1971. * Retrieves the object associated to a key on a this node. The object
  1972. * must first have been set to this node by calling
  1973. * <code>setUserData</code> with the same key.
  1974. * @param n The node the object is associated to.
  1975. * @param key The key the object is associated to.
  1976. * @return Returns the <code>DOMObject</code> associated to the given key
  1977. * on this node, or <code>null</code> if there was none.
  1978. * @since DOM Level 3
  1979. */
  1980. public Object getUserData(Node n, String key) {
  1981. if (userData == null) {
  1982. return null;
  1983. }
  1984. Hashtable t = (Hashtable) userData.get(n);
  1985. if (t == null) {
  1986. return null;
  1987. }
  1988. Object o = t.get(key);
  1989. if (o != null) {
  1990. UserDataRecord r = (UserDataRecord) o;
  1991. return r.fData;
  1992. }
  1993. return null;
  1994. }
  1995. protected Hashtable getUserDataRecord(Node n){
  1996. if (userData == null) {
  1997. return null;
  1998. }
  1999. Hashtable t = (Hashtable) userData.get(n);
  2000. if (t == null) {
  2001. return null;
  2002. }
  2003. return t;
  2004. }
  2005. /**
  2006. * Remove user data table for the given node.
  2007. * @param n The node this operation applies to.
  2008. * @return The removed table.
  2009. */
  2010. Hashtable removeUserDataTable(Node n) {
  2011. if (userData == null) {
  2012. return null;
  2013. }
  2014. return (Hashtable) userData.get(n);
  2015. }
  2016. /**
  2017. * Set user data table for the given node.
  2018. * @param n The node this operation applies to.
  2019. * @param data The user data table.
  2020. */
  2021. void setUserDataTable(Node n, Hashtable data) {
  2022. if (userData == null)
  2023. userData = new Hashtable();
  2024. if (data != null) {
  2025. userData.put(n, data);
  2026. }
  2027. }
  2028. /**
  2029. * Call user data handlers when a node is deleted (finalized)
  2030. * @param n The node this operation applies to.
  2031. * @param c The copy node or null.
  2032. * @param operation The operation - import, clone, or delete.
  2033. */
  2034. void callUserDataHandlers(Node n, Node c, short operation) {
  2035. if (userData == null) {
  2036. return;
  2037. }
  2038. //Hashtable t = (Hashtable) userData.get(n);
  2039. if(n instanceof NodeImpl){
  2040. Hashtable t = ((NodeImpl)n).getUserDataRecord();
  2041. if (t == null || t.isEmpty()) {
  2042. return;
  2043. }
  2044. callUserDataHandlers(n, c, operation,t);
  2045. }
  2046. }
  2047. /**
  2048. * Call user data handlers when a node is deleted (finalized)
  2049. * @param n The node this operation applies to.
  2050. * @param c The copy node or null.
  2051. * @param operation The operation - import, clone, or delete.
  2052. * @param handlers Data associated with n.
  2053. */
  2054. void callUserDataHandlers(Node n, Node c, short operation,Hashtable userData) {
  2055. if (userData == null || userData.isEmpty()) {
  2056. return;
  2057. }
  2058. Enumeration keys = userData.keys();
  2059. while (keys.hasMoreElements()) {
  2060. String key = (String) keys.nextElement();
  2061. UserDataRecord r = (UserDataRecord) userData.get(key);
  2062. if (r.fHandler != null) {
  2063. r.fHandler.handle(operation, key, r.fData, n, c);
  2064. }
  2065. }
  2066. }
  2067. /**
  2068. * Call user data handlers to let them know the nodes they are related to
  2069. * are being deleted. The alternative would be to do that on Node but
  2070. * because the nodes are used as the keys we have a reference to them that
  2071. * prevents them from being gc'ed until the document is. At the same time,
  2072. * doing it here has the advantage of avoiding a finalize() method on Node,
  2073. * which would affect all nodes and not just the ones that have a user
  2074. * data.
  2075. */
  2076. // Temporarily comment out this method, because
  2077. // 1. It seems that finalizers are not guaranteed to be called, so the
  2078. // functionality is not implemented.
  2079. // 2. It affects the performance greatly in multi-thread environment.
  2080. // -SG
  2081. /*public void finalize() {
  2082. if (userData == null) {
  2083. return;
  2084. }
  2085. Enumeration nodes = userData.keys();
  2086. while (nodes.hasMoreElements()) {
  2087. Object node = nodes.nextElement();
  2088. Hashtable t = (Hashtable) userData.get(node);
  2089. if (t != null && !t.isEmpty()) {
  2090. Enumeration keys = t.keys();
  2091. while (keys.hasMoreElements()) {
  2092. String key = (String) keys.nextElement();
  2093. UserDataRecord r = (UserDataRecord) t.get(key);
  2094. if (r.fHandler != null) {
  2095. r.fHandler.handle(UserDataHandler.NODE_DELETED,
  2096. key, r.fData, null, null);
  2097. }
  2098. }
  2099. }
  2100. }
  2101. }*/
  2102. protected final void checkNamespaceWF( String qname, int colon1,
  2103. int colon2) {
  2104. if (!errorChecking) {
  2105. return;
  2106. }
  2107. // it is an error for NCName to have more than one ':'
  2108. // check if it is valid QName [Namespace in XML production 6]
  2109. // :camera , nikon:camera:minolta, camera:
  2110. if (colon1 == 0 || colon1 == qname.length() - 1 || colon2 != colon1) {
  2111. String msg =
  2112. DOMMessageFormatter.formatMessage(
  2113. DOMMessageFormatter.DOM_DOMAIN,
  2114. "NAMESPACE_ERR",
  2115. null);
  2116. throw new DOMException(DOMException.NAMESPACE_ERR, msg);
  2117. }
  2118. }
  2119. protected final void checkDOMNSErr(String prefix,
  2120. String namespace) {
  2121. if (errorChecking) {
  2122. if (namespace == null) {
  2123. String msg =
  2124. DOMMessageFormatter.formatMessage(
  2125. DOMMessageFormatter.DOM_DOMAIN,
  2126. "NAMESPACE_ERR",
  2127. null);
  2128. throw new DOMException(DOMException.NAMESPACE_ERR, msg);
  2129. }
  2130. else if (prefix.equals("xml")
  2131. && !namespace.equals(NamespaceContext.XML_URI)) {
  2132. String msg =
  2133. DOMMessageFormatter.formatMessage(
  2134. DOMMessageFormatter.DOM_DOMAIN,
  2135. "NAMESPACE_ERR",
  2136. null);
  2137. throw new DOMException(DOMException.NAMESPACE_ERR, msg);
  2138. }
  2139. else if (
  2140. prefix.equals("xmlns")
  2141. && !namespace.equals(NamespaceContext.XMLNS_URI)
  2142. || (!prefix.equals("xmlns")
  2143. && namespace.equals(NamespaceContext.XMLNS_URI))) {
  2144. String msg =
  2145. DOMMessageFormatter.formatMessage(
  2146. DOMMessageFormatter.DOM_DOMAIN,
  2147. "NAMESPACE_ERR",
  2148. null);
  2149. throw new DOMException(DOMException.NAMESPACE_ERR, msg);
  2150. }
  2151. }
  2152. }
  2153. /**
  2154. * Checks if the given qualified name is legal with respect
  2155. * to the version of XML to which this document must conform.
  2156. *
  2157. * @param prefix prefix of qualified name
  2158. * @param local local part of qualified name
  2159. */
  2160. protected final void checkQName(String prefix, String local) {
  2161. if (!errorChecking) {
  2162. return;
  2163. }
  2164. // check that both prefix and local part match NCName
  2165. boolean validNCName = false;
  2166. if (!xml11Version) {
  2167. validNCName = (prefix == null || XMLChar.isValidNCName(prefix))
  2168. && XMLChar.isValidNCName(local);
  2169. }
  2170. else {
  2171. validNCName = (prefix == null || XML11Char.isXML11ValidNCName(prefix))
  2172. && XML11Char.isXML11ValidNCName(local);
  2173. }
  2174. if (!validNCName) {
  2175. // REVISIT: add qname parameter to the message
  2176. String msg =
  2177. DOMMessageFormatter.formatMessage(
  2178. DOMMessageFormatter.DOM_DOMAIN,
  2179. "INVALID_CHARACTER_ERR",
  2180. null);
  2181. throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
  2182. }
  2183. }
  2184. /**
  2185. * We could have more xml versions in future , but for now we could
  2186. * do with this to handle XML 1.0 and 1.1
  2187. */
  2188. boolean isXML11Version(){
  2189. return xml11Version;
  2190. }
  2191. boolean isNormalizeDocRequired(){
  2192. // REVISIT: Implement to optimize when normalization
  2193. // is required
  2194. return true;
  2195. }
  2196. //we should be checking the (elements, attribute, entity etc.) names only when
  2197. //version of the document is changed.
  2198. boolean isXMLVersionChanged(){
  2199. return xmlVersionChanged ;
  2200. }
  2201. /**
  2202. * NON-DOM: kept for backward compatibility
  2203. * Store user data related to a given node
  2204. * This is a place where we could use weak references! Indeed, the node
  2205. * here won't be GC'ed as long as some user data is attached to it, since
  2206. * the userData table will have a reference to the node.
  2207. */
  2208. protected void setUserData(NodeImpl n, Object data) {
  2209. setUserData(n, "XERCES1DOMUSERDATA", data, null);
  2210. }
  2211. /**
  2212. * NON-DOM: kept for backward compatibility
  2213. * Retreive user data related to a given node
  2214. */
  2215. protected Object getUserData(NodeImpl n) {
  2216. return getUserData(n, "XERCES1DOMUSERDATA");
  2217. }
  2218. // Event related methods overidden in subclass
  2219. protected void addEventListener(NodeImpl node, String type,
  2220. EventListener listener,
  2221. boolean useCapture) {
  2222. // does nothing by default - overidden in subclass
  2223. }
  2224. protected void removeEventListener(NodeImpl node, String type,
  2225. EventListener listener,
  2226. boolean useCapture) {
  2227. // does nothing by default - overidden in subclass
  2228. }
  2229. protected void copyEventListeners(NodeImpl src, NodeImpl tgt) {
  2230. // does nothing by default - overidden in subclass
  2231. }
  2232. protected boolean dispatchEvent(NodeImpl node, Event event) {
  2233. // does nothing by default - overidden in subclass
  2234. return false;
  2235. }
  2236. // Notification methods overidden in subclasses
  2237. /**
  2238. * A method to be called when some text was changed in a text node,
  2239. * so that live objects can be notified.
  2240. */
  2241. void replacedText(NodeImpl node) {
  2242. }
  2243. /**
  2244. * A method to be called when some text was deleted from a text node,
  2245. * so that live objects can be notified.
  2246. */
  2247. void deletedText(NodeImpl node, int offset, int count) {
  2248. }
  2249. /**
  2250. * A method to be called when some text was inserted into a text node,
  2251. * so that live objects can be notified.
  2252. */
  2253. void insertedText(NodeImpl node, int offset, int count) {
  2254. }
  2255. /**
  2256. * A method to be called when a character data node has been modified
  2257. */
  2258. void modifyingCharacterData(NodeImpl node) {
  2259. }
  2260. /**
  2261. * A method to be called when a character data node has been modified
  2262. */
  2263. void modifiedCharacterData(NodeImpl node, String oldvalue, String value) {
  2264. }
  2265. /**
  2266. * A method to be called when a node is about to be inserted in the tree.
  2267. */
  2268. void insertingNode(NodeImpl node, boolean replace) {
  2269. }
  2270. /**
  2271. * A method to be called when a node has been inserted in the tree.
  2272. */
  2273. void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) {
  2274. }
  2275. /**
  2276. * A method to be called when a node is about to be removed from the tree.
  2277. */
  2278. void removingNode(NodeImpl node, NodeImpl oldChild, boolean replace) {
  2279. }
  2280. /**
  2281. * A method to be called when a node has been removed from the tree.
  2282. */
  2283. void removedNode(NodeImpl node, boolean replace) {
  2284. }
  2285. /**
  2286. * A method to be called when a node is about to be replaced in the tree.
  2287. */
  2288. void replacingNode(NodeImpl node) {
  2289. }
  2290. /**
  2291. * A method to be called when a node has been replaced in the tree.
  2292. */
  2293. void replacedNode(NodeImpl node) {
  2294. }
  2295. /**
  2296. * A method to be called when an attribute value has been modified
  2297. */
  2298. void modifiedAttrValue(AttrImpl attr, String oldvalue) {
  2299. }
  2300. /**
  2301. * A method to be called when an attribute node has been set
  2302. */
  2303. void setAttrNode(AttrImpl attr, AttrImpl previous) {
  2304. }
  2305. /**
  2306. * A method to be called when an attribute node has been removed
  2307. */
  2308. void removedAttrNode(AttrImpl attr, NodeImpl oldOwner, String name) {
  2309. }
  2310. /**
  2311. * A method to be called when an attribute node has been renamed
  2312. */
  2313. void renamedAttrNode(Attr oldAt, Attr newAt) {
  2314. }
  2315. /**
  2316. * A method to be called when an element has been renamed
  2317. */
  2318. void renamedElement(Element oldEl, Element newEl) {
  2319. }
  2320. } // class CoreDocumentImpl