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