Project dom4j 1.5.2 [5/2/05 10:13 PM]
 
Coverage - org/dom4j/io/XPPReader.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: XPPReader.java,v 1.5 2004/06/25 08:03:38 maartenc Exp $
   */
 
  package org.dom4j.io;
 
  import java.io.BufferedReader;
  import java.io.File;
  import java.io.FileReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.Reader;
  import java.net.URL;
 
  import org.dom4j.Document;
  import org.dom4j.DocumentException;
  import org.dom4j.DocumentFactory;
  import org.dom4j.Element;
  import org.dom4j.ElementHandler;
  import org.dom4j.xpp.ProxyXmlStartTag;
  import org.gjt.xpp.XmlEndTag;
  import org.gjt.xpp.XmlPullParser;
  import org.gjt.xpp.XmlPullParserException;
  import org.gjt.xpp.XmlPullParserFactory;
 
  /** <p><code>XPPReader</code> is a Reader of DOM4J documents that 
    * uses the fast 
    * <a href="http://www.extreme.indiana.edu/soap/xpp/">XML Pull Parser 2.x</a>.
    * It does not currently support comments, CDATA or ProcessingInstructions or
    * validation but it is very fast for use in SOAP style environments.</p>
    *
    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
    * @version $Revision: 1.5 $
    */
  public class XPPReader {
 
      /** <code>DocumentFactory</code> used to create new document objects */
      private DocumentFactory factory;
      
      /** <code>XmlPullParser</code> used to parse XML */
      private XmlPullParser xppParser;
      
      /** <code>XmlPullParser</code> used to parse XML */
      private XmlPullParserFactory xppFactory;
      
      /** DispatchHandler to call when each <code>Element</code> is encountered */
      private DispatchHandler dispatchHandler;
   
          
      
0x       public XPPReader() {
0x       }
 
0x       public XPPReader(DocumentFactory factory) {
0x           this.factory = factory;
0x       }
 
      
      
          
      /** <p>Reads a Document from the given <code>File</code></p>
        *
        * @param file is the <code>File</code> to read from.
        * @return the newly created Document instance
        * @throws DocumentException if an error occurs during parsing.
        * @throws MalformedURLException if a URL could not be made for the given File
        */
      public Document read(File file) throws DocumentException, IOException, XmlPullParserException {
0x           String systemID = file.getAbsolutePath();
0x           return read( new BufferedReader( new FileReader( file ) ), systemID );
      }
      
      /** <p>Reads a Document from the given <code>URL</code></p>
        *
        * @param url <code>URL</code> to read from.
        * @return the newly created Document instance
        * @throws DocumentException if an error occurs during parsing.
        */
      public Document read(URL url) throws DocumentException, IOException, XmlPullParserException {
0x           String systemID = url.toExternalForm();
0x           return read( createReader( url.openStream() ), systemID);
      }
      
      /** <p>Reads a Document from the given URL or filename.</p>
        *
        * <p>
        * If the systemID contains a <code>':'</code> character then it is
        * assumed to be a URL otherwise its assumed to be a file name.
        * If you want finer grained control over this mechansim then please
        * explicitly pass in either a {@link URL} or a {@link File} instance
        * instead of a {@link String} to denote the source of the document.
        * </p>
        *
        * @param systemID is a URL for a document or a file name.
        * @return the newly created Document instance
        * @throws DocumentException if an error occurs during parsing.
        * @throws MalformedURLException if a URL could not be made for the given File
        */
      public Document read(String systemID) throws DocumentException, IOException, XmlPullParserException {
0/2 0x           if ( systemID.indexOf( ':' ) >= 0 ) {
              // lets assume its a URL
0x               return read(new URL(systemID));
          }
          else {
              // lets assume that we are given a file name
0x               return read( new File(systemID) );
          }
      }
 
      /** <p>Reads a Document from the given stream</p>
        *
        * @param in <code>InputStream</code> to read from.
        * @return the newly created Document instance
        * @throws DocumentException if an error occurs during parsing.
        */
      public Document read(InputStream in) throws DocumentException, IOException, XmlPullParserException {
0x           return read( createReader( in ) );
      }
 
      /** <p>Reads a Document from the given <code>Reader</code></p>
        *
        * @param reader is the reader for the input
        * @return the newly created Document instance
        * @throws DocumentException if an error occurs during parsing.
        */
      public Document read(Reader reader) throws DocumentException, IOException, XmlPullParserException {
0x           getXPPParser().setInput(reader);
0x           return parseDocument();
      }
 
      /** <p>Reads a Document from the given array of characters</p>
        *
        * @param text is the text to parse
        * @return the newly created Document instance
        * @throws DocumentException if an error occurs during parsing.
        */
      public Document read(char[] text) throws DocumentException, IOException, XmlPullParserException {
0x           getXPPParser().setInput(text);
0x           return parseDocument();
      }
 
      /** <p>Reads a Document from the given stream</p>
        *
        * @param in <code>InputStream</code> to read from.
        * @param systemID is the URI for the input
        * @return the newly created Document instance
        * @throws DocumentException if an error occurs during parsing.
        */
      public Document read(InputStream in, String systemID) throws DocumentException, IOException, XmlPullParserException {
0x           return read( createReader( in ), systemID );
      }
 
      /** <p>Reads a Document from the given <code>Reader</code></p>
        *
        * @param reader is the reader for the input
        * @param systemID is the URI for the input
        * @return the newly created Document instance
        * @throws DocumentException if an error occurs during parsing.
        */
      public Document read(Reader reader, String systemID) throws DocumentException, IOException, XmlPullParserException {
0x           Document document = read( reader );
0x           document.setName( systemID );
0x           return document;
      }
 
      
      // Properties
      //-------------------------------------------------------------------------                
 
      public XmlPullParser getXPPParser() throws XmlPullParserException {
0/2 0x           if ( xppParser == null ) {
0x               xppParser = getXPPFactory().newPullParser();
          }
0x           return xppParser;
      }
      
      public XmlPullParserFactory getXPPFactory() throws XmlPullParserException {
0/2 0x           if ( xppFactory == null ) {
0x               xppFactory = XmlPullParserFactory.newInstance();
          }
0x           return xppFactory;
      }
 
      public void setXPPFactory(XmlPullParserFactory xppFactory) {
0x           this.xppFactory = xppFactory;
0x       }
      
      /** @return the <code>DocumentFactory</code> used to create document objects
        */
      public DocumentFactory getDocumentFactory() {
0/2 0x           if (factory == null) {
0x               factory = DocumentFactory.getInstance();
          }
0x           return factory;
      }
 
      /** <p>This sets the <code>DocumentFactory</code> used to create new documents.
        * This method allows the building of custom DOM4J tree objects to be implemented
        * easily using a custom derivation of {@link DocumentFactory}</p>
        *
        * @param factory <code>DocumentFactory</code> used to create DOM4J objects
        */
      public void setDocumentFactory(DocumentFactory factory) {
0x           this.factory = factory;
0x       }
 
      
      /** Adds the <code>ElementHandler</code> to be called when the 
        * specified path is encounted.
        *
        * @param path is the path to be handled
        * @param handler is the <code>ElementHandler</code> to be called
        * by the event based processor.
        */
      public void addHandler(String path, ElementHandler handler) {
0x           getDispatchHandler().addHandler(path, handler);   
0x       }
      
      /** Removes the <code>ElementHandler</code> from the event based
        * processor, for the specified path.
        *
        * @param path is the path to remove the <code>ElementHandler</code> for.
        */
      public void removeHandler(String path) {
0x           getDispatchHandler().removeHandler(path);   
0x       }
      
      /** When multiple <code>ElementHandler</code> instances have been 
        * registered, this will set a default <code>ElementHandler</code>
        * to be called for any path which does <b>NOT</b> have a handler
        * registered.
        * @param handler is the <code>ElementHandler</code> to be called
        * by the event based processor.
        */
      public void setDefaultHandler(ElementHandler handler) {
0x           getDispatchHandler().setDefaultHandler(handler);   
0x       }
      
      // Implementation methods    
      //-------------------------------------------------------------------------                    
      protected Document parseDocument() throws DocumentException, IOException, XmlPullParserException {
0x           Document document = getDocumentFactory().createDocument();
0x           Element parent = null;
0x           XmlPullParser xppParser = getXPPParser();
0x           xppParser.setNamespaceAware(true);
0x           ProxyXmlStartTag startTag = new ProxyXmlStartTag();
0x           XmlEndTag endTag = xppFactory.newEndTag();
          while (true) {
0x               int type = xppParser.next();
0x               switch (type) {
                  case XmlPullParser.END_DOCUMENT: {
0x                       return document;
                  }
                  case XmlPullParser.START_TAG: {
0x                       xppParser.readStartTag( startTag );
0x                       Element newElement = startTag.getElement();
0/2 0x                       if ( parent != null ) {
0x                           parent.add( newElement );
                      }
                      else {
0x                           document.add( newElement );
                      }
0x                       parent = newElement;
0x                       break;
                  }
                  case XmlPullParser.END_TAG: {
0x                       xppParser.readEndTag( endTag );
0/2 0x                       if (parent != null) {
0x                           parent = parent.getParent();
                      }
                      break;
                  }
                  case XmlPullParser.CONTENT: {
0x                       String text = xppParser.readContent();
0/2 0x                       if ( parent != null ) {
0x                           parent.addText( text );
                      }
                      else {
0x                           throw new DocumentException( "Cannot have text content outside of the root document" );
                      }
                      break;
                  }
                  default: {
0x                       throw new DocumentException( "Error: unknown PullParser type: " + type );
                  }
              }
          }
      }
 
      protected DispatchHandler getDispatchHandler() {
0/2 0x           if (dispatchHandler == null) {
0x               dispatchHandler = new DispatchHandler();
          }
0x           return dispatchHandler;   
      }
      
      protected void setDispatchHandler(DispatchHandler dispatchHandler) {
0x           this.dispatchHandler = dispatchHandler;
0x       }
      
      /** Factory method to create a Reader from the given InputStream.
       */
      protected Reader createReader(InputStream in) throws IOException {
0x           return new BufferedReader( new InputStreamReader( in ) );
      }    
  }
 
 
 
 
  /*
   * 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: XPPReader.java,v 1.5 2004/06/25 08:03:38 maartenc Exp $
   */