/tools/Ruby/lib/ruby/1.8/xsd/datatypes.rb

http://github.com/agross/netopenspace · Ruby · 1269 lines · 992 code · 224 blank · 53 comment · 74 complexity · c6b57d3c397b31011746a17cf8013d1d MD5 · raw file

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