View Javadoc

1   /* $Id: XMLStreamReaderToContentHandler.java,v 1.6 2006/01/23 18:50:02 sandoz Exp $
2    *
3    * Copyright (c) 2004, Sun Microsystems, Inc.
4    * All rights reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions are
8    * met:
9    *
10   *     * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *
13   *     * Redistributions in binary form must reproduce the above
14   *      copyright notice, this list of conditions and the following
15   *       disclaimer in the documentation and/or other materials provided
16   *       with the distribution.
17   *
18   *     * Neither the name of Sun Microsystems, Inc. nor the names of its
19   *       contributors may be used to endorse or promote products derived
20   *       from this software without specific prior written permission.
21   *
22   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   */
34  
35  package org.mule.module.xml.stax;
36  
37  import javanet.staxutils.DummyLocator;
38  import javanet.staxutils.StAXReaderToContentHandler;
39  import javanet.staxutils.helpers.XMLFilterImplEx;
40  
41  import javax.xml.namespace.QName;
42  import javax.xml.stream.Location;
43  import javax.xml.stream.XMLStreamConstants;
44  import javax.xml.stream.XMLStreamException;
45  import javax.xml.stream.XMLStreamReader;
46  
47  import org.xml.sax.Attributes;
48  import org.xml.sax.Locator;
49  import org.xml.sax.SAXException;
50  import org.xml.sax.helpers.AttributesImpl;
51  
52  /**
53   * This is a simple utility class that adapts StAX events from an
54   * {@link javax.xml.stream.XMLStreamReader} to SAX events on a
55   * {@link org.xml.sax.ContentHandler}, bridging between the two parser technologies.
56   * 
57   * @author Ryan.Shoemaker@Sun.COM
58   * @version 1.0
59   */
60  public class XMLStreamReaderToContentHandler implements StAXReaderToContentHandler
61  {
62  
63      // StAX event source
64      private final XMLStreamReader staxStreamReader;
65  
66      // SAX event sinks
67      private XMLFilterImplEx filter;
68  
69      /**
70       * Construct a new StAX to SAX adapter that will convert a StAX event stream into
71       * a SAX event stream.
72       * 
73       * @param staxCore StAX event source
74       * @param filter SAX event sink
75       */
76      public XMLStreamReaderToContentHandler(XMLStreamReader staxCore, XMLFilterImplEx filter)
77      {
78          staxStreamReader = staxCore;
79  
80          this.filter = filter;
81      }
82  
83      /*
84       * @see StAXReaderToContentHandler#bridge()
85       */
86      public void bridge() throws XMLStreamException
87      {
88  
89          try
90          {
91              // remembers the nest level of elements to know when we are done.
92              int depth = 0;
93              boolean isDocument = false;
94  
95              handleStartDocument();
96  
97              // if the parser is at the start document, procees any comments or PIs
98              int event = staxStreamReader.getEventType();
99              if (event == XMLStreamConstants.START_DOCUMENT)
100             {
101                 isDocument = true;
102                 event = staxStreamReader.next();
103                 while (event != XMLStreamConstants.START_ELEMENT)
104                 {
105                     switch (event)
106                     {
107                         case XMLStreamConstants.COMMENT :
108                             handleComment();
109                             break;
110                         case XMLStreamConstants.PROCESSING_INSTRUCTION :
111                             handlePI();
112                             break;
113                     }
114                     event = staxStreamReader.next();
115                 };
116             }
117 
118             if (event != XMLStreamConstants.START_ELEMENT)
119                 throw new IllegalStateException("The current event is not START_ELEMENT\n but" + event);
120 
121             do
122             {
123                 // These are all of the events listed in the javadoc for
124                 // XMLEvent.
125                 // The spec only really describes 11 of them.
126                 switch (event)
127                 {
128                     case XMLStreamConstants.START_ELEMENT :
129                         depth++;
130                         handleStartElement();
131                         break;
132                     case XMLStreamConstants.END_ELEMENT :
133                         handleEndElement();
134                         depth--;
135                         break;
136                     case XMLStreamConstants.CHARACTERS :
137                         handleCharacters();
138                         break;
139                     case XMLStreamConstants.ENTITY_REFERENCE :
140                         handleEntityReference();
141                         break;
142                     case XMLStreamConstants.PROCESSING_INSTRUCTION :
143                         handlePI();
144                         break;
145                     case XMLStreamConstants.COMMENT :
146                         handleComment();
147                         break;
148                     case XMLStreamConstants.DTD :
149                         handleDTD();
150                         break;
151                     case XMLStreamConstants.ATTRIBUTE :
152                         handleAttribute();
153                         break;
154                     case XMLStreamConstants.NAMESPACE :
155                         handleNamespace();
156                         break;
157                     case XMLStreamConstants.CDATA :
158                         handleCDATA();
159                         break;
160                     case XMLStreamConstants.ENTITY_DECLARATION :
161                         handleEntityDecl();
162                         break;
163                     case XMLStreamConstants.NOTATION_DECLARATION :
164                         handleNotationDecl();
165                         break;
166                     case XMLStreamConstants.SPACE :
167                         handleSpace();
168                         break;
169                     default :
170                         throw new InternalError("processing event: " + event);
171                 }
172 
173                 event = staxStreamReader.next();
174             }
175             while (depth != 0);
176 
177             // procees any remaining comments or PIs
178             if (isDocument)
179             {
180                 while (event != XMLStreamConstants.END_DOCUMENT)
181                 {
182                     switch (event)
183                     {
184                         case XMLStreamConstants.COMMENT :
185                             handleComment();
186                             break;
187                         case XMLStreamConstants.PROCESSING_INSTRUCTION :
188                             handlePI();
189                             break;
190                     }
191                     event = staxStreamReader.next();
192                 }
193             }
194 
195             handleEndDocument();
196         }
197         catch (SAXException e)
198         {
199             throw new XMLStreamException(e);
200         }
201     }
202 
203     protected void handleEndDocument() throws SAXException
204     {
205         filter.endDocument();
206     }
207 
208     protected void handleStartDocument() throws SAXException
209     {
210         final Location location = staxStreamReader.getLocation();
211         if (location != null)
212         {
213             filter.setDocumentLocator(new Locator()
214             {
215                 public int getColumnNumber()
216                 {
217                     return location.getColumnNumber();
218                 }
219 
220                 public int getLineNumber()
221                 {
222                     return location.getLineNumber();
223                 }
224 
225                 public String getPublicId()
226                 {
227                     return location.getPublicId();
228                 }
229 
230                 public String getSystemId()
231                 {
232                     return location.getSystemId();
233                 }
234             });
235         }
236         else
237         {
238             filter.setDocumentLocator(new DummyLocator());
239         }
240         filter.startDocument();
241     }
242 
243     protected void handlePI() throws XMLStreamException
244     {
245         try
246         {
247             filter.processingInstruction(staxStreamReader.getPITarget(), staxStreamReader.getPIData());
248         }
249         catch (SAXException e)
250         {
251             throw new XMLStreamException(e);
252         }
253     }
254 
255     protected void handleCharacters() throws XMLStreamException
256     {
257         char[] chars = staxStreamReader.getText().toCharArray();
258 
259         try
260         {
261             filter.characters(chars, 0, chars.length);
262         }
263         catch (SAXException e)
264         {
265             throw new XMLStreamException(e);
266         }
267     }
268 
269     protected void handleEndElement() throws XMLStreamException
270     {
271         QName qName = staxStreamReader.getName();
272 
273         try
274         {
275             // fire endElement
276             String prefix = qName.getPrefix();
277             String rawname;
278             if (prefix == null || prefix.length() == 0)
279                 rawname = qName.getLocalPart();
280             else
281                 rawname = prefix + ':' + qName.getLocalPart();
282 
283             filter.endElement(qName.getNamespaceURI(), qName.getLocalPart(), rawname);
284 
285             // end namespace bindings
286             int nsCount = staxStreamReader.getNamespaceCount();
287             for (int i = nsCount - 1; i >= 0; i--)
288             {
289                 String nsprefix = staxStreamReader.getNamespacePrefix(i);
290                 if (nsprefix == null)
291                 { // true for default namespace
292                     nsprefix = "";
293                 }
294                 filter.endPrefixMapping(nsprefix);
295             }
296         }
297         catch (SAXException e)
298         {
299             throw new XMLStreamException(e);
300         }
301     }
302 
303     protected void handleStartElement() throws XMLStreamException
304     {
305 
306         try
307         {
308             // start namespace bindings
309             int nsCount = staxStreamReader.getNamespaceCount();
310             for (int i = 0; i < nsCount; i++)
311             {
312                 String uri = staxStreamReader.getNamespaceURI(i);
313                 if (uri == null)
314                 {
315                     uri = "";
316                 }
317                 String prefix = staxStreamReader.getNamespacePrefix(i);
318                 if (prefix == null)
319                 { // true for default namespace
320                     prefix = "";
321                 }
322                 filter.startPrefixMapping(prefix, uri);
323             }
324 
325             // fire startElement
326             QName qName = staxStreamReader.getName();
327             String prefix = qName.getPrefix();
328             String rawname;
329             if (prefix == null || prefix.length() == 0)
330                 rawname = qName.getLocalPart();
331             else
332                 rawname = prefix + ':' + qName.getLocalPart();
333             Attributes attrs = getAttributes();
334             filter.startElement(qName.getNamespaceURI(), qName.getLocalPart(), rawname, attrs);
335         }
336         catch (SAXException e)
337         {
338             throw new XMLStreamException(e);
339         }
340     }
341 
342     /**
343      * Get the attributes associated with the given START_ELEMENT or ATTRIBUTE
344      * StAXevent.
345      * 
346      * @return the StAX attributes converted to an org.xml.sax.Attributes
347      */
348     protected Attributes getAttributes()
349     {
350         AttributesImpl attrs = new AttributesImpl();
351 
352         int eventType = staxStreamReader.getEventType();
353         if (eventType != XMLStreamConstants.ATTRIBUTE && eventType != XMLStreamConstants.START_ELEMENT)
354         {
355             throw new InternalError("getAttributes() attempting to process: " + eventType);
356         }
357 
358         // Add namspace declarations if required
359         if (filter.getNamespacePrefixes())
360         {
361             for (int i = 0; i < staxStreamReader.getNamespaceCount(); i++)
362             {
363                 String uri = staxStreamReader.getNamespaceURI(i);
364                 if (uri == null) uri = "";
365 
366                 String prefix = staxStreamReader.getNamespacePrefix(i);
367                 if (prefix == null) prefix = "";
368 
369                 String qName = "xmlns";
370                 if (prefix.length() == 0)
371                 {
372                     prefix = qName;
373                 }
374                 else
375                 {
376                     qName = qName + ':' + prefix;
377                 }
378                 attrs.addAttribute("http://www.w3.org/2000/xmlns/", prefix, qName, "CDATA", uri);
379             }
380         }
381 
382         // gather non-namespace attrs
383         for (int i = 0; i < staxStreamReader.getAttributeCount(); i++)
384         {
385             String uri = staxStreamReader.getAttributeNamespace(i);
386             if (uri == null) uri = "";
387             String localName = staxStreamReader.getAttributeLocalName(i);
388             String prefix = staxStreamReader.getAttributePrefix(i);
389             String qName;
390             if (prefix == null || prefix.length() == 0)
391                 qName = localName;
392             else
393                 qName = prefix + ':' + localName;
394             String type = staxStreamReader.getAttributeType(i);
395             String value = staxStreamReader.getAttributeValue(i);
396 
397             attrs.addAttribute(uri, localName, qName, type, value);
398         }
399 
400         return attrs;
401     }
402 
403     protected void handleNamespace()
404     {
405         // no-op ???
406         // namespace events don't normally occur outside of a startElement
407         // or endElement
408     }
409 
410     protected void handleAttribute()
411     {
412         // no-op ???
413         // attribute events don't normally occur outside of a startElement
414         // or endElement
415     }
416 
417     protected void handleDTD()
418     {
419         // no-op ???
420         // it seems like we need to pass this info along, but how?
421     }
422 
423     protected void handleComment() throws XMLStreamException
424     {
425         int textLength = staxStreamReader.getTextLength();
426         int textStart = staxStreamReader.getTextStart();
427         char[] chars = new char[textLength];
428 
429         staxStreamReader.getTextCharacters(textStart, chars, 0, textLength);
430 
431         try
432         {
433             filter.comment(chars, 0, textLength);
434         }
435         catch (SAXException e)
436         {
437             throw new XMLStreamException(e);
438         }
439     }
440 
441     protected void handleEntityReference()
442     {
443         // no-op ???
444     }
445 
446     protected void handleSpace()
447     {
448         // no-op ???
449         // this event is listed in the javadoc, but not in the spec.
450     }
451 
452     protected void handleNotationDecl()
453     {
454         // no-op ???
455         // this event is listed in the javadoc, but not in the spec.
456     }
457 
458     protected void handleEntityDecl()
459     {
460         // no-op ???
461         // this event is listed in the javadoc, but not in the spec.
462     }
463 
464     protected void handleCDATA()
465     {
466         // no-op ???
467         // this event is listed in the javadoc, but not in the spec.
468     }
469 }