From 11dbedfaad4a9a9521ece2198a8dc491678b1902 Mon Sep 17 00:00:00 2001 From: shyouhei Date: Wed, 29 Aug 2007 04:06:12 +0000 Subject: add tag v1_8_6_5001 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_8_6_5001@13304 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ruby_1_8_6/lib/xsd/datatypes.rb | 1269 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1269 insertions(+) create mode 100644 ruby_1_8_6/lib/xsd/datatypes.rb (limited to 'ruby_1_8_6/lib/xsd/datatypes.rb') diff --git a/ruby_1_8_6/lib/xsd/datatypes.rb b/ruby_1_8_6/lib/xsd/datatypes.rb new file mode 100644 index 0000000000..bbe6c8578f --- /dev/null +++ b/ruby_1_8_6/lib/xsd/datatypes.rb @@ -0,0 +1,1269 @@ +# XSD4R - XML Schema Datatype implementation. +# Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/qname' +require 'xsd/charset' +require 'uri' + + +### +## XMLSchamaDatatypes general definitions. +# +module XSD + + +Namespace = 'http://www.w3.org/2001/XMLSchema' +InstanceNamespace = 'http://www.w3.org/2001/XMLSchema-instance' + +AttrType = 'type' +NilValue = 'true' + +AnyTypeLiteral = 'anyType' +AnySimpleTypeLiteral = 'anySimpleType' +NilLiteral = 'nil' +StringLiteral = 'string' +BooleanLiteral = 'boolean' +DecimalLiteral = 'decimal' +FloatLiteral = 'float' +DoubleLiteral = 'double' +DurationLiteral = 'duration' +DateTimeLiteral = 'dateTime' +TimeLiteral = 'time' +DateLiteral = 'date' +GYearMonthLiteral = 'gYearMonth' +GYearLiteral = 'gYear' +GMonthDayLiteral = 'gMonthDay' +GDayLiteral = 'gDay' +GMonthLiteral = 'gMonth' +HexBinaryLiteral = 'hexBinary' +Base64BinaryLiteral = 'base64Binary' +AnyURILiteral = 'anyURI' +QNameLiteral = 'QName' + +NormalizedStringLiteral = 'normalizedString' +#3.3.2 token +#3.3.3 language +#3.3.4 NMTOKEN +#3.3.5 NMTOKENS +#3.3.6 Name +#3.3.7 NCName +#3.3.8 ID +#3.3.9 IDREF +#3.3.10 IDREFS +#3.3.11 ENTITY +#3.3.12 ENTITIES +IntegerLiteral = 'integer' +NonPositiveIntegerLiteral = 'nonPositiveInteger' +NegativeIntegerLiteral = 'negativeInteger' +LongLiteral = 'long' +IntLiteral = 'int' +ShortLiteral = 'short' +ByteLiteral = 'byte' +NonNegativeIntegerLiteral = 'nonNegativeInteger' +UnsignedLongLiteral = 'unsignedLong' +UnsignedIntLiteral = 'unsignedInt' +UnsignedShortLiteral = 'unsignedShort' +UnsignedByteLiteral = 'unsignedByte' +PositiveIntegerLiteral = 'positiveInteger' + +AttrTypeName = QName.new(InstanceNamespace, AttrType) +AttrNilName = QName.new(InstanceNamespace, NilLiteral) + +AnyTypeName = QName.new(Namespace, AnyTypeLiteral) +AnySimpleTypeName = QName.new(Namespace, AnySimpleTypeLiteral) + +class Error < StandardError; end +class ValueSpaceError < Error; end + + +### +## The base class of all datatypes with Namespace. +# +class NSDBase + @@types = [] + + attr_accessor :type + + def self.inherited(klass) + @@types << klass + end + + def self.types + @@types + end + + def initialize + end + + def init(type) + @type = type + end +end + + +### +## The base class of XSD datatypes. +# +class XSDAnySimpleType < NSDBase + include XSD + Type = QName.new(Namespace, AnySimpleTypeLiteral) + + # @data represents canonical space (ex. Integer: 123). + attr_reader :data + # @is_nil represents this data is nil or not. + attr_accessor :is_nil + + def initialize(value = nil) + init(Type, value) + end + + # true or raise + def check_lexical_format(value) + screen_data(value) + true + end + + # set accepts a string which follows lexical space (ex. String: "+123"), or + # an object which follows canonical space (ex. Integer: 123). + def set(value) + if value.nil? + @is_nil = true + @data = nil + _set(nil) + else + @is_nil = false + _set(screen_data(value)) + end + end + + # to_s creates a string which follows lexical space (ex. String: "123"). + def to_s() + if @is_nil + "" + else + _to_s + end + end + +private + + def init(type, value) + super(type) + set(value) + end + + # raises ValueSpaceError if check failed + def screen_data(value) + value + end + + def _set(value) + @data = value + end + + def _to_s + @data.to_s + end +end + +class XSDNil < XSDAnySimpleType + Type = QName.new(Namespace, NilLiteral) + Value = 'true' + + def initialize(value = nil) + init(Type, value) + end +end + + +### +## Primitive datatypes. +# +class XSDString < XSDAnySimpleType + Type = QName.new(Namespace, StringLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data(value) + unless XSD::Charset.is_ces(value, XSD::Charset.encoding) + raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") + end + value + end +end + +class XSDBoolean < XSDAnySimpleType + Type = QName.new(Namespace, BooleanLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data(value) + if value.is_a?(String) + str = value.strip + if str == 'true' || str == '1' + true + elsif str == 'false' || str == '0' + false + else + raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") + end + else + value ? true : false + end + end +end + +class XSDDecimal < XSDAnySimpleType + Type = QName.new(Namespace, DecimalLiteral) + + def initialize(value = nil) + init(Type, value) + end + + def nonzero? + (@number != '0') + end + +private + + def screen_data(d) + if d.is_a?(String) + # Integer("00012") => 10 in Ruby. + d.sub!(/^([+\-]?)0*(?=\d)/, "\\1") + end + screen_data_str(d) + end + + def screen_data_str(str) + /^([+\-]?)(\d*)(?:\.(\d*)?)?$/ =~ str.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") + end + sign = $1 || '+' + int_part = $2 + frac_part = $3 + int_part = '0' if int_part.empty? + frac_part = frac_part ? frac_part.sub(/0+$/, '') : '' + point = - frac_part.size + number = int_part + frac_part + # normalize + if sign == '+' + sign = '' + elsif sign == '-' + if number == '0' + sign = '' + end + end + [sign, point, number] + end + + def _set(data) + if data.nil? + @sign = @point = @number = @data = nil + return + end + @sign, @point, @number = data + @data = _to_s + @data.freeze + end + + # 0.0 -> 0; right? + def _to_s + str = @number.dup + if @point.nonzero? + str[@number.size + @point, 0] = '.' + end + @sign + str + end +end + +module FloatConstants + NaN = 0.0/0.0 + POSITIVE_INF = +1.0/0.0 + NEGATIVE_INF = -1.0/0.0 + POSITIVE_ZERO = +1.0/POSITIVE_INF + NEGATIVE_ZERO = -1.0/POSITIVE_INF + MIN_POSITIVE_SINGLE = 2.0 ** -149 +end + +class XSDFloat < XSDAnySimpleType + include FloatConstants + Type = QName.new(Namespace, FloatLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data(value) + # "NaN".to_f => 0 in some environment. libc? + if value.is_a?(Float) + return narrow32bit(value) + end + str = value.to_s.strip + if str == 'NaN' + NaN + elsif str == 'INF' + POSITIVE_INF + elsif str == '-INF' + NEGATIVE_INF + else + if /^[+\-\.\deE]+$/ !~ str + raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") + end + # Float("-1.4E") might fail on some system. + str << '0' if /e$/i =~ str + begin + return narrow32bit(Float(str)) + rescue ArgumentError + raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") + end + end + end + + def _to_s + if @data.nan? + 'NaN' + elsif @data.infinite? == 1 + 'INF' + elsif @data.infinite? == -1 + '-INF' + else + sign = XSDFloat.positive?(@data) ? '+' : '-' + sign + sprintf("%.10g", @data.abs).sub(/[eE]([+-])?0+/) { 'e' + $1 } + end + end + + # Convert to single-precision 32-bit floating point value. + def narrow32bit(f) + if f.nan? || f.infinite? + f + elsif f.abs < MIN_POSITIVE_SINGLE + XSDFloat.positive?(f) ? POSITIVE_ZERO : NEGATIVE_ZERO + else + f + end + end + + def self.positive?(value) + (1 / value) > 0.0 + end +end + +# Ruby's Float is double-precision 64-bit floating point value. +class XSDDouble < XSDAnySimpleType + include FloatConstants + Type = QName.new(Namespace, DoubleLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data(value) + # "NaN".to_f => 0 in some environment. libc? + if value.is_a?(Float) + return value + end + str = value.to_s.strip + if str == 'NaN' + NaN + elsif str == 'INF' + POSITIVE_INF + elsif str == '-INF' + NEGATIVE_INF + else + begin + return Float(str) + rescue ArgumentError + # '1.4e' cannot be parsed on some architecture. + if /e\z/i =~ str + begin + return Float(str + '0') + rescue ArgumentError + raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") + end + else + raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") + end + end + end + end + + def _to_s + if @data.nan? + 'NaN' + elsif @data.infinite? == 1 + 'INF' + elsif @data.infinite? == -1 + '-INF' + else + sign = (1 / @data > 0.0) ? '+' : '-' + sign + sprintf("%.16g", @data.abs).sub(/[eE]([+-])?0+/) { 'e' + $1 } + end + end +end + +class XSDDuration < XSDAnySimpleType + Type = QName.new(Namespace, DurationLiteral) + + attr_accessor :sign + attr_accessor :year + attr_accessor :month + attr_accessor :day + attr_accessor :hour + attr_accessor :min + attr_accessor :sec + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data(value) + /^([+\-]?)P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/ =~ value.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") + end + if ($5 and ((!$2 and !$3 and !$4) or (!$6 and !$7 and !$8))) + # Should we allow 'PT5S' here? + raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") + end + sign = $1 + year = $2.to_i + month = $3.to_i + day = $4.to_i + hour = $6.to_i + min = $7.to_i + sec = $8 ? XSDDecimal.new($8) : 0 + [sign, year, month, day, hour, min, sec] + end + + def _set(data) + if data.nil? + @sign = @year = @month = @day = @hour = @min = @sec = @data = nil + return + end + @sign, @year, @month, @day, @hour, @min, @sec = data + @data = _to_s + @data.freeze + end + + def _to_s + str = '' + str << @sign if @sign + str << 'P' + l = '' + l << "#{ @year }Y" if @year.nonzero? + l << "#{ @month }M" if @month.nonzero? + l << "#{ @day }D" if @day.nonzero? + r = '' + r << "#{ @hour }H" if @hour.nonzero? + r << "#{ @min }M" if @min.nonzero? + r << "#{ @sec }S" if @sec.nonzero? + str << l + if l.empty? + str << "0D" + end + unless r.empty? + str << "T" << r + end + str + end +end + + +require 'rational' +require 'date' + +module XSDDateTimeImpl + SecInDay = 86400 # 24 * 60 * 60 + + def to_obj(klass) + if klass == Time + to_time + elsif klass == Date + to_date + elsif klass == DateTime + to_datetime + else + nil + end + end + + def to_time + begin + if @data.offset * SecInDay == Time.now.utc_offset + d = @data + usec = (d.sec_fraction * SecInDay * 1000000).round + Time.local(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec) + else + d = @data.newof + usec = (d.sec_fraction * SecInDay * 1000000).round + Time.gm(d.year, d.month, d.mday, d.hour, d.min, d.sec, usec) + end + rescue ArgumentError + nil + end + end + + def to_date + Date.new0(@data.class.jd_to_ajd(@data.jd, 0, 0), 0, @data.start) + end + + def to_datetime + data + end + + def tz2of(str) + /^(?:Z|(?:([+\-])(\d\d):(\d\d))?)$/ =~ str + sign = $1 + hour = $2.to_i + min = $3.to_i + + of = case sign + when '+' + of = +(hour.to_r * 60 + min) / 1440 # 24 * 60 + when '-' + of = -(hour.to_r * 60 + min) / 1440 # 24 * 60 + else + 0 + end + of + end + + def of2tz(offset) + diffmin = offset * 24 * 60 + if diffmin.zero? + 'Z' + else + ((diffmin < 0) ? '-' : '+') << format('%02d:%02d', + (diffmin.abs / 60.0).to_i, (diffmin.abs % 60.0).to_i) + end + end + + def screen_data(t) + # convert t to a DateTime as an internal representation. + if t.respond_to?(:to_datetime) # 1.9 or later + t.to_datetime + elsif t.is_a?(DateTime) + t + elsif t.is_a?(Date) + t = screen_data_str(t) + t <<= 12 if t.year < 0 + t + elsif t.is_a?(Time) + jd = DateTime.civil_to_jd(t.year, t.mon, t.mday, DateTime::ITALY) + fr = DateTime.time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) + + t.usec.to_r / 1000000 / SecInDay + of = t.utc_offset.to_r / SecInDay + DateTime.new0(DateTime.jd_to_ajd(jd, fr, of), of, DateTime::ITALY) + else + screen_data_str(t) + end + end + + def add_tz(s) + s + of2tz(@data.offset) + end +end + +class XSDDateTime < XSDAnySimpleType + include XSDDateTimeImpl + Type = QName.new(Namespace, DateTimeLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data_str(t) + /^([+\-]?\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") + end + if $1 == '0000' + raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") + end + year = $1.to_i + if year < 0 + year += 1 + end + mon = $2.to_i + mday = $3.to_i + hour = $4.to_i + min = $5.to_i + sec = $6.to_i + secfrac = $7 + zonestr = $8 + data = DateTime.civil(year, mon, mday, hour, min, sec, tz2of(zonestr)) + if secfrac + diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / SecInDay + data += diffday + # FYI: new0 and jd_to_rjd are not necessary to use if you don't have + # exceptional reason. + end + [data, secfrac] + end + + def _set(data) + if data.nil? + @data = @secfrac = nil + return + end + @data, @secfrac = data + end + + def _to_s + year = (@data.year > 0) ? @data.year : @data.year - 1 + s = format('%.4d-%02d-%02dT%02d:%02d:%02d', + year, @data.mon, @data.mday, @data.hour, @data.min, @data.sec) + if @data.sec_fraction.nonzero? + if @secfrac + s << ".#{ @secfrac }" + else + s << sprintf("%.16f", + (@data.sec_fraction * SecInDay).to_f).sub(/^0/, '').sub(/0*$/, '') + end + end + add_tz(s) + end +end + +class XSDTime < XSDAnySimpleType + include XSDDateTimeImpl + Type = QName.new(Namespace, TimeLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data_str(t) + /^(\d\d):(\d\d):(\d\d(?:\.(\d*))?)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") + end + hour = $1.to_i + min = $2.to_i + sec = $3.to_i + secfrac = $4 + zonestr = $5 + data = DateTime.civil(1, 1, 1, hour, min, sec, tz2of(zonestr)) + if secfrac + diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / SecInDay + data += diffday + end + [data, secfrac] + end + + def _set(data) + if data.nil? + @data = @secfrac = nil + return + end + @data, @secfrac = data + end + + def _to_s + s = format('%02d:%02d:%02d', @data.hour, @data.min, @data.sec) + if @data.sec_fraction.nonzero? + if @secfrac + s << ".#{ @secfrac }" + else + s << sprintf("%.16f", + (@data.sec_fraction * SecInDay).to_f).sub(/^0/, '').sub(/0*$/, '') + end + end + add_tz(s) + end +end + +class XSDDate < XSDAnySimpleType + include XSDDateTimeImpl + Type = QName.new(Namespace, DateLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data_str(t) + /^([+\-]?\d{4,})-(\d\d)-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") + end + year = $1.to_i + if year < 0 + year += 1 + end + mon = $2.to_i + mday = $3.to_i + zonestr = $4 + DateTime.civil(year, mon, mday, 0, 0, 0, tz2of(zonestr)) + end + + def _to_s + year = (@data.year > 0) ? @data.year : @data.year - 1 + s = format('%.4d-%02d-%02d', year, @data.mon, @data.mday) + add_tz(s) + end +end + +class XSDGYearMonth < XSDAnySimpleType + include XSDDateTimeImpl + Type = QName.new(Namespace, GYearMonthLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data_str(t) + /^([+\-]?\d{4,})-(\d\d)(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") + end + year = $1.to_i + if year < 0 + year += 1 + end + mon = $2.to_i + zonestr = $3 + DateTime.civil(year, mon, 1, 0, 0, 0, tz2of(zonestr)) + end + + def _to_s + year = (@data.year > 0) ? @data.year : @data.year - 1 + s = format('%.4d-%02d', year, @data.mon) + add_tz(s) + end +end + +class XSDGYear < XSDAnySimpleType + include XSDDateTimeImpl + Type = QName.new(Namespace, GYearLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data_str(t) + /^([+\-]?\d{4,})(Z|(?:([+\-])(\d\d):(\d\d))?)?$/ =~ t.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") + end + year = $1.to_i + if year < 0 + year += 1 + end + zonestr = $2 + DateTime.civil(year, 1, 1, 0, 0, 0, tz2of(zonestr)) + end + + def _to_s + year = (@data.year > 0) ? @data.year : @data.year - 1 + s = format('%.4d', year) + add_tz(s) + end +end + +class XSDGMonthDay < XSDAnySimpleType + include XSDDateTimeImpl + Type = QName.new(Namespace, GMonthDayLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data_str(t) + /^(\d\d)-(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") + end + mon = $1.to_i + mday = $2.to_i + zonestr = $3 + DateTime.civil(1, mon, mday, 0, 0, 0, tz2of(zonestr)) + end + + def _to_s + s = format('%02d-%02d', @data.mon, @data.mday) + add_tz(s) + end +end + +class XSDGDay < XSDAnySimpleType + include XSDDateTimeImpl + Type = QName.new(Namespace, GDayLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data_str(t) + /^(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") + end + mday = $1.to_i + zonestr = $2 + DateTime.civil(1, 1, mday, 0, 0, 0, tz2of(zonestr)) + end + + def _to_s + s = format('%02d', @data.mday) + add_tz(s) + end +end + +class XSDGMonth < XSDAnySimpleType + include XSDDateTimeImpl + Type = QName.new(Namespace, GMonthLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data_str(t) + /^(\d\d)(Z|(?:[+\-]\d\d:\d\d)?)?$/ =~ t.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ t }'.") + end + mon = $1.to_i + zonestr = $2 + DateTime.civil(1, mon, 1, 0, 0, 0, tz2of(zonestr)) + end + + def _to_s + s = format('%02d', @data.mon) + add_tz(s) + end +end + +class XSDHexBinary < XSDAnySimpleType + Type = QName.new(Namespace, HexBinaryLiteral) + + # String in Ruby could be a binary. + def initialize(value = nil) + init(Type, value) + end + + def set_encoded(value) + if /^[0-9a-fA-F]*$/ !~ value + raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") + end + @data = String.new(value).strip + @is_nil = false + end + + def string + [@data].pack("H*") + end + +private + + def screen_data(value) + value.unpack("H*")[0].tr('a-f', 'A-F') + end +end + +class XSDBase64Binary < XSDAnySimpleType + Type = QName.new(Namespace, Base64BinaryLiteral) + + # String in Ruby could be a binary. + def initialize(value = nil) + init(Type, value) + end + + def set_encoded(value) + if /^[A-Za-z0-9+\/=]*$/ !~ value + raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") + end + @data = String.new(value).strip + @is_nil = false + end + + def string + @data.unpack("m")[0] + end + +private + + def screen_data(value) + [value].pack("m").strip + end +end + +class XSDAnyURI < XSDAnySimpleType + Type = QName.new(Namespace, AnyURILiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data(value) + begin + URI.parse(value.to_s.strip) + rescue URI::InvalidURIError + raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") + end + end +end + +class XSDQName < XSDAnySimpleType + Type = QName.new(Namespace, QNameLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data(value) + /^(?:([^:]+):)?([^:]+)$/ =~ value.to_s.strip + unless Regexp.last_match + raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") + end + prefix = $1 + localpart = $2 + [prefix, localpart] + end + + def _set(data) + if data.nil? + @prefix = @localpart = @data = nil + return + end + @prefix, @localpart = data + @data = _to_s + @data.freeze + end + + def _to_s + if @prefix + "#{ @prefix }:#{ @localpart }" + else + "#{ @localpart }" + end + end +end + + +### +## Derived types +# +class XSDNormalizedString < XSDString + Type = QName.new(Namespace, NormalizedStringLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data(value) + if /[\t\r\n]/ =~ value + raise ValueSpaceError.new("#{ type }: cannot accept '#{ value }'.") + end + super + end +end + +class XSDInteger < XSDDecimal + Type = QName.new(Namespace, IntegerLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def screen_data_str(str) + begin + data = Integer(str) + rescue ArgumentError + raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") + end + unless validate(data) + raise ValueSpaceError.new("#{ type }: cannot accept '#{ str }'.") + end + data + end + + def _set(value) + @data = value + end + + def _to_s() + @data.to_s + end + + def validate(v) + max = maxinclusive + min = mininclusive + (max.nil? or v <= max) and (min.nil? or v >= min) + end + + def maxinclusive + nil + end + + def mininclusive + nil + end + + PositiveMinInclusive = 1 + def positive(v) + PositiveMinInclusive <= v + end +end + +class XSDNonPositiveInteger < XSDInteger + Type = QName.new(Namespace, NonPositiveIntegerLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + 0 + end + + def mininclusive + nil + end +end + +class XSDNegativeInteger < XSDNonPositiveInteger + Type = QName.new(Namespace, NegativeIntegerLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + -1 + end + + def mininclusive + nil + end +end + +class XSDLong < XSDInteger + Type = QName.new(Namespace, LongLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + +9223372036854775807 + end + + def mininclusive + -9223372036854775808 + end +end + +class XSDInt < XSDLong + Type = QName.new(Namespace, IntLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + +2147483647 + end + + def mininclusive + -2147483648 + end +end + +class XSDShort < XSDInt + Type = QName.new(Namespace, ShortLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + +32767 + end + + def mininclusive + -32768 + end +end + +class XSDByte < XSDShort + Type = QName.new(Namespace, ByteLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + +127 + end + + def mininclusive + -128 + end +end + +class XSDNonNegativeInteger < XSDInteger + Type = QName.new(Namespace, NonNegativeIntegerLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + nil + end + + def mininclusive + 0 + end +end + +class XSDUnsignedLong < XSDNonNegativeInteger + Type = QName.new(Namespace, UnsignedLongLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + +18446744073709551615 + end + + def mininclusive + 0 + end +end + +class XSDUnsignedInt < XSDUnsignedLong + Type = QName.new(Namespace, UnsignedIntLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + +4294967295 + end + + def mininclusive + 0 + end +end + +class XSDUnsignedShort < XSDUnsignedInt + Type = QName.new(Namespace, UnsignedShortLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + +65535 + end + + def mininclusive + 0 + end +end + +class XSDUnsignedByte < XSDUnsignedShort + Type = QName.new(Namespace, UnsignedByteLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + +255 + end + + def mininclusive + 0 + end +end + +class XSDPositiveInteger < XSDNonNegativeInteger + Type = QName.new(Namespace, PositiveIntegerLiteral) + + def initialize(value = nil) + init(Type, value) + end + +private + + def maxinclusive + nil + end + + def mininclusive + 1 + end +end + + +end -- cgit v1.2.3