root/trunk/src/java/org/jcoderz/commons/util/XmlUtil.java

Revision 1633, 11.2 kB (checked in by amandel, 21 months ago)

#81 open the stream directly in StreamSource? to avoid whitespace in path issue.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.commons.util;
34
35import java.io.File;
36import java.io.FileOutputStream;
37import java.io.IOException;
38import javax.xml.transform.stream.StreamResult;
39import org.xml.sax.Attributes;
40
41/**
42 * This class holds utility methods for common xml topics.
43 *
44 * @author Andreas Mandel
45 */
46public final class XmlUtil
47{
48   /**
49    * Immutable and always empty version of a
50    * {@link org.xml.sax.Attributes} object.
51    */
52    public static final Attributes EMPTY_ATTRIBUTES = new EmptyAttribute();
53
54    private static final int INDENT = 2;
55    private static final String SPACES = "                           ";
56
57   /** No instances. */
58   private XmlUtil ()
59   {
60      //  No instances.
61   }
62
63   /**
64    * Immutable implementation of a empty attribute list.
65    * @see Attributes
66    */
67   private static final class EmptyAttribute
68         implements Attributes
69   {
70       /** {@inheritDoc} */
71      public int getLength ()
72      {
73         return 0;
74      }
75
76      /** {@inheritDoc} */
77      public String getLocalName (int index)
78      {
79         return null;
80      }
81
82      /** {@inheritDoc} */
83      public String getQName (int index)
84      {
85         return null;
86      }
87
88      /** {@inheritDoc} */
89      public String getType (int index)
90      {
91         return null;
92      }
93
94      /** {@inheritDoc} */
95      public String getURI (int index)
96      {
97         return null;
98      }
99
100      /** {@inheritDoc} */
101      public String getValue (int index)
102      {
103         return null;
104      }
105
106      /** {@inheritDoc} */
107      public int getIndex (String qName)
108      {
109         return -1;
110      }
111
112      /** {@inheritDoc} */
113      public String getType (String qName)
114      {
115         return null;
116      }
117
118      /** {@inheritDoc} */
119      public String getValue (String qName)
120      {
121         return null;
122      }
123
124      /** {@inheritDoc} */
125      public int getIndex (String uri, String localName)
126      {
127         return -1;
128      }
129
130      /** {@inheritDoc} */
131      public String getType (String uri, String localName)
132      {
133         return null;
134      }
135
136      /** {@inheritDoc} */
137      public String getValue (String uri, String localName)
138      {
139         return null;
140      }
141   }
142
143   /**
144    * Encode a string so that it can be safely used as attribute value in
145    * XML output.
146    * @param attribute the attribute value to be encoded.
147    * @return a string representing the attribute value that can be safely
148    *         used in XML output.
149    */
150   public static String attributeEscape (String attribute)
151   {
152      final StringBuffer sb = new StringBuffer();
153      if (attribute != null)
154      {
155         char c;
156         final int l = attribute.length();
157         for (int i = 0; i < l; i++)
158         {
159            c = attribute.charAt(i);
160            switch (c)
161            {
162               case '<':
163                  sb.append("&lt;");
164                  break;
165               case '>':
166                   sb.append("&gt;");
167                   break;
168               case '\'':
169                  sb.append("&apos;");
170                  break;
171               case '"':
172                   sb.append("&quot;");
173                   break;
174               case '&':
175                  sb.append("&amp;");
176                  break;
177               default :
178                  if (c > Byte.MAX_VALUE
179                      || Character.isISOControl(c))
180                  {
181                     sb.append("&#x");
182                     sb.append(Integer.toHexString(c));
183                     sb.append(';');
184                  }
185                  else
186                  {
187                     sb.append(c);
188                  }
189            }
190         }
191      }
192      return sb.toString();
193   }
194
195   /**
196    * Encode a string so that it can be safely used as text in an element
197    * for XML output.
198    * @param text the element text body.
199    * @return a string so that it can be safely used as text in an element
200    *       for XML output.
201    */
202   public static String escape (String text)
203   {
204      final StringBuffer sb = new StringBuffer();
205      if (text != null)
206      {
207         char c;
208         final int l = text.length();
209         for (int i = 0; i < l; i++)
210         {
211            c = text.charAt(i);
212            switch (c)
213            {
214               case '<':
215                  sb.append("&lt;");
216                  break;
217               case '>':  // only needed to avoid ]]>
218                   sb.append("&gt;");
219                   break;
220               case '&':
221                  sb.append("&amp;");
222                  break;
223               default :
224                  if (c > Byte.MAX_VALUE)
225                  {
226                     sb.append("&#x");
227                     sb.append(Integer.toHexString(c));
228                     sb.append(';');
229                  }
230                  else
231                  {
232                     sb.append(c);
233                  }
234            }
235         }
236      }
237      return sb.toString();
238   }
239
240   /**
241    * Simple xml formatter.
242    * This code might fail for several input. In this case the
243    * original input is returned.
244    * @param org the input to be formated.
245    * @return the input in xml formated (human readable) form or the
246    *   input string.
247    */
248   public static String formatXml (String org)
249   {
250      String result = org;
251      try
252      {
253         final String in = org.trim();
254         if (in.charAt(0) == '<') // && sb.charAt(1) == '?')
255         {
256             final StringBuffer sb = new StringBuffer();
257             boolean nestedTag = false;
258             int indent = 0;
259             for (int t = 0; t < in.length(); t++)
260             {
261               char c = in.charAt(t);
262
263               switch (c)
264               {
265                  case '<':
266                     t++;
267                     c = in.charAt(t);
268                     switch (c)
269                     {
270                        case '/':
271                           if (!nestedTag)
272                           {
273                              indent -= INDENT;
274                              sb.append("</");
275                           }
276                           else
277                           {
278                              sb.append('\n');
279                              indent -= INDENT;
280                              indent(indent, sb);
281                              sb.append("</");
282                           }
283                           nestedTag = true;
284                           break;
285                        case '?':
286                        case '!':
287                           if (t != 1)
288                           {
289                               sb.append('\n');
290                           }
291                           sb.append('<');
292                           sb.append(c);
293                           break;
294                        default:
295                           nestedTag = false;
296                           if (sb.length() > 0)
297                           {
298                               sb.append('\n');
299                           }
300                           indent(indent, sb);
301                           sb.append('<');
302                           sb.append(c);
303                           indent += INDENT;
304                           break;
305                     }
306                     break;
307                  case '/':
308                      sb.append(c);
309                     if (in.charAt(t + 1) == '>')
310                     {
311                        indent -= INDENT;
312                        nestedTag = true;
313                     }
314                     break;
315                  case '\n':
316                  case '\r':
317                     break;
318                  case '>':
319                  default:
320                      sb.append(c);
321                     break;
322               }
323            }
324            result = sb.toString();
325         }
326      }
327      catch (Exception ex)
328      {
329         result = org;
330         // CHECKME: Nicer exception handling no formated output...
331      }
332      return result;
333   }
334
335    /**
336     * Creae a stream result based on a File.
337     * Other than the default implementation not only the File is used to
338     * initialize the result, but also a Stream is opened and initialized.
339     * This works around an issue with whitespaces in the pathname which
340     * otherwise would lead to a file not found exception
341     * <pre>
342     * Error during transformation: javax.xml.transform.TransformerException: java.io.FileNotFoundException: ...%20...
343     *   at org.apache.xalan.transformer.TransformerImpl.createSerializationHandler(TransformerImpl.java:1218)
344     *   at org.apache.xalan.transformer.TransformerImpl.createSerializationHandler(TransformerImpl.java:1060)
345     *   at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1268)
346     *   at org.apache.xalan.transformer.TransformerImpl.transform(TransformerImpl.java:1251)
347     *   ....
348     * </pre>.
349     * The caller must ensure that the created outputstream is closed.
350     * @param outFile the file to be used in the stream result.
351     * @return a new StreamResult piontint to the given File.
352     * @throws IOException in case of an issue while creating the stream.
353     */
354    public static StreamResult createStreamResult(File outFile)
355        throws IOException
356    {
357        final StreamResult result = new StreamResult(outFile);
358        // set the stream directly to avoid issues with blanks in the
359        // filename.
360        result.setOutputStream(new FileOutputStream(outFile));
361        return result;
362    }
363
364   private static void indent (final int i, StringBuffer b)
365   {
366       if (i > SPACES.length())
367       {
368           b.append(SPACES);
369           indent(i - SPACES.length(), b);
370       }
371       else
372       {
373           b.append(SPACES.substring(0, i));
374       }
375   }
376
377
378}
Note: See TracBrowser for help on using the browser.