View Javadoc
1   /*
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  
26  package com.sun.org.apache.xalan.internal.xsltc.trax;
27  
28  import java.io.IOException;
29  import java.util.Iterator;
30  
31  import org.xml.sax.Attributes;
32  import org.xml.sax.ContentHandler;
33  import org.xml.sax.DTDHandler;
34  import org.xml.sax.EntityResolver;
35  import org.xml.sax.ErrorHandler;
36  import org.xml.sax.InputSource;
37  import org.xml.sax.Locator;
38  import org.xml.sax.SAXException;
39  import org.xml.sax.SAXNotRecognizedException;
40  import org.xml.sax.SAXNotSupportedException;
41  import org.xml.sax.XMLReader;
42  import org.xml.sax.ext.LexicalHandler;
43  import org.xml.sax.helpers.AttributesImpl;
44  import org.xml.sax.ext.Locator2;
45  import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl;
46  
47  import javax.xml.namespace.QName;
48  import javax.xml.stream.XMLEventReader;
49  import javax.xml.stream.XMLStreamConstants;
50  import javax.xml.stream.XMLStreamException;
51  import javax.xml.stream.events.Attribute;
52  import javax.xml.stream.events.Characters;
53  import javax.xml.stream.events.EndElement;
54  import javax.xml.stream.events.Namespace;
55  import javax.xml.stream.events.ProcessingInstruction;
56  import javax.xml.stream.events.StartElement;
57  import javax.xml.stream.events.XMLEvent;
58  import javax.xml.stream.events.StartDocument;
59  
60  
61  /**
62   * @author Suresh Kumar
63   * @author Sunitha Reddy
64   * @since 1.6
65   */
66  public 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 }