1 package net.sf.saxon.value; 2 3 import net.sf.saxon.Err; 4 import net.sf.saxon.ConversionContext; 5 import net.sf.saxon.expr.XPathContext; 6 import net.sf.saxon.om.Item; 7 import net.sf.saxon.om.SequenceIterator; 8 import net.sf.saxon.om.FastStringBuffer; 9 import net.sf.saxon.om.XMLChar; 10 import net.sf.saxon.trans.DynamicError; 11 import net.sf.saxon.trans.XPathException; 12 import net.sf.saxon.type.*; 13 14 15 18 19 public class StringValue extends AtomicValue { 20 21 public static final StringValue EMPTY_STRING = new StringValue(""); 22 public static final StringValue SINGLE_SPACE = new StringValue(" "); 23 24 27 protected CharSequence value; protected int length = -1; 30 33 34 protected StringValue() { 35 value = ""; 36 } 37 38 44 45 public StringValue(CharSequence value) { 46 this.value = (value == null ? "" : value); 47 } 48 49 55 56 public static StringValue makeStringValue(CharSequence value) { 57 if (value == null || value.length() == 0) { 58 return StringValue.EMPTY_STRING; 59 } else { 60 return new StringValue(value); 61 } 62 } 63 64 67 68 public final String getStringValue() { 69 return (String ) (value = value.toString()); 70 } 71 72 76 77 public final CharSequence getStringValueCS() { 78 return value; 79 } 80 81 93 94 public AtomicValue convertPrimitive(BuiltInAtomicType requiredType, boolean validate, ConversionContext conversion) { 95 int req = requiredType.getFingerprint(); 96 if (req == Type.STRING || req == Type.ATOMIC || req == Type.ITEM) { 97 return this; 98 } 99 return convertStringToBuiltInType(value, requiredType, validate); 100 } 101 102 114 115 public static AtomicValue convertStringToBuiltInType(CharSequence value, BuiltInAtomicType requiredType, 116 boolean validate) { 117 try { 118 switch (requiredType.getFingerprint()) { 119 case Type.BOOLEAN: { 120 return BooleanValue.fromString(value); 121 } 122 case Type.NUMBER: 123 case Type.DOUBLE: 124 return new DoubleValue(value); 125 126 case Type.INTEGER: 127 return IntegerValue.stringToInteger(value); 128 129 130 case Type.UNSIGNED_LONG: 131 case Type.UNSIGNED_INT: 132 case Type.UNSIGNED_SHORT: 133 case Type.UNSIGNED_BYTE: 134 if (validate) { 135 for (int c=0; c<value.length(); c++) { 136 if (value.charAt(c) == '+') { 137 ValidationException err = new ValidationException( 138 "An unsigned number must not contain a plus sign"); 139 return new ValidationErrorValue(err); 140 } 141 } 142 } 143 case Type.NON_POSITIVE_INTEGER: 145 case Type.NEGATIVE_INTEGER: 146 case Type.LONG: 147 case Type.INT: 148 case Type.SHORT: 149 case Type.BYTE: 150 case Type.NON_NEGATIVE_INTEGER: 151 case Type.POSITIVE_INTEGER: 152 AtomicValue iv = IntegerValue.stringToInteger(value); 153 if (iv instanceof ValidationErrorValue) { 154 return iv; 156 } 157 ValidationException err; 158 if (iv instanceof IntegerValue) { 159 err = ((IntegerValue)iv).convertToSubtype(requiredType, validate); 160 } else { 161 err = ((BigIntegerValue)iv).convertToSubType(requiredType, validate); 162 } 163 return (err == null ? iv : new ValidationErrorValue(err)); 164 case Type.DECIMAL: 165 return DecimalValue.makeDecimalValue(value, validate); 166 case Type.FLOAT: 167 return new FloatValue(value); 168 case Type.DATE: 169 return new DateValue(value); 170 case Type.DATE_TIME: 171 return new DateTimeValue(value); 172 case Type.TIME: 173 return new TimeValue(value); 174 case Type.G_YEAR: 175 return new GYearValue(value); 176 case Type.G_YEAR_MONTH: 177 return new GYearMonthValue(value); 178 case Type.G_MONTH: 179 return new GMonthValue(value); 180 case Type.G_MONTH_DAY: 181 return new GMonthDayValue(value); 182 case Type.G_DAY: 183 return new GDayValue(value); 184 case Type.DURATION: 185 return new DurationValue(value); 186 case Type.YEAR_MONTH_DURATION: 187 return new MonthDurationValue(value); 188 case Type.DAY_TIME_DURATION: 189 return new SecondsDurationValue(value); 190 case Type.UNTYPED_ATOMIC: 191 case Type.ANY_SIMPLE_TYPE: 192 return new UntypedAtomicValue(value); 193 case Type.STRING: 194 case Type.ATOMIC: 195 case Type.ITEM: 196 return makeStringValue(value); 197 case Type.NORMALIZED_STRING: 198 case Type.TOKEN: 199 case Type.LANGUAGE: 200 case Type.NAME: 201 case Type.NCNAME: 202 case Type.ID: 203 case Type.IDREF: 204 case Type.ENTITY: 205 case Type.NMTOKEN: 206 return RestrictedStringValue.makeRestrictedString(value, requiredType.getFingerprint(), validate); 207 case Type.ANY_URI: 208 if (AnyURIValue.isValidURI(value)) { 209 return new AnyURIValue(value); 210 } else { 211 throw new ValidationException("Invalid URI: " + value.toString()); 212 } 213 case Type.HEX_BINARY: 214 return new HexBinaryValue(value); 215 case Type.BASE64_BINARY: 216 return new Base64BinaryValue(value); 217 default: 218 throw new ValidationException("Cannot convert string to type " + 219 Err.wrap(requiredType.getDisplayName())); 220 } 221 } catch (ValidationException err) { 222 if (err.getErrorCodeLocalPart() == null) { 223 err.setErrorCode("FORG0001"); 224 } 225 return new ValidationErrorValue(err); 226 } catch (XPathException err) { 227 if (err.getErrorCodeLocalPart() == null) { 228 err.setErrorCode("FORG0001"); 229 } 230 ValidationException ve = new ValidationException(err.getMessage()); 231 if (err.getErrorCodeLocalPart() == null) { 232 ve.setErrorCode("FORG0001"); 233 } else { 234 ve.setErrorCode(err.getErrorCodeLocalPart()); 235 } 236 return new ValidationErrorValue(ve); 237 } 238 } 239 240 252 253 public static AtomicValue convertStringToAtomicType( 254 CharSequence value, AtomicType targetType, boolean validate) { 255 if (targetType instanceof BuiltInAtomicType) { 256 return convertStringToBuiltInType(value, (BuiltInAtomicType)targetType, validate); 257 } else { 258 AtomicValue v = convertStringToBuiltInType( 259 value, 260 (BuiltInAtomicType)targetType.getPrimitiveItemType(), 261 validate); 262 if (v instanceof ValidationErrorValue) { 263 return v; 265 } 266 return targetType.makeDerivedValue(v, value, validate); 267 } 268 } 269 270 271 275 276 public ItemType getItemType() { 277 return Type.STRING_TYPE; 278 } 279 280 284 285 public int getStringLength() { 286 if (length == -1) { 288 length = getStringLength(value); 289 } 290 return length; 291 } 292 293 298 299 public static int getStringLength(CharSequence s) { 300 int n = 0; 301 for (int i = 0; i < s.length(); i++) { 302 int c = (int) s.charAt(i); 303 if (c < 55296 || c > 56319) n++; } 305 return n; 306 } 307 308 311 312 public SequenceIterator iterateCharacters() { 313 return new CharacterIterator(); 314 } 315 316 319 320 public static int[] expand(CharSequence s) { 321 int[] array = new int[getStringLength(s)]; 322 int o = 0; 323 for (int i = 0; i < s.length(); i++) { 324 int charval; 325 int c = s.charAt(i); 326 if (c >= 55296 && c <= 56319) { 327 charval = ((c - 55296) * 1024) + ((int) s.charAt(i + 1) - 56320) + 65536; 329 i++; 330 } else { 331 charval = c; 332 } 333 array[o++] = charval; 334 } 335 return array; 336 } 337 338 341 342 public static CharSequence contract(int[] codes, int used) { 343 FastStringBuffer sb = new FastStringBuffer(codes.length); 344 for (int i=0; i<used; i++) { 345 if (codes[i]<65536) { 346 sb.append((char)codes[i]); 347 } 348 else { sb.append(XMLChar.highSurrogate(codes[i])); 350 sb.append(XMLChar.lowSurrogate(codes[i])); 351 } 352 } 353 return sb; 354 } 355 356 361 362 public boolean equals(Object other) { 363 if (other instanceof AnyURIValue) { 365 throw new ClassCastException ("Cannot compare string to anyURI"); 366 } 367 StringValue otherVal = (StringValue) ((AtomicValue) other).getPrimitiveValue(); 369 return getStringValue().equals(otherVal.getStringValue()); 371 } 372 373 public int hashCode() { 374 return getStringValue().hashCode(); 375 } 376 377 384 385 public boolean schemaEquals(Value obj) { 386 if (obj instanceof AtomicValue) { 387 obj = ((AtomicValue)obj).getPrimitiveValue(); 388 } 389 if (obj instanceof StringValue) { 390 return value.toString().equals(((StringValue)obj).value.toString()); 391 } else { 392 return false; 393 } 394 } 395 396 public boolean effectiveBooleanValue(XPathContext context) throws XPathException { 397 return value.length() > 0; 398 } 399 400 401 404 405 public Object convertToJava(Class target, XPathContext context) throws XPathException { 406 if (target == Object .class) { 407 return value; 408 } else if (target.isAssignableFrom(StringValue.class)) { 409 return this; 410 } else if (target == String .class || target == CharSequence .class) { 411 return getStringValue(); 412 } else if (target == boolean.class) { 413 BooleanValue bval = (BooleanValue) convert(Type.BOOLEAN, context); 414 return Boolean.valueOf(bval.getBooleanValue()); 415 } else if (target == Boolean .class) { 416 BooleanValue bval = (BooleanValue) convert(Type.BOOLEAN, context); 417 return Boolean.valueOf(bval.getBooleanValue()); 418 } else if (target == double.class) { 419 DoubleValue dval = (DoubleValue) convert(Type.DOUBLE, context); 420 return new Double (dval.getDoubleValue()); 421 } else if (target == Double .class) { 422 DoubleValue dval = (DoubleValue) convert(Type.DOUBLE, context); 423 return new Double (dval.getDoubleValue()); 424 } else if (target == float.class) { 425 DoubleValue dval = (DoubleValue) convert(Type.DOUBLE, context); 426 return new Float (dval.getDoubleValue()); 427 } else if (target == Float .class) { 428 DoubleValue dval = (DoubleValue) convert(Type.DOUBLE, context); 429 return new Float (dval.getDoubleValue()); 430 } else if (target == long.class) { 431 IntegerValue dval = (IntegerValue) convert(Type.INTEGER, context); 432 return new Long (dval.longValue()); 433 } else if (target == Long .class) { 434 IntegerValue dval = (IntegerValue) convert(Type.INTEGER, context); 435 return new Long (dval.longValue()); 436 } else if (target == int.class) { 437 IntegerValue dval = (IntegerValue) convert(Type.INTEGER, context); 438 return new Integer ((int) dval.longValue()); 439 } else if (target == Integer .class) { 440 IntegerValue dval = (IntegerValue) convert(Type.INTEGER, context); 441 return new Integer ((int) dval.longValue()); 442 } else if (target == short.class) { 443 IntegerValue dval = (IntegerValue) convert(Type.INTEGER, context); 444 return new Short ((short) dval.longValue()); 445 } else if (target == Short .class) { 446 IntegerValue dval = (IntegerValue) convert(Type.INTEGER, context); 447 return new Short ((short) dval.longValue()); 448 } else if (target == byte.class) { 449 IntegerValue dval = (IntegerValue) convert(Type.INTEGER, context); 450 return new Byte ((byte) dval.longValue()); 451 } else if (target == Byte .class) { 452 IntegerValue dval = (IntegerValue) convert(Type.INTEGER, context); 453 return new Byte ((byte) dval.longValue()); 454 } else if (target == char.class || target == Character .class) { 455 if (value.length() == 1) { 456 return new Character (value.charAt(0)); 457 } else { 458 DynamicError de = new DynamicError("Cannot convert string to Java char unless length is 1"); 459 de.setXPathContext(context); 460 de.setErrorCode("SAXON:0000"); 461 throw de; 462 } 463 } else { 464 Object o = super.convertToJava(target, context); 465 if (o == null) { 466 DynamicError err = new DynamicError( 467 "Conversion of string to " + target.getName() + " is not supported"); 468 err.setXPathContext(context); 469 err.setErrorCode("SAXON:0000"); 470 throw err; 471 } 472 return o; 473 } 474 } 475 476 public String toString() { 477 return "\"" + value + '\"'; 478 } 479 480 481 485 486 487 public final class CharacterIterator implements SequenceIterator { 488 489 int inpos = 0; int outpos = 0; int current = -1; 493 496 497 public CharacterIterator() { 498 } 499 500 public Item next() { 501 if (inpos < value.length()) { 502 int c = value.charAt(inpos++); 503 if (c >= 55296 && c <= 56319) { 504 current = ((c - 55296) * 1024) + ((int) value.charAt(inpos++) - 56320) + 65536; 506 } else { 507 current = c; 508 } 509 outpos++; 510 return new IntegerValue(current); 511 } else { 512 outpos = -1; 513 return null; 514 } 515 } 516 517 public Item current() { 518 if (outpos < 1) { 519 return null; 520 } 521 return new IntegerValue(current); 522 } 523 524 public int position() { 525 return outpos; 526 } 527 528 public SequenceIterator getAnother() { 529 return new CharacterIterator(); 530 } 531 532 539 540 public int getProperties() { 541 return 0; 542 } 543 } 544 545 546 } 547 548 566 | Popular Tags |