View Javadoc

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.5 2004/03/19 20:17:55 maartenc Exp $
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 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