1 /*
   2  * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 // XMLReaderAdapter.java - adapt an SAX2 XMLReader to a SAX1 Parser
  27 // http://www.saxproject.org
  28 // Written by David Megginson
  29 // NO WARRANTY!  This class is in the public domain.
  30 // $Id: XMLReaderAdapter.java,v 1.3 2004/11/03 22:53:09 jsuttor Exp $
  31 
  32 package org.xml.sax.helpers;
  33 
  34 import java.io.IOException;
  35 import java.util.Locale;
  36 
  37 import org.xml.sax.Parser;      // deprecated
  38 import org.xml.sax.Locator;
  39 import org.xml.sax.InputSource;
  40 import org.xml.sax.AttributeList; // deprecated
  41 import org.xml.sax.EntityResolver;
  42 import org.xml.sax.DTDHandler;
  43 import org.xml.sax.DocumentHandler; // deprecated
  44 import org.xml.sax.ErrorHandler;
  45 import org.xml.sax.SAXException;
  46 
  47 import org.xml.sax.XMLReader;
  48 import org.xml.sax.Attributes;
  49 import org.xml.sax.ContentHandler;
  50 import org.xml.sax.SAXNotSupportedException;
  51 
  52 
  53 /**
  54  * Adapt a SAX2 XMLReader as a SAX1 Parser.
  55  *
  56  * <blockquote>
  57  * <em>This module, both source code and documentation, is in the
  58  * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
  59  * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
  60  * for further information.
  61  * </blockquote>
  62  *
  63  * <p>This class wraps a SAX2 {@link org.xml.sax.XMLReader XMLReader}
  64  * and makes it act as a SAX1 {@link org.xml.sax.Parser Parser}.  The XMLReader
  65  * must support a true value for the
  66  * http://xml.org/sax/features/namespace-prefixes property or parsing will fail
  67  * with a {@link org.xml.sax.SAXException SAXException}; if the XMLReader
  68  * supports a false value for the http://xml.org/sax/features/namespaces
  69  * property, that will also be used to improve efficiency.</p>
  70  *
  71  * @since SAX 2.0
  72  * @author David Megginson
  73  * @see org.xml.sax.Parser
  74  * @see org.xml.sax.XMLReader
  75  */
  76 public class XMLReaderAdapter implements Parser, ContentHandler
  77 {
  78 
  79 
  80     ////////////////////////////////////////////////////////////////////
  81     // Constructor.
  82     ////////////////////////////////////////////////////////////////////
  83 
  84 
  85     /**
  86      * Create a new adapter.
  87      *
  88      * <p>Use the "org.xml.sax.driver" property to locate the SAX2
  89      * driver to embed.</p>
  90      *
  91      * @exception org.xml.sax.SAXException If the embedded driver
  92      *            cannot be instantiated or if the
  93      *            org.xml.sax.driver property is not specified.
  94      */
  95     public XMLReaderAdapter ()
  96       throws SAXException
  97     {
  98         setup(XMLReaderFactory.createXMLReader());
  99     }
 100 
 101 
 102     /**
 103      * Create a new adapter.
 104      *
 105      * <p>Create a new adapter, wrapped around a SAX2 XMLReader.
 106      * The adapter will make the XMLReader act like a SAX1
 107      * Parser.</p>
 108      *
 109      * @param xmlReader The SAX2 XMLReader to wrap.
 110      * @exception java.lang.NullPointerException If the argument is null.
 111      */
 112     public XMLReaderAdapter (XMLReader xmlReader)
 113     {
 114         setup(xmlReader);
 115     }
 116 
 117 
 118 
 119     /**
 120      * Internal setup.
 121      *
 122      * @param xmlReader The embedded XMLReader.
 123      */
 124     private void setup (XMLReader xmlReader)
 125     {
 126         if (xmlReader == null) {
 127             throw new NullPointerException("XMLReader must not be null");
 128         }
 129         this.xmlReader = xmlReader;
 130         qAtts = new AttributesAdapter();
 131     }
 132 
 133 
 134 
 135     ////////////////////////////////////////////////////////////////////
 136     // Implementation of org.xml.sax.Parser.
 137     ////////////////////////////////////////////////////////////////////
 138 
 139 
 140     /**
 141      * Set the locale for error reporting.
 142      *
 143      * <p>This is not supported in SAX2, and will always throw
 144      * an exception.</p>
 145      *
 146      * @param locale the locale for error reporting.
 147      * @see org.xml.sax.Parser#setLocale
 148      * @exception org.xml.sax.SAXException Thrown unless overridden.
 149      */
 150     public void setLocale (Locale locale)
 151         throws SAXException
 152     {
 153         throw new SAXNotSupportedException("setLocale not supported");
 154     }
 155 
 156 
 157     /**
 158      * Register the entity resolver.
 159      *
 160      * @param resolver The new resolver.
 161      * @see org.xml.sax.Parser#setEntityResolver
 162      */
 163     public void setEntityResolver (EntityResolver resolver)
 164     {
 165         xmlReader.setEntityResolver(resolver);
 166     }
 167 
 168 
 169     /**
 170      * Register the DTD event handler.
 171      *
 172      * @param handler The new DTD event handler.
 173      * @see org.xml.sax.Parser#setDTDHandler
 174      */
 175     public void setDTDHandler (DTDHandler handler)
 176     {
 177         xmlReader.setDTDHandler(handler);
 178     }
 179 
 180 
 181     /**
 182      * Register the SAX1 document event handler.
 183      *
 184      * <p>Note that the SAX1 document handler has no Namespace
 185      * support.</p>
 186      *
 187      * @param handler The new SAX1 document event handler.
 188      * @see org.xml.sax.Parser#setDocumentHandler
 189      */
 190     public void setDocumentHandler (DocumentHandler handler)
 191     {
 192         documentHandler = handler;
 193     }
 194 
 195 
 196     /**
 197      * Register the error event handler.
 198      *
 199      * @param handler The new error event handler.
 200      * @see org.xml.sax.Parser#setErrorHandler
 201      */
 202     public void setErrorHandler (ErrorHandler handler)
 203     {
 204         xmlReader.setErrorHandler(handler);
 205     }
 206 
 207 
 208     /**
 209      * Parse the document.
 210      *
 211      * <p>This method will throw an exception if the embedded
 212      * XMLReader does not support the
 213      * http://xml.org/sax/features/namespace-prefixes property.</p>
 214      *
 215      * @param systemId The absolute URL of the document.
 216      * @exception java.io.IOException If there is a problem reading
 217      *            the raw content of the document.
 218      * @exception org.xml.sax.SAXException If there is a problem
 219      *            processing the document.
 220      * @see #parse(org.xml.sax.InputSource)
 221      * @see org.xml.sax.Parser#parse(java.lang.String)
 222      */
 223     public void parse (String systemId)
 224         throws IOException, SAXException
 225     {
 226         parse(new InputSource(systemId));
 227     }
 228 
 229 
 230     /**
 231      * Parse the document.
 232      *
 233      * <p>This method will throw an exception if the embedded
 234      * XMLReader does not support the
 235      * http://xml.org/sax/features/namespace-prefixes property.</p>
 236      *
 237      * @param input An input source for the document.
 238      * @exception java.io.IOException If there is a problem reading
 239      *            the raw content of the document.
 240      * @exception org.xml.sax.SAXException If there is a problem
 241      *            processing the document.
 242      * @see #parse(java.lang.String)
 243      * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
 244      */
 245     public void parse (InputSource input)
 246         throws IOException, SAXException
 247     {
 248         setupXMLReader();
 249         xmlReader.parse(input);
 250     }
 251 
 252 
 253     /**
 254      * Set up the XML reader.
 255      */
 256     private void setupXMLReader ()
 257         throws SAXException
 258     {
 259         xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
 260         try {
 261             xmlReader.setFeature("http://xml.org/sax/features/namespaces",
 262                                  false);
 263         } catch (SAXException e) {
 264             // NO OP: it's just extra information, and we can ignore it
 265         }
 266         xmlReader.setContentHandler(this);
 267     }
 268 
 269 
 270 
 271     ////////////////////////////////////////////////////////////////////
 272     // Implementation of org.xml.sax.ContentHandler.
 273     ////////////////////////////////////////////////////////////////////
 274 
 275 
 276     /**
 277      * Set a document locator.
 278      *
 279      * @param locator The document locator.
 280      * @see org.xml.sax.ContentHandler#setDocumentLocator
 281      */
 282     public void setDocumentLocator (Locator locator)
 283     {
 284         if (documentHandler != null)
 285             documentHandler.setDocumentLocator(locator);
 286     }
 287 
 288 
 289     /**
 290      * Start document event.
 291      *
 292      * @exception org.xml.sax.SAXException The client may raise a
 293      *            processing exception.
 294      * @see org.xml.sax.ContentHandler#startDocument
 295      */
 296     public void startDocument ()
 297         throws SAXException
 298     {
 299         if (documentHandler != null)
 300             documentHandler.startDocument();
 301     }
 302 
 303 
 304     /**
 305      * End document event.
 306      *
 307      * @exception org.xml.sax.SAXException The client may raise a
 308      *            processing exception.
 309      * @see org.xml.sax.ContentHandler#endDocument
 310      */
 311     public void endDocument ()
 312         throws SAXException
 313     {
 314         if (documentHandler != null)
 315             documentHandler.endDocument();
 316     }
 317 
 318 
 319     /**
 320      * Adapt a SAX2 start prefix mapping event.
 321      *
 322      * @param prefix The prefix being mapped.
 323      * @param uri The Namespace URI being mapped to.
 324      * @see org.xml.sax.ContentHandler#startPrefixMapping
 325      */
 326     public void startPrefixMapping (String prefix, String uri)
 327     {
 328     }
 329 
 330 
 331     /**
 332      * Adapt a SAX2 end prefix mapping event.
 333      *
 334      * @param prefix The prefix being mapped.
 335      * @see org.xml.sax.ContentHandler#endPrefixMapping
 336      */
 337     public void endPrefixMapping (String prefix)
 338     {
 339     }
 340 
 341 
 342     /**
 343      * Adapt a SAX2 start element event.
 344      *
 345      * @param uri The Namespace URI.
 346      * @param localName The Namespace local name.
 347      * @param qName The qualified (prefixed) name.
 348      * @param atts The SAX2 attributes.
 349      * @exception org.xml.sax.SAXException The client may raise a
 350      *            processing exception.
 351      * @see org.xml.sax.ContentHandler#endDocument
 352      */
 353     public void startElement (String uri, String localName,
 354                               String qName, Attributes atts)
 355         throws SAXException
 356     {
 357         if (documentHandler != null) {
 358             qAtts.setAttributes(atts);
 359             documentHandler.startElement(qName, qAtts);
 360         }
 361     }
 362 
 363 
 364     /**
 365      * Adapt a SAX2 end element event.
 366      *
 367      * @param uri The Namespace URI.
 368      * @param localName The Namespace local name.
 369      * @param qName The qualified (prefixed) name.
 370      * @exception org.xml.sax.SAXException The client may raise a
 371      *            processing exception.
 372      * @see org.xml.sax.ContentHandler#endElement
 373      */
 374     public void endElement (String uri, String localName,
 375                             String qName)
 376         throws SAXException
 377     {
 378         if (documentHandler != null)
 379             documentHandler.endElement(qName);
 380     }
 381 
 382 
 383     /**
 384      * Adapt a SAX2 characters event.
 385      *
 386      * @param ch An array of characters.
 387      * @param start The starting position in the array.
 388      * @param length The number of characters to use.
 389      * @exception org.xml.sax.SAXException The client may raise a
 390      *            processing exception.
 391      * @see org.xml.sax.ContentHandler#characters
 392      */
 393     public void characters (char ch[], int start, int length)
 394         throws SAXException
 395     {
 396         if (documentHandler != null)
 397             documentHandler.characters(ch, start, length);
 398     }
 399 
 400 
 401     /**
 402      * Adapt a SAX2 ignorable whitespace event.
 403      *
 404      * @param ch An array of characters.
 405      * @param start The starting position in the array.
 406      * @param length The number of characters to use.
 407      * @exception org.xml.sax.SAXException The client may raise a
 408      *            processing exception.
 409      * @see org.xml.sax.ContentHandler#ignorableWhitespace
 410      */
 411     public void ignorableWhitespace (char ch[], int start, int length)
 412         throws SAXException
 413     {
 414         if (documentHandler != null)
 415             documentHandler.ignorableWhitespace(ch, start, length);
 416     }
 417 
 418 
 419     /**
 420      * Adapt a SAX2 processing instruction event.
 421      *
 422      * @param target The processing instruction target.
 423      * @param data The remainder of the processing instruction
 424      * @exception org.xml.sax.SAXException The client may raise a
 425      *            processing exception.
 426      * @see org.xml.sax.ContentHandler#processingInstruction
 427      */
 428     public void processingInstruction (String target, String data)
 429         throws SAXException
 430     {
 431         if (documentHandler != null)
 432             documentHandler.processingInstruction(target, data);
 433     }
 434 
 435 
 436     /**
 437      * Adapt a SAX2 skipped entity event.
 438      *
 439      * @param name The name of the skipped entity.
 440      * @see org.xml.sax.ContentHandler#skippedEntity
 441      * @exception org.xml.sax.SAXException Throwable by subclasses.
 442      */
 443     public void skippedEntity (String name)
 444         throws SAXException
 445     {
 446     }
 447 
 448 
 449 
 450     ////////////////////////////////////////////////////////////////////
 451     // Internal state.
 452     ////////////////////////////////////////////////////////////////////
 453 
 454     XMLReader xmlReader;
 455     DocumentHandler documentHandler;
 456     AttributesAdapter qAtts;
 457 
 458 
 459 
 460     ////////////////////////////////////////////////////////////////////
 461     // Internal class.
 462     ////////////////////////////////////////////////////////////////////
 463 
 464 
 465     /**
 466      * Internal class to wrap a SAX2 Attributes object for SAX1.
 467      */
 468     final class AttributesAdapter implements AttributeList
 469     {
 470         AttributesAdapter ()
 471         {
 472         }
 473 
 474 
 475         /**
 476          * Set the embedded Attributes object.
 477          *
 478          * @param The embedded SAX2 Attributes.
 479          */
 480         void setAttributes (Attributes attributes)
 481         {
 482             this.attributes = attributes;
 483         }
 484 
 485 
 486         /**
 487          * Return the number of attributes.
 488          *
 489          * @return The length of the attribute list.
 490          * @see org.xml.sax.AttributeList#getLength
 491          */
 492         public int getLength ()
 493         {
 494             return attributes.getLength();
 495         }
 496 
 497 
 498         /**
 499          * Return the qualified (prefixed) name of an attribute by position.
 500          *
 501          * @return The qualified name.
 502          * @see org.xml.sax.AttributeList#getName
 503          */
 504         public String getName (int i)
 505         {
 506             return attributes.getQName(i);
 507         }
 508 
 509 
 510         /**
 511          * Return the type of an attribute by position.
 512          *
 513          * @return The type.
 514          * @see org.xml.sax.AttributeList#getType(int)
 515          */
 516         public String getType (int i)
 517         {
 518             return attributes.getType(i);
 519         }
 520 
 521 
 522         /**
 523          * Return the value of an attribute by position.
 524          *
 525          * @return The value.
 526          * @see org.xml.sax.AttributeList#getValue(int)
 527          */
 528         public String getValue (int i)
 529         {
 530             return attributes.getValue(i);
 531         }
 532 
 533 
 534         /**
 535          * Return the type of an attribute by qualified (prefixed) name.
 536          *
 537          * @return The type.
 538          * @see org.xml.sax.AttributeList#getType(java.lang.String)
 539          */
 540         public String getType (String qName)
 541         {
 542             return attributes.getType(qName);
 543         }
 544 
 545 
 546         /**
 547          * Return the value of an attribute by qualified (prefixed) name.
 548          *
 549          * @return The value.
 550          * @see org.xml.sax.AttributeList#getValue(java.lang.String)
 551          */
 552         public String getValue (String qName)
 553         {
 554             return attributes.getValue(qName);
 555         }
 556 
 557         private Attributes attributes;
 558     }
 559 
 560 }
 561 
 562 // end of XMLReaderAdapter.java