1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/istack/internal/XMLStreamReaderToContentHandler.java Tue Mar 06 16:09:35 2012 -0800 1.3 @@ -0,0 +1,388 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.istack.internal; 1.30 + 1.31 +import org.xml.sax.ContentHandler; 1.32 +import org.xml.sax.SAXException; 1.33 +import org.xml.sax.Locator; 1.34 +import org.xml.sax.Attributes; 1.35 +import org.xml.sax.helpers.AttributesImpl; 1.36 + 1.37 +import javax.xml.stream.XMLStreamReader; 1.38 +import javax.xml.stream.XMLStreamException; 1.39 +import javax.xml.stream.XMLStreamConstants; 1.40 +import javax.xml.namespace.QName; 1.41 + 1.42 +/** 1.43 + * This is a simple utility class that adapts StAX events from an 1.44 + * {@link XMLStreamReader} to SAX events on a 1.45 + * {@link ContentHandler}, bridging between the two 1.46 + * parser technologies. 1.47 + * 1.48 + * @author Ryan.Shoemaker@Sun.COM 1.49 + * @version 1.0 1.50 + */ 1.51 +public class XMLStreamReaderToContentHandler { 1.52 + 1.53 + // StAX event source 1.54 + private final XMLStreamReader staxStreamReader; 1.55 + 1.56 + // SAX event sink 1.57 + private final ContentHandler saxHandler; 1.58 + 1.59 + // if true, when the conversion is completed, leave the cursor to the last 1.60 + // event that was fired (such as end element) 1.61 + private final boolean eagerQuit; 1.62 + 1.63 + /** 1.64 + * If true, not start/endDocument event. 1.65 + */ 1.66 + private final boolean fragment; 1.67 + 1.68 + // array of the even length of the form { prefix0, uri0, prefix1, uri1, ... } 1.69 + private final String[] inscopeNamespaces; 1.70 + 1.71 + /** 1.72 + * @see #XMLStreamReaderToContentHandler(XMLStreamReader, ContentHandler, boolean, boolean, String[]) 1.73 + */ 1.74 + public XMLStreamReaderToContentHandler(XMLStreamReader staxCore, ContentHandler saxCore, boolean eagerQuit, boolean fragment) { 1.75 + this(staxCore, saxCore, eagerQuit, fragment, new String[0]); 1.76 + } 1.77 + 1.78 + /** 1.79 + * Construct a new StAX to SAX adapter that will convert a StAX event 1.80 + * stream into a SAX event stream. 1.81 + * 1.82 + * @param staxCore 1.83 + * StAX event source 1.84 + * @param saxCore 1.85 + * SAXevent sink 1.86 + * @param eagerQuit 1.87 + * @param fragment 1.88 + * @param inscopeNamespaces 1.89 + * array of the even length of the form { prefix0, uri0, prefix1, uri1, ... } 1.90 + */ 1.91 + public XMLStreamReaderToContentHandler(XMLStreamReader staxCore, ContentHandler saxCore, 1.92 + boolean eagerQuit, boolean fragment, String[] inscopeNamespaces) { 1.93 + this.staxStreamReader = staxCore; 1.94 + this.saxHandler = saxCore; 1.95 + this.eagerQuit = eagerQuit; 1.96 + this.fragment = fragment; 1.97 + this.inscopeNamespaces = inscopeNamespaces; 1.98 + assert inscopeNamespaces.length%2 == 0; 1.99 + } 1.100 + 1.101 + 1.102 + /* 1.103 + * @see StAXReaderToContentHandler#bridge() 1.104 + */ 1.105 + public void bridge() throws XMLStreamException { 1.106 + 1.107 + try { 1.108 + // remembers the nest level of elements to know when we are done. 1.109 + int depth=0; 1.110 + 1.111 + // if the parser is at the start tag, proceed to the first element 1.112 + int event = staxStreamReader.getEventType(); 1.113 + if(event == XMLStreamConstants.START_DOCUMENT) { 1.114 + // nextTag doesn't correctly handle DTDs 1.115 + while( !staxStreamReader.isStartElement() ) 1.116 + event = staxStreamReader.next(); 1.117 + } 1.118 + 1.119 + 1.120 + if( event!=XMLStreamConstants.START_ELEMENT) 1.121 + throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event); 1.122 + 1.123 + handleStartDocument(); 1.124 + 1.125 + for(int i=0; i < inscopeNamespaces.length; i+=2) { 1.126 + saxHandler.startPrefixMapping(inscopeNamespaces[i], inscopeNamespaces[i+1]); 1.127 + } 1.128 + 1.129 + OUTER: 1.130 + do { 1.131 + // These are all of the events listed in the javadoc for 1.132 + // XMLEvent. 1.133 + // The spec only really describes 11 of them. 1.134 + switch (event) { 1.135 + case XMLStreamConstants.START_ELEMENT : 1.136 + depth++; 1.137 + handleStartElement(); 1.138 + break; 1.139 + case XMLStreamConstants.END_ELEMENT : 1.140 + handleEndElement(); 1.141 + depth--; 1.142 + if(depth==0 && eagerQuit) 1.143 + break OUTER; 1.144 + break; 1.145 + case XMLStreamConstants.CHARACTERS : 1.146 + handleCharacters(); 1.147 + break; 1.148 + case XMLStreamConstants.ENTITY_REFERENCE : 1.149 + handleEntityReference(); 1.150 + break; 1.151 + case XMLStreamConstants.PROCESSING_INSTRUCTION : 1.152 + handlePI(); 1.153 + break; 1.154 + case XMLStreamConstants.COMMENT : 1.155 + handleComment(); 1.156 + break; 1.157 + case XMLStreamConstants.DTD : 1.158 + handleDTD(); 1.159 + break; 1.160 + case XMLStreamConstants.ATTRIBUTE : 1.161 + handleAttribute(); 1.162 + break; 1.163 + case XMLStreamConstants.NAMESPACE : 1.164 + handleNamespace(); 1.165 + break; 1.166 + case XMLStreamConstants.CDATA : 1.167 + handleCDATA(); 1.168 + break; 1.169 + case XMLStreamConstants.ENTITY_DECLARATION : 1.170 + handleEntityDecl(); 1.171 + break; 1.172 + case XMLStreamConstants.NOTATION_DECLARATION : 1.173 + handleNotationDecl(); 1.174 + break; 1.175 + case XMLStreamConstants.SPACE : 1.176 + handleSpace(); 1.177 + break; 1.178 + default : 1.179 + throw new InternalError("processing event: " + event); 1.180 + } 1.181 + 1.182 + event=staxStreamReader.next(); 1.183 + } while (depth!=0); 1.184 + 1.185 + for(int i=0; i < inscopeNamespaces.length; i+=2) { 1.186 + saxHandler.endPrefixMapping(inscopeNamespaces[i]); 1.187 + } 1.188 + 1.189 + handleEndDocument(); 1.190 + } catch (SAXException e) { 1.191 + throw new XMLStreamException2(e); 1.192 + } 1.193 + } 1.194 + 1.195 + private void handleEndDocument() throws SAXException { 1.196 + if(fragment) 1.197 + return; 1.198 + 1.199 + saxHandler.endDocument(); 1.200 + } 1.201 + 1.202 + private void handleStartDocument() throws SAXException { 1.203 + if(fragment) 1.204 + return; 1.205 + 1.206 + saxHandler.setDocumentLocator(new Locator() { 1.207 + public int getColumnNumber() { 1.208 + return staxStreamReader.getLocation().getColumnNumber(); 1.209 + } 1.210 + public int getLineNumber() { 1.211 + return staxStreamReader.getLocation().getLineNumber(); 1.212 + } 1.213 + public String getPublicId() { 1.214 + return staxStreamReader.getLocation().getPublicId(); 1.215 + } 1.216 + public String getSystemId() { 1.217 + return staxStreamReader.getLocation().getSystemId(); 1.218 + } 1.219 + }); 1.220 + saxHandler.startDocument(); 1.221 + } 1.222 + 1.223 + private void handlePI() throws XMLStreamException { 1.224 + try { 1.225 + saxHandler.processingInstruction( 1.226 + staxStreamReader.getPITarget(), 1.227 + staxStreamReader.getPIData()); 1.228 + } catch (SAXException e) { 1.229 + throw new XMLStreamException2(e); 1.230 + } 1.231 + } 1.232 + 1.233 + private void handleCharacters() throws XMLStreamException { 1.234 + try { 1.235 + saxHandler.characters( 1.236 + staxStreamReader.getTextCharacters(), 1.237 + staxStreamReader.getTextStart(), 1.238 + staxStreamReader.getTextLength() ); 1.239 + } catch (SAXException e) { 1.240 + throw new XMLStreamException2(e); 1.241 + } 1.242 + } 1.243 + 1.244 + private void handleEndElement() throws XMLStreamException { 1.245 + QName qName = staxStreamReader.getName(); 1.246 + 1.247 + try { 1.248 + String pfix = qName.getPrefix(); 1.249 + String rawname = (pfix == null || pfix.length() == 0) 1.250 + ? qName.getLocalPart() 1.251 + : pfix + ':' + qName.getLocalPart(); 1.252 + // fire endElement 1.253 + saxHandler.endElement( 1.254 + qName.getNamespaceURI(), 1.255 + qName.getLocalPart(), 1.256 + rawname); 1.257 + 1.258 + // end namespace bindings 1.259 + int nsCount = staxStreamReader.getNamespaceCount(); 1.260 + for (int i = nsCount - 1; i >= 0; i--) { 1.261 + String prefix = staxStreamReader.getNamespacePrefix(i); 1.262 + if (prefix == null) { // true for default namespace 1.263 + prefix = ""; 1.264 + } 1.265 + saxHandler.endPrefixMapping(prefix); 1.266 + } 1.267 + } catch (SAXException e) { 1.268 + throw new XMLStreamException2(e); 1.269 + } 1.270 + } 1.271 + 1.272 + private void handleStartElement() throws XMLStreamException { 1.273 + 1.274 + try { 1.275 + // start namespace bindings 1.276 + int nsCount = staxStreamReader.getNamespaceCount(); 1.277 + for (int i = 0; i < nsCount; i++) { 1.278 + saxHandler.startPrefixMapping( 1.279 + fixNull(staxStreamReader.getNamespacePrefix(i)), 1.280 + fixNull(staxStreamReader.getNamespaceURI(i))); 1.281 + } 1.282 + 1.283 + // fire startElement 1.284 + QName qName = staxStreamReader.getName(); 1.285 + String prefix = qName.getPrefix(); 1.286 + String rawname; 1.287 + if(prefix==null || prefix.length()==0) 1.288 + rawname = qName.getLocalPart(); 1.289 + else 1.290 + rawname = prefix + ':' + qName.getLocalPart(); 1.291 + Attributes attrs = getAttributes(); 1.292 + saxHandler.startElement( 1.293 + qName.getNamespaceURI(), 1.294 + qName.getLocalPart(), 1.295 + rawname, 1.296 + attrs); 1.297 + } catch (SAXException e) { 1.298 + throw new XMLStreamException2(e); 1.299 + } 1.300 + } 1.301 + 1.302 + private static String fixNull(String s) { 1.303 + if(s==null) return ""; 1.304 + else return s; 1.305 + } 1.306 + 1.307 + /** 1.308 + * Get the attributes associated with the given START_ELEMENT or ATTRIBUTE 1.309 + * StAXevent. 1.310 + * 1.311 + * @return the StAX attributes converted to an org.xml.sax.Attributes 1.312 + */ 1.313 + private Attributes getAttributes() { 1.314 + AttributesImpl attrs = new AttributesImpl(); 1.315 + 1.316 + int eventType = staxStreamReader.getEventType(); 1.317 + if (eventType != XMLStreamConstants.ATTRIBUTE 1.318 + && eventType != XMLStreamConstants.START_ELEMENT) { 1.319 + throw new InternalError( 1.320 + "getAttributes() attempting to process: " + eventType); 1.321 + } 1.322 + 1.323 + // in SAX, namespace declarations are not part of attributes by default. 1.324 + // (there's a property to control that, but as far as we are concerned 1.325 + // we don't use it.) So don't add xmlns:* to attributes. 1.326 + 1.327 + // gather non-namespace attrs 1.328 + for (int i = 0; i < staxStreamReader.getAttributeCount(); i++) { 1.329 + String uri = staxStreamReader.getAttributeNamespace(i); 1.330 + if(uri==null) uri=""; 1.331 + String localName = staxStreamReader.getAttributeLocalName(i); 1.332 + String prefix = staxStreamReader.getAttributePrefix(i); 1.333 + String qName; 1.334 + if(prefix==null || prefix.length()==0) 1.335 + qName = localName; 1.336 + else 1.337 + qName = prefix + ':' + localName; 1.338 + String type = staxStreamReader.getAttributeType(i); 1.339 + String value = staxStreamReader.getAttributeValue(i); 1.340 + 1.341 + attrs.addAttribute(uri, localName, qName, type, value); 1.342 + } 1.343 + 1.344 + return attrs; 1.345 + } 1.346 + 1.347 + private void handleNamespace() { 1.348 + // no-op ??? 1.349 + // namespace events don't normally occur outside of a startElement 1.350 + // or endElement 1.351 + } 1.352 + 1.353 + private void handleAttribute() { 1.354 + // no-op ??? 1.355 + // attribute events don't normally occur outside of a startElement 1.356 + // or endElement 1.357 + } 1.358 + 1.359 + private void handleDTD() { 1.360 + // no-op ??? 1.361 + // it seems like we need to pass this info along, but how? 1.362 + } 1.363 + 1.364 + private void handleComment() { 1.365 + // no-op ??? 1.366 + } 1.367 + 1.368 + private void handleEntityReference() { 1.369 + // no-op ??? 1.370 + } 1.371 + 1.372 + private void handleSpace() { 1.373 + // no-op ??? 1.374 + // this event is listed in the javadoc, but not in the spec. 1.375 + } 1.376 + 1.377 + private void handleNotationDecl() { 1.378 + // no-op ??? 1.379 + // this event is listed in the javadoc, but not in the spec. 1.380 + } 1.381 + 1.382 + private void handleEntityDecl() { 1.383 + // no-op ??? 1.384 + // this event is listed in the javadoc, but not in the spec. 1.385 + } 1.386 + 1.387 + private void handleCDATA() { 1.388 + // no-op ??? 1.389 + // this event is listed in the javadoc, but not in the spec. 1.390 + } 1.391 +}