zcommon/src/main/java/org/zkoss/idom/Document.java
/* Document.java
Purpose:
Description:
History:
2001/10/21 16:36:39, Create, Tom M. Yeh.
Copyright (C) 2001 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.idom;
import java.util.List;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.zkoss.idom.impl.AbstractGroup;
import org.zkoss.idom.impl.DOMImplementation;
import org.zkoss.idom.impl.FacadeNodeList;
import org.zkoss.util.NotableLinkedList;
/**
* Represents Document which is also W3C/DOM's document,
* i.e., org.w3c.dom.Document.
*
* @author tomyeh
* @see Element
*/
public class Document extends AbstractGroup implements org.w3c.dom.Document {
/** The document type. */
private DocType _docType;
/** The root element. */
private Element _root;
private String _docURI, _ver = "1.0";
private boolean _stdalone, _stricterrck = true;
/** Constructor.
*/
public Document(Element root, DocType dt) {
setRootElement(root);
setDocType(dt);
}
/** Constructor.
*/
public Document(Element root) {
setRootElement(root);
}
/** Constructor.
*/
public Document() {
}
//-- Document extras --//
/**
* Gets the root element.
*/
public final Element getRootElement() {
return _root;
}
/**
* Sets the root element.
*/
public final void setRootElement(Element root) {
if (root == null) {
if (_root != null)
_children.remove(_root);
} else {
if (_root != null)
_children.set(_children.indexOf(_root), root);
else
_children.add(root);
}
}
/**
* Gets the document type.
*/
public final DocType getDocType() {
return _docType;
}
/**
* Sets the document type.
*/
public final void setDocType(DocType docType) {
if (docType == null) {
if (_docType != null)
_children.remove(_docType);
} else {
if (_docType != null)
_children.set(_children.indexOf(_docType), docType);
else
_children.add(docType);
}
}
//-- AbstractGroup --//
protected final List<Item> newChildren() {
return new ChildArray(); //note: it doesn't use that of AbstractGroup
}
//-- Item --//
public final String getName() {
return "#document";
}
//-- Node --//
public final short getNodeType() {
return DOCUMENT_NODE;
}
//-- org.w3c.dom.Document --//
public final DocumentType getDoctype() {
return getDocType();
}
public final org.w3c.dom.Element getDocumentElement() {
return getRootElement();
}
public final org.w3c.dom.DOMImplementation getImplementation() {
return DOMImplementation.THE;
}
// Unlike Crimson's createXxx, we don't set document here,
// because, in iDOM, document is decided automatically.
public final org.w3c.dom.Element createElement(String lname) {
return new Element(lname);
}
public final org.w3c.dom.Element
createElementNS(String nsURI, String tname) {
return new Element(nsURI, tname);
}
public final Attr createAttribute(String lname) {
return new Attribute(lname, null);
}
public final Attr createAttributeNS(String nsURI, String tname) {
return new Attribute(nsURI, tname, null);
}
public final org.w3c.dom.DocumentFragment createDocumentFragment() {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, getLocator()); //NOT YET
}
public final org.w3c.dom.Text createTextNode(String data) {
return new Text(data);
}
public final org.w3c.dom.Comment createComment(String data) {
return new Comment(data);
}
public final CDATASection createCDATASection(String data) {
return new CData(data);
}
public final org.w3c.dom.ProcessingInstruction
createProcessingInstruction(String target, String data) {
return new ProcessingInstruction(target, data);
}
public final org.w3c.dom.EntityReference
createEntityReference(String name) {
return new EntityReference(name);
}
/** Gets elements that matches the tag name.
*
* <p>Unlike other implementations (Xerces or Crimson), the returned list
* is a snapshot of the current tree -- not a "live" representation.
*/
public final NodeList getElementsByTagName(String tname) {
return new FacadeNodeList(getElements(tname));
}
/** Gets elements that matches the tag name and namespace.
*
* <p>Unlike other implementations (Xerces or Crimson), the returned list
* is a snapshot of the current tree -- not a "live" representation.
*/
public final NodeList getElementsByTagNameNS
(String nsURI, String lname) {
return new FacadeNodeList(getElements(nsURI, lname, 0));
}
public final org.w3c.dom.Element getElementById(String elementId) {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, getLocator()); //NOT YET
}
public final Node importNode(Node importedNode, boolean deep) {
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, getLocator()); //NOT YET
}
public String getInputEncoding() {
return null; //Level 3 not yet
}
public String getXmlEncoding() {
return null; //Level 3 not yet
}
public boolean getXmlStandalone() {
return _stdalone; //Level 3 not yet
}
public void setXmlStandalone(boolean xmlStandalone) throws DOMException {
_stdalone = xmlStandalone; //Level 3 not yet
}
public String getXmlVersion() {
return _ver;
}
public void setXmlVersion(String xmlVersion) throws DOMException {
_ver = xmlVersion; //Level 3 not yet
}
public boolean getStrictErrorChecking() {
return _stricterrck; //Level 3 not yet
}
public void setStrictErrorChecking(boolean strictErrorChecking) {
_stricterrck = strictErrorChecking; //Level 3 not yet
}
public String getDocumentURI() {
return _docURI; //Level 3 not yet
}
public void setDocumentURI(String documentURI) {
_docURI = documentURI; //Level 3 not yet
}
public Node adoptNode(Node source) throws DOMException {
throw new UnsupportedOperationException("DOM Level 3");
}
public DOMConfiguration getDomConfig() {
throw new UnsupportedOperationException("DOM Level 3");
}
public void normalizeDocument() {
//Level 3 not yet
}
public Node renameNode(Node n, String namespaceURI, String qualifiedName)
throws DOMException {
throw new UnsupportedOperationException("DOM Level 3");
}
//-- Object --//
public final String toString() {
StringBuffer sb = new StringBuffer(128).append("[Document: ");
if (_docType != null)
sb.append(_docType.toString());
if (_root != null)
sb.append(_root.toString());
return sb.append(']').toString();
}
//-- ChildArray --//
protected class ChildArray extends NotableLinkedList<Item> {
protected ChildArray() {
}
protected void onAdd(Item newElement, Item followingElement) {
checkAdd(newElement, followingElement, false);
}
protected void onSet(Item newElement, Item replaced) {
assert(replaced != null);
checkAdd(newElement, replaced, true);
}
private void checkAdd(Item newItem, Item other, boolean replace) {
//allowed type?
if (!(newItem instanceof Element) && !(newItem instanceof DocType)
&& !(newItem instanceof Comment)
&& !(newItem instanceof ProcessingInstruction)
&& !(newItem instanceof EntityReference))
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
"Invalid type: "+(newItem!=null ? newItem.getClass(): null)+" "+newItem, getLocator());
//to be safe, no auto-detach
if (newItem.getParent() != null)
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
"Item, "+newItem.toString()+", owned by other, "+newItem.getParent(), getLocator());
//reject add unless no one is set before
if (Document.this._root != null && (newItem instanceof Element)
&& (!replace || !(other instanceof Element)))
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
"Only one root element is allowed, when adding "+newItem, getLocator());
if (Document.this._docType != null && (newItem instanceof DocType)
&& (!replace || !(other instanceof DocType)))
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
"Only one document type is allowed, when adding "+newItem, getLocator());
if (replace)
onRemove(other);
newItem.setParent(Document.this);
if (newItem instanceof Element)
Document.this._root = (Element)newItem;
else if (newItem instanceof DocType)
Document.this._docType = (DocType)newItem;
}
protected void onRemove(Item item) {
item.setParent(null);
if (item instanceof Element)
Document.this._root = null;
else if (item instanceof DocType)
Document.this._docType = null;
}
}
}