| 1 |
# XSD4R - XML Schema Datatype implementation. |
|---|
| 2 |
# Copyright (C) 2000-2007 NAKAMURA, Hiroshi <nahi@ruby-lang.org>. |
|---|
| 3 |
|
|---|
| 4 |
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can |
|---|
| 5 |
# redistribute it and/or modify it under the same terms of Ruby's license; |
|---|
| 6 |
# either the dual license version in 2003, or any later version. |
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
require 'xsd/qname' |
|---|
| 10 |
require 'xsd/charset' |
|---|
| 11 |
require 'soap/nestedexception' |
|---|
| 12 |
require 'uri' |
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
### |
|---|
| 16 |
## XMLSchamaDatatypes general definitions. |
|---|
| 17 |
# |
|---|
| 18 |
module XSD |
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
Namespace = 'http://www.w3.org/2001/XMLSchema' |
|---|
| 22 |
InstanceNamespace = 'http://www.w3.org/2001/XMLSchema-instance' |
|---|
| 23 |
|
|---|
| 24 |
AttrType = 'type' |
|---|
| 25 |
NilValue = 'true' |
|---|
| 26 |
|
|---|
| 27 |
AnyTypeLiteral = 'anyType' |
|---|
| 28 |
AnySimpleTypeLiteral = 'anySimpleType' |
|---|
| 29 |
NilLiteral = 'nil' |
|---|
| 30 |
StringLiteral = 'string' |
|---|
| 31 |
BooleanLiteral = 'boolean' |
|---|
| 32 |
DecimalLiteral = 'decimal' |
|---|
| 33 |
FloatLiteral = 'float' |
|---|
| 34 |
DoubleLiteral = 'double' |
|---|
| 35 |
DurationLiteral = 'duration' |
|---|
| 36 |
DateTimeLiteral = 'dateTime' |
|---|
| 37 |
TimeLiteral = 'time' |
|---|
| 38 |
DateLiteral = 'date' |
|---|
| 39 |
GYearMonthLiteral = 'gYearMonth' |
|---|
| 40 |
GYearLiteral = 'gYear' |
|---|
| 41 |
GMonthDayLiteral = 'gMonthDay' |
|---|
| 42 |
GDayLiteral = 'gDay' |
|---|
| 43 |
GMonthLiteral = 'gMonth' |
|---|
| 44 |
HexBinaryLiteral = 'hexBinary' |
|---|
| 45 |
Base64BinaryLiteral = 'base64Binary' |
|---|
| 46 |
AnyURILiteral = 'anyURI' |
|---|
| 47 |
QNameLiteral = 'QName' |
|---|
| 48 |
|
|---|
| 49 |
NormalizedStringLiteral = 'normalizedString' |
|---|
| 50 |
TokenLiteral = 'token' |
|---|
| 51 |
LanguageLiteral = 'language' |
|---|
| 52 |
NMTOKENLiteral = 'NMTOKEN' |
|---|
| 53 |
NMTOKENSLiteral = 'NMTOKENS' |
|---|
| 54 |
NameLiteral = 'Name' |
|---|
| 55 |
NCNameLiteral = 'NCName' |
|---|
| 56 |
IDLiteral = 'ID' |
|---|
| 57 |
IDREFLiteral = 'IDREF' |
|---|
| 58 |
IDREFSLiteral = 'IDREFS' |
|---|
| 59 |
ENTITYLiteral = 'ENTITY' |
|---|
| 60 |
ENTITIESLiteral = 'ENTITIES' |
|---|
| 61 |
IntegerLiteral = 'integer' |
|---|
| 62 |
NonPositiveIntegerLiteral = 'nonPositiveInteger' |
|---|
| 63 |
NegativeIntegerLiteral = 'negativeInteger' |
|---|
| 64 |
LongLiteral = 'long' |
|---|
| 65 |
IntLiteral = 'int' |
|---|
| 66 |
ShortLiteral = 'short' |
|---|
| 67 |
ByteLiteral = 'byte' |
|---|
| 68 |
NonNegativeIntegerLiteral = 'nonNegativeInteger' |
|---|
| 69 |
UnsignedLongLiteral = 'unsignedLong' |
|---|
| 70 |
UnsignedIntLiteral = 'unsignedInt' |
|---|
| 71 |
UnsignedShortLiteral = 'unsignedShort' |
|---|
| 72 |
UnsignedByteLiteral = 'unsignedByte' |
|---|
| 73 |
PositiveIntegerLiteral = 'positiveInteger' |
|---|
| 74 |
|
|---|
| 75 |
AttrTypeName = QName.new(InstanceNamespace, AttrType) |
|---|
| 76 |
AttrNilName = QName.new(InstanceNamespace, NilLiteral) |
|---|
| 77 |
|
|---|
| 78 |
AnyTypeName = QName.new(Namespace, AnyTypeLiteral) |
|---|
| 79 |
AnySimpleTypeName = QName.new(Namespace, AnySimpleTypeLiteral) |
|---|
| 80 |
|
|---|
| 81 |
class Error < StandardError; include ::SOAP::NestedException; end |
|---|
| 82 |
class ValueSpaceError < Error; end |
|---|
| 83 |
|
|---|
| 84 |
|
|---|
| 85 |
### |
|---|
| 86 |
## The base class of all datatypes with Namespace. |
|---|
| 87 |
# |
|---|
| 88 |
class NSDBase |
|---|
| 89 |
@@types = [] |
|---|
| 90 |
|
|---|
| 91 |
attr_accessor :type |
|---|
| 92 |
|
|---|
| 93 |
def self.inherited(klass) |
|---|
| 94 |
@@types << klass |
|---|
| 95 |
end |
|---|
| 96 |
|
|---|
| 97 |
def self.types |
|---|
| 98 |
@@types |
|---|
| 99 |
end |
|---|
| 100 |
|
|---|
| 101 |
def initialize |
|---|
| 102 |
end |
|---|
| 103 |
|
|---|
| 104 |
def init(type) |
|---|
| 105 |
@type = type |
|---|
| 106 |
end |
|---|
| 107 |
end |
|---|
| 108 |
|
|---|
| 109 |
|
|---|
| 110 |
### |
|---|
| 111 |
## The base class of XSD datatypes. |
|---|
| 112 |
# |
|---|
| 113 |
class XSDAnySimpleType < NSDBase |
|---|
| 114 |
include XSD |
|---|
| 115 |
Type = QName.new(Namespace, AnySimpleTypeLiteral) |
|---|
| 116 |
|
|---|
| 117 |
# @data represents canonical space (ex. Integer: 123). |
|---|
| 118 |
attr_reader :data |
|---|
| 119 |
# @is_nil represents this data is nil or not. |
|---|
| 120 |
attr_accessor :is_nil |
|---|
| 121 |
|
|---|
| 122 |
def initialize(value = nil) |
|---|
| 123 |
init(Type, value) |
|---|
| 124 |
end |
|---|
| 125 |
|
|---|
| 126 |
# true or raise |
|---|
| 127 |
def check_lexical_format(value) |
|---|
| 128 |
screen_data(value) |
|---|
| 129 |
true |
|---|
| 130 |
end |
|---|
| 131 |
|
|---|
| 132 |
# set accepts a string which follows lexical space (ex. String: "+123"), or |
|---|
| 133 |
# an object which follows canonical space (ex. Integer: 123). |
|---|
| 134 |
def set(value) |
|---|
| 135 |
if value.nil? |
|---|
| 136 |
@is_nil = true |
|---|
| 137 |
@data = nil |
|---|
| 138 |
_set(nil) |
|---|
| 139 |
else |
|---|
| 140 |
@is_nil = false |
|---|
| 141 |
_set(screen_data(value)) |
|---|
| 142 |
end |
|---|
| 143 |
end |
|---|
| 144 |
|
|---|
| 145 |
# to_s creates a string which follows lexical space (ex. String: "123"). |
|---|
| 146 |
def to_s() |
|---|
| 147 |
if @is_nil |
|---|
| 148 |
"" |
|---|
| 149 |
else |
|---|
| 150 |
_to_s |
|---|
| 151 |
end |
|---|
| 152 |
end |
|---|
| 153 |
|
|---|
| 154 |
private |
|---|
| 155 |
|
|---|
| 156 |
def init(type, value) |
|---|
| 157 |
super(type) |
|---|
| 158 |
set(value) |
|---|
| 159 |
end |
|---|
| 160 |
|
|---|
| 161 |
# raises ValueSpaceError if check failed |
|---|
| 162 |
def screen_data(value) |
|---|
| 163 |
value |
|---|
| 164 |
end |
|---|
| 165 |
|
|---|
| 166 |
def _set(value) |
|---|
| 167 |
@data = value |
|---|
| 168 |
end |
|---|
| 169 |
|
|---|
| 170 |
def _to_s |
|---|
| 171 |
@data.to_s |
|---|
| 172 |
end |
|---|
| 173 |
end |
|---|
| 174 |
|
|---|
| 175 |
class XSDNil < XSDAnySimpleType |
|---|
| 176 |
Type = QName.new(Namespace, NilLiteral) |
|---|
| 177 |
Value = 'true' |
|---|
| 178 |
|
|---|
| 179 |
def initialize(value = nil) |
|---|
| 180 |
init(Type, value) |
|---|
| 181 |
end |
|---|
| 182 |
end |
|---|
| 183 |
|
|---|
| 184 |
|
|---|
| 185 |
### |
|---|
| 186 |
## Primitive datatypes. |
|---|
| 187 |
# |
|---|
| 188 |
class XSDString < XSDAnySimpleType |
|---|
| 189 |
Type = QName.new(Namespace, StringLiteral) |
|---|
| 190 |
|
|---|
| 191 |
def initialize(value = nil) |
|---|
| 192 |
init(Type, value) |
|---|
| 193 |
end |
|---|
| 194 |
|
|---|
| 195 |
@@strict_ces_validation = false |
|---|
| 196 |
|
|---|
| 197 |
def self.strict_ces_validation=(strict_ces_validation) |
|---|
| 198 |
@@strict_ces_validation = strict_ces_validation |
|---|
| 199 |
end |
|---|
| 200 |
|
|---|
| 201 |
def self.strict_ces_validation |
|---|
| 202 |
@@strict_ces_validation |
|---|
| 203 |
end |
|---|
| 204 |
|
|---|
| 205 |
private |
|---|
| 206 |
|
|---|
| 207 |
def screen_data(value) |
|---|
| 208 |
if ::XSD::XSDString.strict_ces_validation |
|---|
| 209 |
externalces = XSD::Charset.encoding |
|---|
| 210 |
unless XSD::Charset.is_ces(value, externalces) |
|---|
| 211 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") |
|---|
| 212 |
end |
|---|
| 213 |
end |
|---|
| 214 |
value |
|---|
| 215 |
end |
|---|
| 216 |
end |
|---|
| 217 |
|
|---|
| 218 |
class XSDBoolean < XSDAnySimpleType |
|---|
| 219 |
Type = QName.new(Namespace, BooleanLiteral) |
|---|
| 220 |
|
|---|
| 221 |
def initialize(value = nil) |
|---|
| 222 |
init(Type, value) |
|---|
| 223 |
end |
|---|
| 224 |
|
|---|
| 225 |
private |
|---|
| 226 |
|
|---|
| 227 |
def screen_data(value) |
|---|
| 228 |
if value.is_a?(String) |
|---|
| 229 |
str = value.strip |
|---|
| 230 |
if str == 'true' || str == '1' |
|---|
| 231 |
true |
|---|
| 232 |
elsif str == 'false' || str == '0' |
|---|
| 233 |
false |
|---|
| 234 |
else |
|---|
| 235 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") |
|---|
| 236 |
end |
|---|
| 237 |
else |
|---|
| 238 |
value ? true : false |
|---|
| 239 |
end |
|---|
| 240 |
end |
|---|
| 241 |
end |
|---|
| 242 |
|
|---|
| 243 |
class XSDDecimal < XSDAnySimpleType |
|---|
| 244 |
Type = QName.new(Namespace, DecimalLiteral) |
|---|
| 245 |
|
|---|
| 246 |
def initialize(value = nil) |
|---|
| 247 |
init(Type, value) |
|---|
| 248 |
end |
|---|
| 249 |
|
|---|
| 250 |
def nonzero? |
|---|
| 251 |
(@number != '0') |
|---|
| 252 |
end |
|---|
| 253 |
|
|---|
| 254 |
private |
|---|
| 255 |
|
|---|
| 256 |
def screen_data(d) |
|---|
| 257 |
if d.is_a?(String) |
|---|
| 258 |
# Integer("00012") => 10 in Ruby. |
|---|
| 259 |
d.sub!(/^([+\-]?)0*(?=\d)/, "\\1") |
|---|
| 260 |
end |
|---|
| 261 |
screen_data_str(d) |
|---|
| 262 |
end |
|---|
| 263 |
|
|---|
| 264 |
def screen_data_str(str) |
|---|
| 265 |
/^([+\-]?)(\d*)(?:\.(\d*)?)?$/ =~ str.to_s.strip |
|---|
| 266 |
unless Regexp.last_match |
|---|
| 267 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") |
|---|
| 268 |
end |
|---|
| 269 |
sign = $1 || '+' |
|---|
| 270 |
int_part = $2 |
|---|
| 271 |
frac_part = $3 |
|---|
| 272 |
int_part = '0' if int_part.empty? |
|---|
| 273 |
frac_part = frac_part ? frac_part.sub(/0+$/, '') : '' |
|---|
| 274 |
point = - frac_part.size |
|---|
| 275 |
number = int_part + frac_part |
|---|
| 276 |
# normalize |
|---|
| 277 |
if sign == '+' |
|---|
| 278 |
sign = '' |
|---|
| 279 |
elsif sign == '-' |
|---|
| 280 |
if number == '0' |
|---|
| 281 |
sign = '' |
|---|
| 282 |
end |
|---|
| 283 |
end |
|---|
| 284 |
[sign, point, number] |
|---|
| 285 |
end |
|---|
| 286 |
|
|---|
| 287 |
def _set(data) |
|---|
| 288 |
if data.nil? |
|---|
| 289 |
@sign = @point = @number = @data = nil |
|---|
| 290 |
return |
|---|
| 291 |
end |
|---|
| 292 |
@sign, @point, @number = data |
|---|
| 293 |
@data = _to_s |
|---|
| 294 |
@data.freeze |
|---|
| 295 |
end |
|---|
| 296 |
|
|---|
| 297 |
# 0.0 -> 0; right? |
|---|
| 298 |
def _to_s |
|---|
| 299 |
str = @number.dup |
|---|
| 300 |
if @point.nonzero? |
|---|
| 301 |
str[@number.size + @point, 0] = '.' |
|---|
| 302 |
end |
|---|
| 303 |
@sign + str |
|---|
| 304 |
end |
|---|
| 305 |
end |
|---|
| 306 |
|
|---|
| 307 |
module FloatConstants |
|---|
| 308 |
NaN = 0.0/0.0 |
|---|
| 309 |
POSITIVE_INF = +1.0/0.0 |
|---|
| 310 |
NEGATIVE_INF = -1.0/0.0 |
|---|
| 311 |
POSITIVE_ZERO = +1.0/POSITIVE_INF |
|---|
| 312 |
NEGATIVE_ZERO = -1.0/POSITIVE_INF |
|---|
| 313 |
MIN_POSITIVE_SINGLE = 2.0 ** -149 |
|---|
| 314 |
end |
|---|
| 315 |
|
|---|
| 316 |
class XSDFloat < XSDAnySimpleType |
|---|
| 317 |
include FloatConstants |
|---|
| 318 |
Type = QName.new(Namespace, FloatLiteral) |
|---|
| 319 |
|
|---|
| 320 |
def initialize(value = nil) |
|---|
| 321 |
init(Type, value) |
|---|
| 322 |
end |
|---|
| 323 |
|
|---|
| 324 |
private |
|---|
| 325 |
|
|---|
| 326 |
def screen_data(value) |
|---|
| 327 |
# "NaN".to_f => 0 in some environment. libc? |
|---|
| 328 |
if value.is_a?(Float) |
|---|
| 329 |
return narrow32bit(value) |
|---|
| 330 |
end |
|---|
| 331 |
str = value.to_s.strip |
|---|
| 332 |
if str == 'NaN' |
|---|
| 333 |
NaN |
|---|
| 334 |
elsif str == 'INF' |
|---|
| 335 |
POSITIVE_INF |
|---|
| 336 |
elsif str == '-INF' |
|---|
| 337 |
NEGATIVE_INF |
|---|
| 338 |
else |
|---|
| 339 |
if /^[+\-\.\deE]+$/ !~ str |
|---|
| 340 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") |
|---|
| 341 |
end |
|---|
| 342 |
# Float("-1.4E") might fail on some system. |
|---|
| 343 |
str << '0' if /e$/i =~ str |
|---|
| 344 |
begin |
|---|
| 345 |
return narrow32bit(Float(str)) |
|---|
| 346 |
rescue ArgumentError |
|---|
| 347 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.", $!) |
|---|
| 348 |
end |
|---|
| 349 |
end |
|---|
| 350 |
end |
|---|
| 351 |
|
|---|
| 352 |
def _to_s |
|---|
| 353 |
if @data.nan? |
|---|
| 354 |
'NaN' |
|---|
| 355 |
elsif @data.infinite? == 1 |
|---|
| 356 |
'INF' |
|---|
| 357 |
elsif @data.infinite? == -1 |
|---|
| 358 |
'-INF' |
|---|
| 359 |
else |
|---|
| 360 |
sign = XSDFloat.positive?(@data) ? '+' : '-' |
|---|
| 361 |
sign + sprintf("%.10g", @data.abs).sub(/[eE]([+-])?0+/) { 'e' + $1 } |
|---|
| 362 |
end |
|---|
| 363 |
end |
|---|
| 364 |
|
|---|
| 365 |
# Convert to single-precision 32-bit floating point value. |
|---|
| 366 |
def narrow32bit(f) |
|---|
| 367 |
if f.nan? || f.infinite? |
|---|
| 368 |
f |
|---|
| 369 |
elsif f.abs < MIN_POSITIVE_SINGLE |
|---|
| 370 |
XSDFloat.positive?(f) ? POSITIVE_ZERO : NEGATIVE_ZERO |
|---|
| 371 |
else |
|---|
| 372 |
f |
|---|
| 373 |
end |
|---|
| 374 |
end |
|---|
| 375 |
|
|---|
| 376 |
def self.positive?(value) |
|---|
| 377 |
(1 / value) > 0.0 |
|---|
| 378 |
end |
|---|
| 379 |
end |
|---|
| 380 |
|
|---|
| 381 |
# Ruby's Float is double-precision 64-bit floating point value. |
|---|
| 382 |
class XSDDouble < XSDAnySimpleType |
|---|
| 383 |
include FloatConstants |
|---|
| 384 |
Type = QName.new(Namespace, DoubleLiteral) |
|---|
| 385 |
|
|---|
| 386 |
def initialize(value = nil) |
|---|
| 387 |
init(Type, value) |
|---|
| 388 |
end |
|---|
| 389 |
|
|---|
| 390 |
private |
|---|
| 391 |
|
|---|
| 392 |
def screen_data(value) |
|---|
| 393 |
# "NaN".to_f => 0 in some environment. libc? |
|---|
| 394 |
if value.is_a?(Float) |
|---|
| 395 |
return value |
|---|
| 396 |
end |
|---|
| 397 |
str = value.to_s.strip |
|---|
| 398 |
if str == 'NaN' |
|---|
| 399 |
NaN |
|---|
| 400 |
elsif str == 'INF' |
|---|
| 401 |
POSITIVE_INF |
|---|
| 402 |
elsif str == '-INF' |
|---|
| 403 |
NEGATIVE_INF |
|---|
| 404 |
else |
|---|
| 405 |
begin |
|---|
| 406 |
return Float(str) |
|---|
| 407 |
rescue ArgumentError |
|---|
| 408 |
# '1.4e' cannot be parsed on some architecture. |
|---|
| 409 |
if /e\z/i =~ str |
|---|
| 410 |
begin |
|---|
| 411 |
return Float(str + '0') |
|---|
| 412 |
rescue ArgumentError |
|---|
| 413 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.", $!) |
|---|
| 414 |
end |
|---|
| 415 |
else |
|---|
| 416 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.", $!) |
|---|
| 417 |
end |
|---|
| 418 |
end |
|---|
| 419 |
end |
|---|
| 420 |
end |
|---|
| 421 |
|
|---|
| 422 |
def _to_s |
|---|
| 423 |
if @data.nan? |
|---|
| 424 |
'NaN' |
|---|
| 425 |
elsif @data.infinite? == 1 |
|---|
| 426 |
'INF' |
|---|
| 427 |
elsif @data.infinite? == -1 |
|---|
| 428 |
'-INF' |
|---|
| 429 |
else |
|---|
| 430 |
sign = (1 / @data > 0.0) ? '+' : '-' |
|---|
| 431 |
sign + sprintf("%.16g", @data.abs).sub(/[eE]([+-])?0+/) { 'e' + $1 } |
|---|
| 432 |
end |
|---|
| 433 |
end |
|---|
| 434 |
end |
|---|
| 435 |
|
|---|
| 436 |
class XSDDuration < XSDAnySimpleType |
|---|
| 437 |
Type = QName.new(Namespace, DurationLiteral) |
|---|
| 438 |
|
|---|
| 439 |
attr_accessor :sign |
|---|
| 440 |
attr_accessor :year |
|---|
| 441 |
attr_accessor :month |
|---|
| 442 |
attr_accessor :day |
|---|
| 443 |
attr_accessor :hour |
|---|
| 444 |
attr_accessor :min |
|---|
| 445 |
attr_accessor :sec |
|---|
| 446 |
|
|---|
| 447 |
def initialize(value = nil) |
|---|
| 448 |
init(Type, value) |
|---|
| 449 |
end |
|---|
| 450 |
|
|---|
| 451 |
private |
|---|
| 452 |
|
|---|
| 453 |
def screen_data(value) |
|---|
| 454 |
/^([+\-]?)P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/ =~ value.to_s.strip |
|---|
| 455 |
unless Regexp.last_match |
|---|
| 456 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") |
|---|
| 457 |
end |
|---|
| 458 |
if $5 and !$6 and !$7 and !$8 |
|---|
| 459 |
# allows durations lower than a day such as 'PT5S'. |
|---|
| 460 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") |
|---|
| 461 |
end |
|---|
| 462 |
sign = $1 |
|---|
| 463 |
year = $2.to_i |
|---|
| 464 |
month = $3.to_i |
|---|
| 465 |
day = $4.to_i |
|---|
| 466 |
hour = $6.to_i |
|---|
| 467 |
min = $7.to_i |
|---|
| 468 |
sec = $8 ? XSDDecimal.new($8) : 0 |
|---|
| 469 |
[sign, year, month, day, hour, min, sec] |
|---|
| 470 |
end |
|---|
| 471 |
|
|---|
| 472 |
def _set(data) |
|---|
| 473 |
if data.nil? |
|---|
| 474 |
@sign = @year = @month = @day = @hour = @min = @sec = @data = nil |
|---|
| 475 |
return |
|---|
| 476 |
end |
|---|
| 477 |
@sign, @year, @month, @day, @hour, @min, @sec = data |
|---|
| 478 |
@data = _to_s |
|---|
| 479 |
@data.freeze |
|---|
| 480 |
end |
|---|
| 481 |
|
|---|
| 482 |
def _to_s |
|---|
| 483 |
str = '' |
|---|
| 484 |
str << @sign if @sign |
|---|
| 485 |
str << 'P' |
|---|
| 486 |
l = '' |
|---|
| 487 |
l << "#{ @year }Y" if @year.nonzero? |
|---|
| 488 |
l << "#{ @month }M" if @month.nonzero? |
|---|
| 489 |
l << "#{ @day }D" if @day.nonzero? |
|---|
| 490 |
r = '' |
|---|
| 491 |
r << "#{ @hour }H" if @hour.nonzero? |
|---|
| 492 |
r << "#{ @min }M" if @min.nonzero? |
|---|
| 493 |
r << "#{ @sec }S" if @sec.nonzero? |
|---|
| 494 |
str << l |
|---|
| 495 |
unless r.empty? |
|---|
| 496 |
str << "T" << r |
|---|
| 497 |
end |
|---|
| 498 |
if l.empty? and r.empty? |
|---|
| 499 |
str << "0D" |
|---|
| 500 |
end |
|---|
| 501 |
str |
|---|
| 502 |
end |
|---|
| 503 |
end |
|---|
| 504 |
|
|---|
| 505 |
|
|---|
| 506 |
require 'rational' |
|---|
| 507 |
require 'date' |
|---|
| 508 |
|
|---|
| 509 |
module XSDDateTimeImpl |
|---|
| 510 |
DayInSec = 86400 # 24 * 60 * 60 |
|---|
| 511 |
DayInMicro = 86400_000_000 |
|---|
| 512 |
|
|---|
| 513 |
def to_obj(klass) |
|---|
| 514 |
if klass == Time |
|---|
| 515 |
to_time |
|---|
| 516 |
elsif klass == Date |
|---|
| 517 |
to_date |
|---|
| 518 |
elsif klass == DateTime |
|---|
| 519 |
to_datetime |
|---|
| 520 |
else |
|---|
| 521 |
nil |
|---|
| 522 |
end |
|---|
| 523 |
end |
|---|
| 524 |
|
|---|
| 525 |
def to_time |
|---|
| 526 |
begin |
|---|
| 527 |
if @data.offset * DayInSec == Time.now.utc_offset |
|---|
| 528 |
d = @data |
|---|
| 529 |
usec = (d.sec_fraction * DayInMicro).round |
|---|
| 530 |
Time.local(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec) |
|---|
| 531 |
else |
|---|
| 532 |
d = @data.newof |
|---|
| 533 |
usec = (d.sec_fraction * DayInMicro).round |
|---|
| 534 |
Time.gm(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec) |
|---|
| 535 |
end |
|---|
| 536 |
rescue ArgumentError |
|---|
| 537 |
nil |
|---|
| 538 |
end |
|---|
| 539 |
end |
|---|
| 540 |
|
|---|
| 541 |
def to_date |
|---|
| 542 |
Date.new0(@data.class.jd_to_ajd(@data.jd, 0, 0), 0, @data.start) |
|---|
| 543 |
end |
|---|
| 544 |
|
|---|
| 545 |
def to_datetime |
|---|
| 546 |
data |
|---|
| 547 |
end |
|---|
| 548 |
|
|---|
| 549 |
def tz2of(str) |
|---|
| 550 |
/^(?:Z|(?:([+\-])(\d\d):(\d\d))?)$/ =~ str |
|---|
| 551 |
sign = $1 |
|---|
| 552 |
hour = $2.to_i |
|---|
| 553 |
min = $3.to_i |
|---|
| 554 |
|
|---|
| 555 |
of = case sign |
|---|
| 556 |
when '+' |
|---|
| 557 |
of = +(hour.to_r * 60 + min) / 1440 # 24 * 60 |
|---|
| 558 |
when '-' |
|---|
| 559 |
of = -(hour.to_r * 60 + min) / 1440 # 24 * 60 |
|---|
| 560 |
else |
|---|
| 561 |
0 |
|---|
| 562 |
end |
|---|
| 563 |
of |
|---|
| 564 |
end |
|---|
| 565 |
|
|---|
| 566 |
def of2tz(offset) |
|---|
| 567 |
diffmin = offset * 24 * 60 |
|---|
| 568 |
if diffmin.zero? |
|---|
| 569 |
'Z' |
|---|
| 570 |
else |
|---|
| 571 |
((diffmin < 0) ? '-' : '+') << format('%02d:%02d', |
|---|
| 572 |
(diffmin.abs / 60.0).to_i, (diffmin.abs % 60.0).to_i) |
|---|
| 573 |
end |
|---|
| 574 |
end |
|---|
| 575 |
|
|---|
| 576 |
def screen_data(t) |
|---|
| 577 |
# convert t to a DateTime as an internal representation. |
|---|
| 578 |
if t.respond_to?(:to_datetime) # 1.9 or later |
|---|
| 579 |
t.to_datetime |
|---|
| 580 |
elsif t.is_a?(DateTime) |
|---|
| 581 |
t |
|---|
| 582 |
elsif t.is_a?(Date) |
|---|
| 583 |
t = screen_data_str(t) |
|---|
| 584 |
t <<= 12 if t.year < 0 |
|---|
| 585 |
t |
|---|
| 586 |
elsif t.is_a?(Time) |
|---|
| 587 |
jd = DateTime.civil_to_jd(t.year, t.mon, t.mday, DateTime::ITALY) |
|---|
| 588 |
fr = DateTime.time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) + |
|---|
| 589 |
t.usec.to_r / DayInMicro |
|---|
| 590 |
of = t.utc_offset.to_r / DayInSec |
|---|
| 591 |
DateTime.new0(DateTime.jd_to_ajd(jd, fr, of), of, DateTime::ITALY) |
|---|
| 592 |
else |
|---|
| 593 |
screen_data_str(t) |
|---|
| 594 |
end |
|---|
| 595 |
end |
|---|
| 596 |
|
|---|
| 597 |
def add_tz(s) |
|---|
| 598 |
s + of2tz(@data.offset) |
|---|
| 599 |
end |
|---|
| 600 |
end |
|---|
| 601 |
|
|---|
| 602 |
class XSDDateTime < XSDAnySimpleType |
|---|
| 603 |
include XSDDateTimeImpl |
|---|
| 604 |
Type = QName.new(Namespace, DateTimeLiteral) |
|---|
| 605 |
|
|---|
| 606 |
def initialize(value = nil) |
|---|
| 607 |
init(Type, value) |
|---|
| 608 |
end |
|---|
| 609 |
|
|---|
| 610 |
private |
|---|
| 611 |
|
|---|
| 612 |
def screen_data_str(t) |
|---|
| 613 |
/^([+\-]?\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip |
|---|
| 614 |
unless Regexp.last_match |
|---|
| 615 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") |
|---|
| 616 |
end |
|---|
| 617 |
if $1 == '0000' |
|---|
| 618 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") |
|---|
| 619 |
end |
|---|
| 620 |
year = $1.to_i |
|---|
| 621 |
if year < 0 |
|---|
| 622 |
year += 1 |
|---|
| 623 |
end |
|---|
| 624 |
mon = $2.to_i |
|---|
| 625 |
mday = $3.to_i |
|---|
| 626 |
hour = $4.to_i |
|---|
| 627 |
min = $5.to_i |
|---|
| 628 |
sec = $6.to_i |
|---|
| 629 |
secfrac = $7 |
|---|
| 630 |
zonestr = $8 |
|---|
| 631 |
data = DateTime.civil(year, mon, mday, hour, min, sec, tz2of(zonestr)) |
|---|
| 632 |
if secfrac |
|---|
| 633 |
diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / DayInSec |
|---|
| 634 |
data += diffday |
|---|
| 635 |
# FYI: new0 and jd_to_rjd are not necessary to use if you don't have |
|---|
| 636 |
# exceptional reason. |
|---|
| 637 |
end |
|---|
| 638 |
[data, secfrac] |
|---|
| 639 |
end |
|---|
| 640 |
|
|---|
| 641 |
def _set(data) |
|---|
| 642 |
if data.nil? |
|---|
| 643 |
@data = @secfrac = nil |
|---|
| 644 |
return |
|---|
| 645 |
end |
|---|
| 646 |
@data, @secfrac = data |
|---|
| 647 |
end |
|---|
| 648 |
|
|---|
| 649 |
def _to_s |
|---|
| 650 |
year = (@data.year > 0) ? @data.year : @data.year - 1 |
|---|
| 651 |
s = format('%.4d-%02d-%02dT%02d:%02d:%02d', |
|---|
| 652 |
year, @data.mon, @data.mday, @data.hour, @data.min, @data.sec) |
|---|
| 653 |
if @data.sec_fraction.nonzero? |
|---|
| 654 |
if @secfrac |
|---|
| 655 |
s << ".#{ @secfrac }" |
|---|
| 656 |
else |
|---|
| 657 |
s << sprintf("%.16f", |
|---|
| 658 |
(@data.sec_fraction * DayInSec).to_f).sub(/^0/, '').sub(/0*$/, '') |
|---|
| 659 |
end |
|---|
| 660 |
end |
|---|
| 661 |
add_tz(s) |
|---|
| 662 |
end |
|---|
| 663 |
end |
|---|
| 664 |
|
|---|
| 665 |
class XSDTime < XSDAnySimpleType |
|---|
| 666 |
include XSDDateTimeImpl |
|---|
| 667 |
Type = QName.new(Namespace, TimeLiteral) |
|---|
| 668 |
|
|---|
| 669 |
def initialize(value = nil) |
|---|
| 670 |
init(Type, value) |
|---|
| 671 |
end |
|---|
| 672 |
|
|---|
| 673 |
private |
|---|
| 674 |
|
|---|
| 675 |
def screen_data_str(t) |
|---|
| 676 |
/^(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip |
|---|
| 677 |
unless Regexp.last_match |
|---|
| 678 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") |
|---|
| 679 |
end |
|---|
| 680 |
hour = $1.to_i |
|---|
| 681 |
min = $2.to_i |
|---|
| 682 |
sec = $3.to_i |
|---|
| 683 |
secfrac = $4 |
|---|
| 684 |
zonestr = $5 |
|---|
| 685 |
data = DateTime.civil(1, 1, 1, hour, min, sec, tz2of(zonestr)) |
|---|
| 686 |
if secfrac |
|---|
| 687 |
diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / DayInSec |
|---|
| 688 |
data += diffday |
|---|
| 689 |
end |
|---|
| 690 |
[data, secfrac] |
|---|
| 691 |
end |
|---|
| 692 |
|
|---|
| 693 |
def _set(data) |
|---|
| 694 |
if data.nil? |
|---|
| 695 |
@data = @secfrac = nil |
|---|
| 696 |
return |
|---|
| 697 |
end |
|---|
| 698 |
@data, @secfrac = data |
|---|
| 699 |
end |
|---|
| 700 |
|
|---|
| 701 |
def _to_s |
|---|
| 702 |
s = format('%02d:%02d:%02d', @data.hour, @data.min, @data.sec) |
|---|
| 703 |
if @data.sec_fraction.nonzero? |
|---|
| 704 |
if @secfrac |
|---|
| 705 |
s << ".#{ @secfrac }" |
|---|
| 706 |
else |
|---|
| 707 |
s << sprintf("%.16f", |
|---|
| 708 |
(@data.sec_fraction * DayInSec).to_f).sub(/^0/, '').sub(/0*$/, '') |
|---|
| 709 |
end |
|---|
| 710 |
end |
|---|
| 711 |
add_tz(s) |
|---|
| 712 |
end |
|---|
| 713 |
end |
|---|
| 714 |
|
|---|
| 715 |
class XSDDate < XSDAnySimpleType |
|---|
| 716 |
include XSDDateTimeImpl |
|---|
| 717 |
Type = QName.new(Namespace, DateLiteral) |
|---|
| 718 |
|
|---|
| 719 |
def initialize(value = nil) |
|---|
| 720 |
init(Type, value) |
|---|
| 721 |
end |
|---|
| 722 |
|
|---|
| 723 |
private |
|---|
| 724 |
|
|---|
| 725 |
def screen_data_str(t) |
|---|
| 726 |
/^([+\-]?\d{4,})-(\d\d)-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip |
|---|
| 727 |
unless Regexp.last_match |
|---|
| 728 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") |
|---|
| 729 |
end |
|---|
| 730 |
year = $1.to_i |
|---|
| 731 |
if year < 0 |
|---|
| 732 |
year += 1 |
|---|
| 733 |
end |
|---|
| 734 |
mon = $2.to_i |
|---|
| 735 |
mday = $3.to_i |
|---|
| 736 |
zonestr = $4 |
|---|
| 737 |
DateTime.civil(year, mon, mday, 0, 0, 0, tz2of(zonestr)) |
|---|
| 738 |
end |
|---|
| 739 |
|
|---|
| 740 |
def _to_s |
|---|
| 741 |
year = (@data.year > 0) ? @data.year : @data.year - 1 |
|---|
| 742 |
s = format('%.4d-%02d-%02d', year, @data.mon, @data.mday) |
|---|
| 743 |
add_tz(s) |
|---|
| 744 |
end |
|---|
| 745 |
end |
|---|
| 746 |
|
|---|
| 747 |
class XSDGYearMonth < XSDAnySimpleType |
|---|
| 748 |
include XSDDateTimeImpl |
|---|
| 749 |
Type = QName.new(Namespace, GYearMonthLiteral) |
|---|
| 750 |
|
|---|
| 751 |
def initialize(value = nil) |
|---|
| 752 |
init(Type, value) |
|---|
| 753 |
end |
|---|
| 754 |
|
|---|
| 755 |
private |
|---|
| 756 |
|
|---|
| 757 |
def screen_data_str(t) |
|---|
| 758 |
/^([+\-]?\d{4,})-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip |
|---|
| 759 |
unless Regexp.last_match |
|---|
| 760 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") |
|---|
| 761 |
end |
|---|
| 762 |
year = $1.to_i |
|---|
| 763 |
if year < 0 |
|---|
| 764 |
year += 1 |
|---|
| 765 |
end |
|---|
| 766 |
mon = $2.to_i |
|---|
| 767 |
zonestr = $3 |
|---|
| 768 |
DateTime.civil(year, mon, 1, 0, 0, 0, tz2of(zonestr)) |
|---|
| 769 |
end |
|---|
| 770 |
|
|---|
| 771 |
def _to_s |
|---|
| 772 |
year = (@data.year > 0) ? @data.year : @data.year - 1 |
|---|
| 773 |
s = format('%.4d-%02d', year, @data.mon) |
|---|
| 774 |
add_tz(s) |
|---|
| 775 |
end |
|---|
| 776 |
end |
|---|
| 777 |
|
|---|
| 778 |
class XSDGYear < XSDAnySimpleType |
|---|
| 779 |
include XSDDateTimeImpl |
|---|
| 780 |
Type = QName.new(Namespace, GYearLiteral) |
|---|
| 781 |
|
|---|
| 782 |
def initialize(value = nil) |
|---|
| 783 |
init(Type, value) |
|---|
| 784 |
end |
|---|
| 785 |
|
|---|
| 786 |
private |
|---|
| 787 |
|
|---|
| 788 |
def screen_data_str(t) |
|---|
| 789 |
/^([+\-]?\d{4,})(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip |
|---|
| 790 |
unless Regexp.last_match |
|---|
| 791 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") |
|---|
| 792 |
end |
|---|
| 793 |
year = $1.to_i |
|---|
| 794 |
if year < 0 |
|---|
| 795 |
year += 1 |
|---|
| 796 |
end |
|---|
| 797 |
zonestr = $2 |
|---|
| 798 |
DateTime.civil(year, 1, 1, 0, 0, 0, tz2of(zonestr)) |
|---|
| 799 |
end |
|---|
| 800 |
|
|---|
| 801 |
def _to_s |
|---|
| 802 |
year = (@data.year > 0) ? @data.year : @data.year - 1 |
|---|
| 803 |
s = format('%.4d', year) |
|---|
| 804 |
add_tz(s) |
|---|
| 805 |
end |
|---|
| 806 |
end |
|---|
| 807 |
|
|---|
| 808 |
class XSDGMonthDay < XSDAnySimpleType |
|---|
| 809 |
include XSDDateTimeImpl |
|---|
| 810 |
Type = QName.new(Namespace, GMonthDayLiteral) |
|---|
| 811 |
|
|---|
| 812 |
def initialize(value = nil) |
|---|
| 813 |
init(Type, value) |
|---|
| 814 |
end |
|---|
| 815 |
|
|---|
| 816 |
private |
|---|
| 817 |
|
|---|
| 818 |
def screen_data_str(t) |
|---|
| 819 |
/^--(\d\d)-(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip |
|---|
| 820 |
unless Regexp.last_match |
|---|
| 821 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") |
|---|
| 822 |
end |
|---|
| 823 |
mon = $1.to_i |
|---|
| 824 |
mday = $2.to_i |
|---|
| 825 |
zonestr = $3 |
|---|
| 826 |
DateTime.civil(1, mon, mday, 0, 0, 0, tz2of(zonestr)) |
|---|
| 827 |
end |
|---|
| 828 |
|
|---|
| 829 |
def _to_s |
|---|
| 830 |
s = format('--%02d-%02d', @data.mon, @data.mday) |
|---|
| 831 |
add_tz(s) |
|---|
| 832 |
end |
|---|
| 833 |
end |
|---|
| 834 |
|
|---|
| 835 |
class XSDGDay < XSDAnySimpleType |
|---|
| 836 |
include XSDDateTimeImpl |
|---|
| 837 |
Type = QName.new(Namespace, GDayLiteral) |
|---|
| 838 |
|
|---|
| 839 |
def initialize(value = nil) |
|---|
| 840 |
init(Type, value) |
|---|
| 841 |
end |
|---|
| 842 |
|
|---|
| 843 |
private |
|---|
| 844 |
|
|---|
| 845 |
def screen_data_str(t) |
|---|
| 846 |
/^---(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip |
|---|
| 847 |
unless Regexp.last_match |
|---|
| 848 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") |
|---|
| 849 |
end |
|---|
| 850 |
mday = $1.to_i |
|---|
| 851 |
zonestr = $2 |
|---|
| 852 |
DateTime.civil(1, 1, mday, 0, 0, 0, tz2of(zonestr)) |
|---|
| 853 |
end |
|---|
| 854 |
|
|---|
| 855 |
def _to_s |
|---|
| 856 |
s = format('---%02d', @data.mday) |
|---|
| 857 |
add_tz(s) |
|---|
| 858 |
end |
|---|
| 859 |
end |
|---|
| 860 |
|
|---|
| 861 |
class XSDGMonth < XSDAnySimpleType |
|---|
| 862 |
include XSDDateTimeImpl |
|---|
| 863 |
Type = QName.new(Namespace, GMonthLiteral) |
|---|
| 864 |
|
|---|
| 865 |
def initialize(value = nil) |
|---|
| 866 |
init(Type, value) |
|---|
| 867 |
end |
|---|
| 868 |
|
|---|
| 869 |
private |
|---|
| 870 |
|
|---|
| 871 |
def screen_data_str(t) |
|---|
| 872 |
/^--(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip |
|---|
| 873 |
unless Regexp.last_match |
|---|
| 874 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") |
|---|
| 875 |
end |
|---|
| 876 |
mon = $1.to_i |
|---|
| 877 |
zonestr = $2 |
|---|
| 878 |
DateTime.civil(1, mon, 1, 0, 0, 0, tz2of(zonestr)) |
|---|
| 879 |
end |
|---|
| 880 |
|
|---|
| 881 |
def _to_s |
|---|
| 882 |
s = format('--%02d', @data.mon) |
|---|
| 883 |
add_tz(s) |
|---|
| 884 |
end |
|---|
| 885 |
end |
|---|
| 886 |
|
|---|
| 887 |
class XSDHexBinary < XSDAnySimpleType |
|---|
| 888 |
Type = QName.new(Namespace, HexBinaryLiteral) |
|---|
| 889 |
|
|---|
| 890 |
# String in Ruby could be a binary. |
|---|
| 891 |
def initialize(value = nil) |
|---|
| 892 |
init(Type, value) |
|---|
| 893 |
end |
|---|
| 894 |
|
|---|
| 895 |
def set_encoded(value) |
|---|
| 896 |
if /^[0-9a-fA-F]*$/ !~ value |
|---|
| 897 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") |
|---|
| 898 |
end |
|---|
| 899 |
@data = String.new(value).strip |
|---|
| 900 |
@is_nil = false |
|---|
| 901 |
end |
|---|
| 902 |
|
|---|
| 903 |
def string |
|---|
| 904 |
[@data].pack("H*") |
|---|
| 905 |
end |
|---|
| 906 |
|
|---|
| 907 |
private |
|---|
| 908 |
|
|---|
| 909 |
def screen_data(value) |
|---|
| 910 |
value.unpack("H*")[0].tr('a-f', 'A-F') |
|---|
| 911 |
end |
|---|
| 912 |
end |
|---|
| 913 |
|
|---|
| 914 |
class XSDBase64Binary < XSDAnySimpleType |
|---|
| 915 |
Type = QName.new(Namespace, Base64BinaryLiteral) |
|---|
| 916 |
|
|---|
| 917 |
# String in Ruby could be a binary. |
|---|
| 918 |
def initialize(value = nil) |
|---|
| 919 |
init(Type, value) |
|---|
| 920 |
end |
|---|
| 921 |
|
|---|
| 922 |
def set_encoded(value) |
|---|
| 923 |
if /^[A-Za-z0-9+\/=]*$/ !~ value |
|---|
| 924 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") |
|---|
| 925 |
end |
|---|
| 926 |
@data = String.new(value).strip |
|---|
| 927 |
@is_nil = false |
|---|
| 928 |
end |
|---|
| 929 |
|
|---|
| 930 |
def string |
|---|
| 931 |
@data.unpack("m")[0] |
|---|
| 932 |
end |
|---|
| 933 |
|
|---|
| 934 |
private |
|---|
| 935 |
|
|---|
| 936 |
def screen_data(value) |
|---|
| 937 |
[value].pack("m").strip |
|---|
| 938 |
end |
|---|
| 939 |
end |
|---|
| 940 |
|
|---|
| 941 |
class XSDAnyURI < XSDAnySimpleType |
|---|
| 942 |
Type = QName.new(Namespace, AnyURILiteral) |
|---|
| 943 |
|
|---|
| 944 |
def initialize(value = nil) |
|---|
| 945 |
init(Type, value) |
|---|
| 946 |
end |
|---|
| 947 |
|
|---|
| 948 |
private |
|---|
| 949 |
|
|---|
| 950 |
def screen_data(value) |
|---|
| 951 |
begin |
|---|
| 952 |
URI.parse(value.to_s.strip) |
|---|
| 953 |
rescue URI::InvalidURIError |
|---|
| 954 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.", $!) |
|---|
| 955 |
end |
|---|
| 956 |
end |
|---|
| 957 |
end |
|---|
| 958 |
|
|---|
| 959 |
class XSDQName < XSDAnySimpleType |
|---|
| 960 |
Type = QName.new(Namespace, QNameLiteral) |
|---|
| 961 |
|
|---|
| 962 |
def initialize(value = nil) |
|---|
| 963 |
init(Type, value) |
|---|
| 964 |
end |
|---|
| 965 |
|
|---|
| 966 |
private |
|---|
| 967 |
|
|---|
| 968 |
def screen_data(value) |
|---|
| 969 |
/^(?:([^:]+):)?([^:]+)$/ =~ value.to_s.strip |
|---|
| 970 |
unless Regexp.last_match |
|---|
| 971 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") |
|---|
| 972 |
end |
|---|
| 973 |
prefix = $1 |
|---|
| 974 |
localpart = $2 |
|---|
| 975 |
[prefix, localpart] |
|---|
| 976 |
end |
|---|
| 977 |
|
|---|
| 978 |
def _set(data) |
|---|
| 979 |
if data.nil? |
|---|
| 980 |
@prefix = @localpart = @data = nil |
|---|
| 981 |
return |
|---|
| 982 |
end |
|---|
| 983 |
@prefix, @localpart = data |
|---|
| 984 |
@data = _to_s |
|---|
| 985 |
@data.freeze |
|---|
| 986 |
end |
|---|
| 987 |
|
|---|
| 988 |
def _to_s |
|---|
| 989 |
if @prefix |
|---|
| 990 |
"#{ @prefix }:#{ @localpart }" |
|---|
| 991 |
else |
|---|
| 992 |
"#{ @localpart }" |
|---|
| 993 |
end |
|---|
| 994 |
end |
|---|
| 995 |
end |
|---|
| 996 |
|
|---|
| 997 |
|
|---|
| 998 |
### |
|---|
| 999 |
## Derived types |
|---|
| 1000 |
# |
|---|
| 1001 |
class XSDNormalizedString < XSDString |
|---|
| 1002 |
Type = QName.new(Namespace, NormalizedStringLiteral) |
|---|
| 1003 |
|
|---|
| 1004 |
def initialize(value = nil) |
|---|
| 1005 |
init(Type, value) |
|---|
| 1006 |
end |
|---|
| 1007 |
|
|---|
| 1008 |
private |
|---|
| 1009 |
|
|---|
| 1010 |
def screen_data(value) |
|---|
| 1011 |
super |
|---|
| 1012 |
if /[\t\r\n]/ =~ value |
|---|
| 1013 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") |
|---|
| 1014 |
end |
|---|
| 1015 |
value |
|---|
| 1016 |
end |
|---|
| 1017 |
end |
|---|
| 1018 |
|
|---|
| 1019 |
class XSDToken < XSDNormalizedString |
|---|
| 1020 |
Type = QName.new(Namespace, TokenLiteral) |
|---|
| 1021 |
|
|---|
| 1022 |
def initialize(value = nil) |
|---|
| 1023 |
init(Type, value) |
|---|
| 1024 |
end |
|---|
| 1025 |
|
|---|
| 1026 |
private |
|---|
| 1027 |
|
|---|
| 1028 |
def screen_data(value) |
|---|
| 1029 |
super |
|---|
| 1030 |
if /\A / =~ value or / \Z/ =~ value or value.index(' ') |
|---|
| 1031 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") |
|---|
| 1032 |
end |
|---|
| 1033 |
value |
|---|
| 1034 |
end |
|---|
| 1035 |
end |
|---|
| 1036 |
|
|---|
| 1037 |
class XSDLanguage < XSDToken |
|---|
| 1038 |
Type = QName.new(Namespace, LanguageLiteral) |
|---|
| 1039 |
|
|---|
| 1040 |
def initialize(value = nil) |
|---|
| 1041 |
init(Type, value) |
|---|
| 1042 |
end |
|---|
| 1043 |
|
|---|
| 1044 |
private |
|---|
| 1045 |
|
|---|
| 1046 |
def screen_data(value) |
|---|
| 1047 |
super |
|---|
| 1048 |
# RFC 3066 syntax check |
|---|
| 1049 |
if /\A[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})?\z/ !~ value |
|---|
| 1050 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") |
|---|
| 1051 |
end |
|---|
| 1052 |
value |
|---|
| 1053 |
end |
|---|
| 1054 |
end |
|---|
| 1055 |
|
|---|
| 1056 |
class XSDNMTOKEN < XSDToken |
|---|
| 1057 |
Type = QName.new(Namespace, NMTOKENLiteral) |
|---|
| 1058 |
|
|---|
| 1059 |
def initialize(value = nil) |
|---|
| 1060 |
init(Type, value) |
|---|
| 1061 |
end |
|---|
| 1062 |
|
|---|
| 1063 |
private |
|---|
| 1064 |
|
|---|
| 1065 |
def screen_data(value) |
|---|
| 1066 |
super |
|---|
| 1067 |
# TODO: check lexical space and convert to a value |
|---|
| 1068 |
value |
|---|
| 1069 |
end |
|---|
| 1070 |
end |
|---|
| 1071 |
|
|---|
| 1072 |
class XSDNMTOKENS < XSDNMTOKEN |
|---|
| 1073 |
Type = QName.new(Namespace, NMTOKENSLiteral) |
|---|
| 1074 |
|
|---|
| 1075 |
def initialize(value = nil) |
|---|
| 1076 |
init(Type, value) |
|---|
| 1077 |
end |
|---|
| 1078 |
|
|---|
| 1079 |
private |
|---|
| 1080 |
|
|---|
| 1081 |
def screen_data(value) |
|---|
| 1082 |
# derived by list |
|---|
| 1083 |
# TODO: check lexical space and convert to a value |
|---|
| 1084 |
value |
|---|
| 1085 |
end |
|---|
| 1086 |
end |
|---|
| 1087 |
|
|---|
| 1088 |
class XSDName < XSDToken |
|---|
| 1089 |
Type = QName.new(Namespace, NameLiteral) |
|---|
| 1090 |
|
|---|
| 1091 |
def initialize(value = nil) |
|---|
| 1092 |
init(Type, value) |
|---|
| 1093 |
end |
|---|
| 1094 |
|
|---|
| 1095 |
private |
|---|
| 1096 |
|
|---|
| 1097 |
def screen_data(value) |
|---|
| 1098 |
super |
|---|
| 1099 |
# TODO: check lexical space and convert to a value |
|---|
| 1100 |
value |
|---|
| 1101 |
end |
|---|
| 1102 |
end |
|---|
| 1103 |
|
|---|
| 1104 |
class XSDNCName < XSDName |
|---|
| 1105 |
Type = QName.new(Namespace, NCNameLiteral) |
|---|
| 1106 |
|
|---|
| 1107 |
def initialize(value = nil) |
|---|
| 1108 |
init(Type, value) |
|---|
| 1109 |
end |
|---|
| 1110 |
|
|---|
| 1111 |
private |
|---|
| 1112 |
|
|---|
| 1113 |
def screen_data(value) |
|---|
| 1114 |
super |
|---|
| 1115 |
# TODO: check lexical space and convert to a value |
|---|
| 1116 |
value |
|---|
| 1117 |
end |
|---|
| 1118 |
end |
|---|
| 1119 |
|
|---|
| 1120 |
class XSDID < XSDNCName |
|---|
| 1121 |
Type = QName.new(Namespace, IDLiteral) |
|---|
| 1122 |
|
|---|
| 1123 |
def initialize(value = nil) |
|---|
| 1124 |
init(Type, value) |
|---|
| 1125 |
end |
|---|
| 1126 |
|
|---|
| 1127 |
private |
|---|
| 1128 |
|
|---|
| 1129 |
def screen_data(value) |
|---|
| 1130 |
super |
|---|
| 1131 |
# TODO: check lexical space and convert to a value |
|---|
| 1132 |
value |
|---|
| 1133 |
end |
|---|
| 1134 |
end |
|---|
| 1135 |
|
|---|
| 1136 |
class XSDIDREF < XSDNCName |
|---|
| 1137 |
Type = QName.new(Namespace, IDREFLiteral) |
|---|
| 1138 |
|
|---|
| 1139 |
def initialize(value = nil) |
|---|
| 1140 |
init(Type, value) |
|---|
| 1141 |
end |
|---|
| 1142 |
|
|---|
| 1143 |
private |
|---|
| 1144 |
|
|---|
| 1145 |
def screen_data(value) |
|---|
| 1146 |
super |
|---|
| 1147 |
# TODO: check lexical space and convert to a value |
|---|
| 1148 |
value |
|---|
| 1149 |
end |
|---|
| 1150 |
end |
|---|
| 1151 |
|
|---|
| 1152 |
class XSDIDREFS < XSDIDREF |
|---|
| 1153 |
Type = QName.new(Namespace, IDREFSLiteral) |
|---|
| 1154 |
|
|---|
| 1155 |
def initialize(value = nil) |
|---|
| 1156 |
init(Type, value) |
|---|
| 1157 |
end |
|---|
| 1158 |
|
|---|
| 1159 |
private |
|---|
| 1160 |
|
|---|
| 1161 |
def screen_data(value) |
|---|
| 1162 |
# derived by list |
|---|
| 1163 |
# TODO: check lexical space and convert to a value |
|---|
| 1164 |
value |
|---|
| 1165 |
end |
|---|
| 1166 |
end |
|---|
| 1167 |
|
|---|
| 1168 |
class XSDENTITY < XSDNCName |
|---|
| 1169 |
Type = QName.new(Namespace, ENTITYLiteral) |
|---|
| 1170 |
|
|---|
| 1171 |
def initialize(value = nil) |
|---|
| 1172 |
init(Type, value) |
|---|
| 1173 |
end |
|---|
| 1174 |
|
|---|
| 1175 |
private |
|---|
| 1176 |
|
|---|
| 1177 |
def screen_data(value) |
|---|
| 1178 |
super |
|---|
| 1179 |
# TODO: check lexical space and convert to a value |
|---|
| 1180 |
value |
|---|
| 1181 |
end |
|---|
| 1182 |
end |
|---|
| 1183 |
|
|---|
| 1184 |
class XSDENTITIES < XSDENTITY |
|---|
| 1185 |
Type = QName.new(Namespace, ENTITIESLiteral) |
|---|
| 1186 |
|
|---|
| 1187 |
def initialize(value = nil) |
|---|
| 1188 |
init(Type, value) |
|---|
| 1189 |
end |
|---|
| 1190 |
|
|---|
| 1191 |
private |
|---|
| 1192 |
|
|---|
| 1193 |
def screen_data(value) |
|---|
| 1194 |
# derived by list |
|---|
| 1195 |
# TODO: check lexical space and convert to a value |
|---|
| 1196 |
value |
|---|
| 1197 |
end |
|---|
| 1198 |
end |
|---|
| 1199 |
|
|---|
| 1200 |
class XSDInteger < XSDDecimal |
|---|
| 1201 |
Type = QName.new(Namespace, IntegerLiteral) |
|---|
| 1202 |
|
|---|
| 1203 |
def initialize(value = nil) |
|---|
| 1204 |
init(Type, value) |
|---|
| 1205 |
end |
|---|
| 1206 |
|
|---|
| 1207 |
private |
|---|
| 1208 |
|
|---|
| 1209 |
def screen_data_str(str) |
|---|
| 1210 |
begin |
|---|
| 1211 |
data = Integer(str) |
|---|
| 1212 |
rescue ArgumentError |
|---|
| 1213 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.", $!) |
|---|
| 1214 |
end |
|---|
| 1215 |
unless validate(data) |
|---|
| 1216 |
raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") |
|---|
| 1217 |
end |
|---|
| 1218 |
data |
|---|
| 1219 |
end |
|---|
| 1220 |
|
|---|
| 1221 |
def _set(value) |
|---|
| 1222 |
@data = value |
|---|
| 1223 |
end |
|---|
| 1224 |
|
|---|
| 1225 |
def _to_s() |
|---|
| 1226 |
@data.to_s |
|---|
| 1227 |
end |
|---|
| 1228 |
|
|---|
| 1229 |
def validate(v) |
|---|
| 1230 |
max = maxinclusive |
|---|
| 1231 |
min = mininclusive |
|---|
| 1232 |
(max.nil? or v <= max) and (min.nil? or v >= min) |
|---|
| 1233 |
end |
|---|
| 1234 |
|
|---|
| 1235 |
def maxinclusive |
|---|
| 1236 |
nil |
|---|
| 1237 |
end |
|---|
| 1238 |
|
|---|
| 1239 |
def mininclusive |
|---|
| 1240 |
nil |
|---|
| 1241 |
end |
|---|
| 1242 |
|
|---|
| 1243 |
PositiveMinInclusive = 1 |
|---|
| 1244 |
def positive(v) |
|---|
| 1245 |
PositiveMinInclusive <= v |
|---|
| 1246 |
end |
|---|
| 1247 |
end |
|---|
| 1248 |
|
|---|
| 1249 |
class XSDNonPositiveInteger < XSDInteger |
|---|
| 1250 |
Type = QName.new(Namespace, NonPositiveIntegerLiteral) |
|---|
| 1251 |
|
|---|
| 1252 |
def initialize(value = nil) |
|---|
| 1253 |
init(Type, value) |
|---|
| 1254 |
end |
|---|
| 1255 |
|
|---|
| 1256 |
private |
|---|
| 1257 |
|
|---|
| 1258 |
def maxinclusive |
|---|
| 1259 |
0 |
|---|
| 1260 |
end |
|---|
| 1261 |
|
|---|
| 1262 |
def mininclusive |
|---|
| 1263 |
nil |
|---|
| 1264 |
end |
|---|
| 1265 |
end |
|---|
| 1266 |
|
|---|
| 1267 |
class XSDNegativeInteger < XSDNonPositiveInteger |
|---|
| 1268 |
Type = QName.new(Namespace, NegativeIntegerLiteral) |
|---|
| 1269 |
|
|---|
| 1270 |
def initialize(value = nil) |
|---|
| 1271 |
init(Type, value) |
|---|
| 1272 |
end |
|---|
| 1273 |
|
|---|
| 1274 |
private |
|---|
| 1275 |
|
|---|
| 1276 |
def maxinclusive |
|---|
| 1277 |
-1 |
|---|
| 1278 |
end |
|---|
| 1279 |
|
|---|
| 1280 |
def mininclusive |
|---|
| 1281 |
nil |
|---|
| 1282 |
end |
|---|
| 1283 |
end |
|---|
| 1284 |
|
|---|
| 1285 |
class XSDLong < XSDInteger |
|---|
| 1286 |
Type = QName.new(Namespace, LongLiteral) |
|---|
| 1287 |
|
|---|
| 1288 |
def initialize(value = nil) |
|---|
| 1289 |
init(Type, value) |
|---|
| 1290 |
end |
|---|
| 1291 |
|
|---|
| 1292 |
private |
|---|
| 1293 |
|
|---|
| 1294 |
def maxinclusive |
|---|
| 1295 |
+9223372036854775807 |
|---|
| 1296 |
end |
|---|
| 1297 |
|
|---|
| 1298 |
def mininclusive |
|---|
| 1299 |
-9223372036854775808 |
|---|
| 1300 |
end |
|---|
| 1301 |
end |
|---|
| 1302 |
|
|---|
| 1303 |
class XSDInt < XSDLong |
|---|
| 1304 |
Type = QName.new(Namespace, IntLiteral) |
|---|
| 1305 |
|
|---|
| 1306 |
def initialize(value = nil) |
|---|
| 1307 |
init(Type, value) |
|---|
| 1308 |
end |
|---|
| 1309 |
|
|---|
| 1310 |
private |
|---|
| 1311 |
|
|---|
| 1312 |
def maxinclusive |
|---|
| 1313 |
+2147483647 |
|---|
| 1314 |
end |
|---|
| 1315 |
|
|---|
| 1316 |
def mininclusive |
|---|
| 1317 |
-2147483648 |
|---|
| 1318 |
end |
|---|
| 1319 |
end |
|---|
| 1320 |
|
|---|
| 1321 |
class XSDShort < XSDInt |
|---|
| 1322 |
Type = QName.new(Namespace, ShortLiteral) |
|---|
| 1323 |
|
|---|
| 1324 |
def initialize(value = nil) |
|---|
| 1325 |
init(Type, value) |
|---|
| 1326 |
end |
|---|
| 1327 |
|
|---|
| 1328 |
private |
|---|
| 1329 |
|
|---|
| 1330 |
def maxinclusive |
|---|
| 1331 |
+32767 |
|---|
| 1332 |
end |
|---|
| 1333 |
|
|---|
| 1334 |
def mininclusive |
|---|
| 1335 |
-32768 |
|---|
| 1336 |
end |
|---|
| 1337 |
end |
|---|
| 1338 |
|
|---|
| 1339 |
class XSDByte < XSDShort |
|---|
| 1340 |
Type = QName.new(Namespace, ByteLiteral) |
|---|
| 1341 |
|
|---|
| 1342 |
def initialize(value = nil) |
|---|
| 1343 |
init(Type, value) |
|---|
| 1344 |
end |
|---|
| 1345 |
|
|---|
| 1346 |
private |
|---|
| 1347 |
|
|---|
| 1348 |
def maxinclusive |
|---|
| 1349 |
+127 |
|---|
| 1350 |
end |
|---|
| 1351 |
|
|---|
| 1352 |
def mininclusive |
|---|
| 1353 |
-128 |
|---|
| 1354 |
end |
|---|
| 1355 |
end |
|---|
| 1356 |
|
|---|
| 1357 |
class XSDNonNegativeInteger < XSDInteger |
|---|
| 1358 |
Type = QName.new(Namespace, NonNegativeIntegerLiteral) |
|---|
| 1359 |
|
|---|
| 1360 |
def initialize(value = nil) |
|---|
| 1361 |
init(Type, value) |
|---|
| 1362 |
end |
|---|
| 1363 |
|
|---|
| 1364 |
private |
|---|
| 1365 |
|
|---|
| 1366 |
def maxinclusive |
|---|
| 1367 |
nil |
|---|
| 1368 |
end |
|---|
| 1369 |
|
|---|
| 1370 |
def mininclusive |
|---|
| 1371 |
0 |
|---|
| 1372 |
end |
|---|
| 1373 |
end |
|---|
| 1374 |
|
|---|
| 1375 |
class XSDUnsignedLong < XSDNonNegativeInteger |
|---|
| 1376 |
Type = QName.new(Namespace, UnsignedLongLiteral) |
|---|
| 1377 |
|
|---|
| 1378 |
def initialize(value = nil) |
|---|
| 1379 |
init(Type, value) |
|---|
| 1380 |
end |
|---|
| 1381 |
|
|---|
| 1382 |
private |
|---|
| 1383 |
|
|---|
| 1384 |
def maxinclusive |
|---|
| 1385 |
+18446744073709551615 |
|---|
| 1386 |
end |
|---|
| 1387 |
|
|---|
| 1388 |
def mininclusive |
|---|
| 1389 |
0 |
|---|
| 1390 |
end |
|---|
| 1391 |
end |
|---|
| 1392 |
|
|---|
| 1393 |
class XSDUnsignedInt < XSDUnsignedLong |
|---|
| 1394 |
Type = QName.new(Namespace, UnsignedIntLiteral) |
|---|
| 1395 |
|
|---|
| 1396 |
def initialize(value = nil) |
|---|
| 1397 |
init(Type, value) |
|---|
| 1398 |
end |
|---|
| 1399 |
|
|---|
| 1400 |
private |
|---|
| 1401 |
|
|---|
| 1402 |
def maxinclusive |
|---|
| 1403 |
+4294967295 |
|---|
| 1404 |
end |
|---|
| 1405 |
|
|---|
| 1406 |
def mininclusive |
|---|
| 1407 |
0 |
|---|
| 1408 |
end |
<