View Javadoc

1   /*
2    * $Id: AbstractXmlTransformer.java 7976 2007-08-21 14:26:13Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transformers.xml;
12  
13  import org.mule.transformers.AbstractTransformer;
14  
15  import java.io.ByteArrayInputStream;
16  import java.io.StringReader;
17  import java.io.StringWriter;
18  
19  import javax.xml.transform.OutputKeys;
20  import javax.xml.transform.Result;
21  import javax.xml.transform.Source;
22  import javax.xml.transform.Transformer;
23  import javax.xml.transform.TransformerFactory;
24  import javax.xml.transform.TransformerFactoryConfigurationError;
25  import javax.xml.transform.dom.DOMResult;
26  import javax.xml.transform.dom.DOMSource;
27  import javax.xml.transform.stream.StreamResult;
28  import javax.xml.transform.stream.StreamSource;
29  
30  import org.apache.commons.io.output.ByteArrayOutputStream;
31  import org.dom4j.Document;
32  import org.dom4j.io.DocumentResult;
33  import org.dom4j.io.DocumentSource;
34  
35  /**
36   * <code>AbstractXmlTransformer</code> offers some XSLT transform on a DOM (or
37   * other XML-ish) object.
38   */
39  
40  public abstract class AbstractXmlTransformer extends AbstractTransformer
41  {
42      private String outputEncoding;
43  
44      public AbstractXmlTransformer()
45      {
46          registerSourceType(String.class);
47          registerSourceType(byte[].class);
48          registerSourceType(DocumentSource.class);
49          registerSourceType(Document.class);
50          registerSourceType(org.w3c.dom.Document.class);
51          registerSourceType(org.w3c.dom.Element.class);
52      }
53  
54      public Source getXmlSource(Object src)
55      {
56          if (src instanceof byte[])
57          {
58              return new StreamSource(new ByteArrayInputStream((byte[])src));
59          }
60          else if (src instanceof String)
61          {
62              return new StreamSource(new StringReader((String)src));
63          }
64          else if (src instanceof DocumentSource)
65          {
66              return (Source)src;
67          }
68          else if (src instanceof Document)
69          {
70              return new DocumentSource((Document)src);
71          }
72          else if (src instanceof org.w3c.dom.Document || src instanceof org.w3c.dom.Element)
73          {
74              return new DOMSource((org.w3c.dom.Node)src);
75          }
76          else
77              return null;
78      }
79  
80      /**
81       * Result callback interface used when processing XML through JAXP
82       */
83      protected static interface ResultHolder
84      {
85  
86          /**
87           * @return A Result to use in a transformation (e.g. writing a DOM to a
88           *         stream)
89           */
90          Result getResult();
91  
92          /**
93           * @return The actual result as produced after the call to 'transform'.
94           */
95          Object getResultObject();
96      }
97  
98      /**
99       * @param desiredClass Java class representing the desired format
100      * @return Callback interface representing the desiredClass - or null if the
101      *         return class isn't supported (or is null).
102      */
103     protected static ResultHolder getResultHolder(Class desiredClass)
104     {
105         if (desiredClass == null) return null;
106         if (byte[].class.equals(desiredClass))
107         {
108             return new ResultHolder()
109             {
110                 ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
111                 StreamResult result = new StreamResult(resultStream);
112 
113                 public Result getResult()
114                 {
115                     return result;
116                 }
117 
118                 public Object getResultObject()
119                 {
120                     return resultStream.toByteArray();
121                 }
122             };
123         }
124         else if (String.class.equals(desiredClass))
125         {
126             return new ResultHolder()
127             {
128                 StringWriter writer = new StringWriter();
129                 StreamResult result = new StreamResult(writer);
130 
131                 public Result getResult()
132                 {
133                     return result;
134                 }
135 
136                 public Object getResultObject()
137                 {
138                     return writer.getBuffer().toString();
139                 }
140             };
141         }
142         else if (org.w3c.dom.Document.class.isAssignableFrom(desiredClass))
143         {
144             return new ResultHolder()
145             {
146                 DOMResult result = new DOMResult();
147 
148                 public Result getResult()
149                 {
150                     return result;
151                 }
152 
153                 public Object getResultObject()
154                 {
155                     return result.getNode();
156                 }
157             };
158         }
159         else if (org.dom4j.io.DocumentResult.class.isAssignableFrom(desiredClass))
160         {
161             return new ResultHolder()
162             {
163                 DocumentResult result = new DocumentResult();
164 
165                 public Result getResult()
166                 {
167                     return result;
168                 }
169 
170                 public Object getResultObject()
171                 {
172                     return result;
173                 }
174             };
175         }
176         else if (org.dom4j.Document.class.isAssignableFrom(desiredClass))
177         {
178             return new ResultHolder()
179             {
180                 DocumentResult result = new DocumentResult();
181 
182                 public Result getResult()
183                 {
184                     return result;
185                 }
186 
187                 public Object getResultObject()
188                 {
189                     return result.getDocument();
190                 }
191             };
192         }
193         return null;
194     }
195 
196     /**
197      * Converts an XML in-memory representation to a String
198      * 
199      * @param obj Object to convert (could be byte[], String, DOM, DOM4J) 
200      * @return String including XML header using default (UTF-8) encoding  
201 
202      * @throws TransformerFactoryConfigurationError On error
203      * @throws javax.xml.transform.TransformerException On error
204      * 
205      * @deprecated Replaced by convertToText(Object obj, String ouputEncoding) 
206      */
207     protected String convertToText(Object obj)
208         throws TransformerFactoryConfigurationError, javax.xml.transform.TransformerException
209     {
210         return convertToText(obj, null);
211     }
212 
213     /**
214      * Converts an XML in-memory representation to a String using a specific encoding.
215      * If using an encoding which cannot represent specific characters, these are
216      * written as entities, even if they can be represented as a Java String.
217      * 
218      * @param obj Object to convert (could be byte[], String, DOM, or DOM4J Document).
219      * If the object is a byte[], the character
220      * encoding used MUST match the declared encoding standard, or a parse error will occur.
221      * @param outputEncoding Name of the XML encoding to use, e.g. US-ASCII, or null for UTF-8
222      * @return String including XML header using the specified encoding  
223 
224      * @throws TransformerFactoryConfigurationError On error
225      * @throws javax.xml.transform.TransformerException On error
226      */
227     protected String convertToText(Object obj, String outputEncoding)
228     throws TransformerFactoryConfigurationError, javax.xml.transform.TransformerException
229     {
230         // Catch the direct translations
231         if (obj instanceof String)
232         {
233             return (String)obj;
234         }
235         else if (obj instanceof Document)
236         {
237             return ((Document)obj).asXML();
238         }
239         // No easy fix, so use the transformer.
240         Source src = getXmlSource(obj);
241         if (src == null) return null;
242 
243         StringWriter writer = new StringWriter();
244         StreamResult result = new StreamResult(writer);
245 
246         Transformer idTransformer = TransformerFactory.newInstance().newTransformer();
247         if (outputEncoding != null)
248         {
249             idTransformer.setOutputProperty(OutputKeys.ENCODING, outputEncoding);
250         }
251         idTransformer.transform(src, result);
252         return writer.getBuffer().toString();
253     }
254     
255     /**
256      * Converts an XML in-memory representation to a String using a specific encoding.
257      * 
258      * @param obj Object to convert (could be byte[], String, DOM, or DOM4J Document).
259      * If the object is a byte[], the character
260      * encoding used MUST match the declared encoding standard, or a parse error will occur.
261      *   
262      * @param outputEncoding Name of the XML encoding to use, e.g. US-ASCII, or null for UTF-8
263      * @return String including XML header using the specified encoding  
264 
265      * @throws TransformerFactoryConfigurationError On error
266      * @throws javax.xml.transform.TransformerException On error
267      */
268     protected String convertToBytes(Object obj, String outputEncoding)
269         throws TransformerFactoryConfigurationError, javax.xml.transform.TransformerException
270     {
271         // Always use the transformer, even for byte[] (to get the encoding right!)
272         Source src = getXmlSource(obj);
273         if (src == null) return null;
274 
275         StringWriter writer = new StringWriter();
276         StreamResult result = new StreamResult(writer);
277 
278         Transformer idTransformer = TransformerFactory.newInstance().newTransformer();
279         idTransformer.setOutputProperty(OutputKeys.ENCODING, outputEncoding);
280         idTransformer.transform(src, result);
281         return writer.getBuffer().toString();
282     }
283 
284     /**
285      * @return the outputEncoding
286      */
287     public String getOutputEncoding()
288     {
289         return outputEncoding;
290     }
291 
292     /**
293      * @param outputEncoding the outputEncoding to set
294      */
295     public void setOutputEncoding(String outputEncoding)
296     {
297         this.outputEncoding = outputEncoding;
298     }
299         
300 }