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 226184 2005-04-08 10:53:24Z neeraj $ 6 7 package org.xml.sax.helpers; 8 9 import java.io.IOException; 10 import java.util.Locale; 11 12 import org.xml.sax.Parser; // deprecated 13 import org.xml.sax.Locator; 14 import org.xml.sax.InputSource; 15 import org.xml.sax.AttributeList; // deprecated 16 import org.xml.sax.EntityResolver; 17 import org.xml.sax.DTDHandler; 18 import org.xml.sax.DocumentHandler; // deprecated 19 import org.xml.sax.ErrorHandler; 20 import org.xml.sax.SAXException; 21 22 import org.xml.sax.XMLReader; 23 import org.xml.sax.Attributes; 24 import org.xml.sax.ContentHandler; 25 import org.xml.sax.SAXNotSupportedException; 26 27 28 /** 29 * Adapt a SAX2 XMLReader as a SAX1 Parser. 30 * 31 * <blockquote> 32 * <em>This module, both source code and documentation, is in the 33 * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em> 34 * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a> 35 * for further information. 36 * </blockquote> 37 * 38 * <p>This class wraps a SAX2 {@link org.xml.sax.XMLReader XMLReader} 39 * and makes it act as a SAX1 {@link org.xml.sax.Parser Parser}. The XMLReader 40 * must support a true value for the 41 * http://xml.org/sax/features/namespace-prefixes property or parsing will fail 42 * with a {@link org.xml.sax.SAXException SAXException}; if the XMLReader 43 * supports a false value for the http://xml.org/sax/features/namespaces 44 * property, that will also be used to improve efficiency.</p> 45 * 46 * @since SAX 2.0 47 * @author David Megginson 48 * @version 2.0.1 (sax2r2) 49 * @see org.xml.sax.Parser 50 * @see org.xml.sax.XMLReader 51 */ 52 public class XMLReaderAdapter implements Parser, ContentHandler 53 { 54 55 56 //////////////////////////////////////////////////////////////////// 57 // Constructor. 58 //////////////////////////////////////////////////////////////////// 59 60 61 /** 62 * Create a new adapter. 63 * 64 * <p>Use the "org.xml.sax.driver" property to locate the SAX2 65 * driver to embed.</p> 66 * 67 * @exception org.xml.sax.SAXException If the embedded driver 68 * cannot be instantiated or if the 69 * org.xml.sax.driver property is not specified. 70 */ 71 public XMLReaderAdapter () 72 throws SAXException 73 { 74 setup(XMLReaderFactory.createXMLReader()); 75 } 76 77 78 /** 79 * Create a new adapter. 80 * 81 * <p>Create a new adapter, wrapped around a SAX2 XMLReader. 82 * The adapter will make the XMLReader act like a SAX1 83 * Parser.</p> 84 * 85 * @param xmlReader The SAX2 XMLReader to wrap. 86 * @exception java.lang.NullPointerException If the argument is null. 87 */ 88 public XMLReaderAdapter (XMLReader xmlReader) 89 { 90 setup(xmlReader); 91 } 92 93 94 95 /** 96 * Internal setup. 97 * 98 * @param xmlReader The embedded XMLReader. 99 */ 100 private void setup (XMLReader xmlReader) 101 { 102 if (xmlReader == null) { 103 throw new NullPointerException("XMLReader must not be null"); 104 } 105 this.xmlReader = xmlReader; 106 qAtts = new AttributesAdapter(); 107 } 108 109 110 111 //////////////////////////////////////////////////////////////////// 112 // Implementation of org.xml.sax.Parser. 113 //////////////////////////////////////////////////////////////////// 114 115 116 /** 117 * Set the locale for error reporting. 118 * 119 * <p>This is not supported in SAX2, and will always throw 120 * an exception.</p> 121 * 122 * @param locale the locale for error reporting. 123 * @see org.xml.sax.Parser#setLocale 124 * @exception org.xml.sax.SAXException Thrown unless overridden. 125 */ 126 public void setLocale (Locale locale) 127 throws SAXException 128 { 129 throw new SAXNotSupportedException("setLocale not supported"); 130 } 131 132 133 /** 134 * Register the entity resolver. 135 * 136 * @param resolver The new resolver. 137 * @see org.xml.sax.Parser#setEntityResolver 138 */ 139 public void setEntityResolver (EntityResolver resolver) 140 { 141 xmlReader.setEntityResolver(resolver); 142 } 143 144 145 /** 146 * Register the DTD event handler. 147 * 148 * @param handler The new DTD event handler. 149 * @see org.xml.sax.Parser#setDTDHandler 150 */ 151 public void setDTDHandler (DTDHandler handler) 152 { 153 xmlReader.setDTDHandler(handler); 154 } 155 156 157 /** 158 * Register the SAX1 document event handler. 159 * 160 * <p>Note that the SAX1 document handler has no Namespace 161 * support.</p> 162 * 163 * @param handler The new SAX1 document event handler. 164 * @see org.xml.sax.Parser#setDocumentHandler 165 */ 166 public void setDocumentHandler (DocumentHandler handler) 167 { 168 documentHandler = handler; 169 } 170 171 172 /** 173 * Register the error event handler. 174 * 175 * @param handler The new error event handler. 176 * @see org.xml.sax.Parser#setErrorHandler 177 */ 178 public void setErrorHandler (ErrorHandler handler) 179 { 180 xmlReader.setErrorHandler(handler); 181 } 182 183 184 /** 185 * Parse the document. 186 * 187 * <p>This method will throw an exception if the embedded 188 * XMLReader does not support the 189 * http://xml.org/sax/features/namespace-prefixes property.</p> 190 * 191 * @param systemId The absolute URL of the document. 192 * @exception java.io.IOException If there is a problem reading 193 * the raw content of the document. 194 * @exception org.xml.sax.SAXException If there is a problem 195 * processing the document. 196 * @see #parse(org.xml.sax.InputSource) 197 * @see org.xml.sax.Parser#parse(java.lang.String) 198 */ 199 public void parse (String systemId) 200 throws IOException, SAXException 201 { 202 parse(new InputSource(systemId)); 203 } 204 205 206 /** 207 * Parse the document. 208 * 209 * <p>This method will throw an exception if the embedded 210 * XMLReader does not support the 211 * http://xml.org/sax/features/namespace-prefixes property.</p> 212 * 213 * @param input An input source for the document. 214 * @exception java.io.IOException If there is a problem reading 215 * the raw content of the document. 216 * @exception org.xml.sax.SAXException If there is a problem 217 * processing the document. 218 * @see #parse(java.lang.String) 219 * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource) 220 */ 221 public void parse (InputSource input) 222 throws IOException, SAXException 223 { 224 setupXMLReader(); 225 xmlReader.parse(input); 226 } 227 228 229 /** 230 * Set up the XML reader. 231 */ 232 private void setupXMLReader () 233 throws SAXException 234 { 235 xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); 236 try { 237 xmlReader.setFeature("http://xml.org/sax/features/namespaces", 238 false); 239 } catch (SAXException e) { 240 // NO OP: it's just extra information, and we can ignore it 241 } 242 xmlReader.setContentHandler(this); 243 } 244 245 246 247 //////////////////////////////////////////////////////////////////// 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 //////////////////////////////////////////////////////////////////// 427 // Internal state. 428 //////////////////////////////////////////////////////////////////// 429 430 XMLReader xmlReader; 431 DocumentHandler documentHandler; 432 AttributesAdapter qAtts; 433 434 435 436 //////////////////////////////////////////////////////////////////// 437 // Internal class. 438 //////////////////////////////////////////////////////////////////// 439 440 441 /** 442 * Internal class to wrap a SAX2 Attributes object for SAX1. 443 */ 444 final class AttributesAdapter implements AttributeList 445 { 446 AttributesAdapter () 447 { 448 } 449 450 451 /** 452 * Set the embedded Attributes object. 453 * 454 * @param The embedded SAX2 Attributes. 455 */ 456 void setAttributes (Attributes attributes) 457 { 458 this.attributes = attributes; 459 } 460 461 462 /** 463 * Return the number of attributes. 464 * 465 * @return The length of the attribute list. 466 * @see org.xml.sax.AttributeList#getLength 467 */ 468 public int getLength () 469 { 470 return attributes.getLength(); 471 } 472 473 474 /** 475 * Return the qualified (prefixed) name of an attribute by position. 476 * 477 * @return The qualified name. 478 * @see org.xml.sax.AttributeList#getName 479 */ 480 public String getName (int i) 481 { 482 return attributes.getQName(i); 483 } 484 485 486 /** 487 * Return the type of an attribute by position. 488 * 489 * @return The type. 490 * @see org.xml.sax.AttributeList#getType(int) 491 */ 492 public String getType (int i) 493 { 494 return attributes.getType(i); 495 } 496 497 498 /** 499 * Return the value of an attribute by position. 500 * 501 * @return The value. 502 * @see org.xml.sax.AttributeList#getValue(int) 503 */ 504 public String getValue (int i) 505 { 506 return attributes.getValue(i); 507 } 508 509 510 /** 511 * Return the type of an attribute by qualified (prefixed) name. 512 * 513 * @return The type. 514 * @see org.xml.sax.AttributeList#getType(java.lang.String) 515 */ 516 public String getType (String qName) 517 { 518 return attributes.getType(qName); 519 } 520 521 522 /** 523 * Return the value of an attribute by qualified (prefixed) name. 524 * 525 * @return The value. 526 * @see org.xml.sax.AttributeList#getValue(java.lang.String) 527 */ 528 public String getValue (String qName) 529 { 530 return attributes.getValue(qName); 531 } 532 533 private Attributes attributes; 534 } 535 536 } 537 538 // end of XMLReaderAdapter.java