1/* 2 * Copyright (c) 2005, 2015, 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 26package com.sun.org.apache.xalan.internal.xsltc.trax; 27 28import java.io.IOException; 29import java.util.Iterator; 30 31import org.xml.sax.Attributes; 32import org.xml.sax.ContentHandler; 33import org.xml.sax.DTDHandler; 34import org.xml.sax.EntityResolver; 35import org.xml.sax.ErrorHandler; 36import org.xml.sax.InputSource; 37import org.xml.sax.Locator; 38import org.xml.sax.SAXException; 39import org.xml.sax.SAXNotRecognizedException; 40import org.xml.sax.SAXNotSupportedException; 41import org.xml.sax.XMLReader; 42import org.xml.sax.ext.LexicalHandler; 43import org.xml.sax.helpers.AttributesImpl; 44import org.xml.sax.ext.Locator2; 45import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl; 46 47import javax.xml.namespace.QName; 48import javax.xml.stream.XMLEventReader; 49import javax.xml.stream.XMLStreamConstants; 50import javax.xml.stream.XMLStreamException; 51import javax.xml.stream.events.Attribute; 52import javax.xml.stream.events.Characters; 53import javax.xml.stream.events.EndElement; 54import javax.xml.stream.events.Namespace; 55import javax.xml.stream.events.ProcessingInstruction; 56import javax.xml.stream.events.StartElement; 57import javax.xml.stream.events.XMLEvent; 58import javax.xml.stream.events.StartDocument; 59 60 61/** 62 * @author Suresh Kumar 63 * @author Sunitha Reddy 64 * @since 1.6 65 */ 66public class StAXEvent2SAX implements XMLReader, Locator { 67 68 //private final static String EMPTYSTRING = ""; 69 //private static final String XMLNS_PREFIX = "xmlns"; 70 71 // StAX event source 72 private final XMLEventReader staxEventReader; 73 74 //private Node _dom = null; 75 private ContentHandler _sax = null; 76 private LexicalHandler _lex = null; 77 private SAXImpl _saxImpl = null; 78 private String version = null; 79 private String encoding = null; 80 81 82 public StAXEvent2SAX(XMLEventReader staxCore) { 83 staxEventReader = staxCore; 84 } 85 86 public ContentHandler getContentHandler() { 87 return _sax; 88 } 89 90 public void setContentHandler(ContentHandler handler) throws 91 NullPointerException 92 { 93 _sax = handler; 94 if (handler instanceof LexicalHandler) { 95 _lex = (LexicalHandler) handler; 96 } 97 98 if (handler instanceof SAXImpl) { 99 _saxImpl = (SAXImpl)handler; 100 } 101 } 102 103 104 public void parse(InputSource unused) throws IOException, SAXException { 105 try { 106 bridge(); 107 } catch (XMLStreamException e) { 108 throw new SAXException(e); 109 } 110 } 111 112 113 //Main Work Starts Here. 114 public void parse() throws IOException, SAXException, XMLStreamException { 115 bridge(); 116 } 117 118 119 /* public void parse() throws IOException, SAXException { 120 if (_dom != null) { 121 boolean isIncomplete = 122 (_dom.getNodeType() != org.w3c.dom.Node.DOCUMENT_NODE); 123 124 if (isIncomplete) { 125 _sax.startDocument(); 126 parse(_dom); 127 _sax.endDocument(); 128 } 129 else { 130 parse(_dom); 131 } 132 } 133 } 134 */ 135 136 /* 137 * @see StAXReaderToContentHandler#bridge() 138 */ 139 private void bridge() throws XMLStreamException { 140 141 try { 142 // remembers the nest level of elements to know when we are done. 143 int depth=0; 144 boolean startedAtDocument = false; 145 146 XMLEvent event = staxEventReader.peek(); 147 148 if (!event.isStartDocument() && !event.isStartElement()) { 149 throw new IllegalStateException(); 150 } 151 152 if (event.getEventType() == XMLStreamConstants.START_DOCUMENT){ 153 startedAtDocument = true; 154 version = ((StartDocument)event).getVersion(); 155 if (((StartDocument)event).encodingSet()) 156 encoding = ((StartDocument)event).getCharacterEncodingScheme(); 157 event=staxEventReader.nextEvent(); // that gets the one we peeked at 158 event=staxEventReader.nextEvent(); // that really gets the next one 159 } 160 161 handleStartDocument(event); 162 163 // Handle the prolog: http://www.w3.org/TR/REC-xml/#NT-prolog 164 while (event.getEventType() != XMLStreamConstants.START_ELEMENT) { 165 switch (event.getEventType()) { 166 case XMLStreamConstants.CHARACTERS : 167 handleCharacters(event.asCharacters()); 168 break; 169 case XMLStreamConstants.PROCESSING_INSTRUCTION : 170 handlePI((ProcessingInstruction)event); 171 break; 172 case XMLStreamConstants.COMMENT : 173 handleComment(); 174 break; 175 case XMLStreamConstants.DTD : 176 handleDTD(); 177 break; 178 case XMLStreamConstants.SPACE : 179 handleSpace(); 180 break; 181 default : 182 throw new InternalError("processing prolog event: " + event); 183 } 184 event=staxEventReader.nextEvent(); 185 } 186 187 // Process the (document) element 188 do { 189 // These are all of the events listed in the javadoc for 190 // XMLEvent. 191 // The spec only really describes 11 of them. 192 switch (event.getEventType()) { 193 case XMLStreamConstants.START_ELEMENT : 194 depth++; 195 handleStartElement(event.asStartElement()); 196 break; 197 case XMLStreamConstants.END_ELEMENT : 198 handleEndElement(event.asEndElement()); 199 depth--; 200 break; 201 case XMLStreamConstants.CHARACTERS : 202 handleCharacters(event.asCharacters()); 203 break; 204 case XMLStreamConstants.ENTITY_REFERENCE : 205 handleEntityReference(); 206 break; 207 case XMLStreamConstants.PROCESSING_INSTRUCTION : 208 handlePI((ProcessingInstruction)event); 209 break; 210 case XMLStreamConstants.COMMENT : 211 handleComment(); 212 break; 213 case XMLStreamConstants.DTD : 214 handleDTD(); 215 break; 216 case XMLStreamConstants.ATTRIBUTE : 217 handleAttribute(); 218 break; 219 case XMLStreamConstants.NAMESPACE : 220 handleNamespace(); 221 break; 222 case XMLStreamConstants.CDATA : 223 handleCDATA(); 224 break; 225 case XMLStreamConstants.ENTITY_DECLARATION : 226 handleEntityDecl(); 227 break; 228 case XMLStreamConstants.NOTATION_DECLARATION : 229 handleNotationDecl(); 230 break; 231 case XMLStreamConstants.SPACE : 232 handleSpace(); 233 break; 234 default : 235 throw new InternalError("processing event: " + event); 236 } 237 238 event=staxEventReader.nextEvent(); 239 } while (depth!=0); 240 241 if (startedAtDocument) { 242 // Handle the Misc (http://www.w3.org/TR/REC-xml/#NT-Misc) that can follow the document element 243 while (event.getEventType() != XMLStreamConstants.END_DOCUMENT) { 244 switch (event.getEventType()) { 245 case XMLStreamConstants.CHARACTERS : 246 handleCharacters(event.asCharacters()); 247 break; 248 case XMLStreamConstants.PROCESSING_INSTRUCTION : 249 handlePI((ProcessingInstruction)event); 250 break; 251 case XMLStreamConstants.COMMENT : 252 handleComment(); 253 break; 254 case XMLStreamConstants.SPACE : 255 handleSpace(); 256 break; 257 default : 258 throw new InternalError("processing misc event after document element: " + event); 259 } 260 event=staxEventReader.nextEvent(); 261 } 262 } 263 264 handleEndDocument(); 265 } catch (SAXException e) { 266 throw new XMLStreamException(e); 267 } 268 } 269 270 271 private void handleEndDocument() throws SAXException { 272 _sax.endDocument(); 273 } 274 275 private void handleStartDocument(final XMLEvent event) throws SAXException { 276 _sax.setDocumentLocator(new Locator2() { 277 public int getColumnNumber() { 278 return event.getLocation().getColumnNumber(); 279 } 280 public int getLineNumber() { 281 return event.getLocation().getLineNumber(); 282 } 283 public String getPublicId() { 284 return event.getLocation().getPublicId(); 285 } 286 public String getSystemId() { 287 return event.getLocation().getSystemId(); 288 } 289 public String getXMLVersion(){ 290 return version; 291 } 292 public String getEncoding(){ 293 return encoding; 294 } 295 296 }); 297 _sax.startDocument(); 298 } 299 300 private void handlePI(ProcessingInstruction event) 301 throws XMLStreamException { 302 try { 303 _sax.processingInstruction( 304 event.getTarget(), 305 event.getData()); 306 } catch (SAXException e) { 307 throw new XMLStreamException(e); 308 } 309 } 310 311 private void handleCharacters(Characters event) throws XMLStreamException { 312 try { 313 _sax.characters( 314 event.getData().toCharArray(), 315 0, 316 event.getData().length()); 317 } catch (SAXException e) { 318 throw new XMLStreamException(e); 319 } 320 } 321 322 private void handleEndElement(EndElement event) throws XMLStreamException { 323 QName qName = event.getName(); 324 325 //construct prefix:localName from qName 326 String qname = ""; 327 if (qName.getPrefix() != null && qName.getPrefix().trim().length() != 0){ 328 qname = qName.getPrefix() + ":"; 329 } 330 qname += qName.getLocalPart(); 331 332 try { 333 // fire endElement 334 _sax.endElement( 335 qName.getNamespaceURI(), 336 qName.getLocalPart(), 337 qname); 338 339 // end namespace bindings 340 for( Iterator i = event.getNamespaces(); i.hasNext();) { 341 String prefix = (String)i.next(); 342 if( prefix == null ) { // true for default namespace 343 prefix = ""; 344 } 345 _sax.endPrefixMapping(prefix); 346 } 347 } catch (SAXException e) { 348 throw new XMLStreamException(e); 349 } 350 } 351 352 private void handleStartElement(StartElement event) 353 throws XMLStreamException { 354 try { 355 // start namespace bindings 356 for (Iterator i = event.getNamespaces(); i.hasNext();) { 357 String prefix = ((Namespace)i.next()).getPrefix(); 358 if (prefix == null) { // true for default namespace 359 prefix = ""; 360 } 361 _sax.startPrefixMapping( 362 prefix, 363 event.getNamespaceURI(prefix)); 364 } 365 366 // fire startElement 367 QName qName = event.getName(); 368 String prefix = qName.getPrefix(); 369 String rawname; 370 if (prefix == null || prefix.length() == 0) { 371 rawname = qName.getLocalPart(); 372 } else { 373 rawname = prefix + ':' + qName.getLocalPart(); 374 } 375 376 Attributes saxAttrs = getAttributes(event); 377 _sax.startElement( 378 qName.getNamespaceURI(), 379 qName.getLocalPart(), 380 rawname, 381 saxAttrs); 382 } catch (SAXException e) { 383 throw new XMLStreamException(e); 384 } 385 } 386 387 /** 388 * Get the attributes associated with the given START_ELEMENT StAXevent. 389 * 390 * @return the StAX attributes converted to an org.xml.sax.Attributes 391 */ 392 private Attributes getAttributes(StartElement event) { 393 AttributesImpl attrs = new AttributesImpl(); 394 395 if ( !event.isStartElement() ) { 396 throw new InternalError( 397 "getAttributes() attempting to process: " + event); 398 } 399 400 // in SAX, namespace declarations are not part of attributes by default. 401 // (there's a property to control that, but as far as we are concerned 402 // we don't use it.) So don't add xmlns:* to attributes. 403 404 // gather non-namespace attrs 405 for (Iterator i = event.getAttributes(); i.hasNext();) { 406 Attribute staxAttr = (javax.xml.stream.events.Attribute)i.next(); 407 408 String uri = staxAttr.getName().getNamespaceURI(); 409 if (uri == null) { 410 uri = ""; 411 } 412 String localName = staxAttr.getName().getLocalPart(); 413 String prefix = staxAttr.getName().getPrefix(); 414 String qName; 415 if (prefix == null || prefix.length() == 0) { 416 qName = localName; 417 } else { 418 qName = prefix + ':' + localName; 419 } 420 String type = staxAttr.getDTDType(); 421 String value = staxAttr.getValue(); 422 423 attrs.addAttribute(uri, localName, qName, type, value); 424 } 425 426 return attrs; 427 } 428 429 private void handleNamespace() { 430 // no-op ??? 431 // namespace events don't normally occur outside of a startElement 432 // or endElement 433 } 434 435 private void handleAttribute() { 436 // no-op ??? 437 // attribute events don't normally occur outside of a startElement 438 // or endElement 439 } 440 441 private void handleDTD() { 442 // no-op ??? 443 // it seems like we need to pass this info along, but how? 444 } 445 446 private void handleComment() { 447 // no-op ??? 448 } 449 450 private void handleEntityReference() { 451 // no-op ??? 452 } 453 454 private void handleSpace() { 455 // no-op ??? 456 // this event is listed in the javadoc, but not in the spec. 457 } 458 459 private void handleNotationDecl() { 460 // no-op ??? 461 // this event is listed in the javadoc, but not in the spec. 462 } 463 464 private void handleEntityDecl() { 465 // no-op ??? 466 // this event is listed in the javadoc, but not in the spec. 467 } 468 469 private void handleCDATA() { 470 // no-op ??? 471 // this event is listed in the javadoc, but not in the spec. 472 } 473 474 475 /** 476 * This class is only used internally so this method should never 477 * be called. 478 */ 479 public DTDHandler getDTDHandler() { 480 return null; 481 } 482 483 /** 484 * This class is only used internally so this method should never 485 * be called. 486 */ 487 public ErrorHandler getErrorHandler() { 488 return null; 489 } 490 491 /** 492 * This class is only used internally so this method should never 493 * be called. 494 */ 495 public boolean getFeature(String name) throws SAXNotRecognizedException, 496 SAXNotSupportedException 497 { 498 return false; 499 } 500 501 /** 502 * This class is only used internally so this method should never 503 * be called. 504 */ 505 public void setFeature(String name, boolean value) throws 506 SAXNotRecognizedException, SAXNotSupportedException 507 { 508 } 509 510 /** 511 * This class is only used internally so this method should never 512 * be called. 513 */ 514 public void parse(String sysId) throws IOException, SAXException { 515 throw new IOException("This method is not yet implemented."); 516 } 517 518 /** 519 * This class is only used internally so this method should never 520 * be called. 521 */ 522 public void setDTDHandler(DTDHandler handler) throws NullPointerException { 523 } 524 525 /** 526 * This class is only used internally so this method should never 527 * be called. 528 */ 529 public void setEntityResolver(EntityResolver resolver) throws 530 NullPointerException 531 { 532 } 533 534 /** 535 * This class is only used internally so this method should never 536 * be called. 537 */ 538 public EntityResolver getEntityResolver() { 539 return null; 540 } 541 542 /** 543 * This class is only used internally so this method should never 544 * be called. 545 */ 546 public void setErrorHandler(ErrorHandler handler) throws 547 NullPointerException 548 { 549 } 550 551 /** 552 * This class is only used internally so this method should never 553 * be called. 554 */ 555 public void setProperty(String name, Object value) throws 556 SAXNotRecognizedException, SAXNotSupportedException { 557 } 558 559 /** 560 * This class is only used internally so this method should never 561 * be called. 562 */ 563 public Object getProperty(String name) throws SAXNotRecognizedException, 564 SAXNotSupportedException 565 { 566 return null; 567 } 568 569 /** 570 * This class is only used internally so this method should never 571 * be called. 572 */ 573 public int getColumnNumber() { 574 return 0; 575 } 576 577 /** 578 * This class is only used internally so this method should never 579 * be called. 580 */ 581 public int getLineNumber() { 582 return 0; 583 } 584 585 /** 586 * This class is only used internally so this method should never 587 * be called. 588 */ 589 public String getPublicId() { 590 return null; 591 } 592 593 /** 594 * This class is only used internally so this method should never 595 * be called. 596 */ 597 public String getSystemId() { 598 return null; 599 } 600} 601