001 /**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.camel.converter.jaxp;
019
020
021 import java.io.IOException;
022 import java.io.InputStream;
023 import java.io.InputStreamReader;
024 import java.io.Reader;
025 import java.io.StringReader;
026 import java.io.StringWriter;
027 import java.io.ByteArrayInputStream;
028 import java.io.File;
029 import java.lang.reflect.Constructor;
030
031 import javax.xml.parsers.DocumentBuilder;
032 import javax.xml.parsers.DocumentBuilderFactory;
033 import javax.xml.parsers.ParserConfigurationException;
034 import javax.xml.transform.OutputKeys;
035 import javax.xml.transform.Result;
036 import javax.xml.transform.Source;
037 import javax.xml.transform.Transformer;
038 import javax.xml.transform.TransformerConfigurationException;
039 import javax.xml.transform.TransformerException;
040 import javax.xml.transform.TransformerFactory;
041 import javax.xml.transform.dom.DOMResult;
042 import javax.xml.transform.dom.DOMSource;
043 import javax.xml.transform.sax.SAXSource;
044 import javax.xml.transform.stream.StreamResult;
045 import javax.xml.transform.stream.StreamSource;
046
047 import org.w3c.dom.Document;
048 import org.w3c.dom.Element;
049 import org.w3c.dom.Node;
050 import org.xml.sax.InputSource;
051 import org.xml.sax.SAXException;
052 import org.xml.sax.XMLReader;
053 import org.apache.camel.util.ObjectHelper;
054 import org.apache.camel.Converter;
055
056 /**
057 * A helper class to transform to and from various JAXB types such as {@link Source} and {@link Document}
058 *
059 * @version $Revision: 525890 $
060 */
061 @Converter
062 public class XmlConverter {
063 public static final String DEFAULT_CHARSET_PROPERTY = "org.apache.camel.default.charset";
064
065 public static String defaultCharset = ObjectHelper.getSystemProperty(DEFAULT_CHARSET_PROPERTY, "UTF-8");
066
067 private DocumentBuilderFactory documentBuilderFactory;
068 private TransformerFactory transformerFactory;
069
070 /*
071 * When converting a DOM tree to a SAXSource,
072 * we try to use Xalan internal DOM parser if
073 * available. Else, transform the DOM tree
074 * to a String and build a SAXSource on top of
075 * it.
076 */
077 private static final Class dom2SaxClass;
078
079 static {
080 Class cl = null;
081 try {
082 cl = Class.forName("org.apache.xalan.xsltc.trax.DOM2SAX");
083 } catch (Throwable t) {}
084 dom2SaxClass = cl;
085 }
086
087
088 public XmlConverter() {
089 }
090
091 public XmlConverter(DocumentBuilderFactory documentBuilderFactory) {
092 this.documentBuilderFactory = documentBuilderFactory;
093 }
094
095
096 /**
097 * Converts the given input Source into the required result
098 */
099 public void toResult(Source source, Result result) throws TransformerException {
100 if (source == null) {
101 return;
102 }
103 Transformer transformer = createTransfomer();
104 if (transformer == null) {
105 throw new TransformerException("Could not create a transformer - JAXP is misconfigured!");
106 }
107 transformer.setOutputProperty(OutputKeys.ENCODING, defaultCharset);
108 transformer.transform(source, result);
109 }
110
111 /**
112 * Converts the given byte[] to a Source
113 */
114 @Converter
115 public BytesSource toSource(byte[] data) {
116 return new BytesSource(data);
117 }
118
119
120 /**
121 * Converts the given String to a Source
122 */
123 @Converter
124 public StringSource toSource(String data) {
125 return new StringSource(data);
126 }
127
128 /**
129 * Converts the given Document to a Source
130 */
131 @Converter
132 public DOMSource toSource(Document document) {
133 return new DOMSource(document);
134 }
135
136 /**
137 * Converts the given input Source into text
138 */
139 @Converter
140 public String toString(Source source) throws TransformerException {
141 if (source == null) {
142 return null;
143 } else if (source instanceof StringSource) {
144 return ((StringSource) source).getText();
145 } else if (source instanceof BytesSource) {
146 return new String(((BytesSource) source).getData());
147 } else {
148 StringWriter buffer = new StringWriter();
149 toResult(source, new StreamResult(buffer));
150 return buffer.toString();
151 }
152 }
153
154 /**
155 * Converts the given input Node into text
156 */
157 @Converter
158 public String toString(Node node) throws TransformerException {
159 return toString(new DOMSource(node));
160 }
161
162 /**
163 * Converts the source instance to a {@link DOMSource} or returns null if the conversion is not
164 * supported (making it easy to derive from this class to add new kinds of conversion).
165 */
166 @Converter
167 public DOMSource toDOMSource(Source source) throws ParserConfigurationException, IOException, SAXException, TransformerException {
168 if (source instanceof DOMSource) {
169 return (DOMSource) source;
170 }
171 else if (source instanceof SAXSource) {
172 return toDOMSourceFromSAX((SAXSource) source);
173 }
174 else if (source instanceof StreamSource) {
175 return toDOMSourceFromStream((StreamSource) source);
176 }
177 else {
178 return null;
179 }
180 }
181
182 /**
183 * Converts the source instance to a {@link SAXSource} or returns null if the conversion is not
184 * supported (making it easy to derive from this class to add new kinds of conversion).
185 */
186 @Converter
187 public SAXSource toSAXSource(Source source) throws IOException, SAXException, TransformerException {
188 if (source instanceof SAXSource) {
189 return (SAXSource) source;
190 }
191 else if (source instanceof DOMSource) {
192 return toSAXSourceFromDOM((DOMSource) source);
193 }
194 else if (source instanceof StreamSource) {
195 return toSAXSourceFromStream((StreamSource) source);
196 }
197 else {
198 return null;
199 }
200 }
201
202 @Converter
203 public StreamSource toStreamSource(Source source) throws TransformerException {
204 if (source instanceof StreamSource) {
205 return (StreamSource) source;
206 } else if (source instanceof DOMSource) {
207 return toStreamSourceFromDOM((DOMSource) source);
208 } else if (source instanceof SAXSource) {
209 return toStreamSourceFromSAX((SAXSource) source);
210 } else {
211 return null;
212 }
213 }
214
215 @Converter
216 public StreamSource toStreamSourceFromSAX(SAXSource source) throws TransformerException {
217 InputSource inputSource = source.getInputSource();
218 if (inputSource != null) {
219 if (inputSource.getCharacterStream() != null) {
220 return new StreamSource(inputSource.getCharacterStream());
221 }
222 if (inputSource.getByteStream() != null) {
223 return new StreamSource(inputSource.getByteStream());
224 }
225 }
226 String result = toString(source);
227 return new StringSource(result);
228 }
229
230 @Converter
231 public StreamSource toStreamSourceFromDOM(DOMSource source) throws TransformerException {
232 String result = toString(source);
233 return new StringSource(result);
234 }
235
236 @Converter
237 public SAXSource toSAXSourceFromStream(StreamSource source) {
238 InputSource inputSource;
239 if (source.getReader() != null) {
240 inputSource = new InputSource(source.getReader());
241 } else {
242 inputSource = new InputSource(source.getInputStream());
243 }
244 inputSource.setSystemId(source.getSystemId());
245 inputSource.setPublicId(source.getPublicId());
246 return new SAXSource(inputSource);
247 }
248
249 @Converter
250 public Reader toReaderFromSource(Source src) throws TransformerException {
251 StreamSource stSrc = toStreamSource(src);
252 Reader r = stSrc.getReader();
253 if (r == null) {
254 r = new InputStreamReader(stSrc.getInputStream());
255 }
256 return r;
257 }
258
259 @Converter
260 public DOMSource toDOMSourceFromStream(StreamSource source) throws ParserConfigurationException, IOException, SAXException {
261 DocumentBuilder builder = createDocumentBuilder();
262 String systemId = source.getSystemId();
263 Document document = null;
264 Reader reader = source.getReader();
265 if (reader != null) {
266 document = builder.parse(new InputSource(reader));
267 } else {
268 InputStream inputStream = source.getInputStream();
269 if (inputStream != null) {
270 InputSource inputsource = new InputSource(inputStream);
271 inputsource.setSystemId(systemId);
272 document = builder.parse(inputsource);
273 }
274 else {
275 throw new IOException("No input stream or reader available");
276 }
277 }
278 return new DOMSource(document, systemId);
279 }
280
281 @Converter
282 public SAXSource toSAXSourceFromDOM(DOMSource source) throws TransformerException {
283 if (dom2SaxClass != null) {
284 try {
285 Constructor cns = dom2SaxClass.getConstructor(new Class[] { Node.class });
286 XMLReader converter = (XMLReader) cns.newInstance(new Object[] { source.getNode() });
287 return new SAXSource(converter, new InputSource());
288 } catch (Exception e) {
289 throw new TransformerException(e);
290 }
291 } else {
292 String str = toString(source);
293 StringReader reader = new StringReader(str);
294 return new SAXSource(new InputSource(reader));
295 }
296 }
297
298 @Converter
299 public DOMSource toDOMSourceFromSAX(SAXSource source) throws IOException, SAXException, ParserConfigurationException, TransformerException {
300 return new DOMSource(toDOMNodeFromSAX(source));
301 }
302
303 @Converter
304 public Node toDOMNodeFromSAX(SAXSource source) throws ParserConfigurationException, IOException, SAXException, TransformerException {
305 DOMResult result = new DOMResult();
306 toResult(source, result);
307 return result.getNode();
308 }
309
310 /**
311 * Converts the given TRaX Source into a W3C DOM node
312 * @throws SAXException
313 * @throws IOException
314 * @throws ParserConfigurationException
315 */
316 @Converter
317 public Node toDOMNode(Source source) throws TransformerException, ParserConfigurationException, IOException, SAXException {
318 DOMSource domSrc = toDOMSource(source);
319 return domSrc != null ? domSrc.getNode() : null;
320 }
321
322 /**
323 * Create a DOM element from the given source.
324 *
325 * @param source
326 * @return
327 * @throws TransformerException
328 * @throws ParserConfigurationException
329 * @throws IOException
330 * @throws SAXException
331 */
332 @Converter
333 public Element toDOMElement(Source source) throws TransformerException, ParserConfigurationException, IOException, SAXException {
334 Node node = toDOMNode(source);
335 return toDOMElement(node);
336 }
337
338 /**
339 * Create a DOM element from the DOM node.
340 * Simply cast if the node is an Element, or
341 * return the root element if it is a Document.
342 *
343 * @param node
344 * @return
345 * @throws TransformerException
346 */
347 @Converter
348 public Element toDOMElement(Node node) throws TransformerException {
349 // If the node is an document, return the root element
350 if (node instanceof Document) {
351 return ((Document) node).getDocumentElement();
352 // If the node is an element, just cast it
353 } else if (node instanceof Element) {
354 return (Element) node;
355 // Other node types are not handled
356 } else {
357 throw new TransformerException("Unable to convert DOM node to an Element");
358 }
359 }
360
361 /**
362 * Converts the given data to a DOM document
363 *
364 * @param data is the data to be parsed
365 * @return the parsed document
366 */
367 @Converter
368 public Document toDOMDocument(byte[] data) throws IOException, SAXException, ParserConfigurationException {
369 DocumentBuilder documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
370 return documentBuilder.parse(new ByteArrayInputStream(data));
371 }
372
373 /**
374 * Converts the given {@link InputStream} to a DOM document
375 *
376 * @param in is the data to be parsed
377 * @return the parsed document
378 */
379 @Converter
380 public Document toDOMDocument(InputStream in) throws IOException, SAXException, ParserConfigurationException {
381 DocumentBuilder documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
382 return documentBuilder.parse(in);
383 }
384
385 /**
386 * Converts the given {@link InputSource} to a DOM document
387 *
388 * @param in is the data to be parsed
389 * @return the parsed document
390 */
391 @Converter
392 public Document toDOMDocument(InputSource in) throws IOException, SAXException, ParserConfigurationException {
393 DocumentBuilder documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
394 return documentBuilder.parse(in);
395 }
396
397 /**
398 * Converts the given {@link String} to a DOM document
399 *
400 * @param text is the data to be parsed
401 * @return the parsed document
402 */
403 @Converter
404 public Document toDOMDocument(String text) throws IOException, SAXException, ParserConfigurationException {
405 return toDOMDocument(text.getBytes());
406 }
407
408 /**
409 * Converts the given {@link File} to a DOM document
410 *
411 * @param file is the data to be parsed
412 * @return the parsed document
413 */
414 @Converter
415 public Document toDOMDocument(File file) throws IOException, SAXException, ParserConfigurationException {
416 DocumentBuilder documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
417 return documentBuilder.parse(file);
418 }
419
420
421 /**
422 * Create a DOM document from the given source.
423 *
424 * @param source
425 * @return
426 * @throws TransformerException
427 * @throws ParserConfigurationException
428 * @throws IOException
429 * @throws SAXException
430 */
431 @Converter
432 public Document toDOMDocument(Source source) throws TransformerException, ParserConfigurationException, IOException, SAXException {
433 Node node = toDOMNode(source);
434 return toDOMDocument(node);
435 }
436
437 /**
438 * Create a DOM document from the given Node.
439 * If the node is an document, just cast it,
440 * if the node is an root element, retrieve its
441 * owner element or create a new document and import
442 * the node.
443 *
444 * @param node
445 * @return
446 * @throws ParserConfigurationException
447 * @throws TransformerException
448 */
449 @Converter
450 public Document toDOMDocument(Node node) throws ParserConfigurationException, TransformerException {
451 // If the node is the document, just cast it
452 if (node instanceof Document) {
453 return (Document) node;
454 // If the node is an element
455 } else if (node instanceof Element) {
456 Element elem = (Element) node;
457 // If this is the root element, return its owner document
458 if (elem.getOwnerDocument().getDocumentElement() == elem) {
459 return elem.getOwnerDocument();
460 // else, create a new doc and copy the element inside it
461 } else {
462 Document doc = createDocument();
463 doc.appendChild(doc.importNode(node, true));
464 return doc;
465 }
466 // other element types are not handled
467 } else {
468 throw new TransformerException("Unable to convert DOM node to a Document");
469 }
470 }
471
472 // Properties
473 //-------------------------------------------------------------------------
474 public DocumentBuilderFactory getDocumentBuilderFactory() {
475 if (documentBuilderFactory == null) {
476 documentBuilderFactory = createDocumentBuilderFactory();
477 }
478 return documentBuilderFactory;
479 }
480
481 public void setDocumentBuilderFactory(DocumentBuilderFactory documentBuilderFactory) {
482 this.documentBuilderFactory = documentBuilderFactory;
483 }
484
485
486 // Helper methods
487 //-------------------------------------------------------------------------
488 public DocumentBuilderFactory createDocumentBuilderFactory() {
489 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
490 factory.setNamespaceAware(true);
491 factory.setIgnoringElementContentWhitespace(true);
492 factory.setIgnoringComments(true);
493 return factory;
494 }
495
496
497 public DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
498 DocumentBuilderFactory factory = getDocumentBuilderFactory();
499 return factory.newDocumentBuilder();
500 }
501
502 public Document createDocument() throws ParserConfigurationException {
503 DocumentBuilder builder = createDocumentBuilder();
504 return builder.newDocument();
505 }
506
507 public TransformerFactory getTransformerFactory() {
508 if (transformerFactory == null) {
509 transformerFactory = createTransformerFactory();
510 }
511 return transformerFactory;
512 }
513
514 public void setTransformerFactory(TransformerFactory transformerFactory) {
515 this.transformerFactory = transformerFactory;
516 }
517
518 public Transformer createTransfomer() throws TransformerConfigurationException {
519 TransformerFactory factory = getTransformerFactory();
520 return factory.newTransformer();
521 }
522
523 public TransformerFactory createTransformerFactory() {
524 TransformerFactory answer = TransformerFactory.newInstance();
525 return answer;
526 }
527
528 }