1 /* 2 * Copyright (c) 2005, 2019, 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 boolean startedAtDocument = false; 123 124 // skip over START_DOCUMENT 125 int event = staxStreamReader.getEventType(); 126 if (event == XMLStreamConstants.START_DOCUMENT) { 127 startedAtDocument = true; 128 event = staxStreamReader.next(); 129 } 130 131 handleStartDocument(); 132 133 // Handle the prolog: http://www.w3.org/TR/REC-xml/#NT-prolog 134 while (event != XMLStreamConstants.START_ELEMENT) { 135 switch (event) { 136 case XMLStreamConstants.CHARACTERS : 137 handleCharacters(); 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.SPACE : 149 handleSpace(); 150 break; 151 default : 152 throw new InternalError("processing prolog event: " + event); 153 } 154 event=staxStreamReader.next(); 155 } 156 157 do { 158 // These are all of the events listed in the javadoc for 159 // XMLEvent. 160 // The spec only really describes 11 of them. 161 switch (event) { 162 case XMLStreamConstants.START_ELEMENT : 163 depth++; 164 handleStartElement(); 165 break; 166 case XMLStreamConstants.END_ELEMENT : 167 handleEndElement(); 168 depth--; 169 break; 170 case XMLStreamConstants.CHARACTERS : 171 handleCharacters(); 172 break; 173 case XMLStreamConstants.ENTITY_REFERENCE : 174 handleEntityReference(); 175 break; 176 case XMLStreamConstants.PROCESSING_INSTRUCTION : 177 handlePI(); 178 break; 179 case XMLStreamConstants.COMMENT : 180 handleComment(); 181 break; 182 case XMLStreamConstants.DTD : 183 handleDTD(); 184 break; 185 case XMLStreamConstants.ATTRIBUTE : 186 handleAttribute(); 187 break; 188 case XMLStreamConstants.NAMESPACE : 189 handleNamespace(); 190 break; 191 case XMLStreamConstants.CDATA : 192 handleCDATA(); 193 break; 194 case XMLStreamConstants.ENTITY_DECLARATION : 195 handleEntityDecl(); 196 break; 197 case XMLStreamConstants.NOTATION_DECLARATION : 198 handleNotationDecl(); 199 break; 200 case XMLStreamConstants.SPACE : 201 handleSpace(); 202 break; 203 default : 204 throw new InternalError("processing event: " + event); 205 } 206 207 event=staxStreamReader.next(); 208 } while (depth!=0); 209 210 if (startedAtDocument) { 211 // Handle the Misc (http://www.w3.org/TR/REC-xml/#NT-Misc) that can follow the document element 212 while (event != XMLStreamConstants.END_DOCUMENT) { 213 switch (event) { 214 case XMLStreamConstants.CHARACTERS : 215 handleCharacters(); 216 break; 217 case XMLStreamConstants.PROCESSING_INSTRUCTION : 218 handlePI(); 219 break; 220 case XMLStreamConstants.COMMENT : 221 handleComment(); 222 break; 223 case XMLStreamConstants.SPACE : 224 handleSpace(); 225 break; 226 default : 227 throw new InternalError("processing misc event after document element: " + event); 228 } 229 event=staxStreamReader.next(); 230 } 231 } 232 233 handleEndDocument(); 234 } catch (SAXException e) { 235 throw new XMLStreamException(e); 236 } 237 } 238 239 private void handleEndDocument() throws SAXException { 240 _sax.endDocument(); 241 } 242 243 private void handleStartDocument() throws SAXException { 244 _sax.setDocumentLocator(new Locator2() { 245 public int getColumnNumber() { 246 return staxStreamReader.getLocation().getColumnNumber(); 247 } 248 public int getLineNumber() { 249 return staxStreamReader.getLocation().getLineNumber(); 250 } 251 public String getPublicId() { 252 return staxStreamReader.getLocation().getPublicId(); 253 } 254 public String getSystemId() { 255 return staxStreamReader.getLocation().getSystemId(); 256 } 257 public String getXMLVersion() { 258 return staxStreamReader.getVersion(); 259 } 260 public String getEncoding() { 261 return staxStreamReader.getEncoding(); 262 } 263 }); 264 _sax.startDocument(); 265 } 266 267 private void handlePI() throws XMLStreamException { 268 try { 269 _sax.processingInstruction( 270 staxStreamReader.getPITarget(), 271 staxStreamReader.getPIData()); 272 } catch (SAXException e) { 273 throw new XMLStreamException(e); 274 } 275 } 276 277 private void handleCharacters() throws XMLStreamException { 278 279 // workaround for bugid 5046319 - switch over to commented section 280 // below when it is fixed. 281 int textLength = staxStreamReader.getTextLength(); 282 char[] chars = new char[textLength]; 283 284 staxStreamReader.getTextCharacters(0, chars, 0, textLength); 285 286 try { 287 _sax.characters(chars, 0, chars.length); 288 } catch (SAXException e) { 289 throw new XMLStreamException(e); 290 } 291 292 293 // int start = 0; 294 // int len; 295 // do { 296 // len = staxStreamReader.getTextCharacters(start, buf, 0, buf.length); 297 // start += len; 298 // try { 299 // _sax.characters(buf, 0, len); 300 // } catch (SAXException e) { 301 // throw new XMLStreamException(e); 302 // } 303 // } while (len == buf.length); 304 } 305 306 private void handleEndElement() throws XMLStreamException { 307 QName qName = staxStreamReader.getName(); 308 309 try { 310 //construct prefix:localName from qName 311 String qname = ""; 312 if (qName.getPrefix() != null && qName.getPrefix().trim().length() != 0){ 313 qname = qName.getPrefix() + ":"; 314 } 315 qname += qName.getLocalPart(); 316 317 // fire endElement 318 _sax.endElement( 319 qName.getNamespaceURI(), 320 qName.getLocalPart(), 321 qname); 322 323 // end namespace bindings 324 int nsCount = staxStreamReader.getNamespaceCount(); 325 for (int i = nsCount - 1; i >= 0; i--) { 326 String prefix = staxStreamReader.getNamespacePrefix(i); 327 if (prefix == null) { // true for default namespace 328 prefix = ""; 329 } 330 _sax.endPrefixMapping(prefix); 331 } 332 } catch (SAXException e) { 333 throw new XMLStreamException(e); 334 } 335 } 336 337 private void handleStartElement() throws XMLStreamException { 338 339 try { 340 // start namespace bindings 341 int nsCount = staxStreamReader.getNamespaceCount(); 342 for (int i = 0; i < nsCount; i++) { 343 String prefix = staxStreamReader.getNamespacePrefix(i); 344 if (prefix == null) { // true for default namespace 345 prefix = ""; 346 } 347 String uri = staxStreamReader.getNamespaceURI(i); 348 if (uri == null && prefix.isEmpty()) { // true for default namespace 349 uri = ""; 350 } 351 352 _sax.startPrefixMapping(prefix, uri); 353 } 354 355 // fire startElement 356 QName qName = staxStreamReader.getName(); 357 String prefix = qName.getPrefix(); 358 String rawname; 359 if(prefix==null || prefix.length()==0) 360 rawname = qName.getLocalPart(); 361 else 362 rawname = prefix + ':' + qName.getLocalPart(); 363 Attributes attrs = getAttributes(); 364 _sax.startElement( 365 qName.getNamespaceURI(), 366 qName.getLocalPart(), 367 rawname, 368 attrs); 369 } catch (SAXException e) { 370 throw new XMLStreamException(e); 371 } 372 } 373 374 /** 375 * Get the attributes associated with the given START_ELEMENT or ATTRIBUTE 376 * StAXevent. 377 * 378 * @return the StAX attributes converted to an org.xml.sax.Attributes 379 */ 380 private Attributes getAttributes() { 381 AttributesImpl attrs = new AttributesImpl(); 382 383 int eventType = staxStreamReader.getEventType(); 384 if (eventType != XMLStreamConstants.ATTRIBUTE 385 && eventType != XMLStreamConstants.START_ELEMENT) { 386 throw new InternalError( 387 "getAttributes() attempting to process: " + eventType); 388 } 389 390 // in SAX, namespace declarations are not part of attributes by default. 391 // (there's a property to control that, but as far as we are concerned 392 // we don't use it.) So don't add xmlns:* to attributes. 393 394 // gather non-namespace attrs 395 for (int i = 0; i < staxStreamReader.getAttributeCount(); i++) { 396 String uri = staxStreamReader.getAttributeNamespace(i); 397 if(uri==null) uri=""; 398 String localName = staxStreamReader.getAttributeLocalName(i); 399 String prefix = staxStreamReader.getAttributePrefix(i); 400 String qName; 401 if(prefix==null || prefix.length()==0) 402 qName = localName; 403 else 404 qName = prefix + ':' + localName; 405 String type = staxStreamReader.getAttributeType(i); 406 String value = staxStreamReader.getAttributeValue(i); 407 408 attrs.addAttribute(uri, localName, qName, type, value); 409 } 410 411 return attrs; 412 } 413 414 private void handleNamespace() { 415 // no-op ??? 416 // namespace events don't normally occur outside of a startElement 417 // or endElement 418 } 419 420 private void handleAttribute() { 421 // no-op ??? 422 // attribute events don't normally occur outside of a startElement 423 // or endElement 424 } 425 426 private void handleDTD() { 427 // no-op ??? 428 // it seems like we need to pass this info along, but how? 429 } 430 431 private void handleComment() { 432 // no-op ??? 433 } 434 435 private void handleEntityReference() { 436 // no-op ??? 437 } 438 439 private void handleSpace() { 440 // no-op ??? 441 // this event is listed in the javadoc, but not in the spec. 442 } 443 444 private void handleNotationDecl() { 445 // no-op ??? 446 // this event is listed in the javadoc, but not in the spec. 447 } 448 449 private void handleEntityDecl() { 450 // no-op ??? 451 // this event is listed in the javadoc, but not in the spec. 452 } 453 454 private void handleCDATA() { 455 // no-op ??? 456 // this event is listed in the javadoc, but not in the spec. 457 } 458 459 460 /** 461 * This class is only used internally so this method should never 462 * be called. 463 */ 464 public DTDHandler getDTDHandler() { 465 return null; 466 } 467 468 /** 469 * This class is only used internally so this method should never 470 * be called. 471 */ 472 public ErrorHandler getErrorHandler() { 473 return null; 474 } 475 476 /** 477 * This class is only used internally so this method should never 478 * be called. 479 */ 480 public boolean getFeature(String name) throws SAXNotRecognizedException, 481 SAXNotSupportedException 482 { 483 return false; 484 } 485 486 /** 487 * This class is only used internally so this method should never 488 * be called. 489 */ 490 public void setFeature(String name, boolean value) throws 491 SAXNotRecognizedException, SAXNotSupportedException 492 { 493 } 494 495 /** 496 * This class is only used internally so this method should never 497 * be called. 498 */ 499 public void setDTDHandler(DTDHandler handler) throws NullPointerException { 500 } 501 502 /** 503 * This class is only used internally so this method should never 504 * be called. 505 */ 506 public void setEntityResolver(EntityResolver resolver) throws 507 NullPointerException 508 { 509 } 510 511 /** 512 * This class is only used internally so this method should never 513 * be called. 514 */ 515 public EntityResolver getEntityResolver() { 516 return null; 517 } 518 519 /** 520 * This class is only used internally so this method should never 521 * be called. 522 */ 523 public void setErrorHandler(ErrorHandler handler) throws 524 NullPointerException 525 { 526 } 527 528 /** 529 * This class is only used internally so this method should never 530 * be called. 531 */ 532 public void setProperty(String name, Object value) throws 533 SAXNotRecognizedException, SAXNotSupportedException { 534 } 535 536 /** 537 * This class is only used internally so this method should never 538 * be called. 539 */ 540 public Object getProperty(String name) throws SAXNotRecognizedException, 541 SAXNotSupportedException 542 { 543 return null; 544 } 545 546 /** 547 * This class is only used internally so this method should never 548 * be called. 549 */ 550 public int getColumnNumber() { 551 return 0; 552 } 553 554 /** 555 * This class is only used internally so this method should never 556 * be called. 557 */ 558 public int getLineNumber() { 559 return 0; 560 } 561 562 /** 563 * This class is only used internally so this method should never 564 * be called. 565 */ 566 public String getPublicId() { 567 return null; 568 } 569 570 /** 571 * This class is only used internally so this method should never 572 * be called. 573 */ 574 public String getSystemId() { 575 return null; 576 } 577 578 }