001: /* Document.java
002:
003: {{IS_NOTE
004:
005: Purpose:
006: Description:
007: History:
008: 2001/10/21 16:36:39, Create, Tom M. Yeh.
009: }}IS_NOTE
010:
011: Copyright (C) 2001 Potix Corporation. All Rights Reserved.
012:
013: {{IS_RIGHT
014: This program is distributed under GPL Version 2.0 in the hope that
015: it will be useful, but WITHOUT ANY WARRANTY.
016: }}IS_RIGHT
017: */
018: package org.zkoss.idom;
019:
020: import java.util.List;
021: import java.util.Iterator;
022:
023: import org.w3c.dom.Node;
024: import org.w3c.dom.NodeList;
025: import org.w3c.dom.Attr;
026: import org.w3c.dom.DocumentType;
027: import org.w3c.dom.CDATASection;
028: import org.w3c.dom.DOMConfiguration;
029:
030: import org.zkoss.util.CheckableTreeArray;
031: import org.zkoss.xml.FacadeNodeList;
032: import org.zkoss.idom.impl.*;
033:
034: /**
035: * Represents Document which is also W3C/DOM's document,
036: * ie, org.w3c.dom.Document.
037: *
038: * @author tomyeh
039: * @see Element
040: */
041: public class Document extends AbstractGroup implements
042: org.w3c.dom.Document {
043: /** The document type. */
044: private DocType _docType;
045: /** The root element. */
046: private Element _root;
047: private String _docURI, _ver = "1.0";
048: private boolean _stdalone, _stricterrck = true;
049:
050: /** Constructor.
051: */
052: public Document(Element root, DocType dt) {
053: setRootElement(root);
054: setDocType(dt);
055: }
056:
057: /** Constructor.
058: */
059: public Document(Element root) {
060: setRootElement(root);
061: }
062:
063: /** Constructor.
064: */
065: public Document() {
066: }
067:
068: //-- Document extras --//
069: /**
070: * Gets the root element.
071: */
072: public final Element getRootElement() {
073: return _root;
074: }
075:
076: /**
077: * Sets the root element.
078: */
079: public final void setRootElement(Element root) {
080: checkWritable();
081: if (root == null) {
082: if (_root != null)
083: _children.remove(_root); //then calls this.setModified
084: } else {
085: if (_root != null)
086: _children.set(_children.indexOf(_root), root);
087: else
088: _children.add(root);
089: }
090: }
091:
092: /**
093: * Gets the document type.
094: */
095: public final DocType getDocType() {
096: return _docType;
097: }
098:
099: /**
100: * Sets the document type.
101: */
102: public final void setDocType(DocType docType) {
103: checkWritable();
104: if (docType == null) {
105: if (_docType != null)
106: _children.remove(_docType); //then calls this.setModified
107: } else {
108: if (_docType != null)
109: _children.set(_children.indexOf(_docType), docType);
110: else
111: _children.add(docType);
112: }
113: }
114:
115: //-- AbstractGroup --//
116: protected final List newChildren() {
117: return new ChildArray(); //note: it doesn't use that of AbstractGroup
118: }
119:
120: //-- Item --//
121: public final String getName() {
122: return "#document";
123: }
124:
125: //-- Node --//
126: public final short getNodeType() {
127: return DOCUMENT_NODE;
128: }
129:
130: //-- org.w3c.dom.Document --//
131: public final DocumentType getDoctype() {
132: return getDocType();
133: }
134:
135: public final org.w3c.dom.Element getDocumentElement() {
136: return getRootElement();
137: }
138:
139: public final org.w3c.dom.DOMImplementation getImplementation() {
140: return DOMImplementation.THE;
141: }
142:
143: // Unlike Crimson's createXxx, we don't set document here,
144: // because, in iDOM, document is decided automatically.
145:
146: public final org.w3c.dom.Element createElement(String lname) {
147: return new Element(lname);
148: }
149:
150: public final org.w3c.dom.Element createElementNS(String nsURI,
151: String tname) {
152: return new Element(nsURI, tname);
153: }
154:
155: public final Attr createAttribute(String lname) {
156: return new Attribute(lname, null);
157: }
158:
159: public final Attr createAttributeNS(String nsURI, String tname) {
160: return new Attribute(nsURI, tname, null);
161: }
162:
163: public final org.w3c.dom.DocumentFragment createDocumentFragment() {
164: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
165: getLocator()); //NOT YET
166: }
167:
168: public final org.w3c.dom.Text createTextNode(String data) {
169: return new Text(data);
170: }
171:
172: public final org.w3c.dom.Comment createComment(String data) {
173: return new Comment(data);
174: }
175:
176: public final CDATASection createCDATASection(String data) {
177: return new CData(data);
178: }
179:
180: public final org.w3c.dom.ProcessingInstruction createProcessingInstruction(
181: String target, String data) {
182: return new ProcessingInstruction(target, data);
183: }
184:
185: public final org.w3c.dom.EntityReference createEntityReference(
186: String name) {
187: return new EntityReference(name);
188: }
189:
190: /** Gets elements that matches the tag name.
191: *
192: * <p>Unlike other implementations (Xerces or Crimson), the returned list
193: * is a snapshot of the current tree -- not a "live" representation.
194: */
195: public final NodeList getElementsByTagName(String tname) {
196: return new FacadeNodeList(getElements(tname));
197: }
198:
199: /** Gets elements that matches the tag name and namespace.
200: *
201: * <p>Unlike other implementations (Xerces or Crimson), the returned list
202: * is a snapshot of the current tree -- not a "live" representation.
203: */
204: public final NodeList getElementsByTagNameNS(String nsURI,
205: String lname) {
206: return new FacadeNodeList(getElements(nsURI, lname, 0));
207: }
208:
209: public final org.w3c.dom.Element getElementById(String elementId) {
210: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
211: getLocator()); //NOT YET
212: }
213:
214: public final Node importNode(Node importedNode, boolean deep) {
215: throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
216: getLocator()); //NOT YET
217: }
218:
219: public String getInputEncoding() {
220: return null; //Level 3 not yet
221: }
222:
223: public String getXmlEncoding() {
224: return null; //Level 3 not yet
225: }
226:
227: public boolean getXmlStandalone() {
228: return _stdalone; //Level 3 not yet
229: }
230:
231: public void setXmlStandalone(boolean xmlStandalone)
232: throws DOMException {
233: _stdalone = xmlStandalone; //Level 3 not yet
234: }
235:
236: public String getXmlVersion() {
237: return _ver;
238: }
239:
240: public void setXmlVersion(String xmlVersion) throws DOMException {
241: _ver = xmlVersion; //Level 3 not yet
242: }
243:
244: public boolean getStrictErrorChecking() {
245: return _stricterrck; //Level 3 not yet
246: }
247:
248: public void setStrictErrorChecking(boolean strictErrorChecking) {
249: _stricterrck = strictErrorChecking; //Level 3 not yet
250: }
251:
252: public String getDocumentURI() {
253: return _docURI; //Level 3 not yet
254:
255: }
256:
257: public void setDocumentURI(String documentURI) {
258: _docURI = documentURI; //Level 3 not yet
259: }
260:
261: public Node adoptNode(Node source) throws DOMException {
262: throw new UnsupportedOperationException("DOM Level 3");
263: }
264:
265: public DOMConfiguration getDomConfig() {
266: throw new UnsupportedOperationException("DOM Level 3");
267: }
268:
269: public void normalizeDocument() {
270: //Level 3 not yet
271: }
272:
273: public Node renameNode(Node n, String namespaceURI,
274: String qualifiedName) throws DOMException {
275: throw new UnsupportedOperationException("DOM Level 3");
276: }
277:
278: //-- Object --//
279: public final String toString() {
280: StringBuffer sb = new StringBuffer(128).append("[Document: ");
281: if (_docType != null)
282: sb.append(_docType.toString());
283: if (_root != null)
284: sb.append(_root.toString());
285: return sb.append(']').toString();
286: }
287:
288: //-- ChildArray --//
289: protected class ChildArray extends CheckableTreeArray {
290: protected ChildArray() {
291: }
292:
293: protected void onAdd(Object newElement, Object followingElement) {
294: checkAdd(newElement, followingElement, false);
295: }
296:
297: protected void onSet(Object newElement, Object replaced) {
298: assert (replaced != null);
299: checkAdd(newElement, replaced, true);
300: }
301:
302: private void checkAdd(Object newVal, Object other,
303: boolean replace) {
304: checkWritable();
305:
306: //allowed type?
307: if (!(newVal instanceof Element)
308: && !(newVal instanceof DocType)
309: && !(newVal instanceof Comment)
310: && !(newVal instanceof ProcessingInstruction)
311: && !(newVal instanceof EntityReference))
312: throw new DOMException(
313: DOMException.HIERARCHY_REQUEST_ERR,
314: "Invalid type: "
315: + (newVal != null ? newVal.getClass()
316: : null) + " " + newVal,
317: getLocator());
318:
319: //to be safe, no auto-detach
320: Item newItem = (Item) newVal;
321: if (newItem.getParent() != null)
322: throw new DOMException(
323: DOMException.HIERARCHY_REQUEST_ERR, "Item, "
324: + newItem.toString()
325: + ", owned by other, "
326: + newItem.getParent(), getLocator());
327:
328: //reject add unless no one is set before
329: if (Document.this ._root != null
330: && (newItem instanceof Element)
331: && (!replace || !(other instanceof Element)))
332: throw new DOMException(
333: DOMException.HIERARCHY_REQUEST_ERR,
334: "Only one root element is allowed, when adding "
335: + newItem, getLocator());
336: if (Document.this ._docType != null
337: && (newItem instanceof DocType)
338: && (!replace || !(other instanceof DocType)))
339: throw new DOMException(
340: DOMException.HIERARCHY_REQUEST_ERR,
341: "Only one document type is allowed, when adding "
342: + newItem, getLocator());
343:
344: if (replace)
345: onRemove(other);
346: newItem.setParent(Document.this ); //then calls this.setModified
347:
348: if (newItem instanceof Element)
349: Document.this ._root = (Element) newItem;
350: else if (newItem instanceof DocType)
351: Document.this ._docType = (DocType) newItem;
352: }
353:
354: protected void onRemove(Object item) {
355: checkWritable();
356:
357: ((Item) item).setParent(null); //then calls this.setModified
358:
359: if (item instanceof Element)
360: Document.this ._root = null;
361: else if (item instanceof DocType)
362: Document.this._docType = null;
363: }
364: }
365: }
|