View Javadoc

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