View Javadoc

1   /* $Id: ContentHandlerToXMLStreamWriter.java,v 1.1 2004/11/03 01:18:59 dandiep 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  package org.codehaus.xfire.xmlbeans.util;
35  
36  import org.xml.sax.Attributes;
37  import org.xml.sax.Locator;
38  import org.xml.sax.SAXException;
39  import org.xml.sax.helpers.DefaultHandler;
40  
41  import javax.xml.stream.XMLStreamException;
42  import javax.xml.stream.XMLStreamWriter;
43  import java.util.Stack;
44  
45  /***
46  * This is a simple utility class that adapts SAX events into StAX
47  * {@link javax.xml.stream.XMLStreamWriter} events, bridging between
48  * the two parser technologies.
49  *
50  * This ContentHandler does not own the XMLStreamWriter.  Therefore, it will
51  * not close or flush the writer at any point.
52  * 
53  * @author Ryan.Shoemaker@Sun.COM
54  * @version 1.0
55  */
56  public class ContentHandlerToXMLStreamWriter extends DefaultHandler {
57  
58     // SAX events will be sent to this XMLStreamWriter
59     private final XMLStreamWriter staxWriter;
60  
61     // storage for prefix bindings
62     private final Stack prefixBindings;
63  
64     private boolean writeStart;
65     
66     public ContentHandlerToXMLStreamWriter(XMLStreamWriter staxCore, boolean writeStart) {
67         this.staxWriter = staxCore;
68         prefixBindings = new Stack(); // default of 10 seems reasonable
69         this.writeStart = writeStart;
70     }
71  
72     /*
73      * (non-Javadoc)
74      * 
75      * @see org.xml.sax.ContentHandler#endDocument()
76      */
77     public void endDocument() throws SAXException {
78         try {
79  
80             staxWriter.flush();
81         } catch (XMLStreamException e) {
82             throw new SAXException(e);
83         }
84     }
85  
86     /*
87      * (non-Javadoc)
88      * 
89      * @see org.xml.sax.ContentHandler#startDocument()
90      */
91     public void startDocument() throws SAXException {
92  
93     }
94  
95     /*
96      * (non-Javadoc)
97      * 
98      * @see org.xml.sax.ContentHandler#characters(char[], int, int)
99      */
100    public void characters(char[] ch, int start, int length)
101        throws SAXException {
102 
103        try {
104            staxWriter.writeCharacters(ch, start, length);
105        } catch (XMLStreamException e) {
106            throw new SAXException(e);
107        }
108 
109    }
110 
111    /*
112     * (non-Javadoc)
113     * 
114     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
115     */
116    public void ignorableWhitespace(char[] ch, int start, int length)
117        throws SAXException {
118        
119        characters(ch,start,length);
120    }
121 
122    /*
123     * (non-Javadoc)
124     * 
125     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
126     */
127    public void endPrefixMapping(String prefix) throws SAXException 
128    {
129        // TODO: no-op?
130 
131        // I think we can ignore these SAX events because StAX
132        // automatically scopes the prefix bindings.
133    }
134 
135    /*
136     * (non-Javadoc)
137     * 
138     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
139     */
140    public void skippedEntity(String name) throws SAXException {
141        try {
142            staxWriter.writeEntityRef(name);
143        } catch (XMLStreamException e) {
144            throw new SAXException(e);
145        }
146    }
147 
148    /*
149     * (non-Javadoc)
150     * 
151     * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
152     */
153    public void setDocumentLocator(Locator locator) {
154        // TODO: no-op?
155        // there doesn't seem to be any way to pass location info
156        // along to the XMLStreamWriter. On the XMLEventWriter side, you
157        // can set the location info on the event objects.
158    }
159 
160    /*
161     * (non-Javadoc)
162     * 
163     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String,
164     *      java.lang.String)
165     */
166    public void processingInstruction(String target, String data)
167        throws SAXException {
168 
169        try {
170            staxWriter.writeProcessingInstruction(target, data);
171        } catch (XMLStreamException e) {
172            throw new SAXException(e);
173        }
174 
175    }
176 
177    /*
178     * (non-Javadoc)
179     * 
180     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String,
181     *      java.lang.String)
182     */
183    public void startPrefixMapping(String prefix, String uri)
184        throws SAXException {
185 
186        if (prefix.equals("xml")) {
187            return;
188        }
189 
190        // defend against parsers that pass null in for "xmlns" prefix
191        if (prefix == null) {
192            prefix = "";
193        }
194 
195        prefixBindings.add(prefix);
196        prefixBindings.add(uri);
197    }
198 
199    /*
200     * (non-Javadoc)
201     * 
202     * @see org.xml.sax.ContentHandler#endElement(java.lang.String,
203     *      java.lang.String, java.lang.String)
204     */
205    public void endElement(String namespaceURI, String localName, String qName)
206        throws SAXException {
207 
208        try {
209            // TODO: is this all we have to do?
210            staxWriter.writeEndElement();
211        } catch (XMLStreamException e) {
212            throw new SAXException(e);
213        }
214    }
215 
216     public void startElement(String uri, String localName,
217             String qName, Attributes atts) throws SAXException
218     {
219         //System.out.println(qName + " " + uri);
220         try
221         {
222             String prefix = getPrefix(qName);
223             //System.out.println(prefix);
224             
225             if ( uri != null )
226             {
227                 if ( prefix.equals("") )
228                 {
229                     String defNS = staxWriter.getNamespaceContext().getNamespaceURI("");
230                     if ( !defNS.equals(uri) )
231                     {
232                         staxWriter.setDefaultNamespace(uri);
233                         staxWriter.writeStartElement( uri, localName );
234                         staxWriter.writeDefaultNamespace( uri );
235                     }
236                     else
237                     {
238                         staxWriter.writeStartElement( uri, localName );
239                     }  
240                 }
241                 else
242                 {
243                     staxWriter.setPrefix( prefix, uri );
244                     
245                     staxWriter.writeStartElement( 
246                         prefix,
247                         localName,
248                         uri);
249                 }
250             }
251             else
252             {
253                 staxWriter.writeStartElement( localName );
254             }
255             
256             String nsuri, nsprefix;
257             while (prefixBindings.size() != 0)
258             {
259                 nsuri = (String) prefixBindings.pop();
260                 nsprefix = (String) prefixBindings.pop();
261                 if (nsprefix.length() != 0)
262                 {
263                     //System.out.println("writing " + nsprefix + " : " + nsuri);
264                     // this method handles "", null, and "xmlns" prefixes
265                     // properly
266                     staxWriter.writeNamespace(nsprefix, nsuri);
267                 }
268             }
269             staxWriter.flush();
270             //writeAttributes(atts);
271         }
272         catch (XMLStreamException e)
273         {
274             throw new RuntimeException(e);
275         }
276 
277     }
278 
279     /***
280      * Generate a StAX writeAttribute event for each attribute
281      * 
282      * @param atts
283      *            attributes from the SAX event
284      */
285     private void writeAttributes(Attributes atts) throws XMLStreamException
286     {
287         for (int i = 0; i < atts.getLength(); i++)
288         {
289             System.out.println("writing attribute " + atts.getQName(i));
290             staxWriter.writeAttribute(getPrefix(atts.getQName(i)), atts
291                     .getURI(i), atts.getLocalName(i), atts.getValue(i));
292         }
293     }
294 
295     /***
296      * Pull the prefix off of the specified QName.
297      * 
298      * @param qName
299      *            the QName
300      * @return the prefix or the empty string if it doesn't exist.
301      */
302     private String getPrefix(String qName)
303     {
304         int idx = qName.indexOf(':');
305         if (idx == -1)
306         {
307             return "";
308         }
309         else
310         {
311             return qName.substring(0, idx);
312         }
313     }
314 
315 }