ParentNode.java revision 286
1109N/A * Copyright 1999-2002,2004,2005 The Apache Software Foundation. 1109N/A * Licensed under the Apache License, Version 2.0 (the "License"); 1109N/A * you may not use this file except in compliance with the License. 1109N/A * You may obtain a copy of the License at 1109N/A * Unless required by applicable law or agreed to in writing, software 1109N/A * distributed under the License is distributed on an "AS IS" BASIS, 1109N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1109N/A * See the License for the specific language governing permissions and 1109N/A * limitations under the License. 1109N/A * ParentNode inherits from ChildNode and adds the capability of having child 1109N/A * nodes. Not every node in the DOM can have children, so only nodes that can 1109N/A * should inherit from this class and pay the price for it. 1109N/A * ParentNode, just like NodeImpl, also implements NodeList, so it can 1109N/A * return itself in response to the getChildNodes() query. This eliminiates 1109N/A * the need for a separate ChildNodeList object. Note that this is an 1109N/A * IMPLEMENTATION DETAIL; applications should _never_ assume that 1109N/A * this identity exists. On the other hand, subclasses may need to override 1109N/A * this, in case of conflicting names. This is the case for the classes 1109N/A * HTMLSelectElementImpl and HTMLFormElementImpl of the HTML DOM. 1109N/A * While we have a direct reference to the first child, the last child is 1109N/A * stored as the previous sibling of the first child. First child nodes are 1109N/A * marked as being so, and getNextSibling hides this fact. 1109N/A * <P>Note: Not all parent nodes actually need to also be a child. At some 1109N/A * point we used to have ParentNode inheriting from NodeImpl and another class 1109N/A * called ChildAndParentNode that inherited from ChildNode. But due to the lack 1109N/A * of multiple inheritance a lot of code had to be duplicated which led to a 1109N/A * maintenance nightmare. At the same time only a few nodes (Document, 1109N/A * DocumentFragment, Entity, and Attribute) cannot be a child so the gain in 1109N/A * memory wasn't really worth it. The only type for which this would be the 1109N/A * case is Attribute, but we deal with there in another special way, so this is 1109N/A * This class doesn't directly support mutation events, however, it notifies 1109N/A * the document when mutations are performed so that the document class do so. 1109N/A * <p><b>WARNING</b>: Some of the code here is partially duplicated in 1109N/A * AttrImpl, be careful to keep these two classes in sync! 1109N/A * @author Arnaud Le Hors, IBM 1109N/A * @author Joe Kesselman, IBM 1109N/A /** Serialization version. */ 1109N/A * No public constructor; only subclasses of ParentNode should be 1109N/A * instantiated, and those normally via a Document's factory methods /** Constructor for serialization. */ * Returns a duplicate of a given node. You can consider this a * generic "copy constructor" for nodes. The newly returned object should * be completely independent of the source object's subtree, so changes * in one after the clone has been made will not affect the other. * Example: Cloning a Text node will copy both the node and the text it * Example: Cloning something that has children -- Element or Attr, for * example -- will _not_ clone those children unless a "deep clone" * has been requested. A shallow clone of an Attr node will yield an * empty Attr of the same name. * NOTE: Clones will always be read/write, even if the node being cloned * is read-only, to permit applications using only the DOM API to obtain * editable copies of locked portions of the tree. // Need to break the association w/ original kids // invalidate cache for children NodeList // Then, if deep, clone the kids too. }
// cloneNode(boolean):Node * Find the Document that this Node belongs to (the document in * whose context the Node was created). The Node may or may not * currently be part of that Document's actual contents. * same as above but returns internal type and this one is not overridden * by CoreDocumentImpl to return null * set the ownerDocument of this node and its children /* setting the owner document of self, after it's children makes the data of children available to the new document. */ * Test whether this node has any children. Convenience shorthand * for (Node.getFirstChild()!=null) * Obtain a NodeList enumerating all children of this node. If there * are none, an (initially) empty NodeList is returned. * NodeLists are "live"; as children are added/removed the NodeList * will immediately reflect those changes. Also, the NodeList refers * to the actual nodes, so changes to those nodes made via the DOM tree * will be reflected in the NodeList and vice versa. * In this implementation, Nodes implement the NodeList interface and * provide their own getChildNodes() support. Other DOMs may solve this }
// getChildNodes():NodeList /** The first child of this Node, or null if none. */ }
// getFirstChild():Node /** The last child of this Node, or null if none. */ // last child is stored as the previous sibling of first child // store lastChild as previous sibling of first child * Move one or more node(s) to our list of children. Note that this * implicitly removes them from their previous parent. * @param newChild The Node to be moved to our subtree. As a * convenience feature, inserting a DocumentNode will instead insert * @param refChild Current child which newChild should be placed * immediately before. If refChild is null, the insertion occurs * after all existing Nodes, like appendChild(). * @return newChild, in its new state (relocated, or emptied in the case of * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a * type that shouldn't be a child of this node, or if newChild is an * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a * different owner document than we do. * @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is // Tail-call; optimizer should be able to do good things with. }
// insertBefore(Node,Node):Node /** NON-DOM INTERNAL: Within DOM actions,we sometimes need to be able * to control which mutation events are spawned. This version of the * insertBefore operation allows us to do so. It is not intended * for use by application programs. // SLOW BUT SAFE: We could insert the whole subtree without // parent's child-list, patch the parent pointers, set the // ends of the list.) But we know some subclasses have special- // case behavior they add to insertBefore(), so we don't risk it. // This approch also takes fewer bytecodes. // NOTE: If one of the children is not a legal child of this // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children // have been transferred. (Alternative behaviors would be to // reparent up to the first failure point or reparent all those // which are acceptable to the target node, neither of which is // as robust. PR-DOM-0818 isn't entirely clear on which it // No need to check kids for right-document; if they weren't, // they wouldn't be kids of that DocFrag. // stupid case that must be handled as a no-op triggering events... // refChild must be a child of this node (or null) // Prevent cycles in the tree // newChild cannot be ancestor of this Node, // and actually cannot be this // Convert to internal type, to avoid repeated casting // Convert to internal type, to avoid repeated casting // Attach before and after // Note: firstChild.previousSibling == lastChild!! // this our first and only child // at the head of the list // somewhere in the middle // update cached length if we have any // if we happen to insert just before the cached node, update // the cache to the new node to match the cached index // otherwise just invalidate the cache }
// internalInsertBefore(Node,Node,boolean):Node * Remove a child from this Node. The removed child's subtree * remains intact so it may be re-inserted elsewhere. * @return oldChild, in its new state (removed). * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is // Tail-call, should be optimizable }
// removeChild(Node) :Node /** NON-DOM INTERNAL: Within DOM actions,we sometimes need to be able * to control which mutation events are spawned. This version of the * removeChild operation allows us to do so. It is not intended * for use by application programs. // update cached length if we have any // if the removed node is the cached node // move the cache to its (soon former) previous sibling // otherwise just invalidate the cache // Patch linked list around oldChild // Note: lastChild == firstChild.previousSibling // removing some other child in the middle // Save previous sibling for normalization checking. // Remove oldInternal's references to tree }
// internalRemoveChild(Node,boolean):Node * Make newChild occupy the location that oldChild used to * have. Note that newChild will first be removed from its previous * parent, if any. Equivalent to inserting newChild before oldChild, * then removing oldChild. * @return oldChild, in its new state (removed). * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a * type that shouldn't be a child of this node, or if newChild is * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a * different owner document than we do. * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is // If Mutation Events are being generated, this operation might // throw aggregate events twice when modifying an Attr -- once // on insertion and once on removal. DOM Level 2 does not specify // this as either desirable or undesirable, but hints that // aggregations should be issued only once per user request. // internal method taking a StringBuffer in parameter // internal method returning whether to take the given node's text content // get rid of any existing children // create a Text node to hold the given content * Count the immediate children of this node. Use to implement // get rid of trivial cases // otherwise request a cache object // start from the cached node if we have one }
// nodeListGetLength():int * NodeList method: Count the immediate children of this node * Return the Nth immediate child of this node, or null if the index is * out of bounds. Use to implement NodeList.item(). // get rid of trivial case // otherwise request a cache object if (i != -
1 && n !=
null) {
// release cache if reaching last child or first child // we can keep using the cache until it is actually reused // fNodeListCache will be nulled by the pool (document) if that // fNodeListCache = null; }
// nodeListItem(int):Node * NodeList method: Return the Nth immediate child of this node, or * null if the index is out of bounds. * @return org.w3c.dom.Node * Create a NodeList to access children that is use by subclass elements * that have methods named getLength() or item(int). ChildAndParentNode * optimizes getChildNodes() by implementing NodeList itself. However if * a subclass Element implements methods with the same name as the NodeList * methods, they will override the actually methods in this class. * To use this method, the subclass should implement getChildNodes() and * have it call this method. The resulting NodeList instance maybe * shared and cached in a transient field, but the cached value must be * cleared if the node is cloned. * @see NodeList.getLength() * @see NodeList.item(int) }
// getChildNodesUnoptimized():NodeList // DOM2: methods, getters, setters * Override default behavior to call normalize() on this Node's * children. It is up to implementors or Node to override normalize() // No need to normalize if already normalized. * DOM Level 3 WD- Experimental. * Override inherited behavior from NodeImpl to support deep equal. // there are many ways to do this test, and there isn't any way // better than another. Performance may vary greatly depending on // the implementations involved. This one should work fine for us. * Override default behavior so that if deep is true, children are also * Note: this will not change the state of an EntityReference or its * children, which are always read-only. }
// setReadOnly(boolean,boolean) * Override this method in subclass to hook in efficient * internal data structure. // By default just change the flag to avoid calling this method again * Checks the normalized state of this node after inserting a child. * If the inserted child causes this node to be unnormalized, then this * node is flagged accordingly. * The conditions for changing the normalized state are: * <li>The inserted child is a text node and one of its adjacent siblings * <li>The inserted child is is itself unnormalized. * @param insertedChild the child node that was inserted into this node * @throws NullPointerException if the inserted child is <code>null</code> // See if insertion caused this node to be unnormalized. // If an adjacent sibling of the new child is a text node, // flag this node as unnormalized. // If the new child is not normalized, // then this node is inherently not normalized. }
// checkNormalizationAfterInsert(ChildNode) * Checks the normalized of this node after removing a child. * If the removed child causes this node to be unnormalized, then this * node is flagged accordingly. * The conditions for changing the normalized state are: * <li>The removed child had two adjacent siblings that were text nodes. * @param previousSibling the previous sibling of the removed child, or // See if removal caused this node to be unnormalized. // If the adjacent siblings of the removed child were both text nodes, // flag this node as unnormalized. }
// checkNormalizationAfterRemove(Node) }
// writeObject(ObjectOutputStream) /** Deserialize object. */ // perform default deseralization // hardset synchildren - so we don't try to sync - it does not make any // sense to try to synchildren when we just deserialize object. }
// readObject(ObjectInputStream) * a class to store some user data along with its handler /** Serialization version. */