rangeimpl.cpp
来自「IBM的解析xml的工具Xerces的源代码」· C++ 代码 · 共 1,660 行 · 第 1/4 页
CPP
1,660 行
}void RangeImpl::validateNode(const DOM_Node& node) const{ if( fDetached) { throw DOM_DOMException( DOM_DOMException::INVALID_STATE_ERR, null); } if ( !isValidAncestorType(node)) { throw DOM_RangeException( DOM_RangeException::INVALID_NODE_TYPE_ERR, null); }}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);}void RangeImpl::checkIndex(const DOM_Node& node, unsigned int offset) const{ if (offset < 0) { throw DOM_DOMException( DOM_DOMException::INDEX_SIZE_ERR, null ); } short type = node.getNodeType(); if((type == DOM_Node::TEXT_NODE || type == DOM_Node::CDATA_SECTION_NODE || type == DOM_Node::COMMENT_NODE || type == DOM_Node::PROCESSING_INSTRUCTION_NODE)) { if (offset > node.getNodeValue().length()) throw DOM_DOMException( DOM_DOMException::INDEX_SIZE_ERR, null ); else return; } DOM_Node child = node.getFirstChild(); unsigned int i = 0; for (; child != null; i++) { child = child.getNextSibling(); } if (i < offset) { throw DOM_DOMException( DOM_DOMException::INDEX_SIZE_ERR, 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;}/** This is the master routine invoked to visit the nodes* selected by this range. For each such node, different* actions are taken depending on the value of the TraversalType argument.*/DOM_DocumentFragment RangeImpl::traverseContents(TraversalType how){ if (fDetached) throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null); if (fStartContainer == null || fEndContainer == null) { return DOM_DocumentFragment(); // REVIST: Throw exception? } /* Traversal is accomplished by first determining the relationship between the endpoints of the range. For each of four significant relationships, we will delegate the traversal call to a method that can make appropriate assumptions. */ // case 1: same container if ( fStartContainer == fEndContainer ) return traverseSameContainer( how ); // case 2: Child C of start container is ancestor of end container for (DOM_Node node = fStartContainer.getFirstChild(); node != null; node=node.getNextSibling()) { if (isAncestorOf(node, fEndContainer)) return traverseCommonStartContainer( node, how ); } // case 3: Child C of end container is ancestor of start container for (DOM_Node nd = fEndContainer.getFirstChild(); nd != null; nd=nd.getNextSibling()) { if (isAncestorOf(nd, fStartContainer)) return traverseCommonEndContainer( nd, how ); } // case 4: preorder traversal of context tree. // There is a common ancestor container. Find the // ancestor siblings that are children of that container. DOM_Node ancestor = commonAncestorOf(fStartContainer, fEndContainer); return traverseCommonAncestors( ancestor, ancestor, how ); }/** * Visits the nodes selected by this range when we know * a-priori that the start and end containers are the same. * */DOM_DocumentFragment RangeImpl::traverseSameContainer( int how ){ DOM_DocumentFragment frag = null; if ( how!=DELETE_CONTENTS) frag = fDocument.createDocumentFragment(); // If selection is empty, just return the fragment if ( fStartOffset==fEndOffset ) return frag; DOM_Node current = fStartContainer; DOM_Node cloneCurrent = null; // Text node needs special case handling if ( fStartContainer.getNodeType()== DOM_Node::TEXT_NODE ) { cloneCurrent = fStartContainer.cloneNode(false); cloneCurrent.setNodeValue( cloneCurrent.getNodeValue().substringData(fStartOffset, fEndOffset - fStartOffset)); // set the original text node to its new value if ( how != CLONE_CONTENTS ) ((DOM_Text &)fStartContainer).deleteData(fStartOffset, fEndOffset-fStartOffset); if ( how != DELETE_CONTENTS) frag.appendChild(cloneCurrent); } else { // Copy nodes between the start/end offsets. DOM_Node n = getSelectedNode( fStartContainer, fStartOffset ); int cnt = fEndOffset - fStartOffset; while( cnt > 0 ) { DOM_Node sibling = n.getNextSibling(); DOM_Node xferNode = traverseFullySelected( n, how ); if ( frag!=null ) frag.appendChild( xferNode ); --cnt; n = sibling; } } // Nothing is partially selected, so collapse to start point if ( how != CLONE_CONTENTS ) collapse(true); return frag;}/** * Visits the nodes selected by this range when we know * a-priori that the start and end containers are not the * same, but the start container is an ancestor of the end container * */DOM_DocumentFragment RangeImpl::traverseCommonStartContainer( DOM_Node endAncestor, int how ){ DOM_DocumentFragment frag = null; if ( how!=DELETE_CONTENTS) frag = fDocument.createDocumentFragment(); DOM_Node n = traverseRightBoundary( endAncestor, how ); if ( frag!=null ) frag.appendChild( n ); int endIdx = indexOf( endAncestor, fStartContainer ); int cnt = endIdx - fStartOffset; if ( cnt <=0 ) { // Collapse to just before the endAncestor, which // is partially selected. if ( how != CLONE_CONTENTS ) { setEndBefore( endAncestor ); collapse( false ); } return frag; } n = endAncestor.getPreviousSibling(); while( cnt > 0 ) { DOM_Node sibling = n.getPreviousSibling(); DOM_Node xferNode = traverseFullySelected( n, how ); if ( frag!=null ) frag.insertBefore( xferNode, frag.getFirstChild() ); --cnt; n = sibling; } // Collapse to just before the endAncestor, which // is partially selected. if ( how != CLONE_CONTENTS ) { setEndBefore( endAncestor ); collapse( false ); } return frag;}/** * Visits the nodes selected by this range when we know * a-priori that the start and end containers are not the * same, but the end container is an ancestor of the start container * */DOM_DocumentFragment RangeImpl::traverseCommonEndContainer( DOM_Node startAncestor, 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 ); int startIdx = indexOf( startAncestor, fEndContainer ); ++startIdx; // Because we already traversed it.... int cnt = fEndOffset - startIdx; n = startAncestor.getNextSibling(); while( cnt > 0 ) { DOM_Node sibling = n.getNextSibling(); DOM_Node xferNode = traverseFullySelected( n, how ); if ( frag!=null ) frag.appendChild( xferNode ); --cnt; n = sibling; } if ( how != CLONE_CONTENTS ) { setStartAfter( startAncestor ); collapse( true ); } return frag;}/** * 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;}/** * 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,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?