Coverage Report - org.simpleframework.xml.stream.PullReader
 
Classes in this File Line Coverage Branch Coverage Complexity
PullReader
0%
0/34
0%
0/18
1.519
PullReader$1
N/A
N/A
1.519
PullReader$End
0%
0/2
N/A
1.519
PullReader$Entry
0%
0/13
N/A
1.519
PullReader$Start
0%
0/12
N/A
1.519
PullReader$Text
0%
0/7
N/A
1.519
 
 1  
 /*
 2  
  * PullReader.java January 2010
 3  
  *
 4  
  * Copyright (C) 2010, 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  
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 22  
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 23  
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 24  
 import static org.xmlpull.v1.XmlPullParser.TEXT;
 25  
 
 26  
 import org.xmlpull.v1.XmlPullParser;
 27  
 
 28  
 /**
 29  
  * The <code>PullReader</code> is used to provide an event reader 
 30  
  * thats makes use of the XML pull API. This provides the best
 31  
  * performance on the Google Android platform. Providing support
 32  
  * for the XML pull API ensures that a full DOM model does not
 33  
  * need to be build for large documents. It also ensures that
 34  
  * line numbers are available when each event is extracted.
 35  
  * 
 36  
  * @author Niall Gallagher
 37  
  */
 38  
 class PullReader implements EventReader {
 39  
 
 40  
    /**
 41  
     * This is the XML pull parser that is used to create events.
 42  
     */
 43  
    private XmlPullParser parser;
 44  
    
 45  
    /**
 46  
     * This is the previous node that has been read by a peek.
 47  
     */
 48  
    private EventNode peek;
 49  
    
 50  
    /**
 51  
     * Constructor for the <code>PullReader</code> object. This is
 52  
     * provided an XML pull parser which has been initialized with
 53  
     * the XML source document. Each even produced by this reader
 54  
     * will be extracted from the provided XML pull parser.
 55  
     * 
 56  
     * @param parser this is the parser used to create all events
 57  
     */
 58  0
    public PullReader(XmlPullParser parser) {
 59  0
       this.parser = parser;
 60  0
    }
 61  
 
 62  
    /**
 63  
     * This is used to peek at the node from the document. This will
 64  
     * scan through the document, ignoring any comments to find the
 65  
     * next relevant XML event to acquire. Typically events will be
 66  
     * the start and end of an element, as well as any text nodes.
 67  
     * 
 68  
     * @return this returns the next event taken from the source XML
 69  
     */
 70  
    public EventNode peek() throws Exception {
 71  0
       if(peek == null) {
 72  0
          peek = next();
 73  
       }
 74  0
       return peek;
 75  
    }
 76  
    
 77  
    /**
 78  
     * This is used to take the next node from the document. This will
 79  
     * scan through the document, ignoring any comments to find the
 80  
     * next relevant XML event to acquire. Typically events will be
 81  
     * the start and end of an element, as well as any text nodes.
 82  
     * 
 83  
     * @return this returns the next event taken from the source XML
 84  
     */
 85  
    public EventNode next() throws Exception {
 86  0
       EventNode next = peek;
 87  
 
 88  0
       if(next == null) {
 89  0
          next = read();
 90  
       } else {
 91  0
          peek = null;
 92  
       }
 93  0
       return next;
 94  
    }
 95  
    
 96  
    /**
 97  
     * This is used to read the next node from the document. This will
 98  
     * scan through the document, ignoring any comments to find the
 99  
     * next relevant XML event to acquire. Typically events will be
 100  
     * the start and end of an element, as well as any text nodes.
 101  
     * 
 102  
     * @return this returns the next event taken from the document 
 103  
     */
 104  
    private EventNode read() throws Exception {
 105  0
       int event = parser.next();      
 106  
       
 107  0
       if(event != END_DOCUMENT) {
 108  0
          if(event == START_TAG){
 109  0
             return start();
 110  
          }
 111  0
          if(event == TEXT) {
 112  0
             return text();
 113  
          }
 114  0
          if(event == END_TAG) {
 115  0
             return end();
 116  
          }
 117  0
          return read();
 118  
       }
 119  0
       return null;
 120  
    }
 121  
 
 122  
    /**
 123  
     * This is used to convert the next event to a text event. The
 124  
     * conversion process ensures the node can be digested by the core
 125  
     * reader and used to provide an <code>InputNode</code> that can
 126  
     * be used to represent an XML attribute within the source document.
 127  
     *
 128  
     * @return this returns the text event from the XML pull parser
 129  
     */
 130  
    private Text text() throws Exception {
 131  0
       return new Text(parser);
 132  
    }
 133  
    
 134  
    /**
 135  
     * This is used to convert the next event to a start event. The
 136  
     * conversion process ensures the node can be digested by the core
 137  
     * reader and used to provide an <code>InputNode</code> that can
 138  
     * be used to represent an XML elements within the source document.
 139  
     *
 140  
     * @return this returns a start event created from the parser
 141  
     */
 142  
    private Start start() throws Exception {
 143  0
       Start event = new Start(parser);
 144  
       
 145  0
       if(event.isEmpty()) {
 146  0
          return build(event);
 147  
       }
 148  0
       return event;
 149  
    }
 150  
    
 151  
    /**
 152  
     * This is used to build the attributes that are to be used to 
 153  
     * populate the start event. Populating the start event with the
 154  
     * attributes it contains is required so that each element will
 155  
     * contain its associated attributes. Only attributes that are
 156  
     * not reserved will be added to the start event.
 157  
     * 
 158  
     * @param event this is the start event that is to be populated
 159  
     * 
 160  
     * @return this returns a start event with its attributes
 161  
     */
 162  
    private Start build(Start event) throws Exception {
 163  0
       int count = parser.getAttributeCount();
 164  
       
 165  0
       for(int i = 0; i < count; i++) {
 166  0
          Entry entry = attribute(i);
 167  
 
 168  0
          if(!entry.isReserved()) {
 169  0
             event.add(entry);
 170  
          }
 171  
       }
 172  0
       return event;
 173  
    }
 174  
    
 175  
    /**
 176  
     * This is used to convert the provided object to an attribute. The
 177  
     * conversion process ensures the node can be digested by the core
 178  
     * reader and used to provide an <code>InputNode</code> that can
 179  
     * be used to represent an XML attribute within the source document.
 180  
     * 
 181  
     * @param index this is the index of this attribute to create
 182  
     *
 183  
     * @return this returns an attribute created from the given object
 184  
     */
 185  
    private Entry attribute(int index) throws Exception {
 186  0
       return new Entry(parser, index);
 187  
    }
 188  
    
 189  
    /**
 190  
     * This is used to create an event to signify that an element has
 191  
     * just ended. End events are important as they allow the core
 192  
     * reader to determine if a node is still in context. This provides
 193  
     * a more convenient way to use <code>InputNode</code> objects as
 194  
     * they should only ever be able to extract their children. 
 195  
     * 
 196  
     * @return this returns an end event to signify an element close
 197  
     */
 198  
    private End end() throws Exception {
 199  0
       return new End();
 200  
    } 
 201  
    
 202  
    /**
 203  
     * The <code>Entry</code> object is used to represent an attribute
 204  
     * within a start element. This holds the name and value of the
 205  
     * attribute as well as the namespace prefix and reference. These
 206  
     * details can be used to represent the attribute so that should
 207  
     * the core reader require these details they can be acquired.
 208  
     * 
 209  
     * @author Niall Gallagher
 210  
     */
 211  
    private static class Entry extends EventAttribute {
 212  
       
 213  
       /**
 214  
        * This is the XML pull parser source that is used for this.
 215  
        */
 216  
       private final XmlPullParser source;
 217  
       
 218  
       /**
 219  
        * This is the XML namespace reference used by the attribute.
 220  
        */
 221  
       private final String reference;
 222  
       
 223  
       /**
 224  
        * This is the XML namespace prefix used by the attribute.
 225  
        */
 226  
       private final String prefix;
 227  
       
 228  
       /**
 229  
        * This is the name that is used by this attribute.
 230  
        */
 231  
       private final String name;
 232  
       
 233  
       /**
 234  
        * This is the value that is used by this attribute.
 235  
        */
 236  
       private final String value;
 237  
       
 238  
       /**
 239  
        * Constructor for the <code>Entry</code> object. This creates
 240  
        * an attribute object that is used to extract the name, value
 241  
        * namespace prefix, and namespace reference from the provided
 242  
        * node. This is used to populate any start events created.
 243  
        * 
 244  
        * @param source this is the parser used to get the attribute
 245  
        * @param index this is the index of the attribute to get
 246  
        */
 247  0
       public Entry(XmlPullParser source, int index) {
 248  0
          this.reference = source.getAttributeNamespace(index);
 249  0
          this.prefix = source.getAttributePrefix(index);
 250  0
          this.value = source.getAttributeValue(index);
 251  0
          this.name = source.getAttributeName(index);
 252  0
          this.source = source;
 253  0
       }
 254  
       
 255  
       /**
 256  
        * This provides the name of the attribute. This will be the
 257  
        * name of the XML attribute without any namespace prefix. If
 258  
        * the name begins with "xml" then this attribute is reserved.
 259  
        * according to the namespaces for XML 1.0 specification.
 260  
        * 
 261  
        * @return this returns the name of this attribute object
 262  
        */
 263  
       public String getName() {
 264  0
          return name;
 265  
       }
 266  
       
 267  
       /**
 268  
        * This returns the value of the event. This will be the value
 269  
        * that the attribute contains. If the attribute does not have
 270  
        * a value then this returns null or an empty string.
 271  
        * 
 272  
        * @return this returns the value represented by this object
 273  
        */
 274  
       public String getValue() {
 275  0
          return value;
 276  
       }
 277  
       
 278  
       /**
 279  
        * This returns true if the attribute is reserved. An attribute
 280  
        * is considered reserved if it begins with "xml" according to 
 281  
        * the namespaces in XML 1.0 specification. Such attributes are
 282  
        * used for namespaces and other such details.
 283  
        *
 284  
        * @return this returns true if the attribute is reserved
 285  
        */
 286  
       public boolean isReserved() {
 287  0
          return false;
 288  
       }
 289  
       
 290  
       /**
 291  
        * This is used to acquire the namespace reference that this 
 292  
        * attribute is in. A namespace is normally associated with an
 293  
        * attribute if that attribute is prefixed with a known token.
 294  
        * If there is no prefix then this will return null.
 295  
        * 
 296  
        * @return this provides the associated namespace reference
 297  
        */
 298  
       public String getReference() {
 299  0
          return reference;
 300  
       }
 301  
       
 302  
       /**
 303  
        * This is used to acquire the namespace prefix associated with
 304  
        * this attribute. A prefix is used to qualify the attribute
 305  
        * within a namespace. So, if this has a prefix then it should
 306  
        * have a reference associated with it.
 307  
        * 
 308  
        * @return this returns the namespace prefix for the attribute
 309  
        */
 310  
       public String getPrefix() {
 311  0
          return prefix;
 312  
       }
 313  
       
 314  
       /**
 315  
        * This is used to return the node for the attribute. Because 
 316  
        * this represents an XML event the XML parser is returned.
 317  
        * Returning the node helps with certain debugging issues.
 318  
        * 
 319  
        * @return this will return the source object for this
 320  
        */
 321  
       public Object getSource() {
 322  0
          return source;
 323  
       }
 324  
    }
 325  
    
 326  
    /**
 327  
     * The <code>Start</code> object is used to represent the start of
 328  
     * an XML element. This will hold the attributes associated with
 329  
     * the element and will provide the name, the namespace reference
 330  
     * and the namespace prefix. For debugging purposes the source XML
 331  
     * element is provided for this start event.
 332  
     * 
 333  
     * @author Niall Gallagher
 334  
     */
 335  
    private static class Start extends EventElement {
 336  
       
 337  
       /**
 338  
        * This is the XML pull parser source that is used for this.
 339  
        */
 340  
       private final XmlPullParser source;
 341  
       
 342  
       /**
 343  
        * This is the XML namespace reference used by the attribute.
 344  
        */
 345  
       private final String reference;
 346  
       
 347  
       /**
 348  
        * This is the XML namespace prefix used by the attribute.
 349  
        */
 350  
       private final String prefix;
 351  
       
 352  
       /**
 353  
        * This is the name that is used by this attribute.
 354  
        */
 355  
       private final String name;
 356  
       
 357  
       /**
 358  
        * This is the line number where this element was read.
 359  
        */
 360  
       private final int line;
 361  
       
 362  
       /**
 363  
        * Constructor for the <code>Start</code> object. This will 
 364  
        * wrap the provided node and expose the required details such
 365  
        * as the name, namespace prefix and namespace reference. The
 366  
        * provided element node can be acquired for debugging purposes.
 367  
        * 
 368  
        * @param source this is the parser being wrapped by this
 369  
        */
 370  0
       public Start(XmlPullParser source) {
 371  0
          this.reference = source.getNamespace();
 372  0
          this.line = source.getLineNumber();
 373  0
          this.prefix = source.getPrefix();
 374  0
          this.name = source.getName();
 375  0
          this.source = source;     
 376  0
       }
 377  
       
 378  
       /**
 379  
        * This is used to provide the line number the XML event was
 380  
        * encountered at within the XML document. If there is no line
 381  
        * number available for the node then this will return a -1.
 382  
        * 
 383  
        * @return this returns the line number if it is available
 384  
        */
 385  
       public int getLine() {
 386  0
          return line;
 387  
       }
 388  
       
 389  
       /**
 390  
        * This provides the name of the event. This will be the name 
 391  
        * of an XML element the event represents. If there is a prefix
 392  
        * associated with the element, this extracts that prefix.
 393  
        * 
 394  
        * @return this returns the name without the namespace prefix
 395  
        */
 396  
       public String getName() {
 397  0
          return name;
 398  
       }
 399  
       
 400  
       /**
 401  
        * This is used to acquire the namespace reference that this 
 402  
        * node is in. A namespace is normally associated with an XML
 403  
        * element or attribute, so text events and element close events
 404  
        * are not required to contain any namespace references. 
 405  
        * 
 406  
        * @return this will provide the associated namespace reference
 407  
        */
 408  
       public String getReference() {
 409  0
          return reference;
 410  
       }
 411  
       
 412  
       /**
 413  
        * This is used to acquire the namespace prefix associated with
 414  
        * this node. A prefix is used to qualify an XML element or
 415  
        * attribute within a namespace. So, if this represents a text
 416  
        * event then a namespace prefix is not required.
 417  
        * 
 418  
        * @return this returns the namespace prefix for this event
 419  
        */
 420  
       public String getPrefix() {
 421  0
          return prefix;
 422  
       }
 423  
 
 424  
       /**
 425  
        * This is used to return the node for the element. Because 
 426  
        * this represents an XML event the XML parser is returned.
 427  
        * Returning the node helps with certain debugging issues.
 428  
        * 
 429  
        * @return this will return the source object for this
 430  
        */
 431  
       public Object getSource() {
 432  0
          return source;
 433  
       }
 434  
    }
 435  
    
 436  
    /**
 437  
     * The <code>Text</code> object is used to represent a text event.
 438  
     * If wraps a node that holds text consumed from the document. 
 439  
     * These are used by <code>InputNode</code> objects to extract the
 440  
     * text values for elements For debugging this exposes the node.
 441  
     * 
 442  
     * @author Niall Gallagher
 443  
     */
 444  
    private static class Text extends EventToken {
 445  
       
 446  
       /**
 447  
        * This is the XML pull parser used to extract this text event.
 448  
        */
 449  
       private final XmlPullParser source;
 450  
       
 451  
       /**
 452  
        * This is the text value that has been extracted from the XML.
 453  
        */
 454  
       private final String text;
 455  
       
 456  
       /**
 457  
        * Constructor for the <code>Text</code> object. This creates
 458  
        * an event that provides text to the core reader. Text can be
 459  
        * in the form of a CDATA section or a normal text entry.
 460  
        * 
 461  
        * @param source this is the node that represents the text value
 462  
        */
 463  0
       public Text(XmlPullParser source){
 464  0
          this.text = source.getText(); 
 465  0
          this.source = source;
 466  0
       }
 467  
       
 468  
       /**
 469  
        * This is true as this event represents a text token. Text 
 470  
        * tokens are required to provide a value only. So namespace
 471  
        * details and the node name will always return null.
 472  
        *  
 473  
        * @return this returns true as this event represents text  
 474  
        */
 475  
       public boolean isText() {
 476  0
          return true;
 477  
       }
 478  
       
 479  
       /**
 480  
        * This returns the value of the event. This will return the
 481  
        * text value contained within the node. If there is no
 482  
        * text within the node this should return an empty string. 
 483  
        * 
 484  
        * @return this returns the value represented by this event
 485  
        */
 486  
       public String getValue(){
 487  0
          return text;
 488  
       }
 489  
       
 490  
       /**
 491  
        * This is used to return the node for the text. Because 
 492  
        * this represents an XML event the XML parser is returned.
 493  
        * Returning the node helps with certain debugging issues.
 494  
        * 
 495  
        * @return this will return the source object for this
 496  
        */
 497  
       public Object getSource() {
 498  0
          return source;
 499  
       }
 500  
    } 
 501  
    
 502  
    /**
 503  
     * The <code>End</code> object is used to represent the end of an
 504  
     * element. It is used by the core reader to determine which nodes
 505  
     * are in context and which ones are out of context. This allows
 506  
     * the input nodes to determine if it can read any more children.
 507  
     * 
 508  
     * @author Niall Gallagher
 509  
     */
 510  0
    private static class End extends EventToken {
 511  
       
 512  
       /**
 513  
        * This is true as this event represents an element end. Such
 514  
        * events are required by the core reader to determine if a 
 515  
        * node is still in context. This helps to determine if there
 516  
        * are any more children to be read from a specific node.
 517  
        * 
 518  
        * @return this returns true as this token represents an end
 519  
        */
 520  
       public boolean isEnd() {
 521  0
          return true;
 522  
       }
 523  
    }
 524  
 }