001// XMLReaderAdapter.java - adapt an SAX2 XMLReader to a SAX1 Parser 002// Written by David Megginson, sax@megginson.com 003// NO WARRANTY! This class is in the public domain. 004 005// $Id: XMLReaderAdapter.java,v 1.1 2001/03/05 21:40:06 jstrachan Exp $ 006 007package org.xml.sax.helpers; 008 009import java.io.IOException; 010import java.util.Locale; 011 012import org.xml.sax.Parser; // deprecated 013import org.xml.sax.Locator; 014import org.xml.sax.InputSource; 015import org.xml.sax.AttributeList; // deprecated 016import org.xml.sax.EntityResolver; 017import org.xml.sax.DTDHandler; 018import org.xml.sax.DocumentHandler; // deprecated 019import org.xml.sax.ErrorHandler; 020import org.xml.sax.SAXException; 021 022import org.xml.sax.XMLReader; 023import org.xml.sax.Attributes; 024import org.xml.sax.ContentHandler; 025import org.xml.sax.SAXNotSupportedException; 026 027 028/** 029 * Adapt a SAX2 XMLReader as a SAX1 Parser. 030 * 031 * <blockquote> 032 * <em>This module, both source code and documentation, is in the 033 * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em> 034 * </blockquote> 035 * 036 * <p>This class wraps a SAX2 {@link org.xml.sax.XMLReader XMLReader} 037 * and makes it act as a SAX1 {@link org.xml.sax.Parser Parser}. The XMLReader 038 * must support a true value for the 039 * http://xml.org/sax/features/namespace-prefixes property or parsing will fail 040 * with a {@link org.xml.sax.SAXException SAXException}; if the XMLReader 041 * supports a false value for the http://xml.org/sax/features/namespaces 042 * property, that will also be used to improve efficiency.</p> 043 * 044 * @since SAX 2.0 045 * @author David Megginson, 046 * <a href="mailto:sax@megginson.com">sax@megginson.com</a> 047 * @version 2.0 048 * @see org.xml.sax.Parser 049 * @see org.xml.sax.XMLReader 050 */ 051public class XMLReaderAdapter implements Parser, ContentHandler 052{ 053 054 055 //////////////////////////////////////////////////////////////////// 056 // Constructor. 057 //////////////////////////////////////////////////////////////////// 058 059 060 /** 061 * Create a new adapter. 062 * 063 * <p>Use the "org.xml.sax.driver" property to locate the SAX2 064 * driver to embed.</p> 065 * 066 * @exception org.xml.sax.SAXException If the embedded driver 067 * cannot be instantiated or if the 068 * org.xml.sax.driver property is not specified. 069 */ 070 public XMLReaderAdapter () 071 throws SAXException 072 { 073 setup(XMLReaderFactory.createXMLReader()); 074 } 075 076 077 /** 078 * Create a new adapter. 079 * 080 * <p>Create a new adapter, wrapped around a SAX2 XMLReader. 081 * The adapter will make the XMLReader act like a SAX1 082 * Parser.</p> 083 * 084 * @param xmlReader The SAX2 XMLReader to wrap. 085 * @exception java.lang.NullPointerException If the argument is null. 086 */ 087 public XMLReaderAdapter (XMLReader xmlReader) 088 { 089 setup(xmlReader); 090 } 091 092 093 094 /** 095 * Internal setup. 096 * 097 * @param xmlReader The embedded XMLReader. 098 */ 099 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 The locale for error reporting. 122 * @see org.xml.sax.Parser#setLocale 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 documentHandler.setDocumentLocator(locator); 259 } 260 261 262 /** 263 * Start document event. 264 * 265 * @exception org.xml.sax.SAXException The client may raise a 266 * processing exception. 267 * @see org.xml.sax.ContentHandler#startDocument 268 */ 269 public void startDocument () 270 throws SAXException 271 { 272 documentHandler.startDocument(); 273 } 274 275 276 /** 277 * End document event. 278 * 279 * @exception org.xml.sax.SAXException The client may raise a 280 * processing exception. 281 * @see org.xml.sax.ContentHandler#endDocument 282 */ 283 public void endDocument () 284 throws SAXException 285 { 286 documentHandler.endDocument(); 287 } 288 289 290 /** 291 * Adapt a SAX2 start prefix mapping event. 292 * 293 * @param prefix The prefix being mapped. 294 * @param uri The Namespace URI being mapped to. 295 * @see org.xml.sax.ContentHandler#startPrefixMapping 296 */ 297 public void startPrefixMapping (String prefix, String uri) 298 { 299 } 300 301 302 /** 303 * Adapt a SAX2 end prefix mapping event. 304 * 305 * @param prefix The prefix being mapped. 306 * @see org.xml.sax.ContentHandler#endPrefixMapping 307 */ 308 public void endPrefixMapping (String prefix) 309 { 310 } 311 312 313 /** 314 * Adapt a SAX2 start element event. 315 * 316 * @param uri The Namespace URI. 317 * @param localName The Namespace local name. 318 * @param qName The qualified (prefixed) name. 319 * @param atts The SAX2 attributes. 320 * @exception org.xml.sax.SAXException The client may raise a 321 * processing exception. 322 * @see org.xml.sax.ContentHandler#endDocument 323 */ 324 public void startElement (String uri, String localName, 325 String qName, Attributes atts) 326 throws SAXException 327 { 328 qAtts.setAttributes(atts); 329 documentHandler.startElement(qName, qAtts); 330 } 331 332 333 /** 334 * Adapt a SAX2 end element event. 335 * 336 * @param uri The Namespace URI. 337 * @param localName The Namespace local name. 338 * @param qName The qualified (prefixed) name. 339 * @exception org.xml.sax.SAXException The client may raise a 340 * processing exception. 341 * @see org.xml.sax.ContentHandler#endElement 342 */ 343 public void endElement (String uri, String localName, 344 String qName) 345 throws SAXException 346 { 347 documentHandler.endElement(qName); 348 } 349 350 351 /** 352 * Adapt a SAX2 characters event. 353 * 354 * @param ch An array of characters. 355 * @param start The starting position in the array. 356 * @param length The number of characters to use. 357 * @exception org.xml.sax.SAXException The client may raise a 358 * processing exception. 359 * @see org.xml.sax.ContentHandler#characters 360 */ 361 public void characters (char ch[], int start, int length) 362 throws SAXException 363 { 364 documentHandler.characters(ch, start, length); 365 } 366 367 368 /** 369 * Adapt a SAX2 ignorable whitespace event. 370 * 371 * @param ch An array of characters. 372 * @param start The starting position in the array. 373 * @param length The number of characters to use. 374 * @exception org.xml.sax.SAXException The client may raise a 375 * processing exception. 376 * @see org.xml.sax.ContentHandler#ignorableWhitespace 377 */ 378 public void ignorableWhitespace (char ch[], int start, int length) 379 throws SAXException 380 { 381 documentHandler.ignorableWhitespace(ch, start, length); 382 } 383 384 385 /** 386 * Adapt a SAX2 processing instruction event. 387 * 388 * @param target The processing instruction target. 389 * @param data The remainder of the processing instruction 390 * @exception org.xml.sax.SAXException The client may raise a 391 * processing exception. 392 * @see org.xml.sax.ContentHandler#processingInstruction 393 */ 394 public void processingInstruction (String target, String data) 395 throws SAXException 396 { 397 documentHandler.processingInstruction(target, data); 398 } 399 400 401 /** 402 * Adapt a SAX2 skipped entity event. 403 * 404 * @param name The name of the skipped entity. 405 * @see org.xml.sax.ContentHandler#skippedEntity 406 */ 407 public void skippedEntity (String name) 408 throws SAXException 409 { 410 } 411 412 413 414 //////////////////////////////////////////////////////////////////// 415 // Internal state. 416 //////////////////////////////////////////////////////////////////// 417 418 XMLReader xmlReader; 419 DocumentHandler documentHandler; 420 AttributesAdapter qAtts; 421 422 423 424 //////////////////////////////////////////////////////////////////// 425 // Internal class. 426 //////////////////////////////////////////////////////////////////// 427 428 429 /** 430 * Internal class to wrap a SAX2 Attributes object for SAX1. 431 */ 432 final class AttributesAdapter implements AttributeList 433 { 434 AttributesAdapter () 435 { 436 } 437 438 439 /** 440 * Set the embedded Attributes object. 441 * 442 * @param The embedded SAX2 Attributes. 443 */ 444 void setAttributes (Attributes attributes) 445 { 446 this.attributes = attributes; 447 } 448 449 450 /** 451 * Return the number of attributes. 452 * 453 * @return The length of the attribute list. 454 * @see org.xml.sax.AttributeList#getLength 455 */ 456 public int getLength () 457 { 458 return attributes.getLength(); 459 } 460 461 462 /** 463 * Return the qualified (prefixed) name of an attribute by position. 464 * 465 * @return The qualified name. 466 * @see org.xml.sax.AttributeList#getName 467 */ 468 public String getName (int i) 469 { 470 return attributes.getQName(i); 471 } 472 473 474 /** 475 * Return the type of an attribute by position. 476 * 477 * @return The type. 478 * @see org.xml.sax.AttributeList#getType(int) 479 */ 480 public String getType (int i) 481 { 482 return attributes.getType(i); 483 } 484 485 486 /** 487 * Return the value of an attribute by position. 488 * 489 * @return The value. 490 * @see org.xml.sax.AttributeList#getValue(int) 491 */ 492 public String getValue (int i) 493 { 494 return attributes.getValue(i); 495 } 496 497 498 /** 499 * Return the type of an attribute by qualified (prefixed) name. 500 * 501 * @return The type. 502 * @see org.xml.sax.AttributeList#getType(java.lang.String) 503 */ 504 public String getType (String qName) 505 { 506 return attributes.getType(qName); 507 } 508 509 510 /** 511 * Return the value of an attribute by qualified (prefixed) name. 512 * 513 * @return The value. 514 * @see org.xml.sax.AttributeList#getValue(java.lang.String) 515 */ 516 public String getValue (String qName) 517 { 518 return attributes.getValue(qName); 519 } 520 521 private Attributes attributes; 522 } 523 524} 525 526// end of XMLReaderAdapter.java