1 /*
   2  * Copyright (c) 2000, 2017, 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 1.4, SAX 2.0
  72  * @author David Megginson
  73  * @see org.xml.sax.Parser
  74  * @see org.xml.sax.XMLReader
  75  */
  76 @SuppressWarnings("deprecation")
  77 public class XMLReaderAdapter implements Parser, ContentHandler
  78 {
  79 
  80 
  81     ////////////////////////////////////////////////////////////////////
  82     // Constructor.
  83     ////////////////////////////////////////////////////////////////////
  84 
  85 
  86     /**
  87      * Create a new adapter.
  88      *
  89      * <p>Use the "org.xml.sax.driver" property to locate the SAX2
  90      * driver to embed.</p>
  91      *
  92      * @exception org.xml.sax.SAXException If the embedded driver
  93      *            cannot be instantiated or if the
  94      *            org.xml.sax.driver property is not specified.
  95      */
  96     public XMLReaderAdapter ()
  97       throws SAXException
  98     {
  99         setup(XMLReaderFactory.createXMLReader());
 100     }
 101 
 102 
 103     /**
 104      * Create a new adapter.
 105      *
 106      * <p>Create a new adapter, wrapped around a SAX2 XMLReader.
 107      * The adapter will make the XMLReader act like a SAX1
 108      * Parser.</p>
 109      *
 110      * @param xmlReader The SAX2 XMLReader to wrap.
 111      * @exception java.lang.NullPointerException If the argument is null.
 112      */
 113     public XMLReaderAdapter (XMLReader xmlReader)
 114     {
 115         setup(xmlReader);
 116     }
 117 
 118 
 119 
 120     /**
 121      * Internal setup.
 122      *
 123      * @param xmlReader The embedded XMLReader.
 124      */
 125     private void setup (XMLReader xmlReader)
 126     {
 127         if (xmlReader == null) {
 128             throw new NullPointerException("XMLReader must not be null");
 129         }
 130         this.xmlReader = xmlReader;
 131         qAtts = new AttributesAdapter();
 132     }
 133 
 134 
 135 
 136     ////////////////////////////////////////////////////////////////////
 137     // Implementation of org.xml.sax.Parser.
 138     ////////////////////////////////////////////////////////////////////
 139 
 140 
 141     /**
 142      * Set the locale for error reporting.
 143      *
 144      * <p>This is not supported in SAX2, and will always throw
 145      * an exception.</p>
 146      *
 147      * @param locale the locale for error reporting.
 148      * @see org.xml.sax.Parser#setLocale
 149      * @exception org.xml.sax.SAXException Thrown unless overridden.
 150      */
 151     public void setLocale (Locale locale)
 152         throws SAXException
 153     {
 154         throw new SAXNotSupportedException("setLocale not supported");
 155     }
 156 
 157 
 158     /**
 159      * Register the entity resolver.
 160      *
 161      * @param resolver The new resolver.
 162      * @see org.xml.sax.Parser#setEntityResolver
 163      */
 164     public void setEntityResolver (EntityResolver resolver)
 165     {
 166         xmlReader.setEntityResolver(resolver);
 167     }
 168 
 169 
 170     /**
 171      * Register the DTD event handler.
 172      *
 173      * @param handler The new DTD event handler.
 174      * @see org.xml.sax.Parser#setDTDHandler
 175      */
 176     public void setDTDHandler (DTDHandler handler)
 177     {
 178         xmlReader.setDTDHandler(handler);
 179     }
 180 
 181 
 182     /**
 183      * Register the SAX1 document event handler.
 184      *
 185      * <p>Note that the SAX1 document handler has no Namespace
 186      * support.</p>
 187      *
 188      * @param handler The new SAX1 document event handler.
 189      * @see org.xml.sax.Parser#setDocumentHandler
 190      */
 191     public void setDocumentHandler (DocumentHandler handler)
 192     {
 193         documentHandler = handler;
 194     }
 195 
 196 
 197     /**
 198      * Register the error event handler.
 199      *
 200      * @param handler The new error event handler.
 201      * @see org.xml.sax.Parser#setErrorHandler
 202      */
 203     public void setErrorHandler (ErrorHandler handler)
 204     {
 205         xmlReader.setErrorHandler(handler);
 206     }
 207 
 208 
 209     /**
 210      * Parse the document.
 211      *
 212      * <p>This method will throw an exception if the embedded
 213      * XMLReader does not support the
 214      * http://xml.org/sax/features/namespace-prefixes property.</p>
 215      *
 216      * @param systemId The absolute URL of the document.
 217      * @exception java.io.IOException If there is a problem reading
 218      *            the raw content of the document.
 219      * @exception org.xml.sax.SAXException If there is a problem
 220      *            processing the document.
 221      * @see #parse(org.xml.sax.InputSource)
 222      * @see org.xml.sax.Parser#parse(java.lang.String)
 223      */
 224     public void parse (String systemId)
 225         throws IOException, SAXException
 226     {
 227         parse(new InputSource(systemId));
 228     }
 229 
 230 
 231     /**
 232      * Parse the document.
 233      *
 234      * <p>This method will throw an exception if the embedded
 235      * XMLReader does not support the
 236      * http://xml.org/sax/features/namespace-prefixes property.</p>
 237      *
 238      * @param input An input source for the document.
 239      * @exception java.io.IOException If there is a problem reading
 240      *            the raw content of the document.
 241      * @exception org.xml.sax.SAXException If there is a problem
 242      *            processing the document.
 243      * @see #parse(java.lang.String)
 244      * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
 245      */
 246     public void parse (InputSource input)
 247         throws IOException, SAXException
 248     {
 249         setupXMLReader();
 250         xmlReader.parse(input);
 251     }
 252 
 253 
 254     /**
 255      * Set up the XML reader.
 256      */
 257     private void setupXMLReader ()
 258         throws SAXException
 259     {
 260         xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
 261         try {
 262             xmlReader.setFeature("http://xml.org/sax/features/namespaces",
 263                                  false);
 264         } catch (SAXException e) {
 265             // NO OP: it's just extra information, and we can ignore it
 266         }
 267         xmlReader.setContentHandler(this);
 268     }
 269 
 270 
 271 
 272     ////////////////////////////////////////////////////////////////////
 273     // Implementation of org.xml.sax.ContentHandler.
 274     ////////////////////////////////////////////////////////////////////
 275 
 276 
 277     /**
 278      * Set a document locator.
 279      *
 280      * @param locator The document locator.
 281      * @see org.xml.sax.ContentHandler#setDocumentLocator
 282      */
 283     public void setDocumentLocator (Locator locator)
 284     {
 285         if (documentHandler != null)
 286             documentHandler.setDocumentLocator(locator);
 287     }
 288 
 289 
 290     /**
 291      * Start document event.
 292      *
 293      * @exception org.xml.sax.SAXException The client may raise a
 294      *            processing exception.
 295      * @see org.xml.sax.ContentHandler#startDocument
 296      */
 297     public void startDocument ()
 298         throws SAXException
 299     {
 300         if (documentHandler != null)
 301             documentHandler.startDocument();
 302     }
 303 
 304 
 305     /**
 306      * End document event.
 307      *
 308      * @exception org.xml.sax.SAXException The client may raise a
 309      *            processing exception.
 310      * @see org.xml.sax.ContentHandler#endDocument
 311      */
 312     public void endDocument ()
 313         throws SAXException
 314     {
 315         if (documentHandler != null)
 316             documentHandler.endDocument();
 317     }
 318 
 319 
 320     /**
 321      * Adapt a SAX2 start prefix mapping event.
 322      *
 323      * @param prefix The prefix being mapped.
 324      * @param uri The Namespace URI being mapped to.
 325      * @see org.xml.sax.ContentHandler#startPrefixMapping
 326      */
 327     public void startPrefixMapping (String prefix, String uri)
 328     {
 329     }
 330 
 331 
 332     /**
 333      * Adapt a SAX2 end prefix mapping event.
 334      *
 335      * @param prefix The prefix being mapped.
 336      * @see org.xml.sax.ContentHandler#endPrefixMapping
 337      */
 338     public void endPrefixMapping (String prefix)
 339     {
 340     }
 341 
 342 
 343     /**
 344      * Adapt a SAX2 start element event.
 345      *
 346      * @param uri The Namespace URI.
 347      * @param localName The Namespace local name.
 348      * @param qName The qualified (prefixed) name.
 349      * @param atts The SAX2 attributes.
 350      * @exception org.xml.sax.SAXException The client may raise a
 351      *            processing exception.
 352      * @see org.xml.sax.ContentHandler#endDocument
 353      */
 354     public void startElement (String uri, String localName,
 355                               String qName, Attributes atts)
 356         throws SAXException
 357     {
 358         if (documentHandler != null) {
 359             qAtts.setAttributes(atts);
 360             documentHandler.startElement(qName, qAtts);
 361         }
 362     }
 363 
 364 
 365     /**
 366      * Adapt a SAX2 end element event.
 367      *
 368      * @param uri The Namespace URI.
 369      * @param localName The Namespace local name.
 370      * @param qName The qualified (prefixed) name.
 371      * @exception org.xml.sax.SAXException The client may raise a
 372      *            processing exception.
 373      * @see org.xml.sax.ContentHandler#endElement
 374      */
 375     public void endElement (String uri, String localName,
 376                             String qName)
 377         throws SAXException
 378     {
 379         if (documentHandler != null)
 380             documentHandler.endElement(qName);
 381     }
 382 
 383 
 384     /**
 385      * Adapt a SAX2 characters event.
 386      *
 387      * @param ch An array of characters.
 388      * @param start The starting position in the array.
 389      * @param length The number of characters to use.
 390      * @exception org.xml.sax.SAXException The client may raise a
 391      *            processing exception.
 392      * @see org.xml.sax.ContentHandler#characters
 393      */
 394     public void characters (char ch[], int start, int length)
 395         throws SAXException
 396     {
 397         if (documentHandler != null)
 398             documentHandler.characters(ch, start, length);
 399     }
 400 
 401 
 402     /**
 403      * Adapt a SAX2 ignorable whitespace event.
 404      *
 405      * @param ch An array of characters.
 406      * @param start The starting position in the array.
 407      * @param length The number of characters to use.
 408      * @exception org.xml.sax.SAXException The client may raise a
 409      *            processing exception.
 410      * @see org.xml.sax.ContentHandler#ignorableWhitespace
 411      */
 412     public void ignorableWhitespace (char ch[], int start, int length)
 413         throws SAXException
 414     {
 415         if (documentHandler != null)
 416             documentHandler.ignorableWhitespace(ch, start, length);
 417     }
 418 
 419 
 420     /**
 421      * Adapt a SAX2 processing instruction event.
 422      *
 423      * @param target The processing instruction target.
 424      * @param data The remainder of the processing instruction
 425      * @exception org.xml.sax.SAXException The client may raise a
 426      *            processing exception.
 427      * @see org.xml.sax.ContentHandler#processingInstruction
 428      */
 429     public void processingInstruction (String target, String data)
 430         throws SAXException
 431     {
 432         if (documentHandler != null)
 433             documentHandler.processingInstruction(target, data);
 434     }
 435 
 436 
 437     /**
 438      * Adapt a SAX2 skipped entity event.
 439      *
 440      * @param name The name of the skipped entity.
 441      * @see org.xml.sax.ContentHandler#skippedEntity
 442      * @exception org.xml.sax.SAXException Throwable by subclasses.
 443      */
 444     public void skippedEntity (String name)
 445         throws SAXException
 446     {
 447     }
 448 
 449 
 450 
 451     ////////////////////////////////////////////////////////////////////
 452     // Internal state.
 453     ////////////////////////////////////////////////////////////////////
 454 
 455     XMLReader xmlReader;
 456     DocumentHandler documentHandler;
 457     AttributesAdapter qAtts;
 458 
 459 
 460 
 461     ////////////////////////////////////////////////////////////////////
 462     // Internal class.
 463     ////////////////////////////////////////////////////////////////////
 464 
 465 
 466     /**
 467      * Internal class to wrap a SAX2 Attributes object for SAX1.
 468      */
 469     final class AttributesAdapter implements AttributeList
 470     {
 471         AttributesAdapter ()
 472         {
 473         }
 474 
 475 
 476         /**
 477          * Set the embedded Attributes object.
 478          *
 479          * @param The embedded SAX2 Attributes.
 480          */
 481         void setAttributes (Attributes attributes)
 482         {
 483             this.attributes = attributes;
 484         }
 485 
 486 
 487         /**
 488          * Return the number of attributes.
 489          *
 490          * @return The length of the attribute list.
 491          * @see org.xml.sax.AttributeList#getLength
 492          */
 493         public int getLength ()
 494         {
 495             return attributes.getLength();
 496         }
 497 
 498 
 499         /**
 500          * Return the qualified (prefixed) name of an attribute by position.
 501          *
 502          * @return The qualified name.
 503          * @see org.xml.sax.AttributeList#getName
 504          */
 505         public String getName (int i)
 506         {
 507             return attributes.getQName(i);
 508         }
 509 
 510 
 511         /**
 512          * Return the type of an attribute by position.
 513          *
 514          * @return The type.
 515          * @see org.xml.sax.AttributeList#getType(int)
 516          */
 517         public String getType (int i)
 518         {
 519             return attributes.getType(i);
 520         }
 521 
 522 
 523         /**
 524          * Return the value of an attribute by position.
 525          *
 526          * @return The value.
 527          * @see org.xml.sax.AttributeList#getValue(int)
 528          */
 529         public String getValue (int i)
 530         {
 531             return attributes.getValue(i);
 532         }
 533 
 534 
 535         /**
 536          * Return the type of an attribute by qualified (prefixed) name.
 537          *
 538          * @return The type.
 539          * @see org.xml.sax.AttributeList#getType(java.lang.String)
 540          */
 541         public String getType (String qName)
 542         {
 543             return attributes.getType(qName);
 544         }
 545 
 546 
 547         /**
 548          * Return the value of an attribute by qualified (prefixed) name.
 549          *
 550          * @return The value.
 551          * @see org.xml.sax.AttributeList#getValue(java.lang.String)
 552          */
 553         public String getValue (String qName)
 554         {
 555             return attributes.getValue(qName);
 556         }
 557 
 558         private Attributes attributes;
 559     }
 560 
 561 }
 562 
 563 // end of XMLReaderAdapter.java