1 /* 2 * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.org.apache.xalan.internal.xsltc.trax; 27 28 import java.io.IOException; 29 import org.xml.sax.Attributes; 30 import org.xml.sax.ContentHandler; 31 import org.xml.sax.DTDHandler; 32 import org.xml.sax.EntityResolver; 33 import org.xml.sax.ErrorHandler; 34 import org.xml.sax.InputSource; 35 import org.xml.sax.Locator; 36 import org.xml.sax.SAXException; 37 import org.xml.sax.SAXNotRecognizedException; 38 import org.xml.sax.SAXNotSupportedException; 39 import org.xml.sax.XMLReader; 40 import org.xml.sax.ext.LexicalHandler; 41 import org.xml.sax.ext.Locator2; 42 import org.xml.sax.helpers.AttributesImpl; 43 import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl; 44 45 46 47 import javax.xml.namespace.QName; 48 import javax.xml.stream.XMLStreamReader; 49 import javax.xml.stream.XMLStreamConstants; 50 import javax.xml.stream.XMLStreamException; 51 52 53 54 /** 55 * @author Padmaja Vedula 56 * @author Sunitha Reddy 57 */ 58 public class StAXStream2SAX implements XMLReader, Locator { 59 60 //private final static String EMPTYSTRING = ""; 61 //private static final String XMLNS_PREFIX = "xmlns"; 62 63 // StAX Stream source 64 private final XMLStreamReader staxStreamReader; 65 66 //private Node _dom = null; 67 private ContentHandler _sax = null; 68 private LexicalHandler _lex = null; 69 private SAXImpl _saxImpl = null; 70 71 public StAXStream2SAX(XMLStreamReader staxSrc) { 72 staxStreamReader = staxSrc; 73 } 74 75 public ContentHandler getContentHandler() { 76 return _sax; 77 } 78 79 public void setContentHandler(ContentHandler handler) throws 80 NullPointerException 81 { 82 _sax = handler; 83 if (handler instanceof LexicalHandler) { 84 _lex = (LexicalHandler) handler; 85 } 86 87 if (handler instanceof SAXImpl) { 88 _saxImpl = (SAXImpl)handler; 89 } 90 } 91 92 93 public void parse(InputSource unused) throws IOException, SAXException { 94 try { 95 bridge(); 96 } catch (XMLStreamException e) { 97 throw new SAXException(e); 98 } 99 } 100 101 102 //Main Work Starts Here. 103 public void parse() throws IOException, SAXException, XMLStreamException { 104 bridge(); 105 } 106 107 108 /** 109 * This class is only used internally so this method should never 110 * be called. 111 */ 112 public void parse(String sysId) throws IOException, SAXException { 113 throw new IOException("This method is not yet implemented."); 114 } 115 116 117 public void bridge() throws XMLStreamException { 118 119 try { 120 // remembers the nest level of elements to know when we are done. 121 int depth=0; 122 123 // skip over START_DOCUMENT 124 int event = staxStreamReader.getEventType(); 125 if (event == XMLStreamConstants.START_DOCUMENT) { 126 event = staxStreamReader.next(); 127 } 128 129 // If not a START_ELEMENT (e.g., a DTD), skip to next tag 130 if (event != XMLStreamConstants.START_ELEMENT) { 131 event = staxStreamReader.nextTag(); 132 // An error if a START_ELEMENT isn't found now 133 if (event != XMLStreamConstants.START_ELEMENT) { 134 throw new IllegalStateException("The current event is " + 135 "not START_ELEMENT\n but" + event); 136 } 137 } 138 139 handleStartDocument(); 140 141 do { 142 // These are all of the events listed in the javadoc for 143 // XMLEvent. 144 // The spec only really describes 11 of them. 145 switch (event) { 146 case XMLStreamConstants.START_ELEMENT : 147 depth++; 148 handleStartElement(); 149 break; 150 case XMLStreamConstants.END_ELEMENT : 151 handleEndElement(); 152 depth--; 153 break; 154 case XMLStreamConstants.CHARACTERS : 155 handleCharacters(); 156 break; 157 case XMLStreamConstants.ENTITY_REFERENCE : 158 handleEntityReference(); 159 break; 160 case XMLStreamConstants.PROCESSING_INSTRUCTION : 161 handlePI(); 162 break; 163 case XMLStreamConstants.COMMENT : 164 handleComment(); 165 break; 166 case XMLStreamConstants.DTD : 167 handleDTD(); 168 break; 169 case XMLStreamConstants.ATTRIBUTE : 170 handleAttribute(); 171 break; 172 case XMLStreamConstants.NAMESPACE : 173 handleNamespace(); 174 break; 175 case XMLStreamConstants.CDATA : 176 handleCDATA(); 177 break; 178 case XMLStreamConstants.ENTITY_DECLARATION : 179 handleEntityDecl(); 180 break; 181 case XMLStreamConstants.NOTATION_DECLARATION : 182 handleNotationDecl(); 183 break; 184 case XMLStreamConstants.SPACE : 185 handleSpace(); 186 break; 187 default : 188 throw new InternalError("processing event: " + event); 189 } 190 191 event=staxStreamReader.next(); 192 } while (depth!=0); 193 194 handleEndDocument(); 195 } catch (SAXException e) { 196 throw new XMLStreamException(e); 197 } 198 } 199 200 private void handleEndDocument() throws SAXException { 201 _sax.endDocument(); 202 } 203 204 private void handleStartDocument() throws SAXException { 205 _sax.setDocumentLocator(new Locator2() { 206 public int getColumnNumber() { 207 return staxStreamReader.getLocation().getColumnNumber(); 208 } 209 public int getLineNumber() { 210 return staxStreamReader.getLocation().getLineNumber(); 211 } 212 public String getPublicId() { 213 return staxStreamReader.getLocation().getPublicId(); 214 } 215 public String getSystemId() { 216 return staxStreamReader.getLocation().getSystemId(); 217 } 218 public String getXMLVersion() { 219 return staxStreamReader.getVersion(); 220 } 221 public String getEncoding() { 222 return staxStreamReader.getEncoding(); 223 } 224 }); 225 _sax.startDocument(); 226 } 227 228 private void handlePI() throws XMLStreamException { 229 try { 230 _sax.processingInstruction( 231 staxStreamReader.getPITarget(), 232 staxStreamReader.getPIData()); 233 } catch (SAXException e) { 234 throw new XMLStreamException(e); 235 } 236 } 237 238 private void handleCharacters() throws XMLStreamException { 239 240 // workaround for bugid 5046319 - switch over to commented section 241 // below when it is fixed. 242 int textLength = staxStreamReader.getTextLength(); 243 char[] chars = new char[textLength]; 244 245 staxStreamReader.getTextCharacters(0, chars, 0, textLength); 246 247 try { 248 _sax.characters(chars, 0, chars.length); 249 } catch (SAXException e) { 250 throw new XMLStreamException(e); 251 } 252 253 254 // int start = 0; 255 // int len; 256 // do { 257 // len = staxStreamReader.getTextCharacters(start, buf, 0, buf.length); 258 // start += len; 259 // try { 260 // _sax.characters(buf, 0, len); 261 // } catch (SAXException e) { 262 // throw new XMLStreamException(e); 263 // } 264 // } while (len == buf.length); 265 } 266 267 private void handleEndElement() throws XMLStreamException { 268 QName qName = staxStreamReader.getName(); 269 270 try { 271 //construct prefix:localName from qName 272 String qname = ""; 273 if (qName.getPrefix() != null && qName.getPrefix().trim().length() != 0){ 274 qname = qName.getPrefix() + ":"; 275 } 276 qname += qName.getLocalPart(); 277 278 // fire endElement 279 _sax.endElement( 280 qName.getNamespaceURI(), 281 qName.getLocalPart(), 282 qname); 283 284 // end namespace bindings 285 int nsCount = staxStreamReader.getNamespaceCount(); 286 for (int i = nsCount - 1; i >= 0; i--) { 287 String prefix = staxStreamReader.getNamespacePrefix(i); 288 if (prefix == null) { // true for default namespace 289 prefix = ""; 290 } 291 _sax.endPrefixMapping(prefix); 292 } 293 } catch (SAXException e) { 294 throw new XMLStreamException(e); 295 } 296 } 297 298 private void handleStartElement() throws XMLStreamException { 299 300 try { 301 // start namespace bindings 302 int nsCount = staxStreamReader.getNamespaceCount(); 303 for (int i = 0; i < nsCount; i++) { 304 String prefix = staxStreamReader.getNamespacePrefix(i); 305 if (prefix == null) { // true for default namespace 306 prefix = ""; 307 } 308 String uri = staxStreamReader.getNamespaceURI(i); 309 if (uri == null && prefix.isEmpty()) { // true for default namespace 310 uri = ""; 311 } 312 313 _sax.startPrefixMapping(prefix, uri); 314 } 315 316 // fire startElement 317 QName qName = staxStreamReader.getName(); 318 String prefix = qName.getPrefix(); 319 String rawname; 320 if(prefix==null || prefix.length()==0) 321 rawname = qName.getLocalPart(); 322 else 323 rawname = prefix + ':' + qName.getLocalPart(); 324 Attributes attrs = getAttributes(); 325 _sax.startElement( 326 qName.getNamespaceURI(), 327 qName.getLocalPart(), 328 rawname, 329 attrs); 330 } catch (SAXException e) { 331 throw new XMLStreamException(e); 332 } 333 } 334 335 /** 336 * Get the attributes associated with the given START_ELEMENT or ATTRIBUTE 337 * StAXevent. 338 * 339 * @return the StAX attributes converted to an org.xml.sax.Attributes 340 */ 341 private Attributes getAttributes() { 342 AttributesImpl attrs = new AttributesImpl(); 343 344 int eventType = staxStreamReader.getEventType(); 345 if (eventType != XMLStreamConstants.ATTRIBUTE 346 && eventType != XMLStreamConstants.START_ELEMENT) { 347 throw new InternalError( 348 "getAttributes() attempting to process: " + eventType); 349 } 350 351 // in SAX, namespace declarations are not part of attributes by default. 352 // (there's a property to control that, but as far as we are concerned 353 // we don't use it.) So don't add xmlns:* to attributes. 354 355 // gather non-namespace attrs 356 for (int i = 0; i < staxStreamReader.getAttributeCount(); i++) { 357 String uri = staxStreamReader.getAttributeNamespace(i); 358 if(uri==null) uri=""; 359 String localName = staxStreamReader.getAttributeLocalName(i); 360 String prefix = staxStreamReader.getAttributePrefix(i); 361 String qName; 362 if(prefix==null || prefix.length()==0) 363 qName = localName; 364 else 365 qName = prefix + ':' + localName; 366 String type = staxStreamReader.getAttributeType(i); 367 String value = staxStreamReader.getAttributeValue(i); 368 369 attrs.addAttribute(uri, localName, qName, type, value); 370 } 371 372 return attrs; 373 } 374 375 private void handleNamespace() { 376 // no-op ??? 377 // namespace events don't normally occur outside of a startElement 378 // or endElement 379 } 380 381 private void handleAttribute() { 382 // no-op ??? 383 // attribute events don't normally occur outside of a startElement 384 // or endElement 385 } 386 387 private void handleDTD() { 388 // no-op ??? 389 // it seems like we need to pass this info along, but how? 390 } 391 392 private void handleComment() { 393 // no-op ??? 394 } 395 396 private void handleEntityReference() { 397 // no-op ??? 398 } 399 400 private void handleSpace() { 401 // no-op ??? 402 // this event is listed in the javadoc, but not in the spec. 403 } 404 405 private void handleNotationDecl() { 406 // no-op ??? 407 // this event is listed in the javadoc, but not in the spec. 408 } 409 410 private void handleEntityDecl() { 411 // no-op ??? 412 // this event is listed in the javadoc, but not in the spec. 413 } 414 415 private void handleCDATA() { 416 // no-op ??? 417 // this event is listed in the javadoc, but not in the spec. 418 } 419 420 421 /** 422 * This class is only used internally so this method should never 423 * be called. 424 */ 425 public DTDHandler getDTDHandler() { 426 return null; 427 } 428 429 /** 430 * This class is only used internally so this method should never 431 * be called. 432 */ 433 public ErrorHandler getErrorHandler() { 434 return null; 435 } 436 437 /** 438 * This class is only used internally so this method should never 439 * be called. 440 */ 441 public boolean getFeature(String name) throws SAXNotRecognizedException, 442 SAXNotSupportedException 443 { 444 return false; 445 } 446 447 /** 448 * This class is only used internally so this method should never 449 * be called. 450 */ 451 public void setFeature(String name, boolean value) throws 452 SAXNotRecognizedException, SAXNotSupportedException 453 { 454 } 455 456 /** 457 * This class is only used internally so this method should never 458 * be called. 459 */ 460 public void setDTDHandler(DTDHandler handler) throws NullPointerException { 461 } 462 463 /** 464 * This class is only used internally so this method should never 465 * be called. 466 */ 467 public void setEntityResolver(EntityResolver resolver) throws 468 NullPointerException 469 { 470 } 471 472 /** 473 * This class is only used internally so this method should never 474 * be called. 475 */ 476 public EntityResolver getEntityResolver() { 477 return null; 478 } 479 480 /** 481 * This class is only used internally so this method should never 482 * be called. 483 */ 484 public void setErrorHandler(ErrorHandler handler) throws 485 NullPointerException 486 { 487 } 488 489 /** 490 * This class is only used internally so this method should never 491 * be called. 492 */ 493 public void setProperty(String name, Object value) throws 494 SAXNotRecognizedException, SAXNotSupportedException { 495 } 496 497 /** 498 * This class is only used internally so this method should never 499 * be called. 500 */ 501 public Object getProperty(String name) throws SAXNotRecognizedException, 502 SAXNotSupportedException 503 { 504 return null; 505 } 506 507 /** 508 * This class is only used internally so this method should never 509 * be called. 510 */ 511 public int getColumnNumber() { 512 return 0; 513 } 514 515 /** 516 * This class is only used internally so this method should never 517 * be called. 518 */ 519 public int getLineNumber() { 520 return 0; 521 } 522 523 /** 524 * This class is only used internally so this method should never 525 * be called. 526 */ 527 public String getPublicId() { 528 return null; 529 } 530 531 /** 532 * This class is only used internally so this method should never 533 * be called. 534 */ 535 public String getSystemId() { 536 return null; 537 } 538 539 }