Project dom4j 1.5.2 [5/2/05 10:13 PM]
 
Coverage - org/dom4j/tree/AbstractBranch.java
  /*
   * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
   * 
   * This software is open source. 
   * See the bottom of this file for the licence.
   * 
   * $Id: AbstractBranch.java,v 1.41 2004/06/25 08:03:40 maartenc Exp $
   */
 
  package org.dom4j.tree;
 
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  import java.util.StringTokenizer;
 
  import org.dom4j.Branch;
  import org.dom4j.Comment;
  import org.dom4j.Element;
  import org.dom4j.IllegalAddException;
  import org.dom4j.Namespace;
  import org.dom4j.Node;
  import org.dom4j.ProcessingInstruction;
  import org.dom4j.QName;
  import org.dom4j.io.OutputFormat;
 
  /** <p><code>AbstractBranch</code> is an abstract base class for 
    * tree implementors to use for implementation inheritence.</p>
    *
    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
    * @version $Revision: 1.41 $
    */
  public abstract class AbstractBranch extends AbstractNode implements Branch {
 
      /** The output format used by default */
      protected static final OutputFormat outputFormat = new OutputFormat();
 
      protected static final int DEFAULT_CONTENT_LIST_SIZE = 5;
      
      
140660x       public AbstractBranch() { 
140660x       }
 
      
      public boolean isReadOnly() {
234x           return false;
      }    
      
      public boolean hasContent() {
0/2 0x           return nodeCount() > 0;
      }
 
      public List content() {
102x           List backingList = contentList();
102x           return new ContentListFacade(this, backingList);
      }
      
      public String getText() {
26x           List content = contentList();
1/2 26x           if (content != null) {
26x               int size = content.size();
1/2 26x               if (size >= 1) {
26x                   Object first = content.get(0);
26x                   String firstText = getContentAsText( first );
2/2 26x                   if (size == 1) {
                      // optimised to avoid StringBuffer creation
4x                       return firstText;
                  }
                  else {
22x                       StringBuffer buffer = new StringBuffer( firstText );
2/2 72x                       for ( int i = 1; i < size; i++ ) {
50x                           Object node = content.get(i);
50x                           buffer.append( getContentAsText( node ) );
                      }
22x                       return buffer.toString();
                  }
              }
          }
0x           return "";
      }
 
      /** @return the text value of the given content object
       * as text which returns the text value of CDATA, Entity or Text nodes
       */
      protected String getContentAsText(Object content) {
1/2 128x           if ( content instanceof Node) {
128x               Node node = (Node) content;
128x               switch ( node.getNodeType() ) {
                  case CDATA_SECTION_NODE:
                  //case ENTITY_NODE:
                  case ENTITY_REFERENCE_NODE:
                  case TEXT_NODE:
118x                       return node.getText();
              }
          }
0/2 0x           else if ( content instanceof String) {
0x               return (String) content;
          }
10x           return "";
      }
 
      /** @return the XPath defined string-value of the given content object
       */
      protected String getContentAsStringValue(Object content) {
1/2 2448x           if ( content instanceof Node) {
2448x               Node node = (Node) content;
2448x               switch ( node.getNodeType() ) {
                  case CDATA_SECTION_NODE:
                  //case ENTITY_NODE:
                  case ENTITY_REFERENCE_NODE:
                  case TEXT_NODE:
                  case ELEMENT_NODE:
2448x                       return node.getStringValue();
              }
          }
0/2 0x           else if ( content instanceof String) {
0x               return (String) content;
          }
0x           return "";
      }
 
      
      public String getTextTrim() {
20x           String text = getText();
 
20x           StringBuffer textContent = new StringBuffer();
20x           StringTokenizer tokenizer = new StringTokenizer(text);
2/2 50x           while (tokenizer.hasMoreTokens()) {
30x               String str = tokenizer.nextToken();
30x               textContent.append(str);
2/2 30x               if (tokenizer.hasMoreTokens()) {
10x                   textContent.append(" ");  // separator
              }
          }
 
20x           return textContent.toString();
      }
 
      public void setProcessingInstructions(List listOfPIs) {
0/2 0x           for ( Iterator iter = listOfPIs.iterator(); iter.hasNext(); ) {
0x               ProcessingInstruction pi = (ProcessingInstruction) iter.next();
0x               addNode(pi);
          }
0x       }
      
      public Element addElement(String name) {
0x           Element node = getDocumentFactory().createElement( name );
0x           add( node );
0x           return node;
      }
      
      public Element addElement(String qualifiedName, String namespaceURI) {
4x           Element node = getDocumentFactory().createElement( qualifiedName, namespaceURI );
4x           add( node );
4x           return node;
      }
      
      public Element addElement(QName qname) {
109326x           Element node = getDocumentFactory().createElement( qname );
109326x           add( node );
109326x           return node;
      }
      
      public Element addElement(String name, String prefix, String uri) {
0x           Namespace namespace = Namespace.get( prefix, uri );
0x           QName qName = getDocumentFactory().createQName( name, namespace );
0x           return addElement( qName );
      }
      
      // polymorphic node methods    
 
      public void add(Node node) {
16x           switch ( node.getNodeType() ) {
              case ELEMENT_NODE:
16x                   add((Element) node);
16x                   break;
              case COMMENT_NODE:
0x                   add((Comment) node);
0x                   break;
              case PROCESSING_INSTRUCTION_NODE:
0x                   add((ProcessingInstruction) node);
0x                   break;
              default:
0x                   invalidNodeTypeAddException(node);
          }
16x       }
      
      public boolean remove(Node node) {
4x           switch ( node.getNodeType() ) {
              case ELEMENT_NODE:
4x                   return remove((Element) node);
              case COMMENT_NODE:
0x                   return remove((Comment) node);
              case PROCESSING_INSTRUCTION_NODE:
0x                   return remove((ProcessingInstruction) node);
              default:
0x                   invalidNodeTypeAddException(node);
0x                   return false;
          }
      }
      
      // typesafe versions using node classes
      
      public void add(Comment comment) {
8x           addNode(comment);
8x       }
      
      public void add(Element element) {
12048x           addNode(element);
12048x       }
      
      public void add(ProcessingInstruction pi) {
28x           addNode(pi);
28x       }
      
      public boolean remove(Comment comment) {
0x           return removeNode(comment);
      }
      
      public boolean remove(Element element) {
4x           return removeNode(element);
      }
      
      public boolean remove(ProcessingInstruction pi) {
0x           return removeNode(pi);
      }
      
      
      public Element elementByID(String elementID) {
2/2 82x           for ( int i = 0, size = nodeCount(); i < size; i++ ) {
62x               Node node = node(i);
2/2 62x               if ( node instanceof Element ) {
24x                   Element element = (Element) node;
24x                   String id = elementID(element);
4/4 24x                   if ( id != null && id.equals( elementID ) ) {
2x                       return element;
                  }
                  else {
22x                       element = element.elementByID( elementID );
2/2 22x                       if ( element != null ) {
4x                           return element;
                      }
                  }
              }
          }
20x           return null;
      }
      
      public void appendContent(Branch branch) {
2/2 790x           for ( int i = 0, size = branch.nodeCount(); i < size; i++ ) {
546x               Node node = branch.node(i);
546x               add( (Node) node.clone() );
          }
244x       }
          
      
      public Node node(int index) {
160x           Object object = contentList().get(index);
1/2 160x           if (object instanceof Node) {
160x               return (Node) object;
          }
0/2 0x           if (object instanceof String) {
0x               return getDocumentFactory().createText(object.toString());
          }
0x           return null;
      }
      
      public int nodeCount() {
160x           return contentList().size();
      }
      
      public int indexOf(Node node) {
0x           return contentList().indexOf( node );
      }
      
      public Iterator nodeIterator() {
218x           return contentList().iterator();
      }
 
      
      // Implementation methods
      
      /** @return the ID of the given <code>Element</code>
        */
      protected String elementID(Element element) {
          // XXX: there will be other ways of finding the ID
          // XXX: should probably have an IDResolver or something
24x           return element.attributeValue( "ID" );
      }
      
      /** @return the internal List used to manage the content */
      protected abstract List contentList();
 
      /** A Factory Method pattern which creates 
        * a List implementation used to store content
        */
      protected List createContentList() {
50674x           return new ArrayList( DEFAULT_CONTENT_LIST_SIZE );
      }
      
      /** A Factory Method pattern which creates 
        * a List implementation used to store content
        */
      protected List createContentList(int size) {
4x           return new ArrayList( size );
      }
      
      
      /** A Factory Method pattern which creates 
        * a BackedList implementation used to store results of 
        * a filtered content query.     */
      protected BackedList createResultList() {
22028x           return new BackedList( this, contentList() );
      }
      
      /** A Factory Method pattern which creates 
        * a BackedList implementation which contains a single result
        */
      protected List createSingleResultList( Object result ) {
0x           BackedList list = new BackedList( this, contentList(), 1 );
0x           list.addLocal( result );
0x           return list;
      }
      
      /** A Factory Method pattern which creates an empty
        * a BackedList implementation
        */
      protected List createEmptyList() {
12x           return new BackedList( this, contentList(), 0 );
      }
      
      
      protected abstract void addNode(Node node);
      
      protected abstract void addNode(int index, Node node);
      
      protected abstract boolean removeNode(Node node);
      
      
      /** Called when a new child node has been added to me
        * to allow any parent relationships to be created or
        * events to be fired.
        */
      protected abstract void childAdded(Node node);
      
      /** Called when a child node has been removed 
        * to allow any parent relationships to be deleted or
        * events to be fired.
        */
      protected abstract void childRemoved(Node node);
 
      /** Called when the given List content has been removed so
        * each node should have its parent and document relationships
        * cleared
        */
      protected void contentRemoved() {
14x           List content = contentList();
2/2 20x           for ( int i = 0, size = content.size(); i < size; i++ ) {
6x               Object object = content.get(i);
1/2 6x               if ( object instanceof Node ) {
6x                    childRemoved( (Node) object );
              }            
          }
14x       }
 
      /** Called when an invalid node has been added. 
        * Throws an {@link IllegalAddException}.
        */
      protected void invalidNodeTypeAddException(Node node) {
0x           throw new IllegalAddException( "Invalid node type. Cannot add node: " + node + " to this branch: " + this );
      }
      
 
  }
 
 
 
 
  /*
   * Redistribution and use of this software and associated documentation
   * ("Software"), with or without modification, are permitted provided
   * that the following conditions are met:
   *
   * 1. Redistributions of source code must retain copyright
   *    statements and notices.  Redistributions must also contain a
   *    copy of this document.
   *
   * 2. Redistributions in binary form must reproduce the
   *    above copyright notice, this list of conditions and the
   *    following disclaimer in the documentation and/or other
   *    materials provided with the distribution.
   *
   * 3. The name "DOM4J" must not be used to endorse or promote
   *    products derived from this Software without prior written
   *    permission of MetaStuff, Ltd.  For written permission,
   *    please contact dom4j-info@metastuff.com.
   *
   * 4. Products derived from this Software may not be called "DOM4J"
   *    nor may "DOM4J" appear in their names without prior written
   *    permission of MetaStuff, Ltd. DOM4J is a registered
   *    trademark of MetaStuff, Ltd.
   *
   * 5. Due credit should be given to the DOM4J Project - 
   *    http://www.dom4j.org
   *
   * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
   * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
   *
   * $Id: AbstractBranch.java,v 1.41 2004/06/25 08:03:40 maartenc Exp $
   */