/* * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.ukit.dom; import java.util.Hashtable; import java.util.Enumeration; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Node; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.Text; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.DocumentFragment; import org.w3c.dom.EntityReference; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.CDATASection; import org.w3c.dom.NodeList; import org.w3c.dom.UserDataHandler; import org.w3c.dom.DOMException; /** * DOM document node implementation. * * @see org.w3c.dom.Node */ public abstract class XDoc extends XParent implements Document { /** Document's type. */ private DocumentType type; /** DOM implementation this document belongs to. */ private DOMImplementation impl; /** Document's root element. */ private Element root; /** Document's default attributes. Map of qnames to string arrays. */ private Hashtable attrs; /** Document's names. */ private Hashtable names; /* pkg */ final static char FLAG_BUILD = 0x0001; /* set during build */ /* pkg */ char flags; /** * Constructs document object from its document type and DOM implementation * object. */ protected XDoc(DOMImplementation implementation) { super(null, "#document", null); attrs = new Hashtable(); names = new Hashtable(); impl = implementation; } /** * A code representing the type of the underlying object, as defined above. */ public abstract short getNodeType(); /** * The Document Type Declaration (see <code>DocumentType</code>) * associated with this document. For HTML documents as well as XML * documents without a document type declaration this returns * <code>null</code>. The DOM Level 2 does not support editing the * Document Type Declaration. <code>docType</code> cannot be altered in * any way, including through the use of methods inherited from the * <code>Node</code> interface, such as <code>insertNode</code> or * <code>removeNode</code>. */ public DocumentType getDoctype() { return type; } /** * The <code>DOMImplementation</code> object that handles this document. A * DOM application may use objects from multiple implementations. */ public DOMImplementation getImplementation() { return impl; } /** * This is a convenience attribute that allows direct access to the child * node that is the root element of the document. For HTML documents, * this is the element with the tagName "HTML". */ public Element getDocumentElement() { return root; } /** * Creates an element of the type specified. Note that the instance * returned implements the <code>Element</code> interface, so attributes * can be specified directly on the returned object. * <br>In addition, if there are known attributes with default values, * <code>Attr</code> nodes representing them are automatically created * and attached to the element. * <br>To create an element with a qualified name and namespace URI, use * the <code>createElementNS</code> method. * * @param tagName The name of the element type to instantiate. For XML, * this is case-sensitive. For HTML, the <code>tagName</code> * parameter may be provided in any case, but it must be mapped to the * canonical uppercase form by the DOM implementation. * @return A new <code>Element</code> object with the * <code>nodeName</code> attribute set to <code>tagName</code>, and * <code>localName</code>, <code>prefix</code>, and * <code>namespaceURI</code> set to <code>null</code>. * @exception DOMException * INVALID_CHARACTER_ERR: Raised if the specified name contains an * illegal character. */ public Element createElement(String tagName) throws DOMException { XNode._checkName(tagName, false); return new ElmImp(null, tagName, this); } /** * Creates an element of the given qualified name and namespace URI. * HTML-only DOM implementations do not need to implement this method. * * @param namespaceURI The namespace URI of the element to create. * @param qualifiedName The qualified name of the element type to * instantiate. * @return A new <code>Element</code> object with the following * attributes:AttributeValue<code>Node.nodeName</code> * <code>qualifiedName</code><code>Node.namespaceURI</code> * <code>namespaceURI</code><code>Node.prefix</code>prefix, extracted * from <code>qualifiedName</code>, or <code>null</code> if there is * no prefix<code>Node.localName</code>local name, extracted from * <code>qualifiedName</code><code>Element.tagName</code> * <code>qualifiedName</code> * @exception DOMException * INVALID_CHARACTER_ERR: Raised if the specified qualified name * contains an illegal character. * <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is * malformed, if the <code>qualifiedName</code> has a prefix and the * <code>namespaceURI</code> is <code>null</code>, or if the * <code>qualifiedName</code> has a prefix that is "xml" and the * <code>namespaceURI</code> is different from " * http://www.w3.org/XML/1998/namespace" . * * @since DOM Level 2 */ public Element createElementNS(String namespaceURI, String qualifiedName) throws DOMException { int off = XNode._checkNameNS(namespaceURI, qualifiedName); if (off == 5 && qualifiedName.startsWith("xmlns")) throw new DOMException(DOMException.NAMESPACE_ERR, URI_XML); String nsuri = (namespaceURI != null)? namespaceURI: ""; return new ElmImp(nsuri, qualifiedName, this); } /** * Creates an <code>Attr</code> of the given name. Note that the * <code>Attr</code> instance can then be set on an <code>Element</code> * using the <code>setAttributeNode</code> method. * <br>To create an attribute with a qualified name and namespace URI, use * the <code>createAttributeNS</code> method. * * @param name The name of the attribute. * @return A new <code>Attr</code> object with the <code>nodeName</code> * attribute set to <code>name</code>, and <code>localName</code>, * <code>prefix</code>, and <code>namespaceURI</code> set to * <code>null</code>. The value of the attribute is the empty string. * @exception DOMException * INVALID_CHARACTER_ERR: Raised if the specified name contains an * illegal character. */ public Attr createAttribute(String name) throws DOMException { XNode._checkName(name, false); return new AttrImp(null, name, this); } /** * Creates an attribute of the given qualified name and namespace URI. * HTML-only DOM implementations do not need to implement this method. * * @param namespaceURI The namespace URI of the attribute to create. * @param qualifiedName The qualified name of the attribute to instantiate. * @return A new <code>Attr</code> object with the following attributes: * AttributeValue<code>Node.nodeName</code>qualifiedName * <code>Node.namespaceURI</code><code>namespaceURI</code> * <code>Node.prefix</code>prefix, extracted from * <code>qualifiedName</code>, or <code>null</code> if there is no * prefix<code>Node.localName</code>local name, extracted from * <code>qualifiedName</code><code>Attr.name</code> * <code>qualifiedName</code><code>Node.nodeValue</code>the empty * string * @exception DOMException * INVALID_CHARACTER_ERR: Raised if the specified qualified name * contains an illegal character. * <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is * malformed, if the <code>qualifiedName</code> has a prefix and the * <code>namespaceURI</code> is <code>null</code>, if the * <code>qualifiedName</code> has a prefix that is "xml" and the * <code>namespaceURI</code> is different from " * http://www.w3.org/XML/1998/namespace", or if the * <code>qualifiedName</code> is "xmlns" and the * <code>namespaceURI</code> is different from " * http://www.w3.org/2000/xmlns/". * @since DOM Level 2 */ public Attr createAttributeNS(String namespaceURI, String qualifiedName) throws DOMException { XNode._checkNameNS(namespaceURI, qualifiedName); String nsuri = (namespaceURI != null)? namespaceURI: ""; return new AttrImp(nsuri, qualifiedName, this); } /** * Creates a <code>Text</code> node given the specified string. * * @param data The data for the node. * @return The new <code>Text</code> object. */ public Text createTextNode(String data) { return new TextImp(TEXT_NODE, data, this); } /** * Creates a <code>Comment</code> node given the specified string. * * @param data The data for the node. * @return The new <code>Comment</code> object. */ public Comment createComment(String data) { return new CommImp(data, this); } /** * Creates a <code>CDATASection</code> node whose value is the specified * string. * * @param data The data for the <code>CDATASection</code> contents. * @return The new <code>CDATASection</code> object. * @exception DOMException * NOT_SUPPORTED_ERR: Raised if this document is an HTML document. */ public CDATASection createCDATASection(String data) throws DOMException { if (getDocumentElement() != null && "HTML".equals(getDocumentElement().getTagName())) throw new DOMException(DOMException.NOT_SUPPORTED_ERR, ""); return new TextImp(CDATA_SECTION_NODE, data, this); } /** * Creates a <code>ProcessingInstruction</code> node given the specified * name and data strings. * * @param target The target part of the processing instruction. * @param data The data for the node. * @return The new <code>ProcessingInstruction</code> object. * @exception DOMException * INVALID_CHARACTER_ERR: Raised if the specified target contains an * illegal character. * <br>NOT_SUPPORTED_ERR: Raised if this document is an HTML document. */ public ProcessingInstruction createProcessingInstruction( String target, String data) throws DOMException { if (getDocumentElement() != null && "HTML".equals(getDocumentElement().getTagName())) throw new DOMException(DOMException.NOT_SUPPORTED_ERR, ""); XNode._checkName(target, false); return new ProcInstImp(target, data, this); } /** * Creates an <code>EntityReference</code> object. In addition, if the * referenced entity is known, the child list of the * <code>EntityReference</code> node is made the same as that of the * corresponding <code>Entity</code> node.If any descendant of the * <code>Entity</code> node has an unbound namespace prefix, the * corresponding descendant of the created <code>EntityReference</code> * node is also unbound; (its <code>namespaceURI</code> is * <code>null</code>). The DOM Level 2 does not support any mechanism to * resolve namespace prefixes. * * @param name The name of the entity to reference. * @return The new <code>EntityReference</code> object. * @exception DOMException * INVALID_CHARACTER_ERR: Raised if the specified name contains an * illegal character. * <br>NOT_SUPPORTED_ERR: Raised if this document is an HTML document. */ public EntityReference createEntityReference(String name) throws DOMException { XNode._checkName(name, false); return new EntRefImp(name, this); } /** * Creates an empty <code>DocumentFragment</code> object. * * @return A new <code>DocumentFragment</code>. */ public DocumentFragment createDocumentFragment() { return new DocFragImp(this); } /** * Returns a <code>NodeList</code> of all the <code>Elements</code> with a * given tag name in the order in which they are encountered in a * preorder traversal of the <code>Document</code> tree. * * @param tagname The name of the tag to match on. The special value "*" * matches all tags. * @return A new <code>NodeList</code> object containing all the matched * <code>Elements</code>. */ public NodeList getElementsByTagName(String tagname) { ElmFilter filter = new ElmFilter(tagname); if (getDocumentElement() != null) ((XElm)getDocumentElement())._procEachChild(filter); return filter; } /** * Returns a <code>NodeList</code> of all the <code>Elements</code> with a * given local name and namespace URI in the order in which they are * encountered in a preorder traversal of the <code>Document</code> tree. * * @param namespaceURI The namespace URI of the elements to match on. The * special value "*" matches all namespaces. * @param localName The local name of the elements to match on. The * special value "*" matches all local names. * @return A new <code>NodeList</code> object containing all the matched * <code>Elements</code>. * * @since DOM Level 2 */ public NodeList getElementsByTagNameNS(String namespaceURI, String localName) { ElmFilter filter = new ElmFilter(namespaceURI, localName); if (getDocumentElement() != null) ((XElm)getDocumentElement())._procEachChild(filter); return filter; } /** * Returns the <code>Element</code> whose <code>ID</code> is given by * <code>elementId</code>. If no such element exists, returns * <code>null</code>. Behavior is not defined if more than one element * has this <code>ID</code>. The DOM implementation must have * information that says which attributes are of type ID. Attributes * with the name "ID" are not of type ID unless so defined. * Implementations that do not know whether attributes are of type ID or * not are expected to return <code>null</code>. * * @param elementId The unique <code>id</code> value for an element. * @return The matching element. * * @since DOM Level 2 */ public Element getElementById(String elementId) { return ((XElm)getDocumentElement())._getElmById(elementId); } /** * Returns a duplicate of this node, i.e., serves as a generic copy * constructor for nodes. The duplicate node has no parent; ( * <code>parentNode</code> is <code>null</code>.). * <br>Cloning an <code>Element</code> copies all attributes and their * values, including those generated by the XML processor to represent * defaulted attributes, but this method does not copy any text it * contains unless it is a deep clone, since the text is contained in a * child <code>Text</code> node. Cloning an <code>Attribute</code> * directly, as opposed to be cloned as part of an <code>Element</code> * cloning operation, returns a specified attribute ( * <code>specified</code> is <code>true</code>). Cloning any other type * of node simply returns a copy of this node. * <br>Note that cloning an immutable subtree results in a mutable copy, * but the children of an <code>EntityReference</code> clone are readonly * . In addition, clones of unspecified <code>Attr</code> nodes are * specified. And, cloning <code>Document</code>, * <code>DocumentType</code>, <code>Entity</code>, and * <code>Notation</code> nodes is implementation dependent. * * @param deep If <code>true</code>, recursively clone the subtree under * the specified node; if <code>false</code>, clone only the node * itself (and its attributes, if it is an <code>Element</code>). * @return The duplicate node. */ public Node cloneNode(boolean deep) { XDoc doc = new DocImp(impl); // Copy all default attributes Enumeration elms = attrs.keys(); while (elms.hasMoreElements()) { String elm = (String)elms.nextElement(); String dattrs[] = _getDefAttrs(elm); for (int idx = 0; idx < (dattrs.length >> 2); idx++) { int base = idx << 2; doc._setDefAttr(elm, dattrs[base], dattrs[base + 3]); } } if (deep == true) { // Add clones of all children for (int idx = 0; idx < getLength(); idx++) { XNode node = (XNode)(item(idx).cloneNode(true)); node._setDoc(doc); doc._appendChild(node); doc._childAdded(node); } } _notifyUDH(UserDataHandler.NODE_CLONED, doc); return doc; } /** * Imports a node from another document to this document. The returned * node has no parent; (<code>parentNode</code> is <code>null</code>). * The source node is not altered or removed from the original document; * this method creates a new copy of the source node. * <br>For all nodes, importing a node creates a node object owned by the * importing document, with attribute values identical to the source * node's <code>nodeName</code> and <code>nodeType</code>, plus the * attributes related to namespaces (<code>prefix</code>, * <code>localName</code>, and <code>namespaceURI</code>). As in the * <code>cloneNode</code> operation on a <code>Node</code>, the source * node is not altered. * <br>Additional information is copied as appropriate to the * <code>nodeType</code>, attempting to mirror the behavior expected if * a fragment of XML or HTML source was copied from one document to * another, recognizing that the two documents may have different DTDs * in the XML case. The following list describes the specifics for each * type of node. * <dl> * <dt>ATTRIBUTE_NODE</dt> * <dd>The <code>ownerElement</code> attribute * is set to <code>null</code> and the <code>specified</code> flag is * set to <code>true</code> on the generated <code>Attr</code>. The * descendants of the source <code>Attr</code> are recursively imported * and the resulting nodes reassembled to form the corresponding subtree. * Note that the <code>deep</code> parameter has no effect on * <code>Attr</code> nodes; they always carry their children with them * when imported.</dd> * <dt>DOCUMENT_FRAGMENT_NODE</dt> * <dd>If the <code>deep</code> option * was set to <code>true</code>, the descendants of the source element * are recursively imported and the resulting nodes reassembled to form * the corresponding subtree. Otherwise, this simply generates an empty * <code>DocumentFragment</code>.</dd> * <dt>DOCUMENT_NODE</dt> * <dd><code>Document</code> * nodes cannot be imported.</dd> * <dt>DOCUMENT_TYPE_NODE</dt> * <dd><code>DocumentType</code> * nodes cannot be imported.</dd> * <dt>ELEMENT_NODE</dt> * <dd>Specified attribute nodes of the * source element are imported, and the generated <code>Attr</code> * nodes are attached to the generated <code>Element</code>. Default * attributes are not copied, though if the document being imported into * defines default attributes for this element name, those are assigned. * If the <code>importNode</code> <code>deep</code> parameter was set to * <code>true</code>, the descendants of the source element are * recursively imported and the resulting nodes reassembled to form the * corresponding subtree.</dd> * <dt>ENTITY_NODE</dt> * <dd><code>Entity</code> nodes can be * imported, however in the current release of the DOM the * <code>DocumentType</code> is readonly. Ability to add these imported * nodes to a <code>DocumentType</code> will be considered for addition * to a future release of the DOM.On import, the <code>publicId</code>, * <code>systemId</code>, and <code>notationName</code> attributes are * copied. If a <code>deep</code> import is requested, the descendants * of the the source <code>Entity</code> are recursively imported and * the resulting nodes reassembled to form the corresponding subtree.</dd> * <dt> * ENTITY_REFERENCE_NODE</dt> * <dd>Only the <code>EntityReference</code> itself is * copied, even if a <code>deep</code> import is requested, since the * source and destination documents might have defined the entity * differently. If the document being imported into provides a * definition for this entity name, its value is assigned.</dd> * <dt>NOTATION_NODE</dt> * <dd> * <code>Notation</code> nodes can be imported, however in the current * release of the DOM the <code>DocumentType</code> is readonly. Ability * to add these imported nodes to a <code>DocumentType</code> will be * considered for addition to a future release of the DOM.On import, the * <code>publicId</code> and <code>systemId</code> attributes are copied. * Note that the <code>deep</code> parameter has no effect on * <code>Notation</code> nodes since they never have any children.</dd> * <dt> * PROCESSING_INSTRUCTION_NODE</dt> * <dd>The imported node copies its * <code>target</code> and <code>data</code> values from those of the * source node.</dd> * <dt>TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE</dt> * <dd>These three * types of nodes inheriting from <code>CharacterData</code> copy their * <code>data</code> and <code>length</code> attributes from those of * the source node.</dd> * * @param importedNode The node to import. * @param deep If <code>true</code>, recursively import the subtree under * the specified node; if <code>false</code>, import only the node * itself, as explained above. This has no effect on <code>Attr</code> * , <code>EntityReference</code>, and <code>Notation</code> nodes. * @return The imported node that belongs to this <code>Document</code>. * @exception DOMException * NOT_SUPPORTED_ERR: Raised if the type of node being imported is not * supported. * * @since DOM Level 2 */ public Node importNode(Node importedNode, boolean deep) throws DOMException { switch(importedNode.getNodeType()) { case DOCUMENT_NODE: case DOCUMENT_TYPE_NODE: throw new DOMException(DOMException.NOT_SUPPORTED_ERR, ""); default: } XNode node = _clone(importedNode, deep); node._setDoc(this); ((XNode)importedNode)._notifyUDH(UserDataHandler.NODE_IMPORTED, node); return node; } /** * Attempts to adopt a node from another document to this document. If * supported, it changes the <code>ownerDocument</code> of the source * node, its children, as well as the attached attribute nodes if there * are any. If the source node has a parent it is first removed from the * child list of its parent. This effectively allows moving a subtree * from one document to another. Note that if the adopted node is already part of this * document (i.e. the source and target document are the same), this * method still has the effect of removing the source node from the * child list of its parent, if any. The following list describes the * specifics for each type of node. * <dl> * <dt>ATTRIBUTE_NODE</dt> * <dd>The * <code>ownerElement</code> attribute is set to <code>null</code>. The * descendants of the source * <code>Attr</code> are recursively adopted.</dd> * <dt>DOCUMENT_FRAGMENT_NODE</dt> * <dd>The * descendants of the source node are recursively adopted.</dd> * <dt>DOCUMENT_NODE</dt> * <dd> * <code>Document</code> nodes cannot be adopted.</dd> * <dt>DOCUMENT_TYPE_NODE</dt> * <dd> * <code>DocumentType</code> nodes cannot be adopted.</dd> * <dt>ELEMENT_NODE</dt> * <dd>The * descendants of the source element are recursively adopted.</dd> * <dt>ENTITY_NODE</dt> * <dd> * <code>Entity</code> nodes cannot be adopted.</dd> * <dt>ENTITY_REFERENCE_NODE</dt> * <dd>Only * the <code>EntityReference</code> node itself is adopted, the * descendants are discarded, since the source and destination documents * might have defined the entity differently. If the document being * imported into provides a definition for this entity name, its value * is assigned.</dd> * <dt>NOTATION_NODE</dt> * <dd><code>Notation</code> nodes cannot be * adopted.</dd> * <dt>PROCESSING_INSTRUCTION_NODE, TEXT_NODE, CDATA_SECTION_NODE, * COMMENT_NODE</dt> * <dd>These nodes can all be adopted. No specifics.</dd> * </dl> * * @param source The node to move into this document. * @return The adopted node, or <code>null</code> if this operation * fails, such as when the source node comes from a different * implementation. * @exception DOMException * NOT_SUPPORTED_ERR: Raised if the source node is of type * <code>DOCUMENT</code>, <code>DOCUMENT_TYPE</code>, * <code>ENTITY_NODE</code>, <code>NOTATION_NODE</code>. * <br>NO_MODIFICATION_ALLOWED_ERR: Raised when the source node is * readonly. * * @since DOM Level 3 */ public Node adoptNode(Node source) throws DOMException { switch(source.getNodeType()) { case DOCUMENT_NODE: case DOCUMENT_TYPE_NODE: case ENTITY_NODE: case NOTATION_NODE: throw new DOMException(DOMException.NOT_SUPPORTED_ERR, ""); default: } XNode src = (XNode)source; if (src._isRO()) throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, ""); // Detach source form its parent if (src._getParent() != null) { if (src.getNodeType() == ATTRIBUTE_NODE) { Element elm = (Element)src._getParent(); src = (XNode)elm.removeAttributeNode((Attr)src); } else src = (XNode)src._getParent().removeChild(src); } if (src.getOwnerDocument() == this) return src; src._setDoc(this); src._notifyUDH(UserDataHandler.NODE_ADOPTED, src); return src; } /** * Check a new child node. This method throws appropriate exception if this * node does not like new child. A subclass MUST chain this method with * implementation provided by its parent class. */ protected void _checkNewChild(Node newChild, boolean replaceChild) throws DOMException { super._checkNewChild(newChild, replaceChild); XNode child = (XNode)newChild; switch(child.getNodeType()) { case PROCESSING_INSTRUCTION_NODE: case COMMENT_NODE: break; case DOCUMENT_TYPE_NODE: if (child._getDoc() != null && child._getDoc() != this) throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, ""); if (type != null) throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, ""); break; case ELEMENT_NODE: if ((getDocumentElement() != null) && (replaceChild == false)) throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, ""); break; default: throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, ""); } } /** * Notification of child addition. */ protected void _childAdded(XNode child) { switch(child.getNodeType()) { case DOCUMENT_TYPE_NODE: type = (DocumentType)child; break; case ELEMENT_NODE: root = (Element)child; break; default: break; } super._childAdded(child); } /** * Notification of child removal. */ protected void _childRemoving(XNode child) { super._childRemoving(child); switch(child.getNodeType()) { case DOCUMENT_TYPE_NODE: child._setDoc(null); type = null; break; case ELEMENT_NODE: root = null; break; default: break; } } /** * Returns default attributes for specified element or <code>null</code>. * Four strings represent single attribute: 0 - qname, 1 - localname, * 2 - namespace, 3 - value. Therefore, the array size divided by four is * the number of default attributes. */ /* pkg */ final String[] _getDefAttrs(String qname) { if (attrs == null || qname == null) return null; return (String[])attrs.get(qname); } /** * Adds a default attribute to the document. */ /* pkg */ final void _setDefAttr(String tag, String qname, String value) { qname = _intern(qname); String lname = _intern(XNode._getLocalName(qname)); String[] defs = (String[])attrs.get(tag); if (defs == null) { // No default attributes on this element defs = new String[1 << 2]; defs[0] = qname; defs[1] = lname; defs[2] = null; defs[3] = value; } else { // Add one more default attribute to this element String[] list = new String[defs.length + (1 << 2)]; System.arraycopy(defs, 0, list, 0, defs.length); list[defs.length + 0] = qname; list[defs.length + 1] = lname; list[defs.length + 2] = null; list[defs.length + 3] = value; defs = list; } attrs.put(tag, defs); } /** * Insures the document has only one instance of string with content equal * to string provided as an argument. */ protected final String _intern(String str) { if (str == null) return null; String name = (String)names.get(str); if (name == null) { names.put(str, str); name = str; } return name; } /** * Returns clone of the node or <code>null</code>. */ protected XNode _clone(Node node, boolean deep) { switch(node.getNodeType()) { case DOCUMENT_FRAGMENT_NODE: return new DocFragImp((DocFragImp)node, deep); case ELEMENT_NODE: return new ElmImp((ElmImp)node, deep); case ATTRIBUTE_NODE: return new AttrImp((AttrImp)node, deep); case TEXT_NODE: case CDATA_SECTION_NODE: return new TextImp((TextImp)node, deep); case PROCESSING_INSTRUCTION_NODE: return new ProcInstImp((ProcInstImp)node, deep); case COMMENT_NODE: return new CommImp((CommImp)node, deep); case ENTITY_REFERENCE_NODE: return new EntRefImp((EntRefImp)node, deep); case ENTITY_NODE: return new EntImp((EntImp)node, deep); case NOTATION_NODE: return new NotImp((NotImp)node, deep); case DOCUMENT_TYPE_NODE: // See method cloneNode of DocTypeImp class. case DOCUMENT_NODE: // See method cloneNode of this class. default: } return null; } /** * Returns list of supported features. */ protected abstract String[] _getFeatures(); /** * Checks is feature supported. */ protected boolean _isSupported(String feature, String version) { String name = (feature.charAt(0) == '+')? feature.substring(1): feature; String ver = ("".equals(version))? null: version; String[] features = _getDoc()._getFeatures(); for (int idx = 0; idx < features.length; idx++) { if (features[idx].equalsIgnoreCase(name)) { if (ver == null) return true; if ("1.0".equals(ver) || "2.0".equals(ver)) return true; } } return false; } /** * Sets/resets build mode flag. This method reduces amount of work during * document construction by a DOM parser. */ public void _setBuild(boolean build) { if (build == false) flags &= ~FLAG_BUILD; else flags |= FLAG_BUILD; } /** * Returns string representation of the element. */ public String toString() { StringBuffer out = new StringBuffer(); if (type != null) out.append(type.toString()); for (int i = 0; i < getLength(); i++) { if (item(i).getNodeType() != DOCUMENT_TYPE_NODE) out.append(item(i).toString()); } return out.toString(); } }