You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by nd...@apache.org on 2004/06/24 19:57:00 UTC

cvs commit: xml-xerces/java/src/org/apache/xerces/dom TextImpl.java

nddelima    2004/06/24 10:57:00

  Modified:    java/src/org/apache/xerces/dom TextImpl.java
  Log:
  Patch to fix problems with replaceWholeText.
  
  Revision  Changes    Path
  1.24      +252 -64   xml-xerces/java/src/org/apache/xerces/dom/TextImpl.java
  
  Index: TextImpl.java
  ===================================================================
  RCS file: /home/cvs/xml-xerces/java/src/org/apache/xerces/dom/TextImpl.java,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- TextImpl.java	24 Feb 2004 23:23:17 -0000	1.23
  +++ TextImpl.java	24 Jun 2004 17:57:00 -0000	1.24
  @@ -41,6 +41,12 @@
       extends CharacterDataImpl 
       implements CharacterData, Text {
   
  +    // 
  +    // Private Data members
  +    //
  +    //Used by replaceWholeText
  +    private boolean fTextOnlyChildren = false;
  +    
       //
       // Constants
       //
  @@ -183,77 +189,258 @@
       }
   
       /**
  -    * DOM Level 3 WD - Experimental.
  -    */
  -    public Text replaceWholeText(String content)
  -                                 throws DOMException{
  +     * Replaces the text of the current node and all logically-adjacent text
  +     * nodes with the specified text. All logically-adjacent text nodes are
  +     * removed including the current node unless it was the recipient of the
  +     * replacement text.
  +     * 
  +     * @param content
  +     *            The content of the replacing Text node.
  +     * @return text - The Text node created with the specified content.
  +     * @since DOM Level 3
  +     */
  +    public Text replaceWholeText(String content) throws DOMException {
   
           if (needsSyncData()) {
               synchronizeData();
           }
  -
  -        // make sure we can make the replacement
  -        if (!canModify(nextSibling)) {
  -            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 
  -                DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null));
  -        }
  -
  +        //if the content is null
           Node parent = this.getParentNode();
           if (content == null || content.length() == 0) {
               // remove current node
  -            if (parent !=null) { // check if node in the tree 
  +            if (parent != null) { // check if node in the tree
                   parent.removeChild(this);
  -                return null;
               }
  +            return null;
           }
  +
  +        //replace the text node
           Text currentNode = null;
  -    	if (isReadOnly()){
  +        if (isReadOnly()) {
               Text newNode = this.ownerDocument().createTextNode(content);
  -            if (parent !=null) { // check if node in the tree                
  +            if (parent != null) { // check if node in the tree
                   parent.insertBefore(newNode, this);
                   parent.removeChild(this);
                   currentNode = newNode;
               } else {
                   return newNode;
               }
  -        }  else {
  +        } else {
               this.setData(content);
               currentNode = this;
           }
  -        Node sibling =  currentNode.getNextSibling();
  -        while ( sibling !=null) {
  -            parent.removeChild(sibling);
  -            sibling = currentNode.getNextSibling();
  -        }
   
  +        //check logically-adjacent text nodes
  +        Node prev = this.getPreviousSibling();  
  +        while (prev != null) {
  +            fTextOnlyChildren = false;
  +            
  +            // make sure we can make the replacement
  +            if (!canModifyPrev(prev)) {
  +                throw new DOMException(
  +                        DOMException.NO_MODIFICATION_ALLOWED_ERR,
  +                        DOMMessageFormatter.formatMessage(
  +                                DOMMessageFormatter.DOM_DOMAIN,
  +                                "NO_MODIFICATION_ALLOWED_ERR", null));
  +            } else {
  +                //If the logically-adjacent previous node can be replaced
  +                //remove it.  A logically adjacent node can be replaced if 
  +                //it is a Text or CDATASection node or an EntityReference with
  +                //Text and CDATA only children
  +                if ((prev.getNodeType() == Node.TEXT_NODE) || (prev
  +                        .getNodeType() == Node.CDATA_SECTION_NODE)||
  +                        (prev.getNodeType() == Node.ENTITY_REFERENCE_NODE && fTextOnlyChildren)) {
  +                    parent.removeChild(prev);
  +                    prev = this;
  +                }                
  +            }
  +            prev = prev.getPreviousSibling(); 
  +        }
  +        
  +        //check logically-adjacent text nodes        
  +        Node next = this.getNextSibling();
  +        while (next != null) {
  +            fTextOnlyChildren = false;            
  +            
  +            // make sure we can make the replacement
  +            if (!canModifyNext(next)) {
  +                throw new DOMException(
  +                        DOMException.NO_MODIFICATION_ALLOWED_ERR,
  +                        DOMMessageFormatter.formatMessage(
  +                                DOMMessageFormatter.DOM_DOMAIN,
  +                                "NO_MODIFICATION_ALLOWED_ERR", null));
  +            } else {
  +                //If the logically-adjacent next node can be replaced
  +                //remove it.  A logically adjacent node can be replaced if 
  +                //it is a Text or CDATASection node or an EntityReference with
  +                //Text and CDATA only children
  +                if ((next.getNodeType() == Node.TEXT_NODE) || (next
  +                        .getNodeType() == Node.CDATA_SECTION_NODE) ||
  +                        (next.getNodeType() == Node.ENTITY_REFERENCE_NODE && fTextOnlyChildren)) {
  +                    parent.removeChild(next);
  +                    next = this;
  +                }
  +            }
  +            next = next.getNextSibling();
  +        }
  +        
           return currentNode;
       }
   
       /**
  -     * If any EntityReference to be removed has descendants
  -     * that are not EntityReference, Text, or CDATASection
  -     * nodes, the replaceWholeText method must fail before
  -     * performing any modification of the document, raising a
  -     * DOMException with the code NO_MODIFICATION_ALLOWED_ERR.
  +     * If any EntityReference to be removed has descendants that are not
  +     * EntityReference, Text, or CDATASection nodes, the replaceWholeText method
  +     * must fail before performing any modification of the document, raising a
  +     * DOMException with the code NO_MODIFICATION_ALLOWED_ERR. Traverse previous
  +     * siblings of the node to be replaced. If a previous sibling is an
  +     * EntityReference node, get it's last child. If the last child was a Text
  +     * or CDATASection node and its previous siblings are neither a replaceable
  +     * EntityReference or Text or CDATASection nodes, return false. IF the last
  +     * child was neither Text nor CDATASection nor a replaceable EntityReference
  +     * Node, then return true. If the last child was a Text or CDATASection node
  +     * any its previous sibling was not or was an EntityReference that did not
  +     * contain only Text or CDATASection nodes, return false.  Check this recursively
  +     * for EntityReference nodes.
        * 
        * @param node
  -     * @return true - can replace text
  -     *         false - can't replace exception must be raised
  +     * @return true - can replace text false - can't replace exception must be
  +     *         raised
        */
  -    private boolean canModify(Node node){
  -        while (node != null) {
  -            short type = node.getNodeType();
  -            if (type == Node.ENTITY_REFERENCE_NODE) {
  -                if (!canModify(node.getFirstChild())){
  -                    return false;
  +    private boolean canModifyPrev(Node node) {
  +        boolean textLastChild = false;
  +
  +        short type = node.getNodeType();
  +
  +        if (type == Node.ENTITY_REFERENCE_NODE) {
  +            //If the previous sibling was entityreference
  +            //check if its content is replaceable
  +            Node lastChild = node.getLastChild();
  +
  +            //if the entity reference has no children
  +            //return false
  +            if (lastChild == null) {
  +                fTextOnlyChildren = false;
  +                return false;
  +            }
  +            
  +            //The replacement text of the entity reference should
  +            //be either only text,cadatsections or replaceable entity
  +            //reference nodes or the last child should be neither of these
  +            while (lastChild != null) {
  +                short lType = lastChild.getNodeType();
  +
  +                if (lType == Node.TEXT_NODE || lType == Node.CDATA_SECTION_NODE) {
  +                    textLastChild = true;
  +                    fTextOnlyChildren = true;
  +                } else if (lType == Node.ENTITY_REFERENCE_NODE) {
  +                    if (!canModifyPrev(lastChild)) {
  +                        fTextOnlyChildren = false;
  +                        return false;
  +                    } else {
  +                        //If the EntityReference child contains
  +                        //only text, or non-text or ends with a
  +                        //non-text node.
  +                        textLastChild = true;
  +                    }
  +
  +                } else {
  +                    if (textLastChild) {
  +                        fTextOnlyChildren = false;                        
  +                        return false;
  +                    } else {
  +                        return true;
  +                    }
                   }
  +                lastChild = lastChild.getPreviousSibling();
               }
  -            else if (type != Node.TEXT_NODE && 
  -                     type != Node.CDATA_SECTION_NODE) {
  +        } else if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
  +            //If the previous sibling was text or cdatasection move to next
  +            fTextOnlyChildren = true;
  +        } else {
  +            //If the previous sibling was anything but text or
  +            //cdatasection or an entity reference, stop search and
  +            //return true
  +            return true;
  +        }
  +        return true;
  +    }
  +
  +    /**
  +     * If any EntityReference to be removed has descendants that are not
  +     * EntityReference, Text, or CDATASection nodes, the replaceWholeText method
  +     * must fail before performing any modification of the document, raising a
  +     * DOMException with the code NO_MODIFICATION_ALLOWED_ERR. Traverse previous
  +     * siblings of the node to be replaced. If a previous sibling is an
  +     * EntityReference node, get it's last child. If the first child was a Text
  +     * or CDATASection node and its next siblings are neither a replaceable
  +     * EntityReference or Text or CDATASection nodes, return false. IF the first
  +     * child was neither Text nor CDATASection nor a replaceable EntityReference
  +     * Node, then return true. If the first child was a Text or CDATASection node
  +     * any its next sibling was not or was an EntityReference that did not
  +     * contain only Text or CDATASection nodes, return false.  Check this recursively
  +     * for EntityReference nodes.
  +     * 
  +     * @param node
  +     * @return true - can replace text false - can't replace exception must be
  +     *         raised
  +     */
  +
  +    private boolean canModifyNext(Node node) {
  +        boolean textFirstChild = false;
  +
  +        short type = node.getNodeType();
  +
  +        if (type == Node.ENTITY_REFERENCE_NODE) {
  +            //If the previous sibling was entityreference
  +            //check if its content is replaceable
  +            Node firstChild = node.getFirstChild();
  +
  +            //if the entity reference has no children
  +            //return false
  +            if (firstChild == null) {
  +                fTextOnlyChildren = false;
                   return false;
               }
  -
  -            node = node.getNextSibling();
  +            
  +            //The replacement text of the entity reference should
  +            //be either only text,cadatsections or replaceable entity
  +            //reference nodes or the last child should be neither of these
  +            while (firstChild != null) {
  +                short lType = firstChild.getNodeType();
  +
  +                if (lType == Node.TEXT_NODE || lType == Node.CDATA_SECTION_NODE) {
  +                    fTextOnlyChildren = true;
  +                    textFirstChild = true;
  +                } else if (lType == Node.ENTITY_REFERENCE_NODE) {
  +                    if (!canModifyNext(firstChild)) {
  +                        fTextOnlyChildren = false;
  +                        return false;
  +                    } else {
  +                        //If the EntityReference child contains
  +                        //only text, or non-text or ends with a
  +                        //non-text node.
  +                        textFirstChild = true;
  +                    }
  +                } else {
  +                    //If the first child was replaceable text and next
  +                    //children are not, then return false
  +                    if (textFirstChild) {
  +                        fTextOnlyChildren = false;
  +                        return false;
  +                    } else {
  +                        return true;
  +                    }
  +                }
  +                firstChild = firstChild.getNextSibling();
  +            }
  +        } else if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
  +            //If the previous sibling was text or cdatasection move to next
  +            fTextOnlyChildren = true;
  +        } else {
  +            //If the next sibling was anything but text or
  +            //cdatasection or an entity reference, stop search and
  +            //return true
  +            return true;
           }
           return true;
       }
  @@ -275,51 +462,53 @@
       // Text methods
       //
   
  -    /** 
  -     * Break a text node into two sibling nodes.  (Note that if the
  -     * current node has no parent, they won't wind up as "siblings" --
  -     * they'll both be orphans.)
  -     *
  -     * @param offset The offset at which to split. If offset is at the
  -     * end of the available data, the second node will be empty.
  -     *
  -     * @return A reference to the new node (containing data after the
  -     * offset point). The original node will contain data up to that
  -     * point.
  -     *
  -     * @throws DOMException(INDEX_SIZE_ERR) if offset is <0 or >length.
  -     *
  -     * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is read-only.
  +    /**
  +     * Break a text node into two sibling nodes. (Note that if the current node
  +     * has no parent, they won't wind up as "siblings" -- they'll both be
  +     * orphans.)
  +     * 
  +     * @param offset
  +     *            The offset at which to split. If offset is at the end of the
  +     *            available data, the second node will be empty.
  +     * 
  +     * @return A reference to the new node (containing data after the offset
  +     *         point). The original node will contain data up to that point.
  +     * 
  +     * @throws DOMException(INDEX_SIZE_ERR)
  +     *             if offset is <0 or >length.
  +     * 
  +     * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR)
  +     *             if node is read-only.
        */
       public Text splitText(int offset) 
           throws DOMException {
   
  -    	if (isReadOnly()) {
  +        if (isReadOnly()) {
               throw new DOMException(
  -    		DOMException.NO_MODIFICATION_ALLOWED_ERR, 
  +            DOMException.NO_MODIFICATION_ALLOWED_ERR, 
                   DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null));
           }
   
           if (needsSyncData()) {
               synchronizeData();
           }
  -    	if (offset < 0 || offset > data.length() ) {
  +        if (offset < 0 || offset > data.length() ) {
               throw new DOMException(DOMException.INDEX_SIZE_ERR, 
                   DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null));
           }
  -    		
  +            
           // split text into two separate nodes
  -    	Text newText =
  +        Text newText =
               getOwnerDocument().createTextNode(data.substring(offset));
  -    	setNodeValue(data.substring(0, offset));
  +        setNodeValue(data.substring(0, offset));
   
           // insert new text node
           Node parentNode = getParentNode();
  -    	if (parentNode != null) {
  -    		parentNode.insertBefore(newText, nextSibling);
  +        if (parentNode != null) {
  +            parentNode.insertBefore(newText, nextSibling);
           }
   
  -    	return newText;
  +        return newText;
   
       } // splitText(int):Text
   
  @@ -341,6 +530,5 @@
           data = "";
           return olddata;
       }
  -
   
   } // class TextImpl
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: xerces-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xerces-cvs-help@xml.apache.org