001: /* $Id: XMLStreamReaderToContentHandler.java,v 1.6 2006/01/23 18:50:02 sandoz Exp $
002: *
003: * Copyright (c) 2004, Sun Microsystems, Inc.
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * * Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * * Redistributions in binary form must reproduce the above
014: * copyright notice, this list of conditions and the following
015: * disclaimer in the documentation and/or other materials provided
016: * with the distribution.
017: *
018: * * Neither the name of Sun Microsystems, Inc. nor the names of its
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
023: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
024: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
025: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
026: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
027: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
028: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
029: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
030: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
031: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
032: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
033: */
034: package javanet.staxutils;
035:
036: import javanet.staxutils.helpers.XMLFilterImplEx;
037: import javax.xml.namespace.QName;
038: import javax.xml.stream.XMLStreamConstants;
039: import javax.xml.stream.XMLStreamException;
040: import javax.xml.stream.XMLStreamReader;
041: import javax.xml.stream.Location;
042:
043: import org.xml.sax.Attributes;
044: import org.xml.sax.ContentHandler;
045: import org.xml.sax.Locator;
046: import org.xml.sax.SAXException;
047: import org.xml.sax.ext.LexicalHandler;
048: import org.xml.sax.helpers.AttributesImpl;
049:
050: /**
051: * This is a simple utility class that adapts StAX events from an
052: * {@link javax.xml.stream.XMLStreamReader} to SAX events on a
053: * {@link org.xml.sax.ContentHandler}, bridging between the two
054: * parser technologies.
055: *
056: * @author Ryan.Shoemaker@Sun.COM
057: * @version 1.0
058: */
059: public class XMLStreamReaderToContentHandler implements
060: StAXReaderToContentHandler {
061:
062: // StAX event source
063: private final XMLStreamReader staxStreamReader;
064:
065: // SAX event sinks
066: private XMLFilterImplEx filter;
067:
068: /**
069: * Construct a new StAX to SAX adapter that will convert a StAX event
070: * stream into a SAX event stream.
071: *
072: * @param staxCore
073: * StAX event source
074: * @param filter
075: * SAX event sink
076: */
077: public XMLStreamReaderToContentHandler(XMLStreamReader staxCore,
078: XMLFilterImplEx filter) {
079: staxStreamReader = staxCore;
080:
081: this .filter = filter;
082: }
083:
084: /*
085: * @see StAXReaderToContentHandler#bridge()
086: */
087: public void bridge() throws XMLStreamException {
088:
089: try {
090: // remembers the nest level of elements to know when we are done.
091: int depth = 0;
092: boolean isDocument = false;
093:
094: handleStartDocument();
095:
096: // if the parser is at the start document, procees any comments or PIs
097: int event = staxStreamReader.getEventType();
098: if (event == XMLStreamConstants.START_DOCUMENT) {
099: isDocument = true;
100: event = staxStreamReader.next();
101: while (event != XMLStreamConstants.START_ELEMENT) {
102: switch (event) {
103: case XMLStreamConstants.COMMENT:
104: handleComment();
105: break;
106: case XMLStreamConstants.PROCESSING_INSTRUCTION:
107: handlePI();
108: break;
109: }
110: event = staxStreamReader.next();
111: }
112: ;
113: }
114:
115: if (event != XMLStreamConstants.START_ELEMENT)
116: throw new IllegalStateException(
117: "The current event is not START_ELEMENT\n but"
118: + event);
119:
120: do {
121: // These are all of the events listed in the javadoc for
122: // XMLEvent.
123: // The spec only really describes 11 of them.
124: switch (event) {
125: case XMLStreamConstants.START_ELEMENT:
126: depth++;
127: handleStartElement();
128: break;
129: case XMLStreamConstants.END_ELEMENT:
130: handleEndElement();
131: depth--;
132: break;
133: case XMLStreamConstants.CHARACTERS:
134: handleCharacters();
135: break;
136: case XMLStreamConstants.ENTITY_REFERENCE:
137: handleEntityReference();
138: break;
139: case XMLStreamConstants.PROCESSING_INSTRUCTION:
140: handlePI();
141: break;
142: case XMLStreamConstants.COMMENT:
143: handleComment();
144: break;
145: case XMLStreamConstants.DTD:
146: handleDTD();
147: break;
148: case XMLStreamConstants.ATTRIBUTE:
149: handleAttribute();
150: break;
151: case XMLStreamConstants.NAMESPACE:
152: handleNamespace();
153: break;
154: case XMLStreamConstants.CDATA:
155: handleCDATA();
156: break;
157: case XMLStreamConstants.ENTITY_DECLARATION:
158: handleEntityDecl();
159: break;
160: case XMLStreamConstants.NOTATION_DECLARATION:
161: handleNotationDecl();
162: break;
163: case XMLStreamConstants.SPACE:
164: handleSpace();
165: break;
166: default:
167: throw new InternalError("processing event: "
168: + event);
169: }
170:
171: event = staxStreamReader.next();
172: } while (depth != 0);
173:
174: // procees any remaining comments or PIs
175: if (isDocument) {
176: while (event != XMLStreamConstants.END_DOCUMENT) {
177: switch (event) {
178: case XMLStreamConstants.COMMENT:
179: handleComment();
180: break;
181: case XMLStreamConstants.PROCESSING_INSTRUCTION:
182: handlePI();
183: break;
184: }
185: event = staxStreamReader.next();
186: }
187: }
188:
189: handleEndDocument();
190: } catch (SAXException e) {
191: throw new XMLStreamException(e);
192: }
193: }
194:
195: private void handleEndDocument() throws SAXException {
196: filter.endDocument();
197: }
198:
199: private void handleStartDocument() throws SAXException {
200: final Location location = staxStreamReader.getLocation();
201: if (location != null) {
202: filter.setDocumentLocator(new Locator() {
203: public int getColumnNumber() {
204: return location.getColumnNumber();
205: }
206:
207: public int getLineNumber() {
208: return location.getLineNumber();
209: }
210:
211: public String getPublicId() {
212: return location.getPublicId();
213: }
214:
215: public String getSystemId() {
216: return location.getSystemId();
217: }
218: });
219: } else {
220: filter.setDocumentLocator(new DummyLocator());
221: }
222: filter.startDocument();
223: }
224:
225: private void handlePI() throws XMLStreamException {
226: try {
227: filter.processingInstruction(
228: staxStreamReader.getPITarget(), staxStreamReader
229: .getPIData());
230: } catch (SAXException e) {
231: throw new XMLStreamException(e);
232: }
233: }
234:
235: private void handleCharacters() throws XMLStreamException {
236:
237: // workaround for bugid 5046319 - switch over to commented section
238: // below when it is fixed.
239: int textLength = staxStreamReader.getTextLength();
240: int textStart = staxStreamReader.getTextStart();
241: char[] chars = new char[textLength];
242:
243: staxStreamReader.getTextCharacters(textStart, chars, 0,
244: textLength);
245:
246: try {
247: filter.characters(chars, 0, chars.length);
248: } catch (SAXException e) {
249: throw new XMLStreamException(e);
250: }
251:
252: // int start = 0;
253: // int len;
254: // do {
255: // len = staxStreamReader.getTextCharacters(start, buf, 0, buf.length);
256: // start += len;
257: // try {
258: // filter.characters(buf, 0, len);
259: // } catch (SAXException e) {
260: // throw new XMLStreamException(e);
261: // }
262: // } while (len == buf.length);
263: }
264:
265: private void handleEndElement() throws XMLStreamException {
266: QName qName = staxStreamReader.getName();
267:
268: try {
269: // fire endElement
270: String prefix = qName.getPrefix();
271: String rawname;
272: if (prefix == null || prefix.length() == 0)
273: rawname = qName.getLocalPart();
274: else
275: rawname = prefix + ':' + qName.getLocalPart();
276:
277: filter.endElement(qName.getNamespaceURI(), qName
278: .getLocalPart(), rawname);
279:
280: // end namespace bindings
281: int nsCount = staxStreamReader.getNamespaceCount();
282: for (int i = nsCount - 1; i >= 0; i--) {
283: String nsprefix = staxStreamReader
284: .getNamespacePrefix(i);
285: if (nsprefix == null) { // true for default namespace
286: nsprefix = "";
287: }
288: filter.endPrefixMapping(nsprefix);
289: }
290: } catch (SAXException e) {
291: throw new XMLStreamException(e);
292: }
293: }
294:
295: private void handleStartElement() throws XMLStreamException {
296:
297: try {
298: // start namespace bindings
299: int nsCount = staxStreamReader.getNamespaceCount();
300: for (int i = 0; i < nsCount; i++) {
301: String uri = staxStreamReader.getNamespaceURI(i);
302: if (uri == null) {
303: uri = "";
304: }
305: String prefix = staxStreamReader.getNamespacePrefix(i);
306: if (prefix == null) { // true for default namespace
307: prefix = "";
308: }
309: filter.startPrefixMapping(prefix, uri);
310: }
311:
312: // fire startElement
313: QName qName = staxStreamReader.getName();
314: String prefix = qName.getPrefix();
315: String rawname;
316: if (prefix == null || prefix.length() == 0)
317: rawname = qName.getLocalPart();
318: else
319: rawname = prefix + ':' + qName.getLocalPart();
320: Attributes attrs = getAttributes();
321: filter.startElement(qName.getNamespaceURI(), qName
322: .getLocalPart(), rawname, attrs);
323: } catch (SAXException e) {
324: throw new XMLStreamException(e);
325: }
326: }
327:
328: /**
329: * Get the attributes associated with the given START_ELEMENT or ATTRIBUTE
330: * StAXevent.
331: *
332: * @return the StAX attributes converted to an org.xml.sax.Attributes
333: */
334: private Attributes getAttributes() {
335: AttributesImpl attrs = new AttributesImpl();
336:
337: int eventType = staxStreamReader.getEventType();
338: if (eventType != XMLStreamConstants.ATTRIBUTE
339: && eventType != XMLStreamConstants.START_ELEMENT) {
340: throw new InternalError(
341: "getAttributes() attempting to process: "
342: + eventType);
343: }
344:
345: // Add namspace declarations if required
346: if (filter.getNamespacePrefixes()) {
347: for (int i = 0; i < staxStreamReader.getNamespaceCount(); i++) {
348: String uri = staxStreamReader.getNamespaceURI(i);
349: if (uri == null)
350: uri = "";
351:
352: String prefix = staxStreamReader.getNamespacePrefix(i);
353: if (prefix == null)
354: prefix = "";
355:
356: String qName = "xmlns";
357: if (prefix.length() == 0) {
358: prefix = qName;
359: } else {
360: qName = qName + ':' + prefix;
361: }
362: attrs.addAttribute("http://www.w3.org/2000/xmlns/",
363: prefix, qName, "CDATA", uri);
364: }
365: }
366:
367: // gather non-namespace attrs
368: for (int i = 0; i < staxStreamReader.getAttributeCount(); i++) {
369: String uri = staxStreamReader.getAttributeNamespace(i);
370: if (uri == null)
371: uri = "";
372: String localName = staxStreamReader
373: .getAttributeLocalName(i);
374: String prefix = staxStreamReader.getAttributePrefix(i);
375: String qName;
376: if (prefix == null || prefix.length() == 0)
377: qName = localName;
378: else
379: qName = prefix + ':' + localName;
380: String type = staxStreamReader.getAttributeType(i);
381: String value = staxStreamReader.getAttributeValue(i);
382:
383: attrs.addAttribute(uri, localName, qName, type, value);
384: }
385:
386: return attrs;
387: }
388:
389: private void handleNamespace() {
390: // no-op ???
391: // namespace events don't normally occur outside of a startElement
392: // or endElement
393: }
394:
395: private void handleAttribute() {
396: // no-op ???
397: // attribute events don't normally occur outside of a startElement
398: // or endElement
399: }
400:
401: private void handleDTD() {
402: // no-op ???
403: // it seems like we need to pass this info along, but how?
404: }
405:
406: private void handleComment() throws XMLStreamException {
407: int textLength = staxStreamReader.getTextLength();
408: int textStart = staxStreamReader.getTextStart();
409: char[] chars = new char[textLength];
410:
411: staxStreamReader.getTextCharacters(textStart, chars, 0,
412: textLength);
413:
414: try {
415: filter.comment(chars, 0, textLength);
416: } catch (SAXException e) {
417: throw new XMLStreamException(e);
418: }
419: }
420:
421: private void handleEntityReference() {
422: // no-op ???
423: }
424:
425: private void handleSpace() {
426: // no-op ???
427: // this event is listed in the javadoc, but not in the spec.
428: }
429:
430: private void handleNotationDecl() {
431: // no-op ???
432: // this event is listed in the javadoc, but not in the spec.
433: }
434:
435: private void handleEntityDecl() {
436: // no-op ???
437: // this event is listed in the javadoc, but not in the spec.
438: }
439:
440: private void handleCDATA() {
441: // no-op ???
442: // this event is listed in the javadoc, but not in the spec.
443: }
444: }
|