View Javadoc

1   /*
2    * Copyright 2006 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.xml.stream;
18  
19  import java.util.Iterator;
20  import javax.xml.stream.XMLEventReader;
21  import javax.xml.stream.XMLStreamConstants;
22  import javax.xml.stream.XMLStreamException;
23  import javax.xml.stream.events.Attribute;
24  import javax.xml.stream.events.Characters;
25  import javax.xml.stream.events.EndElement;
26  import javax.xml.stream.events.EntityDeclaration;
27  import javax.xml.stream.events.Namespace;
28  import javax.xml.stream.events.NotationDeclaration;
29  import javax.xml.stream.events.ProcessingInstruction;
30  import javax.xml.stream.events.StartElement;
31  import javax.xml.stream.events.XMLEvent;
32  
33  import org.springframework.xml.namespace.QNameUtils;
34  import org.xml.sax.Attributes;
35  import org.xml.sax.SAXException;
36  import org.xml.sax.helpers.AttributesImpl;
37  
38  /**
39   * SAX <code>XMLReader</code> that reads from a StAX <code>XMLEventReader</code>. Consumes <code>XMLEvents</code> from
40   * an <code>XMLEventReader</code>, and calls the corresponding methods on the SAX callback interfaces.
41   *
42   * @author Arjen Poutsma
43   * @see XMLEventReader
44   * @see #setContentHandler(org.xml.sax.ContentHandler)
45   * @see #setDTDHandler(org.xml.sax.DTDHandler)
46   * @see #setEntityResolver(org.xml.sax.EntityResolver)
47   * @see #setErrorHandler(org.xml.sax.ErrorHandler)
48   * @since 1.0.0
49   */
50  public class StaxEventXmlReader extends AbstractStaxXmlReader {
51  
52      private final XMLEventReader reader;
53  
54      /**
55       * Constructs a new instance of the <code>StaxEventXmlReader</code> that reads from the given
56       * <code>XMLEventReader</code>. The supplied event reader must be in <code>XMLStreamConstants.START_DOCUMENT</code>
57       * or <code>XMLStreamConstants.START_ELEMENT</code> state.
58       *
59       * @param reader the <code>XMLEventReader</code> to read from
60       * @throws IllegalStateException if the reader is not at the start of a document or element
61       */
62      public StaxEventXmlReader(XMLEventReader reader) {
63          try {
64              XMLEvent event = reader.peek();
65              if (event == null || !(event.isStartDocument() || event.isStartElement())) {
66                  throw new IllegalStateException("XMLEventReader not at start of document or element");
67              }
68          }
69          catch (XMLStreamException ex) {
70              throw new IllegalStateException("Could not read first element: " + ex.getMessage());
71          }
72  
73          this.reader = reader;
74      }
75  
76      protected void parseInternal() throws SAXException, XMLStreamException {
77          boolean documentStarted = false;
78          boolean documentEnded = false;
79          int elementDepth = 0;
80          XMLEvent event = null;
81          while (reader.hasNext() && elementDepth >= 0) {
82              event = reader.nextEvent();
83              if (!event.isStartDocument() && !event.isEndDocument() && !documentStarted) {
84                  handleStartDocument();
85                  documentStarted = true;
86              }
87              switch (event.getEventType()) {
88                  case XMLStreamConstants.START_ELEMENT:
89                      elementDepth++;
90                      handleStartElement(event.asStartElement());
91                      break;
92                  case XMLStreamConstants.END_ELEMENT:
93                      elementDepth--;
94                      if (elementDepth >= 0) {
95                          handleEndElement(event.asEndElement());
96                      }
97                      break;
98                  case XMLStreamConstants.PROCESSING_INSTRUCTION:
99                      handleProcessingInstruction((ProcessingInstruction) event);
100                     break;
101                 case XMLStreamConstants.CHARACTERS:
102                 case XMLStreamConstants.SPACE:
103                 case XMLStreamConstants.CDATA:
104                     handleCharacters(event.asCharacters());
105                     break;
106                 case XMLStreamConstants.START_DOCUMENT:
107                     setLocator(event.getLocation());
108                     handleStartDocument();
109                     documentStarted = true;
110                     break;
111                 case XMLStreamConstants.END_DOCUMENT:
112                     handleEndDocument();
113                     documentEnded = true;
114                     break;
115                 case XMLStreamConstants.NOTATION_DECLARATION:
116                     handleNotationDeclaration((NotationDeclaration) event);
117                     break;
118                 case XMLStreamConstants.ENTITY_DECLARATION:
119                     handleEntityDeclaration((EntityDeclaration) event);
120                     break;
121             }
122         }
123         if (!documentEnded) {
124             handleEndDocument();
125         }
126 
127     }
128 
129     private void handleCharacters(Characters characters) throws SAXException {
130         if (getContentHandler() != null) {
131             if (characters.isIgnorableWhiteSpace()) {
132                 getContentHandler()
133                         .ignorableWhitespace(characters.getData().toCharArray(), 0, characters.getData().length());
134             }
135             else {
136                 getContentHandler().characters(characters.getData().toCharArray(), 0, characters.getData().length());
137             }
138         }
139     }
140 
141     private void handleEndDocument() throws SAXException {
142         if (getContentHandler() != null) {
143             getContentHandler().endDocument();
144         }
145     }
146 
147     private void handleEndElement(EndElement endElement) throws SAXException {
148         if (getContentHandler() != null) {
149             getContentHandler().endElement(endElement.getName().getNamespaceURI(), endElement.getName().getLocalPart(),
150                     QNameUtils.toQualifiedName(endElement.getName()));
151 
152             for (Iterator i = endElement.getNamespaces(); i.hasNext();) {
153                 Namespace namespace = (Namespace) i.next();
154                 getContentHandler().endPrefixMapping(namespace.getPrefix());
155             }
156         }
157     }
158 
159     private void handleNotationDeclaration(NotationDeclaration declaration) throws SAXException {
160         if (getDTDHandler() != null) {
161             getDTDHandler().notationDecl(declaration.getName(), declaration.getPublicId(), declaration.getSystemId());
162         }
163     }
164 
165     private void handleEntityDeclaration(EntityDeclaration entityDeclaration) throws SAXException {
166         if (getDTDHandler() != null) {
167             getDTDHandler().unparsedEntityDecl(entityDeclaration.getName(), entityDeclaration.getPublicId(),
168                     entityDeclaration.getSystemId(), entityDeclaration.getNotationName());
169         }
170     }
171 
172     private void handleProcessingInstruction(ProcessingInstruction pi) throws SAXException {
173         if (getContentHandler() != null) {
174             getContentHandler().processingInstruction(pi.getTarget(), pi.getData());
175         }
176     }
177 
178     private void handleStartDocument() throws SAXException {
179         if (getContentHandler() != null) {
180             getContentHandler().startDocument();
181         }
182     }
183 
184     private void handleStartElement(StartElement startElement) throws SAXException {
185         if (getContentHandler() != null) {
186             for (Iterator i = startElement.getNamespaces(); i.hasNext();) {
187                 Namespace namespace = (Namespace) i.next();
188                 getContentHandler().startPrefixMapping(namespace.getPrefix(), namespace.getNamespaceURI());
189             }
190 
191             getContentHandler().startElement(startElement.getName().getNamespaceURI(),
192                     startElement.getName().getLocalPart(), QNameUtils.toQualifiedName(startElement.getName()),
193                     getAttributes(startElement));
194         }
195     }
196 
197     private Attributes getAttributes(StartElement event) {
198         AttributesImpl attributes = new AttributesImpl();
199 
200         for (Iterator i = event.getAttributes(); i.hasNext();) {
201             Attribute attribute = (Attribute) i.next();
202             attributes.addAttribute(attribute.getName().getNamespaceURI(), attribute.getName().getLocalPart(),
203                     QNameUtils.toQualifiedName(attribute.getName()), attribute.getDTDType(), attribute.getValue());
204         }
205 
206         return attributes;
207     }
208 
209 }