Coverage Report - org.apache.commons.xmlio.out.XMLEncode
 
Classes in this File Line Coverage Branch Coverage Complexity
XMLEncode
0%
0/104
0%
0/112
5.077
 
 1  
 /*
 2  
  * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons-sandbox//xmlio/src/java/org/apache/commons/xmlio/out/XMLEncode.java,v 1.1 2004/10/08 11:56:20 ozeigermann Exp $
 3  
  * $Revision: 155476 $
 4  
  * $Date: 2005-02-26 13:31:24 +0000 (Sat, 26 Feb 2005) $
 5  
  *
 6  
  * ====================================================================
 7  
  *
 8  
  * Copyright 2004 The Apache Software Foundation 
 9  
  *
 10  
  * Licensed under the Apache License, Version 2.0 (the "License");
 11  
  * you may not use this file except in compliance with the License.
 12  
  * You may obtain a copy of the License at
 13  
  *
 14  
  *     http://www.apache.org/licenses/LICENSE-2.0
 15  
  *
 16  
  * Unless required by applicable law or agreed to in writing, software
 17  
  * distributed under the License is distributed on an "AS IS" BASIS,
 18  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 19  
  * See the License for the specific language governing permissions and
 20  
  * limitations under the License.
 21  
  *
 22  
  */
 23  
 
 24  
 package org.apache.commons.xmlio.out;
 25  
 
 26  
 /**
 27  
  * Collection of XML encoding/decoding helpers. <br>
 28  
  * This is all about the special characters &amp; and &lt;, and for attributes
 29  
  * &quot; and &apos;. These must be encoded/decoded from/to XML.
 30  
  *
 31  
  */
 32  0
 public final class XMLEncode {
 33  
 
 34  
     private final static int CDATA_BLOCK_THRESHOLD_LENGTH = 12;
 35  
     private final static char DEFAULT_QUOTE_CHAR = '"';
 36  
 
 37  
     /** Checks if this text purely consists of the white space characters
 38  
      * ' ',  TAB, NEWLINE.
 39  
      */
 40  
     public final static boolean isWhiteSpace(String text) {
 41  0
         for (int i = 0; i < text.length(); i++) {
 42  0
             char c = text.charAt(i);
 43  0
             if (Character.isWhitespace(c)) {
 44  0
                 continue;
 45  
             } else {
 46  0
                 return false;
 47  
             }
 48  
         }
 49  0
         return true;
 50  
     }
 51  
 
 52  
     /** Makes any text fit into XML attributes. */
 53  
     public final static String xmlEncodeTextForAttribute(String text, char quoteChar) {
 54  0
         if (text == null)
 55  0
             return null;
 56  0
         return xmlEncodeTextAsPCDATA(text, true, quoteChar);
 57  
     }
 58  
 
 59  
     /** Encodes text as XML in the most suitable way, either CDATA block or PCDATA. */
 60  
     public final static String xmlEncodeText(String text) {
 61  0
         if (text == null)
 62  0
             return null;
 63  0
         if (!needsEncoding(text)) {
 64  0
             return text;
 65  
         } else {
 66  
             // only encode as cdata if is is longer than CDATA block overhead:
 67  0
             if (text.length() > CDATA_BLOCK_THRESHOLD_LENGTH) {
 68  0
                 String cdata = xmlEncodeTextAsCDATABlock(text);
 69  0
                 if (cdata != null) {
 70  0
                     return cdata;
 71  
                 }
 72  
             }
 73  
         }
 74  
         // if every thing else fails, do it the save way...
 75  0
         return xmlEncodeTextAsPCDATA(text);
 76  
     }
 77  
 
 78  
     /** Encodes any text as PCDATA. */
 79  
     public final static String xmlEncodeTextAsPCDATA(String text) {
 80  0
         if (text == null)
 81  0
             return null;
 82  0
         return xmlEncodeTextAsPCDATA(text, false);
 83  
     }
 84  
 
 85  
     /** Encodes any text as PCDATA. 
 86  
      * @param forAttribute if you want
 87  
      * quotes and apostrophes specially treated for attributes
 88  
      */
 89  
     public final static String xmlEncodeTextAsPCDATA(String text, boolean forAttribute) {
 90  0
         return xmlEncodeTextAsPCDATA(text, forAttribute, DEFAULT_QUOTE_CHAR);
 91  
     }
 92  
 
 93  
     /** Encodes any text as PCDATA. 
 94  
      * @param forAttribute if you want
 95  
      * quotes and apostrophes specially treated for attributes
 96  
      * @param quoteChar if this is for attributes this <code>char</code> is used to quote the attribute value
 97  
      */
 98  
     public final static String xmlEncodeTextAsPCDATA(String text, boolean forAttribute, char quoteChar) {
 99  0
         if (text == null)
 100  0
             return null;
 101  
         char c;
 102  0
         StringBuffer n = new StringBuffer(text.length() * 2);
 103  0
         for (int i = 0; i < text.length(); i++) {
 104  0
             c = text.charAt(i);
 105  0
             switch (c) {
 106  
                 case '&' :
 107  0
                     n.append("&amp;");
 108  0
                     break;
 109  
                 case '<' :
 110  0
                     n.append("&lt;");
 111  0
                     break;
 112  
                 case '>' : // FIX for sourceforge bug #802520 ("]]>" needs encoding)
 113  0
                     n.append("&gt;");
 114  0
                     break;
 115  
                 case '"' :
 116  0
                     if (forAttribute)
 117  0
                         n.append("&quot;");
 118  
                     else
 119  0
                         n.append(c);
 120  0
                     break;
 121  
                 case '\'' :
 122  0
                     if (forAttribute)
 123  0
                         n.append("&apos;");
 124  
                     else
 125  0
                         n.append(c);
 126  0
                     break;
 127  
                 default :
 128  
                     {
 129  0
                         n.append(c);
 130  
                         break;
 131  
                     }
 132  
             }
 133  
         }
 134  
 
 135  0
         if (forAttribute) {
 136  0
             n.append(quoteChar);
 137  0
             n.insert(0, quoteChar);
 138  
         }
 139  
 
 140  0
         return n.toString();
 141  
     }
 142  
 
 143  
     /** Returns string as CDATA block if possible, otherwise null. */
 144  
     public final static String xmlEncodeTextAsCDATABlock(String text) {
 145  0
         if (text == null)
 146  0
             return null;
 147  0
         if (isCompatibleWithCDATABlock(text)) {
 148  0
             return "<![CDATA[" + text + "]]>";
 149  
         } else {
 150  0
             return null;
 151  
         }
 152  
     }
 153  
 
 154  
     /** Checks if this text needs encoding in order to be represented in XML. */
 155  
     public final static boolean needsEncoding(String text) {
 156  0
         return needsEncoding(text, false);
 157  
     }
 158  
 
 159  
     /** Checks if this text needs encoding in order to be represented in XML.
 160  
      * 
 161  
      * Set <code>checkForAttr</code> if you want to check for storability in 
 162  
      * an attribute. 
 163  
      */
 164  
     public final static boolean needsEncoding(String data, boolean checkForAttr) {
 165  0
         if (data == null)
 166  0
             return false;
 167  
         char c;
 168  0
         for (int i = 0; i < data.length(); i++) {
 169  0
             c = data.charAt(i);
 170  0
             if (c == '&' || c == '<' || (checkForAttr && (c == '"' || c == '\'')))
 171  0
                 return true;
 172  
         }
 173  0
         return false;
 174  
     }
 175  
 
 176  
     /** Can this text be stored into a CDATA block? */
 177  
     public final static boolean isCompatibleWithCDATABlock(String text) {
 178  0
         if (text == null)
 179  0
             return false;
 180  0
         return (text.indexOf("]]>") == -1);
 181  
     }
 182  
 
 183  
     /** Make CDATA out of possibly encoded PCDATA. <br>
 184  
      * E.g. make '&amp;' out of '&amp;amp;'
 185  
      */
 186  
     public final static String xmlDecodeTextToCDATA(String pcdata) {
 187  0
         if (pcdata == null)
 188  0
             return null;
 189  
         char c, c1, c2, c3, c4, c5;
 190  0
         StringBuffer n = new StringBuffer(pcdata.length());
 191  0
         for (int i = 0; i < pcdata.length(); i++) {
 192  0
             c = pcdata.charAt(i);
 193  0
             if (c == '&') {
 194  0
                 c1 = lookAhead(1, i, pcdata);
 195  0
                 c2 = lookAhead(2, i, pcdata);
 196  0
                 c3 = lookAhead(3, i, pcdata);
 197  0
                 c4 = lookAhead(4, i, pcdata);
 198  0
                 c5 = lookAhead(5, i, pcdata);
 199  
 
 200  0
                 if (c1 == 'a' && c2 == 'm' && c3 == 'p' && c4 == ';') {
 201  0
                     n.append("&");
 202  0
                     i += 4;
 203  0
                 } else if (c1 == 'l' && c2 == 't' && c3 == ';') {
 204  0
                     n.append("<");
 205  0
                     i += 3;
 206  0
                 } else if (c1 == 'g' && c2 == 't' && c3 == ';') {
 207  0
                     n.append(">");
 208  0
                     i += 3;
 209  0
                 } else if (c1 == 'q' && c2 == 'u' && c3 == 'o' && c4 == 't' && c5 == ';') {
 210  0
                     n.append("\"");
 211  0
                     i += 5;
 212  0
                 } else if (c1 == 'a' && c2 == 'p' && c3 == 'o' && c4 == 's' && c5 == ';') {
 213  0
                     n.append("'");
 214  0
                     i += 5;
 215  
                 } else
 216  0
                     n.append("&");
 217  
             } else
 218  0
                 n.append(c);
 219  
         }
 220  0
         return n.toString();
 221  
     }
 222  
 
 223  
     private final static char lookAhead(int la, int offset, String data) {
 224  
         try {
 225  0
             return data.charAt(offset + la);
 226  0
         } catch (StringIndexOutOfBoundsException e) {
 227  0
             return 0x0;
 228  
         }
 229  
     }
 230  
 
 231  
     // combine multiple checks in one methods for speed
 232  
     private final static boolean contains(String text, char[] chars) {
 233  0
         if (text == null || chars == null || chars.length == 0) {
 234  0
             return false;
 235  
         }
 236  0
         for (int i = 0; i < text.length(); i++) {
 237  0
             char c = text.charAt(i);
 238  0
             for (int j = 0; j < chars.length; j++) {
 239  0
                 if (chars[j] == c) {
 240  0
                     return true;
 241  
                 }
 242  
             }
 243  
         }
 244  0
         return false;
 245  
     }
 246  
 
 247  
 }