source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/xsd/datatypes.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

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