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