001 // XMLReaderAdapter.java - adapt an SAX2 XMLReader to a SAX1 Parser
002 // http://www.saxproject.org
003 // Written by David Megginson
004 // NO WARRANTY! This class is in the public domain.
005 // $Id: XMLReaderAdapter.java,v 1.2 2006/12/10 20:25:41 gnu_andrew Exp $
006
007 package org.xml.sax.helpers;
008
009 import java.io.IOException;
010 import java.util.Locale;
011
012 import org.xml.sax.Parser; // deprecated
013 import org.xml.sax.Locator;
014 import org.xml.sax.InputSource;
015 import org.xml.sax.AttributeList; // deprecated
016 import org.xml.sax.EntityResolver;
017 import org.xml.sax.DTDHandler;
018 import org.xml.sax.DocumentHandler; // deprecated
019 import org.xml.sax.ErrorHandler;
020 import org.xml.sax.SAXException;
021
022 import org.xml.sax.XMLReader;
023 import org.xml.sax.Attributes;
024 import org.xml.sax.ContentHandler;
025 import 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 * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
035 * for further information.
036 * </blockquote>
037 *
038 * <p>This class wraps a SAX2 {@link org.xml.sax.XMLReader XMLReader}
039 * and makes it act as a SAX1 {@link org.xml.sax.Parser Parser}. The XMLReader
040 * must support a true value for the
041 * http://xml.org/sax/features/namespace-prefixes property or parsing will fail
042 * with a {@link org.xml.sax.SAXException SAXException}; if the XMLReader
043 * supports a false value for the http://xml.org/sax/features/namespaces
044 * property, that will also be used to improve efficiency.</p>
045 *
046 * @since SAX 2.0
047 * @author David Megginson
048 * @version 2.0.1 (sax2r2)
049 * @see org.xml.sax.Parser
050 * @see org.xml.sax.XMLReader
051 */
052 public class XMLReaderAdapter implements Parser, ContentHandler
053 {
054
055
056 ////////////////////////////////////////////////////////////////////
057 // Constructor.
058 ////////////////////////////////////////////////////////////////////
059
060
061 /**
062 * Create a new adapter.
063 *
064 * <p>Use the "org.xml.sax.driver" property to locate the SAX2
065 * driver to embed.</p>
066 *
067 * @exception org.xml.sax.SAXException If the embedded driver
068 * cannot be instantiated or if the
069 * org.xml.sax.driver property is not specified.
070 */
071 public XMLReaderAdapter ()
072 throws SAXException
073 {
074 setup(XMLReaderFactory.createXMLReader());
075 }
076
077
078 /**
079 * Create a new adapter.
080 *
081 * <p>Create a new adapter, wrapped around a SAX2 XMLReader.
082 * The adapter will make the XMLReader act like a SAX1
083 * Parser.</p>
084 *
085 * @param xmlReader The SAX2 XMLReader to wrap.
086 * @exception java.lang.NullPointerException If the argument is null.
087 */
088 public XMLReaderAdapter (XMLReader xmlReader)
089 {
090 setup(xmlReader);
091 }
092
093
094
095 /**
096 * Internal setup.
097 *
098 * @param xmlReader The embedded XMLReader.
099 */
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