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 }