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 org.w3c.dom.DOMException;
  59. import org.w3c.dom.DocumentType;
  60. import org.w3c.dom.Node;
  61. import org.w3c.dom.NamedNodeMap;
  62. import java.util.Hashtable;
  63. import org.w3c.dom.UserDataHandler;
  64. /**
  65. * This class represents a Document Type <em>declaraction</em> in
  66. * the document itself, <em>not</em> a Document Type Definition (DTD).
  67. * An XML document may (or may not) have such a reference.
  68. * <P>
  69. * DocumentType is an Extended DOM feature, used in XML documents but
  70. * not in HTML.
  71. * <P>
  72. * Note that Entities and Notations are no longer children of the
  73. * DocumentType, but are parentless nodes hung only in their
  74. * appropriate NamedNodeMaps.
  75. * <P>
  76. * This area is UNDERSPECIFIED IN REC-DOM-Level-1-19981001
  77. * Most notably, absolutely no provision was made for storing
  78. * and using Element and Attribute information. Nor was the linkage
  79. * between Entities and Entity References nailed down solidly.
  80. *
  81. * @author Arnaud Le Hors, IBM
  82. * @author Joe Kesselman, IBM
  83. * @author Andy Clark, IBM
  84. * @version $Id: DocumentTypeImpl.java,v 1.25 2004/01/16 16:23:50 elena Exp $
  85. * @since PR-DOM-Level-1-19980818.
  86. */
  87. public class DocumentTypeImpl
  88. extends ParentNode
  89. implements DocumentType {
  90. //
  91. // Constants
  92. //
  93. /** Serialization version. */
  94. static final long serialVersionUID = 7751299192316526485L;
  95. //
  96. // Data
  97. //
  98. /** Document type name. */
  99. protected String name;
  100. /** Entities. */
  101. protected NamedNodeMapImpl entities;
  102. /** Notations. */
  103. protected NamedNodeMapImpl notations;
  104. // NON-DOM
  105. /** Elements. */
  106. protected NamedNodeMapImpl elements;
  107. // DOM2: support public ID.
  108. protected String publicID;
  109. // DOM2: support system ID.
  110. protected String systemID;
  111. // DOM2: support internal subset.
  112. protected String internalSubset;
  113. /** The following are required for compareDocumentPosition
  114. */
  115. // Doctype number. Doc types which have no owner may be assigned
  116. // a number, on demand, for ordering purposes for compareDocumentPosition
  117. private int doctypeNumber=0;
  118. //
  119. // Constructors
  120. //
  121. private Hashtable userData = null;
  122. /** Factory method for creating a document type node. */
  123. public DocumentTypeImpl(CoreDocumentImpl ownerDocument, String name) {
  124. super(ownerDocument);
  125. this.name = name;
  126. // DOM
  127. entities = new NamedNodeMapImpl(this);
  128. notations = new NamedNodeMapImpl(this);
  129. // NON-DOM
  130. elements = new NamedNodeMapImpl(this);
  131. } // <init>(CoreDocumentImpl,String)
  132. /** Factory method for creating a document type node. */
  133. public DocumentTypeImpl(CoreDocumentImpl ownerDocument,
  134. String qualifiedName,
  135. String publicID, String systemID) {
  136. this(ownerDocument, qualifiedName);
  137. this.publicID = publicID;
  138. this.systemID = systemID;
  139. } // <init>(CoreDocumentImpl,String)
  140. //
  141. // DOM2: methods.
  142. //
  143. /**
  144. * Introduced in DOM Level 2. <p>
  145. *
  146. * Return the public identifier of this Document type.
  147. * @since WD-DOM-Level-2-19990923
  148. */
  149. public String getPublicId() {
  150. if (needsSyncData()) {
  151. synchronizeData();
  152. }
  153. return publicID;
  154. }
  155. /**
  156. * Introduced in DOM Level 2. <p>
  157. *
  158. * Return the system identifier of this Document type.
  159. * @since WD-DOM-Level-2-19990923
  160. */
  161. public String getSystemId() {
  162. if (needsSyncData()) {
  163. synchronizeData();
  164. }
  165. return systemID;
  166. }
  167. /**
  168. * NON-DOM. <p>
  169. *
  170. * Set the internalSubset given as a string.
  171. */
  172. public void setInternalSubset(String internalSubset) {
  173. if (needsSyncData()) {
  174. synchronizeData();
  175. }
  176. this.internalSubset = internalSubset;
  177. }
  178. /**
  179. * Introduced in DOM Level 2. <p>
  180. *
  181. * Return the internalSubset given as a string.
  182. * @since WD-DOM-Level-2-19990923
  183. */
  184. public String getInternalSubset() {
  185. if (needsSyncData()) {
  186. synchronizeData();
  187. }
  188. return internalSubset;
  189. }
  190. //
  191. // Node methods
  192. //
  193. /**
  194. * A short integer indicating what type of node this is. The named
  195. * constants for this value are defined in the org.w3c.dom.Node interface.
  196. */
  197. public short getNodeType() {
  198. return Node.DOCUMENT_TYPE_NODE;
  199. }
  200. /**
  201. * Returns the document type name
  202. */
  203. public String getNodeName() {
  204. if (needsSyncData()) {
  205. synchronizeData();
  206. }
  207. return name;
  208. }
  209. /** Clones the node. */
  210. public Node cloneNode(boolean deep) {
  211. DocumentTypeImpl newnode = (DocumentTypeImpl)super.cloneNode(deep);
  212. // NamedNodeMaps must be cloned explicitly, to avoid sharing them.
  213. newnode.entities = entities.cloneMap(newnode);
  214. newnode.notations = notations.cloneMap(newnode);
  215. newnode.elements = elements.cloneMap(newnode);
  216. return newnode;
  217. } // cloneNode(boolean):Node
  218. /*
  219. * Get Node text content
  220. * @since DOM Level 3
  221. */
  222. public String getTextContent() throws DOMException {
  223. return null;
  224. }
  225. /*
  226. * Set Node text content
  227. * @since DOM Level 3
  228. */
  229. public void setTextContent(String textContent)
  230. throws DOMException {
  231. // no-op
  232. }
  233. /**
  234. * DOM Level 3 WD- Experimental.
  235. * Override inherited behavior from ParentNodeImpl to support deep equal.
  236. */
  237. public boolean isEqualNode(Node arg) {
  238. if (!super.isEqualNode(arg)) {
  239. return false;
  240. }
  241. if (needsSyncData()) {
  242. synchronizeData();
  243. }
  244. DocumentTypeImpl argDocType = (DocumentTypeImpl) arg;
  245. //test if the following string attributes are equal: publicId,
  246. //systemId, internalSubset.
  247. if ((getPublicId() == null && argDocType.getPublicId() != null)
  248. || (getPublicId() != null && argDocType.getPublicId() == null)
  249. || (getSystemId() == null && argDocType.getSystemId() != null)
  250. || (getSystemId() != null && argDocType.getSystemId() == null)
  251. || (getInternalSubset() == null
  252. && argDocType.getInternalSubset() != null)
  253. || (getInternalSubset() != null
  254. && argDocType.getInternalSubset() == null)) {
  255. return false;
  256. }
  257. if (getPublicId() != null) {
  258. if (!getPublicId().equals(argDocType.getPublicId())) {
  259. return false;
  260. }
  261. }
  262. if (getSystemId() != null) {
  263. if (!getSystemId().equals(argDocType.getSystemId())) {
  264. return false;
  265. }
  266. }
  267. if (getInternalSubset() != null) {
  268. if (!getInternalSubset().equals(argDocType.getInternalSubset())) {
  269. return false;
  270. }
  271. }
  272. //test if NamedNodeMaps entities and notations are equal
  273. NamedNodeMapImpl argEntities = argDocType.entities;
  274. if ((entities == null && argEntities != null)
  275. || (entities != null && argEntities == null))
  276. return false;
  277. if (entities != null && argEntities != null) {
  278. if (entities.getLength() != argEntities.getLength())
  279. return false;
  280. for (int index = 0; entities.item(index) != null; index++) {
  281. Node entNode1 = entities.item(index);
  282. Node entNode2 =
  283. argEntities.getNamedItem(entNode1.getNodeName());
  284. if (!((NodeImpl) entNode1).isEqualNode((NodeImpl) entNode2))
  285. return false;
  286. }
  287. }
  288. NamedNodeMapImpl argNotations = argDocType.notations;
  289. if ((notations == null && argNotations != null)
  290. || (notations != null && argNotations == null))
  291. return false;
  292. if (notations != null && argNotations != null) {
  293. if (notations.getLength() != argNotations.getLength())
  294. return false;
  295. for (int index = 0; notations.item(index) != null; index++) {
  296. Node noteNode1 = notations.item(index);
  297. Node noteNode2 =
  298. argNotations.getNamedItem(noteNode1.getNodeName());
  299. if (!((NodeImpl) noteNode1).isEqualNode((NodeImpl) noteNode2))
  300. return false;
  301. }
  302. }
  303. return true;
  304. } //end isEqualNode
  305. /**
  306. * NON-DOM
  307. * set the ownerDocument of this node and its children
  308. */
  309. void setOwnerDocument(CoreDocumentImpl doc) {
  310. super.setOwnerDocument(doc);
  311. entities.setOwnerDocument(doc);
  312. notations.setOwnerDocument(doc);
  313. elements.setOwnerDocument(doc);
  314. }
  315. /** NON-DOM
  316. * Get the number associated with this doctype.
  317. */
  318. protected int getNodeNumber() {
  319. // If the doctype has a document owner, get the node number
  320. // relative to the owner doc
  321. if (getOwnerDocument()!=null)
  322. return super.getNodeNumber();
  323. // The doctype is disconnected and not associated with any document.
  324. // Assign the doctype a number relative to the implementation.
  325. if (doctypeNumber==0) {
  326. CoreDOMImplementationImpl cd = (CoreDOMImplementationImpl)CoreDOMImplementationImpl.getDOMImplementation();
  327. doctypeNumber = cd.assignDocTypeNumber();
  328. }
  329. return doctypeNumber;
  330. }
  331. //
  332. // DocumentType methods
  333. //
  334. /**
  335. * Name of this document type. If we loaded from a DTD, this should
  336. * be the name immediately following the DOCTYPE keyword.
  337. */
  338. public String getName() {
  339. if (needsSyncData()) {
  340. synchronizeData();
  341. }
  342. return name;
  343. } // getName():String
  344. /**
  345. * Access the collection of general Entities, both external and
  346. * internal, defined in the DTD. For example, in:
  347. * <p>
  348. * <pre>
  349. * <!doctype example SYSTEM "ex.dtd" [
  350. * <!ENTITY foo "foo">
  351. * <!ENTITY bar "bar">
  352. * <!ENTITY % baz "baz">
  353. * ]>
  354. * </pre>
  355. * <p>
  356. * The Entities map includes foo and bar, but not baz. It is promised that
  357. * only Nodes which are Entities will exist in this NamedNodeMap.
  358. * <p>
  359. * For HTML, this will always be null.
  360. * <p>
  361. * Note that "built in" entities such as & and < should be
  362. * converted to their actual characters before being placed in the DOM's
  363. * contained text, and should be converted back when the DOM is rendered
  364. * as XML or HTML, and hence DO NOT appear here.
  365. */
  366. public NamedNodeMap getEntities() {
  367. if (needsSyncChildren()) {
  368. synchronizeChildren();
  369. }
  370. return entities;
  371. }
  372. /**
  373. * Access the collection of Notations defined in the DTD. A
  374. * notation declares, by name, the format of an XML unparsed entity
  375. * or is used to formally declare a Processing Instruction target.
  376. */
  377. public NamedNodeMap getNotations() {
  378. if (needsSyncChildren()) {
  379. synchronizeChildren();
  380. }
  381. return notations;
  382. }
  383. //
  384. // Public methods
  385. //
  386. /**
  387. * NON-DOM: Subclassed to flip the entities' and notations' readonly switch
  388. * as well.
  389. * @see NodeImpl#setReadOnly
  390. */
  391. public void setReadOnly(boolean readOnly, boolean deep) {
  392. if (needsSyncChildren()) {
  393. synchronizeChildren();
  394. }
  395. super.setReadOnly(readOnly, deep);
  396. // set read-only property
  397. elements.setReadOnly(readOnly, true);
  398. entities.setReadOnly(readOnly, true);
  399. notations.setReadOnly(readOnly, true);
  400. } // setReadOnly(boolean,boolean)
  401. /**
  402. * NON-DOM: Access the collection of ElementDefinitions.
  403. * @see ElementDefinitionImpl
  404. */
  405. public NamedNodeMap getElements() {
  406. if (needsSyncChildren()) {
  407. synchronizeChildren();
  408. }
  409. return elements;
  410. }
  411. public Object setUserData(String key,
  412. Object data, UserDataHandler handler) {
  413. if(userData == null)
  414. userData = new Hashtable();
  415. if (data == null) {
  416. if (userData != null) {
  417. Object o = userData.remove(key);
  418. if (o != null) {
  419. UserDataRecord r = (UserDataRecord) o;
  420. return r.fData;
  421. }
  422. }
  423. return null;
  424. }
  425. else {
  426. Object o = userData.put(key, new UserDataRecord(data, handler));
  427. if (o != null) {
  428. UserDataRecord r = (UserDataRecord) o;
  429. return r.fData;
  430. }
  431. }
  432. return null;
  433. }
  434. public Object getUserData(String key) {
  435. if (userData == null) {
  436. return null;
  437. }
  438. Object o = userData.get(key);
  439. if (o != null) {
  440. UserDataRecord r = (UserDataRecord) o;
  441. return r.fData;
  442. }
  443. return null;
  444. }
  445. protected Hashtable getUserDataRecord(){
  446. return userData;
  447. }
  448. } // class DocumentTypeImpl