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