Thu, 31 Aug 2017 15:18:52 +0800
merge
1 /*
2 * Copyright (c) 1997, 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.ws.util.xml;
28 import java.io.IOException;
30 import javax.xml.bind.attachment.AttachmentMarshaller;
31 import javax.xml.stream.XMLStreamConstants;
32 import javax.xml.stream.XMLStreamException;
33 import javax.xml.stream.XMLStreamReader;
34 import javax.xml.stream.XMLStreamWriter;
35 import javax.xml.XMLConstants;
37 import com.sun.xml.internal.ws.streaming.MtomStreamWriter;
38 import com.sun.xml.internal.org.jvnet.staxex.Base64Data;
39 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx;
40 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx;
42 /**
43 * Reads a sub-tree from {@link XMLStreamReader} and writes to {@link XMLStreamWriter}
44 * as-is.
45 *
46 * <p>
47 * This class can be sub-classed to implement a simple transformation logic.
48 *
49 * @author Kohsuke Kawaguchi
50 * @author Ryan Shoemaker
51 */
52 public class XMLStreamReaderToXMLStreamWriter {
54 private static final int BUF_SIZE = 4096;
56 protected XMLStreamReader in;
57 protected XMLStreamWriter out;
59 private char[] buf;
61 boolean optimizeBase64Data = false;
63 AttachmentMarshaller mtomAttachmentMarshaller;
65 /**
66 * Reads one subtree and writes it out.
67 *
68 * <p>
69 * The {@link XMLStreamWriter} never receives a start/end document event.
70 * Those need to be written separately by the caller.
71 */
72 public void bridge(XMLStreamReader in, XMLStreamWriter out) throws XMLStreamException {
73 assert in!=null && out!=null;
74 this.in = in;
75 this.out = out;
77 optimizeBase64Data = (in instanceof XMLStreamReaderEx);
79 if (out instanceof XMLStreamWriterEx && out instanceof MtomStreamWriter) {
80 mtomAttachmentMarshaller = ((MtomStreamWriter) out).getAttachmentMarshaller();
81 }
82 // remembers the nest level of elements to know when we are done.
83 int depth=0;
85 buf = new char[BUF_SIZE];
87 // if the parser is at the start tag, proceed to the first element
88 int event = in.getEventType();
89 if(event == XMLStreamConstants.START_DOCUMENT) {
90 // nextTag doesn't correctly handle DTDs
91 while( !in.isStartElement() ) {
92 event = in.next();
93 if (event == XMLStreamConstants.COMMENT)
94 handleComment();
95 }
96 }
99 if( event!=XMLStreamConstants.START_ELEMENT)
100 throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event);
102 do {
103 // These are all of the events listed in the javadoc for
104 // XMLEvent.
105 // The spec only really describes 11 of them.
106 switch (event) {
107 case XMLStreamConstants.START_ELEMENT :
108 depth++;
109 handleStartElement();
110 break;
111 case XMLStreamConstants.END_ELEMENT :
112 handleEndElement();
113 depth--;
114 if(depth==0)
115 return;
116 break;
117 case XMLStreamConstants.CHARACTERS :
118 handleCharacters();
119 break;
120 case XMLStreamConstants.ENTITY_REFERENCE :
121 handleEntityReference();
122 break;
123 case XMLStreamConstants.PROCESSING_INSTRUCTION :
124 handlePI();
125 break;
126 case XMLStreamConstants.COMMENT :
127 handleComment();
128 break;
129 case XMLStreamConstants.DTD :
130 handleDTD();
131 break;
132 case XMLStreamConstants.CDATA :
133 handleCDATA();
134 break;
135 case XMLStreamConstants.SPACE :
136 handleSpace();
137 break;
138 case XMLStreamConstants.END_DOCUMENT:
139 throw new XMLStreamException("Malformed XML at depth="+depth+", Reached EOF. Event="+event);
140 default :
141 throw new XMLStreamException("Cannot process event: " + event);
142 }
144 event=in.next();
145 } while (depth!=0);
146 }
148 protected void handlePI() throws XMLStreamException {
149 out.writeProcessingInstruction(
150 in.getPITarget(),
151 in.getPIData());
152 }
155 protected void handleCharacters() throws XMLStreamException {
157 CharSequence c = null;
159 if (optimizeBase64Data) {
160 c = ((XMLStreamReaderEx)in).getPCDATA();
161 }
163 if ((c != null) && (c instanceof Base64Data)) {
164 if (mtomAttachmentMarshaller != null) {
165 Base64Data b64d = (Base64Data) c;
166 ((XMLStreamWriterEx)out).writeBinary(b64d.getDataHandler());
167 } else {
168 try {
169 ((Base64Data)c).writeTo(out);
170 } catch (IOException e) {
171 throw new XMLStreamException(e);
172 }
173 }
174 } else {
175 for (int start=0,read=buf.length; read == buf.length; start+=buf.length) {
176 read = in.getTextCharacters(start, buf, 0, buf.length);
177 out.writeCharacters(buf, 0, read);
178 }
179 }
180 }
182 protected void handleEndElement() throws XMLStreamException {
183 out.writeEndElement();
184 }
186 protected void handleStartElement() throws XMLStreamException {
187 String nsUri = in.getNamespaceURI();
188 if(nsUri==null)
189 out.writeStartElement(in.getLocalName());
190 else
191 out.writeStartElement(
192 fixNull(in.getPrefix()),
193 in.getLocalName(),
194 nsUri
195 );
197 // start namespace bindings
198 int nsCount = in.getNamespaceCount();
199 for (int i = 0; i < nsCount; i++) {
200 out.writeNamespace(
201 in.getNamespacePrefix(i),
202 fixNull(in.getNamespaceURI(i))); // zephyr doesn't like null, I don't know what is correct, so just fix null to "" for now
203 }
205 // write attributes
206 int attCount = in.getAttributeCount();
207 for (int i = 0; i < attCount; i++) {
208 handleAttribute(i);
209 }
210 }
212 /**
213 * Writes out the {@code i}-th attribute of the current element.
214 *
215 * <p>
216 * Used from {@link #handleStartElement()}.
217 */
218 protected void handleAttribute(int i) throws XMLStreamException {
219 String nsUri = in.getAttributeNamespace(i);
220 String prefix = in.getAttributePrefix(i);
221 if (fixNull(nsUri).equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
222 //Its a namespace decl, ignore as it is already written.
223 return;
224 }
226 if(nsUri==null || prefix == null || prefix.equals("")) {
227 out.writeAttribute(
228 in.getAttributeLocalName(i),
229 in.getAttributeValue(i)
230 );
231 } else {
232 out.writeAttribute(
233 prefix,
234 nsUri,
235 in.getAttributeLocalName(i),
236 in.getAttributeValue(i)
237 );
238 }
239 }
241 protected void handleDTD() throws XMLStreamException {
242 out.writeDTD(in.getText());
243 }
245 protected void handleComment() throws XMLStreamException {
246 out.writeComment(in.getText());
247 }
249 protected void handleEntityReference() throws XMLStreamException {
250 out.writeEntityRef(in.getText());
251 }
253 protected void handleSpace() throws XMLStreamException {
254 handleCharacters();
255 }
257 protected void handleCDATA() throws XMLStreamException {
258 out.writeCData(in.getText());
259 }
261 private static String fixNull(String s) {
262 if(s==null) return "";
263 else return s;
264 }
265 }