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