Thu, 31 Aug 2017 15:18:52 +0800
merge
1 /*
2 * Copyright (c) 2005, 2013, 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 */
26 package com.sun.xml.internal.stream.buffer.stax;
28 import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer;
29 import com.sun.xml.internal.org.jvnet.staxex.Base64Data;
30 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx;
32 import javax.xml.stream.XMLStreamException;
33 import javax.xml.stream.XMLStreamReader;
34 import java.util.HashMap;
35 import java.util.Map;
37 /**
38 * Create a buffer using an {@link XMLStreamReader}.
39 * <p>
40 * TODO: Implement the marking the stream on the element when an ID
41 * attribute on the element is defined
42 */
43 public class StreamReaderBufferCreator extends StreamBufferCreator {
44 private int _eventType;
45 private boolean _storeInScopeNamespacesOnElementFragment;
46 private Map<String, Integer> _inScopePrefixes;
48 /**
49 * Create a stream reader buffer creator.
50 * <p>
51 * A stream buffer will be created for storing the infoset
52 * from a stream reader.
53 */
54 public StreamReaderBufferCreator() {
55 }
57 /**
58 * Create a stream reader buffer creator using a mutable stream buffer.
59 * <p>
60 * @param buffer the mutable stream buffer.
61 */
62 public StreamReaderBufferCreator(MutableXMLStreamBuffer buffer) {
63 setBuffer(buffer);
64 }
66 /**
67 * Create the buffer from a stream reader.
68 * <p>
69 * The stream reader must be positioned at the start of the document
70 * or the start of an element.
71 * <p>
72 * If the stream is positioned at the start of the document then the
73 * whole document is stored and after storing the stream will be positioned
74 * at the end of the document.
75 * <p>
76 * If the stream is positioned at the start of an element then the
77 * element and all its children will be stored and after storing the stream
78 * will be positioned at the next event after the end of the element.
79 * <p>
80 * @return the mutable stream buffer.
81 * @throws XMLStreamException if the stream reader is not positioned at
82 * the start of the document or at an element.
83 */
84 public MutableXMLStreamBuffer create(XMLStreamReader reader) throws XMLStreamException {
85 if (_buffer == null) {
86 createBuffer();
87 }
88 store(reader);
90 return getXMLStreamBuffer();
91 }
93 /**
94 * Creates the buffer from a stream reader that is an element fragment.
95 * <p>
96 * The stream reader will be moved to the position of the next start of
97 * an element if the stream reader is not already positioned at the start
98 * of an element.
99 * <p>
100 * The element and all its children will be stored and after storing the stream
101 * will be positioned at the next event after the end of the element.
102 * <p>
103 * @param storeInScopeNamespaces true if in-scope namespaces of the element
104 * fragment should be stored.
105 * @return the mutable stream buffer.
106 * @throws XMLStreamException if the stream reader cannot be positioned at
107 * the start of an element.
108 */
109 public MutableXMLStreamBuffer createElementFragment(XMLStreamReader reader,
110 boolean storeInScopeNamespaces) throws XMLStreamException {
111 if (_buffer == null) {
112 createBuffer();
113 }
115 if (!reader.hasNext()) {
116 return _buffer;
117 }
119 _storeInScopeNamespacesOnElementFragment = storeInScopeNamespaces;
121 _eventType = reader.getEventType();
122 if (_eventType != XMLStreamReader.START_ELEMENT) {
123 do {
124 _eventType = reader.next();
125 } while(_eventType != XMLStreamReader.START_ELEMENT && _eventType != XMLStreamReader.END_DOCUMENT);
126 }
128 if (storeInScopeNamespaces) {
129 _inScopePrefixes = new HashMap<String,Integer>();
130 }
132 storeElementAndChildren(reader);
134 return getXMLStreamBuffer();
135 }
137 private void store(XMLStreamReader reader) throws XMLStreamException {
138 if (!reader.hasNext()) {
139 return;
140 }
142 _eventType = reader.getEventType();
143 switch (_eventType) {
144 case XMLStreamReader.START_DOCUMENT:
145 storeDocumentAndChildren(reader);
146 break;
147 case XMLStreamReader.START_ELEMENT:
148 storeElementAndChildren(reader);
149 break;
150 default:
151 throw new XMLStreamException("XMLStreamReader not positioned at a document or element");
152 }
154 increaseTreeCount();
155 }
157 private void storeDocumentAndChildren(XMLStreamReader reader) throws XMLStreamException {
158 storeStructure(T_DOCUMENT);
160 _eventType = reader.next();
161 while (_eventType != XMLStreamReader.END_DOCUMENT) {
162 switch (_eventType) {
163 case XMLStreamReader.START_ELEMENT:
164 storeElementAndChildren(reader);
165 continue;
166 case XMLStreamReader.COMMENT:
167 storeComment(reader);
168 break;
169 case XMLStreamReader.PROCESSING_INSTRUCTION:
170 storeProcessingInstruction(reader);
171 break;
172 }
173 _eventType = reader.next();
174 }
176 storeStructure(T_END);
177 }
179 private void storeElementAndChildren(XMLStreamReader reader) throws XMLStreamException {
180 if (reader instanceof XMLStreamReaderEx) {
181 storeElementAndChildrenEx((XMLStreamReaderEx)reader);
182 } else {
183 storeElementAndChildrenNoEx(reader);
184 }
185 }
187 private void storeElementAndChildrenEx(XMLStreamReaderEx reader) throws XMLStreamException {
188 int depth = 1;
189 if (_storeInScopeNamespacesOnElementFragment) {
190 storeElementWithInScopeNamespaces(reader);
191 } else {
192 storeElement(reader);
193 }
195 while(depth > 0) {
196 _eventType = reader.next();
197 switch (_eventType) {
198 case XMLStreamReader.START_ELEMENT:
199 depth++;
200 storeElement(reader);
201 break;
202 case XMLStreamReader.END_ELEMENT:
203 depth--;
204 storeStructure(T_END);
205 break;
206 case XMLStreamReader.NAMESPACE:
207 storeNamespaceAttributes(reader);
208 break;
209 case XMLStreamReader.ATTRIBUTE:
210 storeAttributes(reader);
211 break;
212 case XMLStreamReader.SPACE:
213 case XMLStreamReader.CHARACTERS:
214 case XMLStreamReader.CDATA: {
215 CharSequence c = reader.getPCDATA();
216 if (c instanceof Base64Data) {
217 storeStructure(T_TEXT_AS_OBJECT);
218 //Instead of clone the Base64Data, the original Base64Data instance is used here to preserve the DataHandler
219 storeContentObject(c);
220 } else {
221 storeContentCharacters(T_TEXT_AS_CHAR_ARRAY,
222 reader.getTextCharacters(), reader.getTextStart(),
223 reader.getTextLength());
224 }
225 break;
226 }
227 case XMLStreamReader.COMMENT:
228 storeComment(reader);
229 break;
230 case XMLStreamReader.PROCESSING_INSTRUCTION:
231 storeProcessingInstruction(reader);
232 break;
233 }
234 }
236 /*
237 * Move to next item after the end of the element
238 * that has been stored
239 */
240 _eventType = reader.next();
241 }
243 private void storeElementAndChildrenNoEx(XMLStreamReader reader) throws XMLStreamException {
244 int depth = 1;
245 if (_storeInScopeNamespacesOnElementFragment) {
246 storeElementWithInScopeNamespaces(reader);
247 } else {
248 storeElement(reader);
249 }
251 while(depth > 0) {
252 _eventType = reader.next();
253 switch (_eventType) {
254 case XMLStreamReader.START_ELEMENT:
255 depth++;
256 storeElement(reader);
257 break;
258 case XMLStreamReader.END_ELEMENT:
259 depth--;
260 storeStructure(T_END);
261 break;
262 case XMLStreamReader.NAMESPACE:
263 storeNamespaceAttributes(reader);
264 break;
265 case XMLStreamReader.ATTRIBUTE:
266 storeAttributes(reader);
267 break;
268 case XMLStreamReader.SPACE:
269 case XMLStreamReader.CHARACTERS:
270 case XMLStreamReader.CDATA: {
271 storeContentCharacters(T_TEXT_AS_CHAR_ARRAY,
272 reader.getTextCharacters(), reader.getTextStart(),
273 reader.getTextLength());
274 break;
275 }
276 case XMLStreamReader.COMMENT:
277 storeComment(reader);
278 break;
279 case XMLStreamReader.PROCESSING_INSTRUCTION:
280 storeProcessingInstruction(reader);
281 break;
282 }
283 }
285 /*
286 * Move to next item after the end of the element
287 * that has been stored
288 */
289 _eventType = reader.next();
290 }
292 private void storeElementWithInScopeNamespaces(XMLStreamReader reader) {
293 storeQualifiedName(T_ELEMENT_LN,
294 reader.getPrefix(), reader.getNamespaceURI(), reader.getLocalName());
296 if (reader.getNamespaceCount() > 0) {
297 storeNamespaceAttributes(reader);
298 }
300 if (reader.getAttributeCount() > 0) {
301 storeAttributes(reader);
302 }
303 }
305 private void storeElement(XMLStreamReader reader) {
306 storeQualifiedName(T_ELEMENT_LN,
307 reader.getPrefix(), reader.getNamespaceURI(), reader.getLocalName());
309 if (reader.getNamespaceCount() > 0) {
310 storeNamespaceAttributes(reader);
311 }
313 if (reader.getAttributeCount() > 0) {
314 storeAttributes(reader);
315 }
316 }
318 /**
319 * A low level method a create a structure element explicitly. This is useful when xsb is
320 * created from a fragment's XMLStreamReader and inscope namespaces can be passed using
321 * this method. Note that there is no way to enumerate namespaces from XMLStreamReader.
322 *
323 * For e.g: Say the SOAP message is as follows
324 *
325 * <S:Envelope xmlns:n1=".."><S:Body><ns2:A> ...
326 *
327 * when xsb is to be created using a reader that is at <ns2:A> tag, the inscope
328 * namespace like 'n1' can be passed using this method.
329 *
330 * WARNING: Instead of using this, try other methods(if you don't know what you are
331 * doing).
332 *
333 * @param ns an array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }.
334 */
335 public void storeElement(String nsURI, String localName, String prefix, String[] ns) {
336 storeQualifiedName(T_ELEMENT_LN, prefix, nsURI, localName);
337 storeNamespaceAttributes(ns);
338 }
340 /**
341 * A low level method a create a structure element explicitly. This is
342 * required to support {@link #storeElement} method.
343 *
344 * WARNING: Instead of using this, try other methods(if you don't know what
345 * you are doing).
346 */
347 public void storeEndElement() {
348 storeStructure(T_END);
349 }
351 private void storeNamespaceAttributes(XMLStreamReader reader) {
352 int count = reader.getNamespaceCount();
353 for (int i = 0; i < count; i++) {
354 storeNamespaceAttribute(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
355 }
356 }
358 /**
359 * @param ns an array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }.
360 */
361 private void storeNamespaceAttributes(String[] ns) {
362 for (int i = 0; i < ns.length; i=i+2) {
363 storeNamespaceAttribute(ns[i], ns[i+1]);
364 }
365 }
367 private void storeAttributes(XMLStreamReader reader) {
368 int count = reader.getAttributeCount();
369 for (int i = 0; i < count; i++) {
370 storeAttribute(reader.getAttributePrefix(i), reader.getAttributeNamespace(i), reader.getAttributeLocalName(i),
371 reader.getAttributeType(i), reader.getAttributeValue(i));
372 }
373 }
375 private void storeComment(XMLStreamReader reader) {
376 storeContentCharacters(T_COMMENT_AS_CHAR_ARRAY,
377 reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength());
378 }
380 private void storeProcessingInstruction(XMLStreamReader reader) {
381 storeProcessingInstruction(reader.getPITarget(), reader.getPIData());
382 }
383 }