bool RangeImpl::hasLegalRootContainer(const DOM_Node& node) const { if ( node==null ) return false; DOM_Node rootContainer = node; for (; rootContainer.getParentNode()!=null; rootContainer = rootContainer.getParentNode()) ; switch( rootContainer.getNodeType() ) { case DOM_Node::ATTRIBUTE_NODE: case DOM_Node::DOCUMENT_NODE: case DOM_Node::DOCUMENT_FRAGMENT_NODE: return true; } return false; }
void RangeImpl::selectNode(const DOM_Node& refNode) { validateNode(refNode); if ( !isLegalContainedNode(refNode)) { throw DOM_RangeException( DOM_RangeException::INVALID_NODE_TYPE_ERR, null); } //First check for the text type node if (refNode.getNodeType() == DOM_Node::TEXT_NODE) { //The node itself is the container. fStartContainer = refNode; fEndContainer = refNode; //Select all the contents of the node fStartOffset = 0; fEndOffset = ((DOM_Text &)refNode).getLength(); return; } DOM_Node parent = refNode.getParentNode(); if (parent != null ) // REVIST: what to do if it IS null? { fStartContainer = parent; fEndContainer = parent; unsigned int i = 0; for (DOM_Node n = parent.getFirstChild(); n!=null, n!=refNode; n = n.getNextSibling()) { i++; } fStartOffset = i; fEndOffset = fStartOffset+1; } }
DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) { if (fDetached) throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null); DOM_Node result; // if we're at the root, return null. if (node == fRoot) return result; // get sibling result = node.getPreviousSibling(); if (result.isNull()) { //if 1st sibling, return parent result = node.getParentNode(); return result; } // if sibling has children, keep getting last child of child. if (result.hasChildNodes()) { while (result.hasChildNodes()) { result = result.getLastChild(); } } return result; }
void RangeImpl::setEndAfter(const DOM_Node& refNode) { if( fDetached) { throw DOM_DOMException( DOM_DOMException::INVALID_STATE_ERR, null); } if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) { throw DOM_RangeException( DOM_RangeException::INVALID_NODE_TYPE_ERR, null); } fEndContainer = refNode.getParentNode(); unsigned int i = 0; for (DOM_Node n = refNode; n!=null; n = n.getPreviousSibling(), i++) ; if (i ==0) fEndOffset = 0; else fEndOffset = i; if ((fDocument != refNode.getOwnerDocument() ) && (refNode.getOwnerDocument().fImpl != 0) ) { fDocument = refNode.getOwnerDocument(); collapse(true); } //compare the start and end boundary point //collapse if start point is after the end point if(compareBoundaryPoints(DOM_Range::END_TO_START, this) == 1) collapse(false); //collapse the range positions to end else fCollapsed = false; }
const DOM_Node RangeImpl::commonAncestorOf(const DOM_Node& pointA, const DOM_Node& pointB) const { if (fDetached) throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null); if (pointA.getOwnerDocument() != pointB.getOwnerDocument()) throw DOM_DOMException( DOM_DOMException::WRONG_DOCUMENT_ERR, null ); //if the containers are same then it itself is its common ancestor. if (pointA == pointB) return pointA; typedef RefVectorOf<NodeImpl> VectorNodes; VectorNodes* startV= new (((DocumentImpl*)fDocument.fImpl)->getMemoryManager()) VectorNodes(1, false, ((DocumentImpl*)fDocument.fImpl)->getMemoryManager()); DOM_Node node; for (node=fStartContainer; node != null; node=node.getParentNode()) { startV->addElement(node.fImpl); } VectorNodes* endV = new (((DocumentImpl*)fDocument.fImpl)->getMemoryManager()) VectorNodes(1, false, ((DocumentImpl*)fDocument.fImpl)->getMemoryManager()); for (node=fEndContainer; node != null; node=node.getParentNode()) { endV->addElement(node.fImpl); } int s = startV->size()-1; int e = endV->size()-1; NodeImpl* commonAncestor = 0; while (s>=0 && e>=0) { if (startV->elementAt(s) == endV->elementAt(e)) { commonAncestor = startV->elementAt(s); } else break; --s; --e; } delete startV; delete endV; return DOM_Node(commonAncestor); }
unsigned short RangeImpl::indexOf(const DOM_Node& child, const DOM_Node& parent) const { unsigned short i = 0; if (child.getParentNode() != parent) return (unsigned short)-1; for(DOM_Node node = child.getPreviousSibling(); node!= null; node=node.getPreviousSibling()) { i++; } return i; }
/** Return node, if matches or any parent if matches. */ DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) { DOM_Node result; for (DOM_Node n = fCurrentNode; n != fRoot; n = n.getParentNode()) { if (node == n) return n; } return result; }
/** * Traverses the "right boundary" of this range and * operates on each "boundary node" according to the * how parameter. It is a-priori assumed * by this method that the right boundary does * not contain the range's start container. * * A "right boundary" is best visualized by thinking * of a sample tree: * A * /|\ * / | \ * / | \ * B C D * /|\ /|\ * E F G H I J * * Imagine first a range that begins between the * "E" and "F" nodes and ends between the * "I" and "J" nodes. The start container is * "B" and the end container is "D". Given this setup, * the following applies: * * Partially Selected Nodes: B, D<br> * Fully Selected Nodes: F, G, C, H, I * * The "right boundary" is the highest subtree node * that contains the ending container. The root of * this subtree is always partially selected. * * In this example, the nodes that are traversed * as "right boundary" nodes are: H, I, and D. * */ DOM_Node RangeImpl::traverseRightBoundary( DOM_Node root, int how ) { DOM_Node next = getSelectedNode( fEndContainer, fEndOffset-1 ); bool isFullySelected = ( next!=fEndContainer ); if ( next==root ) return traverseNode( next, isFullySelected, false, how ); DOM_Node parent = next.getParentNode(); DOM_Node clonedParent = traverseNode( parent, false, false, how ); while( parent!=null ) { while( next!=null ) { DOM_Node prevSibling = next.getPreviousSibling(); DOM_Node clonedChild = traverseNode( next, isFullySelected, false, how ); if ( how!=DELETE_CONTENTS ) { clonedParent.insertBefore( clonedChild, clonedParent.getFirstChild() ); } isFullySelected = true; next = prevSibling; } if ( parent==root ) return clonedParent; next = parent.getPreviousSibling(); parent = parent.getParentNode(); DOM_Node clonedGrandParent = traverseNode( parent, false, false, how ); if ( how!=DELETE_CONTENTS ) clonedGrandParent.appendChild( clonedParent ); clonedParent = clonedGrandParent; } // should never occur return null; }
bool RangeImpl::isValidAncestorType(const DOM_Node& node) const { for (DOM_Node aNode = node; aNode!=null; aNode = aNode.getParentNode()) { short type = aNode.getNodeType(); if ( type == DOM_Node::ENTITY_NODE || type == DOM_Node::NOTATION_NODE || type == DOM_Node::DOCUMENT_TYPE_NODE) return false; } return true; }
//====================================================================== // CJM 4/17/03 ..Needed to update an attribute list... for ContentGuard //====================================================================== bool XMLDocument::setAttributeList(char* path, DataTypeAttribute** dtAttributes) { if (mDoc == NULL) return false; if (path == NULL) return false; DOM_Node child = getNode(mRootNode, path, NULL); char* value = getString(path); if (child == NULL) return false; short nType = child.getNodeType(); DOM_Node parent = child.getParentNode(); if (parent == NULL) return false; char* childName = child.getNodeName().transcode(); DOM_NamedNodeMap nnodeMap = child.getAttributes(); parent.removeChild(child); DOM_Element childElement = mDoc.createElement(childName); delete[] childName; int a = 0; DataTypeAttribute* dtAttribute; while ((dtAttribute = (DataTypeAttribute*)dtAttributes[a++]) != (DataTypeAttribute*)NULL) { childElement.setAttribute(dtAttribute->getName(), dtAttribute->getValue()); } if (nType == DOM_Node::TEXT_NODE) { DOM_Text childText = mDoc.createTextNode((value == NULL)?"":value); childElement.appendChild(childText); } else { if (nType == DOM_Node::CDATA_SECTION_NODE) { DOM_CDATASection childCData = mDoc.createCDATASection((value == NULL)?"":value); childElement.appendChild(childCData); } } parent.appendChild(childElement); return true; }
/** * Traverses the "left boundary" of this range and * operates on each "boundary node" according to the * how parameter. It is a-priori assumed * by this method that the left boundary does * not contain the range's end container. * * A "left boundary" is best visualized by thinking * of a sample tree: * * A * /|\ * / | \ * / | \ * B C D * /|\ /|\ * E F G H I J * * Imagine first a range that begins between the * "E" and "F" nodes and ends between the * "I" and "J" nodes. The start container is * "B" and the end container is "D". Given this setup, * the following applies: * * Partially Selected Nodes: B, D<br> * Fully Selected Nodes: F, G, C, H, I * * The "left boundary" is the highest subtree node * that contains the starting container. The root of * this subtree is always partially selected. * * In this example, the nodes that are traversed * as "left boundary" nodes are: F, G, and B. * */ DOM_Node RangeImpl::traverseLeftBoundary( DOM_Node root, int how ) { DOM_Node next = getSelectedNode( getStartContainer(), getStartOffset() ); bool isFullySelected = ( next!=getStartContainer() ); if ( next==root ) return traverseNode( next, isFullySelected, true, how ); DOM_Node parent = next.getParentNode(); DOM_Node clonedParent = traverseNode( parent, false, true, how ); while( parent!=null ) { while( next!=null ) { DOM_Node nextSibling = next.getNextSibling(); DOM_Node clonedChild = traverseNode( next, isFullySelected, true, how ); if ( how!=DELETE_CONTENTS ) clonedParent.appendChild(clonedChild); isFullySelected = true; next = nextSibling; } if ( parent==root ) return clonedParent; next = parent.getNextSibling(); parent = parent.getParentNode(); DOM_Node clonedGrandParent = traverseNode( parent, false, true, how ); if ( how!=DELETE_CONTENTS ) clonedGrandParent.appendChild( clonedParent ); clonedParent = clonedGrandParent; } // should never occur return null; }
DOM_Node RangeImpl::nextNode(const DOM_Node& node, bool visitChildren) const { if (node == null) return null; DOM_Node result; if (visitChildren) { result = node.getFirstChild(); if (result != null) { return result; } } // if hasSibling, return sibling result = node.getNextSibling(); if (result != null) { return result; } // return parent's 1st sibling. DOM_Node parent = node.getParentNode(); while ( (parent != null) && (parent != fDocument) ) { result = parent.getNextSibling(); if (result != null) { return result; } else { parent = parent.getParentNode(); if (parent == fEndContainer) return parent; } } // end of list, return null return null; }
DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) { if (fDetached) throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null); if (node.isNull()) return fRoot; DOM_Node result; // only check children if we visit children. if (visitChildren) { //if hasChildren, return 1st child. if (node.hasChildNodes()) { result = node.getFirstChild(); return result; } } // if hasSibling, return sibling if (node != fRoot) { result = node.getNextSibling(); if (! result.isNull()) return result; // return parent's 1st sibling. DOM_Node parent = node.getParentNode(); while (!parent.isNull() && parent != fRoot) { result = parent.getNextSibling(); if (!result.isNull()) { return result; } else { parent = parent.getParentNode(); } } // while (parent != null && parent != fRoot) { } // end of list, return null DOM_Node aNull; return aNull; }
//====================================================================== //====================================================================== bool XMLDocument::setValue(DOM_Node currNode, char* path, DataTypeAttribute** dtAttributes, char* value) { if (mDoc == NULL) return false; if (path == NULL) return false; DOM_Node child = getNode(currNode, path, dtAttributes); if (child == NULL) return false; DOM_Node parent = child.getParentNode(); if (parent == NULL) return false; DOM_Node grandChild = child.getFirstChild(); short nType = DOM_Node::TEXT_NODE; if (grandChild != NULL) { nType = grandChild.getNodeType(); if (nType != DOM_Node::TEXT_NODE && nType != DOM_Node::CDATA_SECTION_NODE) return false; } char* childName = child.getNodeName().transcode(); DOM_NamedNodeMap nnodeMap = child.getAttributes(); parent.removeChild(child); DOM_Element childElement = mDoc.createElement(childName); delete[] childName; for (unsigned int i = 0; i < nnodeMap.getLength(); i++) { DOM_Node attNode = nnodeMap.item(i); childElement.setAttribute(attNode.getNodeName(), attNode.getNodeValue()); } if (nType == DOM_Node::TEXT_NODE) { DOM_Text childText = mDoc.createTextNode((value == NULL)?"":value); childElement.appendChild(childText); } else { DOM_CDATASection childCData = mDoc.createCDATASection((value == NULL)?"":value); childElement.appendChild(childCData); } parent.appendChild(childElement); return true; }
DOM_Node TreeWalkerImpl::getParentNode (DOM_Node node) { DOM_Node result; if (node.isNull() || node == fRoot) return result; DOM_Node newNode = node.getParentNode(); if (newNode.isNull()) return result; short accept = acceptNode(newNode); if (accept == DOM_NodeFilter::FILTER_ACCEPT) return newNode; return getParentNode(newNode); }
/** * Utility method for traversing a single node when * we know a-priori that the node if fully * selected. * */ DOM_Node RangeImpl::traverseFullySelected( DOM_Node n, int how ) { switch( how ) { case CLONE_CONTENTS: return n.cloneNode( true ); case EXTRACT_CONTENTS: if ( n.getNodeType()== DOM_Node::DOCUMENT_TYPE_NODE ) { throw DOM_DOMException( DOM_DOMException::HIERARCHY_REQUEST_ERR, null); } return n; case DELETE_CONTENTS: n.getParentNode().removeChild(n); return null; } return null; }
/** * Visits the nodes selected by this range when we know * a-priori that the start and end containers are not * the same, and we also know that neither the start * nor end container is an ancestor of the other. */ DOM_DocumentFragment RangeImpl::traverseCommonAncestors( DOM_Node startAncestor, DOM_Node endAncestor, int how ) { DOM_DocumentFragment frag = null; if ( how!=DELETE_CONTENTS) frag = fDocument.createDocumentFragment(); DOM_Node n = traverseLeftBoundary( startAncestor, how ); if ( frag!=null ) frag.appendChild( n ); DOM_Node commonParent = startAncestor.getParentNode(); int startOffset = indexOf( startAncestor, commonParent ); int endOffset = indexOf( endAncestor, commonParent ); ++startOffset; int cnt = endOffset - startOffset; DOM_Node sibling = startAncestor.getNextSibling(); while( cnt > 0 ) { DOM_Node nextSibling = sibling.getNextSibling(); n = traverseFullySelected( sibling, how ); if ( frag!=null ) frag.appendChild( n ); sibling = nextSibling; --cnt; } n = traverseRightBoundary( endAncestor, how ); if ( frag!=null ) frag.appendChild( n ); if ( how != CLONE_CONTENTS ) { setStartAfter( startAncestor ); collapse( true ); } return frag; }
DOM_Node TreeWalkerImpl::getNextSibling (DOM_Node node) { DOM_Node result; if (node.isNull() || node == fRoot) return result; DOM_Node newNode = node.getNextSibling(); if (newNode.isNull()) { newNode = node.getParentNode(); if (newNode.isNull() || node == fRoot) return result; short parentAccept = acceptNode(newNode); if (parentAccept == DOM_NodeFilter::FILTER_SKIP) { return getNextSibling(newNode); } return result; } short accept = acceptNode(newNode); if (accept == DOM_NodeFilter::FILTER_ACCEPT) return newNode; else if (accept == DOM_NodeFilter::FILTER_SKIP) { DOM_Node fChild = getFirstChild(newNode); if (fChild.isNull()) { return getNextSibling(newNode); } return fChild; } return getNextSibling(newNode); }
void RangeImpl::insertNode(DOM_Node& newNode) { if (newNode == null) return; //don't have to do anything for (DOM_Node aNode = fStartContainer; aNode!=null; aNode = aNode.getParentNode()) { if (aNode.fImpl->isReadOnly()) { throw DOM_DOMException( DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); } } if (fDocument != newNode.getOwnerDocument()) { throw DOM_DOMException( DOM_DOMException::WRONG_DOCUMENT_ERR, null); } // Prevent cycles in the tree. //isKidOK() is not checked here as its taken care by insertBefore() function if (isAncestorOf( newNode, fStartContainer)) { throw DOM_DOMException( DOM_DOMException::HIERARCHY_REQUEST_ERR, null); } if( fDetached) { throw DOM_DOMException( DOM_DOMException::INVALID_STATE_ERR, null); } int type = newNode.getNodeType(); if (type == DOM_Node::ATTRIBUTE_NODE || type == DOM_Node::ENTITY_NODE || type == DOM_Node::NOTATION_NODE || type == DOM_Node::DOCUMENT_NODE) { throw DOM_RangeException( DOM_RangeException::INVALID_NODE_TYPE_ERR, null); } DOM_Node parent; DOM_Node next; if (fStartContainer.getNodeType() == DOM_Node::TEXT_NODE) { //set 'parent' and 'next' here parent = fStartContainer.getParentNode(); //split the text nodes if (fStartOffset > 0) ((DOM_Text &)fStartContainer).splitText(fStartOffset); //update the new start information later. After inserting the first newNode if (fStartOffset == 0) next = fStartContainer; else next = fStartContainer.getNextSibling(); } // end of text handling else { parent = fStartContainer; next = fStartContainer.getFirstChild(); for(unsigned int i = 0; (i < fStartOffset) && (next != null); i++) { next=next.getNextSibling(); } } if (parent != null) { if (next != null) parent.insertBefore(newNode, next); else parent.appendChild(newNode); } }