Coverage Report - org.simpleframework.xml.stream.OutputElement
 
Classes in this File Line Coverage Branch Coverage Complexity
OutputElement
89%
41/46
50%
3/6
1.167
 
 1  
 /*
 2  
  * OutputElement.java July 2006
 3  
  *
 4  
  * Copyright (C) 2006, Niall Gallagher <niallg@users.sf.net>
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 15  
  * implied. See the License for the specific language governing 
 16  
  * permissions and limitations under the License.
 17  
  */
 18  
 
 19  
 package org.simpleframework.xml.stream;
 20  
 
 21  
 /**
 22  
  * The <code>OutputElement</code> object represents an XML element.  
 23  
  * Attributes can be added to this before ant child element has been
 24  
  * acquired from it. Once a child element has been acquired the
 25  
  * attributes will be written an can no longer be manipulated, the
 26  
  * same applies to any text value set for the element.
 27  
  * 
 28  
  * @author Niall Gallagher
 29  
  */ 
 30  1121632
 class OutputElement implements OutputNode {
 31  
    
 32  
    /**
 33  
     * Represents the attributes that have been set for the element.
 34  
     */         
 35  
    private OutputNodeMap table;
 36  
 
 37  
    /**
 38  
     * This is the namespace map that contains the namespaces.
 39  
     */ 
 40  
    private NamespaceMap scope;
 41  
    
 42  
    /**
 43  
     * Used to write the start tag and attributes for the document.
 44  
     */ 
 45  
    private NodeWriter writer;
 46  
    
 47  
    /**
 48  
     * This is the parent XML element to this output node.
 49  
     */
 50  
    private OutputNode parent;
 51  
    
 52  
    /**
 53  
     * This is the namespace reference URI associated with this.
 54  
     */ 
 55  
    private String reference;
 56  
    
 57  
    /**
 58  
     * This is the comment that has been set on this element.
 59  
     */
 60  
    private String comment;
 61  
    
 62  
    /**
 63  
     * Represents the value that has been set for the element.
 64  
     */ 
 65  
    private String value;
 66  
 
 67  
    /**
 68  
     * Represents the name of the element for this output node.
 69  
     */ 
 70  
    private String name;
 71  
    
 72  
    /**
 73  
     * This is the output mode that this element object is using.
 74  
     */
 75  
    private Mode mode;
 76  
    
 77  
    /**
 78  
     * Constructor for the <code>OutputElement</code> object. This is
 79  
     * used to create an output element that can create elements for
 80  
     * an XML document. This requires the writer that is used to 
 81  
     * generate the actual document and the name of this node.
 82  
     *
 83  
     * @param parent this is the parent node to this output node
 84  
     * @param writer this is the writer used to generate the file
 85  
     * @param name this is the name of the element this represents
 86  
     */ 
 87  562116
    public OutputElement(OutputNode parent, NodeWriter writer, String name) {
 88  562116
       this.scope = new PrefixResolver(parent);
 89  562116
       this.table = new OutputNodeMap(this);
 90  562116
       this.mode = Mode.INHERIT;
 91  562116
       this.writer = writer;           
 92  562116
       this.parent = parent;
 93  562116
       this.name = name;
 94  562116
    }     
 95  
 
 96  
    /**
 97  
     * This is used to acquire the prefix for this output node. This 
 98  
     * will search its parent nodes until the prefix that is currently
 99  
     * in scope is found.  If a prefix is not found in the parent 
 100  
     * nodes then a prefix in the current nodes namespace mappings is
 101  
     * searched, failing that the prefix returned is null.
 102  
     *
 103  
     * @return this returns the prefix associated with this node
 104  
     */  
 105  
    public String getPrefix() {
 106  0
       return getPrefix(true);
 107  
    }
 108  
    
 109  
    /**
 110  
     * This is used to acquire the prefix for this output node. If
 111  
     * the output node is an element then this will search its parent
 112  
     * nodes until the prefix that is currently in scope is found. 
 113  
     * If however this node is an attribute then the hierarchy of 
 114  
     * nodes is not searched as attributes to not inherit namespaces.
 115  
     *
 116  
     * @param inherit if there is no explicit prefix then inherit
 117  
     *
 118  
     * @return this returns the prefix associated with this node
 119  
     */  
 120  
    public String getPrefix(boolean inherit) {
 121  1123376
       String prefix = scope.getPrefix(reference);
 122  
 
 123  1123376
       if(inherit) {
 124  0
          if(prefix == null) {
 125  0
             return parent.getPrefix();
 126  
          }
 127  
       }
 128  1123376
       return prefix;
 129  
    }
 130  
    
 131  
    /**
 132  
     * This is used to acquire the namespace URI reference associated
 133  
     * with this node. Although it is recommended that the namespace
 134  
     * reference is a URI it does not have to be, it can be any unique
 135  
     * identifier that can be used to distinguish the qualified names.
 136  
     *
 137  
     * @return this returns the namespace URI reference for this
 138  
     */
 139  
    public String getReference() {
 140  0
       return reference;
 141  
    }
 142  
   
 143  
    /**
 144  
     * This is used to set the reference for the node. Setting the
 145  
     * reference implies that the node is a qualified node within the
 146  
     * XML document. Both elements and attributes can be qualified.
 147  
     * Depending on the prefix set on this node or, failing that, any
 148  
     * parent node for the reference, the element will appear in the
 149  
     * XML document with that string prefixed to the node name.
 150  
     *
 151  
     * @param reference this is used to set the reference for the node
 152  
     */  
 153  
    public void setReference(String reference) {
 154  400
       this.reference = reference;
 155  400
    }
 156  
   
 157  
    /**
 158  
     * This returns the <code>NamespaceMap</code> for this node. Only
 159  
     * an element can have namespaces, so if this node represents an
 160  
     * attribute the elements namespaces will be provided when this is
 161  
     * requested. By adding a namespace it becomes in scope for the
 162  
     * current element all all child elements of that element.
 163  
     *
 164  
     * @return this returns the namespaces associated with the node
 165  
     */ 
 166  
    public NamespaceMap getNamespaces() {
 167  4495996
       return scope;
 168  
    }
 169  
    
 170  
    /**
 171  
     * This is used to acquire the <code>Node</code> that is the
 172  
     * parent of this node. This will return the node that is
 173  
     * the direct parent of this node and allows for siblings to
 174  
     * make use of nodes with their parents if required.  
 175  
     *   
 176  
     * @return this returns the parent node for this node
 177  
     */
 178  
    public OutputNode getParent() {
 179  824
       return parent;
 180  
    }
 181  
    
 182  
    /**
 183  
     * Returns the name of the node that this represents. This is
 184  
     * an immutable property and cannot be changed. This will be
 185  
     * written as the tag name when this has been committed.
 186  
     *  
 187  
     * @return returns the name of the node that this represents
 188  
     */   
 189  
    public String getName() {
 190  1123385
       return name;           
 191  
    }
 192  
   
 193  
    /**
 194  
     * Returns the value for the node that this represents. This 
 195  
     * is a modifiable property for the node and can be changed,
 196  
     * however once committed any change will be irrelevant.
 197  
     * 
 198  
     * @return the name of the value for this node instance
 199  
     */   
 200  
    public String getValue() {
 201  1416384
       return value;
 202  
    }
 203  
    
 204  
    /**
 205  
     * This is used to get the text comment for the element. This can
 206  
     * be null if no comment has been set. If no comment is set on 
 207  
     * the node then no comment will be written to the resulting XML.
 208  
     * 
 209  
     * @return this is the comment associated with this element
 210  
     */
 211  
    public String getComment() {
 212  561691
       return comment;
 213  
    }
 214  
    
 215  
    /**
 216  
     * This method is used to determine if this node is the root 
 217  
     * node for the XML document. The root node is the first node
 218  
     * in the document and has no sibling nodes. This is false
 219  
     * if the node has a parent node or a sibling node.
 220  
     * 
 221  
     * @return true if this is the root node within the document
 222  
     */
 223  
    public boolean isRoot() {
 224  26290
       return writer.isRoot(this);
 225  
    }
 226  
    
 227  
    /**
 228  
     * The <code>Mode</code> is used to indicate the output mode
 229  
     * of this node. Three modes are possible, each determines
 230  
     * how a value, if specified, is written to the resulting XML
 231  
     * document. This is determined by the <code>setData</code>
 232  
     * method which will set the output to be CDATA or escaped, 
 233  
     * if neither is specified the mode is inherited.
 234  
     * 
 235  
     * @return this returns the mode of this output node object
 236  
     */
 237  
    public Mode getMode() {
 238  857129
       return mode;
 239  
    }
 240  
    
 241  
    /**
 242  
     * This is used to set the output mode of this node to either
 243  
     * be CDATA, escaped, or inherited. If the mode is set to data
 244  
     * then any value specified will be written in a CDATA block, 
 245  
     * if this is set to escaped values are escaped. If however 
 246  
     * this method is set to inherited then the mode is inherited
 247  
     * from the parent node.
 248  
     * 
 249  
     * @param mode this is the output mode to set the node to 
 250  
     */
 251  
    public void setMode(Mode mode) {
 252  632
       this.mode = mode;
 253  632
    }
 254  
    
 255  
    /**
 256  
     * This returns a <code>NodeMap</code> which can be used to add
 257  
     * nodes to the element before that element has been committed. 
 258  
     * Nodes can be removed or added to the map and will appear as
 259  
     * attributes on the written element when it is committed.
 260  
     *
 261  
     * @return returns the node map used to manipulate attributes
 262  
     */    
 263  
    public OutputNodeMap getAttributes() {
 264  1121632
       return table;
 265  
    }
 266  
    
 267  
    /**
 268  
     * This is used to set a text comment to the element. This will
 269  
     * be written just before the actual element is written. Only a
 270  
     * single comment can be set for each output node written. 
 271  
     * 
 272  
     * @param comment this is the comment to set on the node
 273  
     */
 274  
    public void setComment(String comment) {
 275  25450
       this.comment = comment;
 276  25450
    }
 277  
 
 278  
    /**
 279  
     * This is used to set a text value to the element. This should
 280  
     * be added to the element if the element contains no child
 281  
     * elements. If the value cannot be added an exception is thrown.
 282  
     * 
 283  
     * @param value this is the text value to add to this element
 284  
     */    
 285  
    public void setValue(String value) {
 286  1171757
       this.value = value;
 287  1171757
    }
 288  
    
 289  
    /**
 290  
     * This is used to change the name of an output node. This will
 291  
     * only affect the name of the node if the node has not yet been
 292  
     * committed. If the node is committed then this will not be
 293  
     * reflected in the resulting XML generated.
 294  
     * 
 295  
     * @param name this is the name to change the node to
 296  
     */
 297  
    public void setName(String name) {
 298  23
       this.name = name;
 299  23
    }
 300  
    
 301  
    /**
 302  
     * This is used to set the output mode of this node to either
 303  
     * be CDATA or escaped. If this is set to true the any value
 304  
     * specified will be written in a CDATA block, if this is set
 305  
     * to false the values is escaped. If however this method is
 306  
     * never invoked then the mode is inherited from the parent.
 307  
     * 
 308  
     * @param data if true the value is written as a CDATA block
 309  
     */
 310  
    public void setData(boolean data) {
 311  418255
       if(data) {
 312  133
          mode = Mode.DATA;
 313  
       } else {
 314  418122
          mode = Mode.ESCAPE;
 315  
       }      
 316  418255
    }
 317  
 
 318  
    /**
 319  
     * This method is used for convinience to add an attribute node 
 320  
     * to the attribute <code>NodeMap</code>. The attribute added
 321  
     * can be removed from the element by useing the node map.
 322  
     * 
 323  
     * @param name this is the name of the attribute to be added
 324  
     * @param value this is the value of the node to be added
 325  
     *
 326  
     * @return this will return the attribute that was just set
 327  
     */    
 328  
    public OutputNode setAttribute(String name, String value) {
 329  209319
       return table.put(name, value);
 330  
    }
 331  
 
 332  
    /**
 333  
     * This is used to create a child element within the element that
 334  
     * this object represents. When a new child is created with this
 335  
     * method then the previous child is committed to the document.
 336  
     * The created <code>OutputNode</code> object can be used to add
 337  
     * attributes to the child element as well as other elements.
 338  
     *
 339  
     * @param name this is the name of the child element to create
 340  
     */    
 341  
    public OutputNode getChild(String name) throws Exception {
 342  537704
       return writer.writeElement(this, name);
 343  
    }
 344  
    
 345  
    /**
 346  
     * This is used to remove any uncommitted changes. Removal of an
 347  
     * output node can only be done if it has no siblings and has
 348  
     * not yet been committed. If the node is committed then this 
 349  
     * will throw an exception to indicate that it cannot be removed. 
 350  
     * 
 351  
     * @throws Exception thrown if the node cannot be removed
 352  
     */
 353  
    public void remove() throws Exception {
 354  418
       writer.remove(this);
 355  418
    }
 356  
    
 357  
    /**
 358  
     * This will commit this element and any uncommitted elements
 359  
     * elements that are decendents of this node. For instance if
 360  
     * any child or grand child remains open under this element
 361  
     * then those elements will be closed before this is closed.
 362  
     *
 363  
     * @throws Exception this is thrown if there is an I/O error
 364  
     */ 
 365  
    public void commit() throws Exception{
 366  139168
       writer.commit(this);
 367  139168
    }
 368  
   
 369  
    /**
 370  
     * This is used to determine whether this node has been committed.
 371  
     * If the node is committed then no further child elements can
 372  
     * be created from this node instance. A node is considered to
 373  
     * be committed if a parent creates another child element or if
 374  
     * the <code>commit</code> method is invoked.
 375  
     *
 376  
     * @return true if the node has been committed
 377  
     */  
 378  
    public boolean isCommitted() {
 379  807
       return writer.isCommitted(this);
 380  
    }
 381  
    
 382  
    /**
 383  
     * This is the string representation of the element. It is
 384  
     * used for debugging purposes. When evaluating the element
 385  
     * the to string can be used to print out the element name.
 386  
     * 
 387  
     * @return this returns a text description of the element
 388  
     */
 389  
    public String toString() {
 390  0
       return String.format("element %s", name);
 391  
    }
 392  
 }