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 + -
显示快捷键?