Clover coverage report - Clover results for XOM 1.2d1
Coverage timestamp: Wed Feb 8 2006 08:31:33 EST
file stats: LOC: 466   Methods: 17
NCLOC: 251   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Text.java 0% 0% 0% 0%
coverage
 1    /* Copyright 2002-2005 Elliotte Rusty Harold
 2   
 3    This library is free software; you can redistribute it and/or modify
 4    it under the terms of version 2.1 of the GNU Lesser General Public
 5    License as published by the Free Software Foundation.
 6   
 7    This library is distributed in the hope that it will be useful,
 8    but WITHOUT ANY WARRANTY; without even the implied warranty of
 9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 10    GNU Lesser General Public License for more details.
 11   
 12    You should have received a copy of the GNU Lesser General Public
 13    License along with this library; if not, write to the
 14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 15    Boston, MA 02111-1307 USA
 16   
 17    You can contact Elliotte Rusty Harold by sending e-mail to
 18    elharo@metalab.unc.edu. Please include the word "XOM" in the
 19    subject line. The XOM home page is located at http://www.xom.nu/
 20    */
 21   
 22    package nu.xom;
 23   
 24    import java.io.UnsupportedEncodingException;
 25   
 26    /**
 27    * <p>
 28    * This class represents a run of text.
 29    * CDATA sections are not treated differently than
 30    * normal text. <code>Text</code> objects may be adjacent to other
 31    * <code>Text</code> objects.
 32    * </p>
 33   
 34    * @author Elliotte Rusty Harold
 35    * @version 1.1b3
 36    *
 37    */
 38    public class Text extends Node {
 39   
 40   
 41    private byte[] data;
 42   
 43   
 44    /**
 45    * <p>
 46    * This constructor creates a new <code>Text</code> object.
 47    * The data is checked for legality according to XML 1.0 rules.
 48    * Characters that can be serialized by escaping them
 49    * such as &lt; and &amp; are allowed. However, characters
 50    * such as the form feed, null, vertical tab,
 51    * unmatched halves of surrogate pairs,
 52    * and 0xFFFE and 0xFFFF are not allowed.
 53    * </p>
 54    *
 55    * @param data the initial text of the object
 56    *
 57    * @throws IllegalCharacterDataException if data contains any
 58    * characters which are illegal in well-formed XML 1.0 such as
 59    * null, vertical tab, or unmatched halves of surrogate pairs
 60    */
 61  0 public Text(String data) {
 62  0 _setValue(data);
 63    }
 64   
 65   
 66    /**
 67    * <p>
 68    * Creates a copy of the specified <code>Text</code> object.
 69    * </p>
 70    *
 71    * @param text the <code>Text</code> object to copy
 72    */
 73  0 public Text(Text text) {
 74    // I'm relying here on the data array being immutable.
 75    // If this ever changes, e.g. by adding an append method,
 76    // this method needs to change too.
 77  0 this.data = text.data;
 78    }
 79   
 80   
 81  0 private Text() {}
 82   
 83   
 84  0 static Text build(String data) {
 85   
 86  0 Text result = new Text();
 87  0 try {
 88  0 result.data = data.getBytes("UTF8");
 89    }
 90    catch (UnsupportedEncodingException ex) {
 91  0 throw new RuntimeException(
 92    "Bad VM! Does not support UTF-8"
 93    );
 94    }
 95  0 return result;
 96   
 97    }
 98   
 99   
 100    /**
 101    * <p>
 102    * Sets the content of the <code>Text</code> object
 103    * to the specified data. The data is checked for
 104    * legality according to XML 1.0 rules. Characters that
 105    * can be serialized such as &lt; and &amp; are allowed.
 106    * However, characters such as the form feed, null,
 107    * vertical tab, unmatched halves of surrogate pairs,
 108    * and 0xFFFE and 0xFFFF are not allowed. Passing null is the same
 109    * as passing the empty string.
 110    * </p>
 111    *
 112    * @param data the text to install in the object
 113    *
 114    * @throws IllegalCharacterDataException if data contains any
 115    * characters which are illegal in well-formed XML 1.0 such as
 116    * null, vertical tab, or unmatched halves of surrogate pairs
 117    */
 118  0 public void setValue(String data) {
 119  0 _setValue(data);
 120    }
 121   
 122   
 123  0 private void _setValue(String data) {
 124   
 125  0 if (data == null) data = "";
 126  0 else Verifier.checkPCDATA(data);
 127  0 try {
 128  0 this.data = data.getBytes("UTF8");
 129    }
 130    catch (UnsupportedEncodingException ex) {
 131  0 throw new RuntimeException(
 132    "Bad VM! Does not support UTF-8"
 133    );
 134    }
 135   
 136    }
 137   
 138    /**
 139    * <p>
 140    * Returns the XPath 1.0 string-value of this <code>Text</code>
 141    * node. The XPath string-value of a text node is the same as
 142    * the text of the node.
 143    * </p>
 144    *
 145    * @return the content of the node
 146    */
 147  0 public final String getValue() {
 148   
 149  0 try {
 150  0 return new String(data, "UTF8");
 151    }
 152    catch (UnsupportedEncodingException ex) {
 153  0 throw new RuntimeException(
 154    "Bad VM! Does not support UTF-8"
 155    );
 156    }
 157   
 158    }
 159   
 160   
 161    /**
 162    * <p>
 163    * Throws <code>IndexOutOfBoundsException</code> because
 164    * texts do not have children.
 165    * </p>
 166    *
 167    * @return never returns because texts do not have children;
 168    * always throws an exception.
 169    *
 170    * @param position the index of the child node to return
 171    *
 172    * @throws IndexOutOfBoundsException because texts
 173    * do not have children
 174    */
 175  0 public final Node getChild(int position) {
 176  0 throw new IndexOutOfBoundsException(
 177    "LeafNodes do not have children");
 178    }
 179   
 180   
 181    /**
 182    * <p>
 183    * Returns 0 because texts do not have children.
 184    * </p>
 185    *
 186    * @return zero
 187    */
 188  0 public final int getChildCount() {
 189  0 return 0;
 190    }
 191   
 192   
 193    /**
 194    * <p>
 195    * Returns a deep copy of this <code>Text</code> with no parent,
 196    * that can be added to this document or a different one.
 197    * </p>
 198    *
 199    * @return a deep copy of this text node with no parent
 200    */
 201  0 public Node copy() {
 202   
 203  0 if (isCDATASection()) {
 204  0 return new CDATASection(this);
 205    }
 206    else {
 207  0 return new Text(this);
 208    }
 209   
 210    }
 211   
 212   
 213    /**
 214    * <p>
 215    * Returns a string containing the XML serialization of this text
 216    * node. Unlike <code>getValue</code>, this method escapes
 217    * characters such as &amp; and &lt; using entity references such
 218    * as <code>&amp;amp;</code> and <code>&amp;lt;</code>.
 219    * It escapes the carriage return (\r) as <code>&amp;#x0D;</code>.
 220    * If this text node is a CDATA section, then it may wrap the value
 221    * in CDATA section delimiters instead of escaping.
 222    * </p>
 223    *
 224    * @return the string form of this text node
 225    */
 226  0 public final String toXML() {
 227  0 return escapeText();
 228    }
 229   
 230   
 231  0 String escapeText() {
 232   
 233  0 String s = getValue();
 234  0 int length = s.length();
 235    // Give the string buffer enough room for a couple of escaped characters
 236  0 StringBuffer result = new StringBuffer(length+12);
 237  0 for (int i = 0; i < length; i++) {
 238  0 char c = s.charAt(i);
 239  0 switch (c) {
 240  0 case '\r':
 241  0 result.append("&#x0D;");
 242  0 break;
 243  0 case 14:
 244    // impossible
 245  0 break;
 246  0 case 15:
 247    // impossible
 248  0 break;
 249  0 case 16:
 250    // impossible
 251  0 break;
 252  0 case 17:
 253    // impossible
 254  0 break;
 255  0 case 18:
 256    // impossible
 257  0 break;
 258  0 case 19:
 259    // impossible
 260  0 break;
 261  0 case 20:
 262    // impossible
 263  0 break;
 264  0 case 21:
 265    // impossible
 266  0 break;
 267  0 case 22:
 268    // impossible
 269  0 break;
 270  0 case 23:
 271    // impossible
 272  0 break;
 273  0 case 24:
 274    // impossible
 275  0 break;
 276  0 case 25:
 277    // impossible
 278  0 break;
 279  0 case 26:
 280    // impossible
 281  0 break;
 282  0 case 27:
 283    // impossible
 284  0 break;
 285  0 case 28:
 286    // impossible
 287  0 break;
 288  0 case 29:
 289    // impossible
 290  0 break;
 291  0 case 30:
 292    // impossible
 293  0 break;
 294  0 case 31:
 295    // impossible
 296  0 break;
 297  0 case ' ':
 298  0 result.append(' ');
 299  0 break;
 300  0 case '!':
 301  0 result.append('!');
 302  0 break;
 303  0 case '"':
 304  0 result.append('"');
 305  0 break;
 306  0 case '#':
 307  0 result.append('#');
 308  0 break;
 309  0 case '$':
 310  0 result.append('$');
 311  0 break;
 312  0 case '%':
 313  0 result.append('%');
 314  0 break;
 315  0 case '&':
 316  0 result.append("&amp;");
 317  0 break;
 318  0 case '\'':
 319  0 result.append('\'');
 320  0 break;
 321  0 case '(':
 322  0 result.append('(');
 323  0 break;
 324  0 case ')':
 325  0 result.append(')');
 326  0 break;
 327  0 case '*':
 328  0 result.append('*');
 329  0 break;
 330  0 case '+':
 331  0 result.append('+');
 332  0 break;
 333  0 case ',':
 334  0 result.append(',');
 335  0 break;
 336  0 case '-':
 337  0 result.append('-');
 338  0 break;
 339  0 case '.':
 340  0 result.append('.');
 341  0 break;
 342  0 case '/':
 343  0 result.append('/');
 344  0 break;
 345  0 case '0':
 346  0 result.append('0');
 347  0 break;
 348  0 case '1':
 349  0 result.append('1');
 350  0 break;
 351  0 case '2':
 352  0 result.append('2');
 353  0 break;
 354  0 case '3':
 355  0 result.append('3');
 356  0 break;
 357  0 case '4':
 358  0 result.append('4');
 359  0 break;
 360  0 case '5':
 361  0 result.append('5');
 362  0 break;
 363  0 case '6':
 364  0 result.append('6');
 365  0 break;
 366  0 case '7':
 367  0 result.append('7');
 368  0 break;
 369  0 case '8':
 370  0 result.append('8');
 371  0 break;
 372  0 case '9':
 373  0 result.append('9');
 374  0 break;
 375  0 case ':':
 376  0 result.append(':');
 377  0 break;
 378  0 case ';':
 379  0 result.append(';');
 380  0 break;
 381  0 case '<':
 382  0 result.append("&lt;");
 383  0 break;
 384  0 case '=':
 385  0 result.append('=');
 386  0 break;
 387  0 case '>':
 388  0 result.append("&gt;");
 389  0 break;
 390  0 default:
 391  0 result.append(c);
 392    }
 393    }
 394   
 395  0 return result.toString();
 396   
 397    }
 398   
 399   
 400  0 boolean isText() {
 401  0 return true;
 402    }
 403   
 404   
 405    /**
 406    * <p>
 407    * Returns a <code>String</code>
 408    * representation of this <code>Text</code> suitable for
 409    * debugging and diagnosis. This is <em>not</em>
 410    * the XML representation of this <code>Text</code> node.
 411    * </p>
 412    *
 413    * @return a non-XML string representation of this node
 414    */
 415  0 public final String toString() {
 416   
 417  0 return "[" + getClass().getName() + ": "
 418    + escapeLineBreaksAndTruncate(getValue()) + "]";
 419   
 420    }
 421   
 422   
 423  0 static String escapeLineBreaksAndTruncate(String s) {
 424   
 425  0 int length = s.length();
 426  0 boolean tooLong = length > 40;
 427  0 if (length > 40) {
 428  0 length = 35;
 429  0 s = s.substring(0, 35);
 430    }
 431   
 432  0 StringBuffer result = new StringBuffer(length);
 433  0 for (int i = 0; i < length; i++) {
 434  0 char c = s.charAt(i);
 435  0 switch (c) {
 436  0 case '\n':
 437  0 result.append("\\n");
 438  0 break;
 439  0 case '\r':
 440  0 result.append("\\r");
 441  0 break;
 442  0 case '\t':
 443  0 result.append("\\t");
 444  0 break;
 445  0 default:
 446  0 result.append(c);
 447    }
 448    }
 449  0 if (tooLong) result.append("...");
 450   
 451  0 return result.toString();
 452   
 453    }
 454   
 455   
 456  0 boolean isCDATASection() {
 457  0 return false;
 458    }
 459   
 460   
 461  0 boolean isEmpty() {
 462  0 return this.data.length == 0;
 463    }
 464   
 465   
 466    }