/*
 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.xml.internal.bind.v2.runtime.unmarshaller;

import java.util.Iterator;

import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

This is a simple utility class that adapts StAX events from an XMLEventReader to unmarshaller events on a XmlVisitor, bridging between the two parser technologies.
Author:Ryan.Shoemaker@Sun.COM
Version:1.0
/** * This is a simple utility class that adapts StAX events from an * {@link XMLEventReader} to unmarshaller events on a * {@link XmlVisitor}, bridging between the two * parser technologies. * * @author Ryan.Shoemaker@Sun.COM * @version 1.0 */
final class StAXEventConnector extends StAXConnector { // StAX event source private final XMLEventReader staxEventReader;
Current event.
/** Current event. */
private XMLEvent event;
Shared and reused Attributes.
/** * Shared and reused {@link Attributes}. */
private final AttributesImpl attrs = new AttributesImpl();
SAX may fire consective characters event, but we don't allow it. so use this buffer to perform buffering.
/** * SAX may fire consective characters event, but we don't allow it. * so use this buffer to perform buffering. */
private final StringBuilder buffer = new StringBuilder(); private boolean seenText;
Construct a new StAX to SAX adapter that will convert a StAX event stream into a SAX event stream.
Params:
  • staxCore – StAX event source
  • visitor – sink
/** * Construct a new StAX to SAX adapter that will convert a StAX event * stream into a SAX event stream. * * @param staxCore * StAX event source * @param visitor * sink */
public StAXEventConnector(XMLEventReader staxCore, XmlVisitor visitor) { super(visitor); staxEventReader = staxCore; } public void bridge() throws XMLStreamException { try { // remembers the nest level of elements to know when we are done. int depth=0; event = staxEventReader.peek(); if( !event.isStartDocument() && !event.isStartElement() ) throw new IllegalStateException(); // if the parser is on START_DOCUMENT, skip ahead to the first element do { event = staxEventReader.nextEvent(); } while( !event.isStartElement() ); handleStartDocument(event.asStartElement().getNamespaceContext()); OUTER: while(true) { // These are all of the events listed in the javadoc for // XMLEvent. // The spec only really describes 11 of them. switch (event.getEventType()) { case XMLStreamConstants.START_ELEMENT : handleStartElement(event.asStartElement()); depth++; break; case XMLStreamConstants.END_ELEMENT : depth--; handleEndElement(event.asEndElement()); if(depth==0) break OUTER; break; case XMLStreamConstants.CHARACTERS : case XMLStreamConstants.CDATA : case XMLStreamConstants.SPACE : handleCharacters(event.asCharacters()); break; } event=staxEventReader.nextEvent(); } handleEndDocument(); event = null; // avoid keeping a stale reference } catch (SAXException e) { throw new XMLStreamException(e); } } protected Location getCurrentLocation() { return event.getLocation(); } protected String getCurrentQName() { QName qName; if(event.isEndElement()) qName = event.asEndElement().getName(); else qName = event.asStartElement().getName(); return getQName(qName.getPrefix(), qName.getLocalPart()); } private void handleCharacters(Characters event) throws SAXException, XMLStreamException { if(!predictor.expectText()) return; // text isn't expected. simply skip seenText = true; // check the next event XMLEvent next; while(true) { next = staxEventReader.peek(); if(!isIgnorable(next)) break; staxEventReader.nextEvent(); } if(isTag(next)) { // this is by far the common case --- you have <foo>abc</foo> or <foo>abc<bar/>...</foo> visitor.text(event.getData()); return; } // otherwise we have things like "abc<!-- test -->def". // concatenate all text buffer.append(event.getData()); while(true) { while(true) { next = staxEventReader.peek(); if(!isIgnorable(next)) break; staxEventReader.nextEvent(); } if(isTag(next)) { // found all adjacent text visitor.text(buffer); buffer.setLength(0); return; } buffer.append(next.asCharacters().getData()); staxEventReader.nextEvent(); // consume } } private boolean isTag(XMLEvent event) { int eventType = event.getEventType(); return eventType==XMLEvent.START_ELEMENT || eventType==XMLEvent.END_ELEMENT; } private boolean isIgnorable(XMLEvent event) { int eventType = event.getEventType(); return eventType==XMLEvent.COMMENT || eventType==XMLEvent.PROCESSING_INSTRUCTION; } private void handleEndElement(EndElement event) throws SAXException { if(!seenText && predictor.expectText()) { visitor.text(""); } // fire endElement QName qName = event.getName(); tagName.uri = fixNull(qName.getNamespaceURI()); tagName.local = qName.getLocalPart(); visitor.endElement(tagName); // end namespace bindings for( Iterator<Namespace> i = event.getNamespaces(); i.hasNext();) { String prefix = fixNull(i.next().getPrefix()); // be defensive visitor.endPrefixMapping(prefix); } seenText = false; } private void handleStartElement(StartElement event) throws SAXException { // start namespace bindings for (Iterator i = event.getNamespaces(); i.hasNext();) { Namespace ns = (Namespace)i.next(); visitor.startPrefixMapping( fixNull(ns.getPrefix()), fixNull(ns.getNamespaceURI())); } // fire startElement QName qName = event.getName(); tagName.uri = fixNull(qName.getNamespaceURI()); String localName = qName.getLocalPart(); tagName.uri = fixNull(qName.getNamespaceURI()); tagName.local = localName; tagName.atts = getAttributes(event); visitor.startElement(tagName); seenText = false; }
Get the attributes associated with the given START_ELEMENT StAXevent.
Returns:the StAX attributes converted to an org.xml.sax.Attributes
/** * Get the attributes associated with the given START_ELEMENT StAXevent. * * @return the StAX attributes converted to an org.xml.sax.Attributes */
private Attributes getAttributes(StartElement event) { attrs.clear(); // in SAX, namespace declarations are not part of attributes by default. // (there's a property to control that, but as far as we are concerned // we don't use it.) So don't add xmlns:* to attributes. // gather non-namespace attrs for (Iterator i = event.getAttributes(); i.hasNext();) { Attribute staxAttr = (Attribute)i.next(); QName name = staxAttr.getName(); String uri = fixNull(name.getNamespaceURI()); String localName = name.getLocalPart(); String prefix = name.getPrefix(); String qName; if (prefix == null || prefix.length() == 0) qName = localName; else qName = prefix + ':' + localName; String type = staxAttr.getDTDType(); String value = staxAttr.getValue(); attrs.addAttribute(uri, localName, qName, type, value); } return attrs; } }