001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.util.xml;
038:
039: import org.xml.sax.Attributes;
040: import org.xml.sax.Locator;
041: import org.xml.sax.SAXException;
042: import org.xml.sax.helpers.DefaultHandler;
043:
044: import javax.xml.stream.XMLStreamException;
045: import javax.xml.stream.XMLStreamWriter;
046: import java.util.Stack;
047:
048: /**
049: * This is a simple utility class that adapts SAX events into StAX
050: * {@link XMLStreamWriter} events, bridging between
051: * the two parser technologies.
052: *
053: * This ContentHandler does not own the XMLStreamWriter. Therefore, it will
054: * not close or flush the writer at any point.
055: *
056: * @author Ryan.Shoemaker@Sun.COM
057: * @version 1.0
058: */
059: public class ContentHandlerToXMLStreamWriter extends DefaultHandler {
060:
061: // SAX events will be sent to this XMLStreamWriter
062: private final XMLStreamWriter staxWriter;
063:
064: // storage for prefix bindings
065: private final Stack prefixBindings;
066:
067: public ContentHandlerToXMLStreamWriter(XMLStreamWriter staxCore) {
068: this .staxWriter = staxCore;
069: prefixBindings = new Stack(); // default of 10 seems reasonable
070: }
071:
072: /*
073: * (non-Javadoc)
074: *
075: * @see org.xml.sax.ContentHandler#endDocument()
076: */
077: public void endDocument() throws SAXException {
078: try {
079: staxWriter.writeEndDocument();
080: staxWriter.flush();
081: } catch (XMLStreamException e) {
082: throw new SAXException(e);
083: }
084: }
085:
086: /*
087: * (non-Javadoc)
088: *
089: * @see org.xml.sax.ContentHandler#startDocument()
090: */
091: public void startDocument() throws SAXException {
092: try {
093: staxWriter.writeStartDocument();
094: } catch (XMLStreamException e) {
095: throw new SAXException(e);
096: }
097: }
098:
099: /*
100: * (non-Javadoc)
101: *
102: * @see org.xml.sax.ContentHandler#characters(char[], int, int)
103: */
104: public void characters(char[] ch, int start, int length)
105: throws SAXException {
106:
107: try {
108: staxWriter.writeCharacters(ch, start, length);
109: } catch (XMLStreamException e) {
110: throw new SAXException(e);
111: }
112:
113: }
114:
115: /*
116: * (non-Javadoc)
117: *
118: * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
119: */
120: public void ignorableWhitespace(char[] ch, int start, int length)
121: throws SAXException {
122:
123: characters(ch, start, length);
124: }
125:
126: /*
127: * (non-Javadoc)
128: *
129: * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
130: */
131: public void endPrefixMapping(String prefix) throws SAXException {
132: // TODO: no-op?
133:
134: // I think we can ignore these SAX events because StAX
135: // automatically scopes the prefix bindings.
136: }
137:
138: /*
139: * (non-Javadoc)
140: *
141: * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
142: */
143: public void skippedEntity(String name) throws SAXException {
144: try {
145: staxWriter.writeEntityRef(name);
146: } catch (XMLStreamException e) {
147: throw new SAXException(e);
148: }
149: }
150:
151: /*
152: * (non-Javadoc)
153: *
154: * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
155: */
156: public void setDocumentLocator(Locator locator) {
157: // TODO: no-op?
158: // there doesn't seem to be any way to pass location info
159: // along to the XMLStreamWriter. On the XMLEventWriter side, you
160: // can set the location info on the event objects.
161: }
162:
163: /*
164: * (non-Javadoc)
165: *
166: * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String,
167: * java.lang.String)
168: */
169: public void processingInstruction(String target, String data)
170: throws SAXException {
171:
172: try {
173: staxWriter.writeProcessingInstruction(target, data);
174: } catch (XMLStreamException e) {
175: throw new SAXException(e);
176: }
177:
178: }
179:
180: /*
181: * (non-Javadoc)
182: *
183: * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String,
184: * java.lang.String)
185: */
186: public void startPrefixMapping(String prefix, String uri)
187: throws SAXException {
188:
189: // defend against parsers that pass null in for "xmlns" prefix
190: if (prefix == null) {
191: prefix = "";
192: }
193:
194: if (prefix.equals("xml")) {
195: return;
196: }
197:
198: prefixBindings.add(prefix);
199: prefixBindings.add(uri);
200: }
201:
202: /*
203: * (non-Javadoc)
204: *
205: * @see org.xml.sax.ContentHandler#endElement(java.lang.String,
206: * java.lang.String, java.lang.String)
207: */
208: public void endElement(String namespaceURI, String localName,
209: String qName) throws SAXException {
210:
211: try {
212: // TODO: is this all we have to do?
213: staxWriter.writeEndElement();
214: } catch (XMLStreamException e) {
215: throw new SAXException(e);
216: }
217: }
218:
219: /*
220: * (non-Javadoc)
221: *
222: * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
223: * java.lang.String, java.lang.String, org.xml.sax.Attributes)
224: */
225: public void startElement(String namespaceURI, String localName,
226: String qName, Attributes atts) throws SAXException {
227:
228: try {
229: staxWriter.writeStartElement(getPrefix(qName), localName,
230: namespaceURI);
231:
232: String uri, prefix;
233: while (prefixBindings.size() != 0) {
234: uri = (String) prefixBindings.pop();
235: prefix = (String) prefixBindings.pop();
236: if (prefix.length() == 0) {
237: staxWriter.setDefaultNamespace(uri);
238: } else {
239: staxWriter.setPrefix(prefix, uri);
240: }
241:
242: // this method handles "", null, and "xmlns" prefixes properly
243: staxWriter.writeNamespace(prefix, uri);
244: }
245:
246: writeAttributes(atts);
247: } catch (XMLStreamException e) {
248: throw new SAXException(e);
249: }
250:
251: }
252:
253: /**
254: * Generate a StAX writeAttribute event for each attribute
255: *
256: * @param atts
257: * attributes from the SAX event
258: */
259: private void writeAttributes(Attributes atts)
260: throws XMLStreamException {
261: for (int i = 0; i < atts.getLength(); i++) {
262: final String prefix = getPrefix(atts.getQName(i));
263: if (!prefix.equals("xmlns")) { // defend againts broken transformers that report xmlns decls as attrs
264: staxWriter.writeAttribute(prefix, atts.getURI(i), atts
265: .getLocalName(i), atts.getValue(i));
266: }
267: }
268: }
269:
270: /**
271: * Pull the prefix off of the specified QName.
272: *
273: * @param qName
274: * the QName
275: * @return the prefix or the empty string if it doesn't exist.
276: */
277: private String getPrefix(String qName) {
278: int idx = qName.indexOf(':');
279: if (idx == -1) {
280: return "";
281: } else {
282: return qName.substring(0, idx);
283: }
284: }
285:
286: }
|