rng-xsd.el 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. ;;; rng-xsd.el --- W3C XML Schema datatypes library for RELAX NG
  2. ;; Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc.
  3. ;; Author: James Clark
  4. ;; Keywords: XML, RelaxNG
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; The main entry point is `rng-xsd-compile'. The validator
  18. ;; knows to use this for the datatype library with URI
  19. ;; http://www.w3.org/2001/XMLSchema-datatypes because it
  20. ;; is the value of the rng-dt-compile property on that URI
  21. ;; as a symbol.
  22. ;;
  23. ;; W3C XML Schema Datatypes are specified by
  24. ;; http://www.w3.org/TR/xmlschema-2/
  25. ;; Guidelines for using them with RELAX NG are described in
  26. ;; http://relaxng.org/xsd.html
  27. ;;; Code:
  28. (require 'rng-dt)
  29. (require 'rng-util)
  30. (require 'xsd-regexp)
  31. ;;;###autoload
  32. (put 'http://www.w3.org/2001/XMLSchema-datatypes
  33. 'rng-dt-compile
  34. 'rng-xsd-compile)
  35. ;;;###autoload
  36. (defun rng-xsd-compile (name params)
  37. "Provides W3C XML Schema as a RELAX NG datatypes library.
  38. NAME is a symbol giving the local name of the datatype. PARAMS is a
  39. list of pairs (PARAM-NAME . PARAM-VALUE) where PARAM-NAME is a symbol
  40. giving the name of the parameter and PARAM-VALUE is a string giving
  41. its value. If NAME or PARAMS are invalid, it calls rng-dt-error
  42. passing it arguments in the same style as format; the value from
  43. rng-dt-error will be returned. Otherwise, it returns a list. The
  44. first member of the list is t if any string is a legal value for the
  45. datatype and nil otherwise. The second argument is a symbol; this
  46. symbol will be called as a function passing it a string followed by
  47. the remaining members of the list. The function must return an object
  48. representing the value of the datatype that was represented by the
  49. string, or nil if the string is not a representation of any value.
  50. The object returned can be any convenient non-nil value, provided
  51. that, if two strings represent the same value, the returned objects
  52. must be equal."
  53. (let ((convert (get name 'rng-xsd-convert)))
  54. (if (not convert)
  55. (rng-dt-error "There is no XSD datatype named %s" name)
  56. (rng-xsd-compile1 name params convert))))
  57. ;;; Parameters
  58. (defun rng-xsd-compile1 (name params convert)
  59. (if (null params)
  60. (cons (equal convert '(identity))
  61. (cond ((eq name 'string) convert)
  62. ((eq name 'normalizedString)
  63. (cons 'rng-xsd-replace-space convert))
  64. ((and (not (eq name 'string))
  65. (or (memq 'identity convert)
  66. (memq 'rng-xsd-convert-any-uri convert)
  67. (memq 'rng-xsd-check-pattern convert)))
  68. (cons 'rng-xsd-collapse-space convert))
  69. (t convert)))
  70. (let* ((param (car params))
  71. (param-name (car param))
  72. (param-value (cdr param)))
  73. (cond ((memq param-name
  74. '(minExclusive maxExclusive minInclusive maxInclusive))
  75. (let ((limit (apply (car convert)
  76. (cons param-value
  77. (cdr convert))))
  78. (less-than-fun (get name 'rng-xsd-less-than)))
  79. (cond ((not limit)
  80. (rng-dt-error "Minimum value %s is not valid"
  81. param-value))
  82. ((not less-than-fun)
  83. (rng-dt-error "Values of type %s are not ordered"
  84. param-name))
  85. (t
  86. (rng-xsd-compile1 name
  87. (cdr params)
  88. (cons (get param-name
  89. 'rng-xsd-check)
  90. (cons less-than-fun
  91. (cons limit convert))))))))
  92. ((memq param-name '(length minLength maxLength))
  93. (let ((limit (rng-xsd-string-to-non-negative-integer param-value))
  94. (length-fun (get name 'rng-xsd-length)))
  95. (cond ((not limit)
  96. (rng-dt-error "Length %s is not valid" param-value))
  97. ((not length-fun)
  98. (rng-dt-error "Values of type %s do not have a length"
  99. param-name))
  100. (t
  101. (rng-xsd-compile1 name
  102. (cdr params)
  103. (cons (get param-name
  104. 'rng-xsd-check)
  105. (cons length-fun
  106. (cons limit convert))))))))
  107. ((memq param-name '(fractionDigits totalDigits))
  108. (let ((n (rng-xsd-string-to-non-negative-integer param-value)))
  109. (cond ((not n)
  110. (rng-dt-error "Number of digits %s is not valid"
  111. param-value))
  112. (t
  113. (rng-xsd-compile1 name
  114. (cdr params)
  115. (cons (get param-name
  116. 'rng-xsd-check)
  117. (cons n convert)))))))
  118. ((eq param-name 'pattern)
  119. (condition-case err
  120. (rng-xsd-compile1 name
  121. (cdr params)
  122. (cons 'rng-xsd-check-pattern
  123. (cons (concat
  124. "\\`"
  125. (xsdre-translate param-value)
  126. "\\'")
  127. convert)))
  128. (xsdre-invalid-regexp
  129. (rng-dt-error "Invalid regular expression (%s)"
  130. (nth 1 err)))))
  131. ((memq param-name '(enumeration whiteSpace))
  132. (rng-dt-error "Facet %s cannot be used in RELAX NG" param-name))
  133. (t (rng-dt-error "Unknown facet %s" param-name))))))
  134. (defun rng-xsd-string-to-non-negative-integer (str)
  135. (and (rng-xsd-convert-integer str)
  136. (let ((n (string-to-number str)))
  137. (and (integerp n)
  138. (>= n 0)
  139. n))))
  140. (defun rng-xsd-collapse-space (str convert &rest args)
  141. (apply convert (cons (mapconcat 'identity (split-string str "[ \t\n\r]+")
  142. " ")
  143. args)))
  144. (defun rng-xsd-replace-space (str convert &rest args)
  145. (apply convert
  146. (cons (let ((i 0)
  147. copied)
  148. (while (and (setq i (string-match "[\r\n\t]" str i))
  149. (or copied (setq copied (copy-sequence str)))
  150. (aset copied i 32)
  151. (setq i (1+ i))))
  152. (or copied str))
  153. args)))
  154. (put 'minExclusive 'rng-xsd-check 'rng-xsd-check-min-exclusive)
  155. (put 'minInclusive 'rng-xsd-check 'rng-xsd-check-min-inclusive)
  156. (put 'maxExclusive 'rng-xsd-check 'rng-xsd-check-max-exclusive)
  157. (put 'maxInclusive 'rng-xsd-check 'rng-xsd-check-max-inclusive)
  158. (put 'length 'rng-xsd-check 'rng-xsd-check-length)
  159. (put 'minLength 'rng-xsd-check 'rng-xsd-check-min-length)
  160. (put 'maxLength 'rng-xsd-check 'rng-xsd-check-max-length)
  161. (put 'fractionDigits 'rng-xsd-check 'rng-xsd-check-fraction-digits)
  162. (put 'totalDigits 'rng-xsd-check 'rng-xsd-check-total-digits)
  163. (defun rng-xsd-check-min-exclusive (str less-than-fun limit convert &rest args)
  164. (let ((obj (apply convert (cons str args))))
  165. (and obj
  166. (funcall less-than-fun limit obj)
  167. obj)))
  168. (defun rng-xsd-check-min-inclusive (str less-than-fun limit convert &rest args)
  169. (let ((obj (apply convert (cons str args))))
  170. (and obj
  171. (or (funcall less-than-fun limit obj)
  172. (equal limit obj))
  173. obj)))
  174. (defun rng-xsd-check-max-exclusive (str less-than-fun limit convert &rest args)
  175. (let ((obj (apply convert (cons str args))))
  176. (and obj
  177. (funcall less-than-fun obj limit)
  178. obj)))
  179. (defun rng-xsd-check-max-inclusive (str less-than-fun limit convert &rest args)
  180. (let ((obj (apply convert (cons str args))))
  181. (and obj
  182. (or (funcall less-than-fun obj limit)
  183. (equal obj limit))
  184. obj)))
  185. (defun rng-xsd-check-min-length (str length-fun limit convert &rest args)
  186. (let ((obj (apply convert (cons str args))))
  187. (and obj
  188. (>= (funcall length-fun obj) limit)
  189. obj)))
  190. (defun rng-xsd-check-max-length (str length-fun limit convert &rest args)
  191. (let ((obj (apply convert (cons str args))))
  192. (and obj
  193. (<= (funcall length-fun obj) limit)
  194. obj)))
  195. (defun rng-xsd-check-length (str length-fun len convert &rest args)
  196. (let ((obj (apply convert (cons str args))))
  197. (and obj
  198. (= (funcall length-fun obj) len)
  199. obj)))
  200. (defun rng-xsd-check-fraction-digits (str n convert &rest args)
  201. (let ((obj (apply convert (cons str args))))
  202. (and obj
  203. (<= (length (aref obj 2)) n)
  204. obj)))
  205. (defun rng-xsd-check-total-digits (str n convert &rest args)
  206. (let ((obj (apply convert (cons str args))))
  207. (and obj
  208. (<= (+ (length (aref obj 1))
  209. (length (aref obj 2)))
  210. n)
  211. obj)))
  212. (defun rng-xsd-check-pattern (str regexp convert &rest args)
  213. (and (let ((case-fold-search nil)) (string-match regexp str))
  214. (apply convert (cons str args))))
  215. (defun rng-xsd-convert-boolean (string)
  216. (and (string-match "\\`[ \t\n\r]*\\(?:\\(true\\|1\\)\\|false\\|0\\)[ \t\n\r]*\\'" string)
  217. (if (match-beginning 1) 'true 'false)))
  218. (defun rng-xsd-convert-decimal (string)
  219. "Convert a string representing a decimal to an object representing it values.
  220. A decimal value is represented by a vector [SIGN INTEGER-DIGITS
  221. FRACTION-DIGITS] where SIGN is 1 or -1, INTEGER-DIGITS is a string
  222. containing zero or more digits, with no leading zero, and
  223. FRACTION-DIGITS is a string containing zero or more digits with no
  224. trailing digits. For example, -0021.0430 would be represented by [-1
  225. \"21\" \"043\"]."
  226. (and (string-match "\\`[ \t\n\r]*\\([-+]\\)?\\(0*\\([1-9][0-9]*\\)?\\(\\.\\([0-9]*[1-9]\\)?0*\\)?\\)[ \t\n\r]*\\'" string)
  227. (let ((digits (match-string 2 string)))
  228. (and (not (string= digits "."))
  229. (not (string= digits ""))))
  230. (let ((integer-digits (match-string 3 string)))
  231. (vector (if (and (equal (match-string 1 string) "-")
  232. ;; Normalize -0 to 0
  233. integer-digits)
  234. -1
  235. 1)
  236. (or integer-digits "")
  237. (or (match-string 5 string) "")))))
  238. (defun rng-xsd-convert-integer (string)
  239. (and (string-match "\\`[ \t\n\r]*\\([-+]\\)?\\(?:0*\\([1-9][0-9]*\\)\\|0+\\)[ \t\n\r]*\\'" string)
  240. (let ((integer-digits (match-string 2 string)))
  241. (vector (if (and (equal (match-string 1 string) "-")
  242. ;; Normalize -0 to 0
  243. integer-digits)
  244. -1
  245. 1)
  246. (or integer-digits "")
  247. ""))))
  248. (defun rng-xsd-decimal< (n1 n2)
  249. (< (rng-xsd-compare-decimal n1 n2) 0))
  250. (defun rng-xsd-compare-decimal (n1 n2)
  251. "Return a < 0, 0, > 0 according as n1 < n2, n1 = n2 or n1 > n2."
  252. (let* ((sign1 (aref n1 0))
  253. (sign2 (aref n2 0))
  254. (sign (- sign1 sign2)))
  255. (if (= sign 0)
  256. (* sign1
  257. (let* ((int1 (aref n1 1))
  258. (int2 (aref n2 1))
  259. (len1 (length int1))
  260. (len2 (length int2))
  261. (lencmp (- len1 len2)))
  262. (if (eq lencmp 0)
  263. (if (string= int1 int2)
  264. (rng-xsd-strcmp (aref n1 2) (aref n2 2))
  265. (rng-xsd-strcmp int1 int2))
  266. lencmp)))
  267. sign)))
  268. (defconst rng-xsd-float-regexp
  269. (concat "\\`[ \r\n\t]*\\(?:"
  270. "\\("
  271. "[-+]?\\(?:[0-9]+\\(?:\\.[0-9]*\\)?\\|\\.[0-9]+\\)"
  272. "\\(?:[eE][-+]?[0-9]+\\)?"
  273. "\\)"
  274. "\\|\\(INF\\)"
  275. "\\|\\(-INF\\)"
  276. "\\|\\(NaN\\)"
  277. "\\)[ \r\n\t]*\\'"))
  278. (defun rng-xsd-convert-float (string)
  279. (cond ((not (string-match rng-xsd-float-regexp string)) nil)
  280. ((match-beginning 1)
  281. (float (string-to-number (match-string 1 string))))
  282. ((match-beginning 2) 1.0e+INF)
  283. ((match-beginning 3) -1.0e+INF)
  284. ;; Don't use a NaN float because we want NaN to be equal to NaN
  285. ((match-beginning 4) 'NaN)))
  286. (defun rng-xsd-float< (f1 f2)
  287. (and (not (eq f1 'NaN))
  288. (not (eq f2 'NaN))
  289. (< f1 f2)))
  290. (defun rng-xsd-convert-token (string regexp)
  291. (and (string-match regexp string)
  292. (match-string 1 string)))
  293. (defun rng-xsd-convert-hex-binary (string)
  294. (and (string-match "\\`[ \r\n\t]*\\(\\(?:[0-9A-Fa-f][0-9A-Fa-f]\\)*\\)[ \r\n\t]*\\'"
  295. string)
  296. (downcase (match-string 1 string))))
  297. (defun rng-xsd-hex-binary-length (obj)
  298. (/ (length obj) 2))
  299. (defconst rng-xsd-base64-binary-regexp
  300. (let ((S "[ \t\r\n]*")
  301. (B04 "[AQgw]")
  302. (B16 "[AEIMQUYcgkosw048]")
  303. (B64 "[A-Za-z0-9+/]"))
  304. (concat "\\`" S "\\(?:\\(?:" B64 S "\\)\\{4\\}\\)*"
  305. "\\(?:" B64 S B64 S B16 S "=" S
  306. "\\|" B64 S B04 S "=" S "=" S "\\)?\\'")))
  307. (defun rng-xsd-convert-base64-binary (string)
  308. (and (string-match rng-xsd-base64-binary-regexp string)
  309. (replace-regexp-in-string "[ \t\r\n]+" "" string t t)))
  310. (defun rng-xsd-base64-binary-length (obj)
  311. (let ((n (* (/ (length obj) 4) 3)))
  312. (if (and (> n 0)
  313. (string= (substring obj -1) "="))
  314. (- n (if (string= (substring obj -2) "==")
  315. 2
  316. 1))
  317. n)))
  318. (defun rng-xsd-convert-any-uri (string)
  319. (and (string-match "\\`\\(?:[^%]\\|%[0-9a-fA-F][0-9a-fA-F]\\)?*\\'" string)
  320. (string-match "\\`[^#]*\\(?:#[^#]*\\)?\\'" string)
  321. (string-match "\\`\\(?:[a-zA-Z][-+.A-Za-z0-9]*:.+\\|[^:]*\\(?:[#/?].*\\)?\\)\\'" string)
  322. string))
  323. (defun rng-xsd-make-date-time-regexp (template)
  324. "Returns a regular expression matching a ISO 8601 date/time.
  325. The template is a string with Y standing for years field, M standing
  326. for months, D standing for day of month, T standing for a literal T, t
  327. standing for time and - standing for a literal hyphen. A time zone is
  328. always allowed at the end. Regardless of the fields appearing in the
  329. template, the regular expression will have twelve groups matching the
  330. year sign, year, month, day of month, hours, minutes, integer seconds,
  331. fractional seconds (including leading period), time zone, time zone
  332. sign, time zone hours, time zone minutes."
  333. (let ((i 0)
  334. (len (length template))
  335. (parts nil)
  336. first last c)
  337. (while (< i len)
  338. (setq c (aref template i))
  339. (setq parts
  340. (cons (cond ((eq c ?Y)
  341. (setq first 0)
  342. (setq last 1)
  343. "\\(-\\)?\\(\\(?:[1-9][0-9]*\\)?[0-9]\\{4\\}\\)")
  344. ((eq c ?M)
  345. (or first
  346. (setq first 2))
  347. (setq last 2)
  348. "\\([0-9][0-9]\\)")
  349. ((eq c ?D)
  350. (or first
  351. (setq first 3))
  352. (setq last 3)
  353. "\\([0-9][0-9]\\)")
  354. ((eq c ?t)
  355. (or first
  356. (setq first 4))
  357. (setq last 7)
  358. "\\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)\\(\\.[0-9]*\\)?")
  359. (t (string c)))
  360. parts))
  361. (setq i (1+ i)))
  362. (while (< last 7)
  363. (setq last (1+ last))
  364. ;; Add dummy fields that can never much but keep the group
  365. ;; numbers uniform.
  366. (setq parts (cons "\\(\\'X\\)?" parts)))
  367. (setq parts (cons "\\(Z\\|\\([-+]\\)\\([0-9][0-9]\\):\\([0-5][0-9]\\)\\)?[ \t\n\r]*\\'"
  368. parts))
  369. (setq parts (cons "\\`[ \t\n\r]*" (nreverse parts)))
  370. (while (> first 0)
  371. (setq first (1- first))
  372. (setq parts (cons "\\(X\\)?" parts)))
  373. (apply 'concat parts)))
  374. (defconst rng-xsd-seconds-per-day (* 24 60 60))
  375. (defconst rng-xsd-days-in-month [31 28 31 30 31 30 31 31 30 31 30 31])
  376. (defun rng-xsd-days-in-month (year month)
  377. (if (and (= month 2) (rng-xsd-leap-year-p year))
  378. 29
  379. (aref rng-xsd-days-in-month (1- month))))
  380. (defconst rng-xsd-months-to-days
  381. (let ((v (make-vector 12 nil))
  382. (total 0)
  383. (i 0))
  384. (while (< i 12)
  385. (setq total (+ total (aref rng-xsd-days-in-month i)))
  386. (aset v i total)
  387. (setq i (1+ i)))
  388. v))
  389. (defun rng-xsd-convert-date-time (string regexp)
  390. "Converts an XML Schema date/time to a list.
  391. Returns nil if invalid. REGEXP is a regexp for parsing the date time
  392. as returned by `rng-xsd-make-date-time-regexp'. The list has 4 members
  393. \(HAS-TIME-ZONE DAY SECOND SECOND-FRACTION), where HAS-TIME-ZONE is t
  394. or nil depending on whether a time zone was specified, DAY is an
  395. integer giving a day number (with Jan 1 1AD being day 1), SECOND is the
  396. second within that day, and SECOND-FRACTION is a float giving the
  397. fractional part of the second."
  398. (and (string-match regexp string)
  399. (let ((year-sign (match-string 1 string))
  400. (year (match-string 2 string))
  401. (month (match-string 3 string))
  402. (day (match-string 4 string))
  403. (hour (match-string 5 string))
  404. (minute (match-string 6 string))
  405. (second (match-string 7 string))
  406. (second-fraction (match-string 8 string))
  407. (has-time-zone (match-string 9 string))
  408. (time-zone-sign (match-string 10 string))
  409. (time-zone-hour (match-string 11 string))
  410. (time-zone-minute (match-string 12 string)))
  411. (setq year-sign (if year-sign -1 1))
  412. (setq year
  413. (if year
  414. (* year-sign
  415. (string-to-number year))
  416. 2000))
  417. (setq month
  418. (if month (string-to-number month) 1))
  419. (setq day
  420. (if day (string-to-number day) 1))
  421. (setq hour
  422. (if hour (string-to-number hour) 0))
  423. (setq minute
  424. (if minute (string-to-number minute) 0))
  425. (setq second
  426. (if second (string-to-number second) 0))
  427. (setq second-fraction
  428. (if second-fraction
  429. (float (string-to-number second-fraction))
  430. 0.0))
  431. (setq has-time-zone (and has-time-zone t))
  432. (setq time-zone-sign
  433. (if (equal time-zone-sign "-") -1 1))
  434. (setq time-zone-hour
  435. (if time-zone-hour (string-to-number time-zone-hour) 0))
  436. (setq time-zone-minute
  437. (if time-zone-minute (string-to-number time-zone-minute) 0))
  438. (and (>= month 1)
  439. (<= month 12)
  440. (>= day 1)
  441. (<= day (rng-xsd-days-in-month year month))
  442. (<= hour 23)
  443. (<= minute 59)
  444. (<= second 60) ; leap second
  445. (<= time-zone-hour 23)
  446. (<= time-zone-minute 59)
  447. (cons has-time-zone
  448. (rng-xsd-add-seconds
  449. (list (rng-xsd-date-to-days year month day)
  450. (rng-xsd-time-to-seconds hour minute second)
  451. second-fraction)
  452. (* (rng-xsd-time-to-seconds time-zone-hour
  453. time-zone-minute
  454. 0)
  455. (- time-zone-sign))))))))
  456. (defun rng-xsd-leap-year-p (year)
  457. (and (= (% year 4) 0)
  458. (or (/= (% year 100) 0)
  459. (= (% year 400) 0))))
  460. (defun rng-xsd-time-to-seconds (hour minute second)
  461. (+ (* (+ (* hour 60)
  462. minute)
  463. 60)
  464. second))
  465. (defconst rng-xsd-max-tz (rng-xsd-time-to-seconds 14 0 0))
  466. (defun rng-xsd-date-time< (dt1 dt2)
  467. (cond ((eq (car dt1) (car dt2))
  468. (rng-xsd-number-list< (cdr dt1) (cdr dt2)))
  469. ((car dt1)
  470. (rng-xsd-number-list< (cdr dt1)
  471. (rng-xsd-add-seconds (cdr dt2)
  472. (- rng-xsd-max-tz))))
  473. (t
  474. (rng-xsd-number-list< (rng-xsd-add-seconds (cdr dt1)
  475. rng-xsd-max-tz)
  476. (cdr dt2)))))
  477. (defun rng-xsd-add-seconds (date offset)
  478. (let ((day (nth 0 date))
  479. (second (+ (nth 1 date) offset))
  480. (fraction (nth 2 date)))
  481. (cond ((< second 0)
  482. (list (1- day)
  483. (+ second rng-xsd-seconds-per-day)
  484. fraction))
  485. ((>= second rng-xsd-seconds-per-day)
  486. (list (1+ day)
  487. (- second rng-xsd-seconds-per-day)
  488. fraction))
  489. (t (list day second fraction)))))
  490. (defun rng-xsd-number-list< (numbers1 numbers2)
  491. (while (and numbers1 (= (car numbers1) (car numbers2)))
  492. (setq numbers1 (cdr numbers1))
  493. (setq numbers2 (cdr numbers2)))
  494. (and numbers1
  495. (< (car numbers1) (car numbers2))))
  496. (defun rng-xsd-date-to-days (year month day)
  497. "Return a unique day number where Jan 1 1 AD is day 1"
  498. (if (> year 0) ; AD
  499. (+ (rng-xsd-days-in-years (- year 1))
  500. (rng-xsd-day-number-in-year year month day))
  501. (- (+ (- (rng-xsd-days-in-years (- 3 year))
  502. (rng-xsd-days-in-years 3))
  503. (- (if (rng-xsd-leap-year-p year) 366 365)
  504. (rng-xsd-day-number-in-year year month day))))))
  505. (defun rng-xsd-days-in-years (years)
  506. "The number of days in YEARS years where the first year is 1AD."
  507. (+ (* 365 years)
  508. (/ years 4)
  509. (- (/ years 100))
  510. (/ years 400)))
  511. (defun rng-xsd-day-number-in-year (year month day)
  512. (+ (if (= month 1)
  513. 0
  514. (aref rng-xsd-months-to-days (- month 2)))
  515. day
  516. (if (and (> month 2)
  517. (rng-xsd-leap-year-p year))
  518. 1
  519. 0)))
  520. (defconst rng-xsd-duration-regexp
  521. "\\`[ \t\r\n]*\\(-\\)?P\
  522. \\([0-9]+Y\\)?\\([0-9]+M\\)?\\([0-9]+D\\)?\
  523. \\(?:T\\([0-9]+H\\)?\\([0-9]+M\\)?\
  524. \\(\\([0-9]+\\(?:\\.[0-9]*\\)?\\|\\.[0-9]+\\)S\\)?\\)?\
  525. [ \t\r\n]*\\'")
  526. (defun rng-xsd-convert-duration (string)
  527. (and (string-match rng-xsd-duration-regexp string)
  528. (let ((last (substring string -1)))
  529. (not (or (string= last "P")
  530. (string= last "T"))))
  531. ;; years months days hours minutes seconds
  532. (let ((v (make-vector 6 0))
  533. (sign (if (match-beginning 1) -1 1))
  534. (i 0))
  535. (while (< i 6)
  536. (let ((start (match-beginning (+ i 2))))
  537. (when start
  538. (aset v i (* sign
  539. (string-to-number
  540. (substring string
  541. start
  542. (1- (match-end (+ i 2)))))))))
  543. (setq i (1+ i)))
  544. ;; Force seconds to be float so that equal works properly.
  545. (aset v 5 (float (aref v 5)))
  546. v)))
  547. (defconst rng-xsd-min-seconds-per-month (* 28 rng-xsd-seconds-per-day))
  548. (defun rng-xsd-duration< (d1 d2)
  549. (let* ((months1 (rng-xsd-duration-months d1))
  550. (months2 (rng-xsd-duration-months d2))
  551. (seconds1 (rng-xsd-duration-seconds d1))
  552. (seconds2 (rng-xsd-duration-seconds d2)))
  553. (cond ((< months1 months2)
  554. (if (< (- seconds1 seconds2) rng-xsd-min-seconds-per-month)
  555. t
  556. (rng-xsd-months-seconds< months1 seconds1 months2 seconds2)))
  557. ((> months1 months2)
  558. (if (< (- seconds2 seconds1) rng-xsd-min-seconds-per-month)
  559. nil
  560. (rng-xsd-months-seconds< months1 seconds1 months2 seconds2)))
  561. (t (< seconds1 seconds2)))))
  562. (defconst xsd-duration-reference-dates
  563. '((1696 . 9) (1697 . 2) (1903 . 3) (1903 . 7)))
  564. (defun rng-xsd-months-seconds< (months1 seconds1 months2 seconds2)
  565. (let ((ret t)
  566. (ref-dates xsd-duration-reference-dates))
  567. (while (let* ((ref-date (car ref-dates))
  568. (ref-year (car ref-date))
  569. (ref-month (cdr ref-date)))
  570. (unless (< (+ (rng-xsd-month-seconds months1
  571. ref-year
  572. ref-month)
  573. seconds1)
  574. (+ (rng-xsd-month-seconds months2
  575. ref-year
  576. ref-month)
  577. seconds2))
  578. (setq ret nil))
  579. (and ret
  580. (setq ref-dates (cdr ref-dates)))))
  581. ret))
  582. (defun rng-xsd-month-seconds (months ref-year ref-month)
  583. "Return the seconds in a number of months starting on a reference date.
  584. Returns a floating point number."
  585. (* (rng-xsd-month-days (abs months) ref-year ref-month)
  586. (float rng-xsd-seconds-per-day)
  587. (if (< months 0) -1.0 1.0)))
  588. (defconst rng-xsd-years-per-gregorian-cycle 400)
  589. (defconst rng-xsd-months-per-gregorian-cycle
  590. (* rng-xsd-years-per-gregorian-cycle 12))
  591. (defconst rng-xsd-leap-years-per-gregorian-cycle (- 100 (- 4 1)))
  592. (defconst rng-xsd-days-per-gregorian-cycle
  593. (+ (* 365 rng-xsd-years-per-gregorian-cycle)
  594. rng-xsd-leap-years-per-gregorian-cycle))
  595. (defun rng-xsd-month-days (months ref-year ref-month)
  596. "Return the days in a number of months starting on a reference date.
  597. MONTHS must be an integer >= 0."
  598. (let ((days 0))
  599. (setq months (mod months rng-xsd-months-per-gregorian-cycle))
  600. ;; This may be rather slow, but it is highly unlikely
  601. ;; ever to be used in real life.
  602. (while (> months 0)
  603. (setq days
  604. (+ (rng-xsd-days-in-month ref-year ref-month)
  605. days))
  606. (setq ref-month
  607. (if (eq ref-month 12)
  608. (progn
  609. (setq ref-year (1+ ref-year))
  610. 1)
  611. (1+ ref-month)))
  612. (setq months (1- months)))
  613. (+ (* (/ months rng-xsd-months-per-gregorian-cycle)
  614. rng-xsd-days-per-gregorian-cycle)
  615. days)))
  616. (defun rng-xsd-duration-months (d)
  617. (+ (* (aref d 0) 12)
  618. (aref d 1)))
  619. (defun rng-xsd-duration-seconds (d)
  620. (+ (* (+ (* (+ (* (aref d 2)
  621. 24.0)
  622. (aref d 3))
  623. 60.0)
  624. (aref d 4))
  625. 60.0)
  626. (aref d 5)))
  627. (defun rng-xsd-convert-qname (string)
  628. (and (string-match "\\`[ \r\n\t]*\\([_[:alpha:]][-._[:alnum:]]*\\(:[_[:alpha:]][-._[:alnum:]]*\\)?\\)[ \r\n\t]*\\'" string)
  629. (let ((colon (match-beginning 2))
  630. (context (apply (car rng-dt-namespace-context-getter)
  631. (cdr rng-dt-namespace-context-getter))))
  632. (if colon
  633. (let* ((prefix (substring string
  634. (match-beginning 1)
  635. colon))
  636. (binding (assoc prefix (cdr context))))
  637. (and binding
  638. (cons (cdr binding)
  639. (substring string
  640. (1+ colon)
  641. (match-end 1)))))
  642. (cons (car context)
  643. (match-string 1 string))))))
  644. (defun rng-xsd-convert-list (string convert &rest args)
  645. (let* ((tokens (split-string string "[ \t\n\r]+"))
  646. (tem tokens))
  647. (while tem
  648. (let ((obj (apply convert
  649. (cons (car tem) args))))
  650. (cond (obj
  651. (setcar tem obj)
  652. (setq tem (cdr tem)))
  653. (t
  654. (setq tokens nil)
  655. (setq tem nil)))))
  656. ;; Fortuitously this returns nil if the list is empty
  657. ;; which is what we want since the list types
  658. ;; have to have one or more members.
  659. tokens))
  660. (defun rng-xsd-strcmp (s1 s2)
  661. (cond ((string= s1 s2) 0)
  662. ((string< s1 s2) -1)
  663. (t 1)))
  664. (put 'string 'rng-xsd-convert '(identity))
  665. (put 'string 'rng-xsd-length 'length)
  666. (put 'string 'rng-xsd-matches-anything t)
  667. (put 'normalizedString 'rng-xsd-convert '(identity))
  668. (put 'normalizedString 'rng-xsd-length 'length)
  669. (put 'normalizedString 'rng-xsd-matches-anything t)
  670. (put 'token 'rng-xsd-convert '(identity))
  671. (put 'token 'rng-xsd-length 'length)
  672. (put 'token 'rng-xsd-matches-anything t)
  673. (put 'hexBinary 'rng-xsd-convert '(rng-xsd-convert-hex-binary))
  674. (put 'hexBinary 'rng-xsd-length 'rng-xsd-hex-binary-length)
  675. (put 'base64Binary 'rng-xsd-convert '(rng-xsd-convert-base64-binary))
  676. (put 'base64Binary 'rng-xsd-length 'rng-xsd-base64-binary-length)
  677. (put 'boolean 'rng-xsd-convert '(rng-xsd-convert-boolean))
  678. (put 'float 'rng-xsd-convert '(rng-xsd-convert-float))
  679. (put 'float 'rng-xsd-less-than 'rng-xsd-float<)
  680. (put 'double 'rng-xsd-convert '(rng-xsd-convert-float))
  681. (put 'double 'rng-xsd-less-than 'rng-xsd-float<)
  682. (put 'decimal 'rng-xsd-convert '(rng-xsd-convert-decimal))
  683. (put 'decimal 'rng-xsd-less-than 'rng-xsd-decimal<)
  684. (put 'integer 'rng-xsd-convert '(rng-xsd-convert-integer))
  685. (put 'integer 'rng-xsd-less-than 'rng-xsd-decimal<)
  686. (defun rng-xsd-def-integer-type (name min max)
  687. (put name 'rng-xsd-less-than 'rng-xsd-decimal<)
  688. (put name
  689. 'rng-xsd-convert
  690. (cdr (rng-xsd-compile 'integer
  691. (append (and min `((minInclusive . ,min)))
  692. (and max `((maxInclusive . ,max))))))))
  693. (defun rng-xsd-def-token-type (name regexp)
  694. (put name 'rng-xsd-convert (list 'rng-xsd-convert-token
  695. (concat "\\`[\r\n\t ]*\\("
  696. regexp
  697. "\\)[\r\n\t ]*\\'")))
  698. (put name 'rng-xsd-length 'length))
  699. (rng-xsd-def-token-type 'NMTOKEN "[-.:_[:alnum:]]+")
  700. (rng-xsd-def-token-type 'Name "[:_[:alpha:]][-.:_[:alnum:]]*")
  701. (rng-xsd-def-token-type 'NCName "[_[:alpha:]][-._[:alnum:]]*")
  702. (rng-xsd-def-token-type 'language
  703. "[a-zA-Z]\\{1,8\\}\\(?:-[a-zA-Z0-9]\\{1,8\\}\\)*")
  704. (put 'ENTITY 'rng-xsd-convert (get 'NCName 'rng-xsd-convert))
  705. (put 'ENTITY 'rng-xsd-length 'length)
  706. (put 'ID 'rng-xsd-convert (get 'NCName 'rng-xsd-convert))
  707. (put 'ID 'rng-xsd-length 'length)
  708. (put 'IDREF 'rng-xsd-convert (get 'NCName 'rng-xsd-convert))
  709. (put 'IDREF 'rng-xsd-length 'length)
  710. (defun rng-xsd-def-list-type (name member-name)
  711. (put name 'rng-xsd-convert (cons 'rng-xsd-convert-list
  712. (get member-name 'rng-xsd-convert)))
  713. (put name 'rng-xsd-length 'length))
  714. (rng-xsd-def-list-type 'NMTOKENS 'NMTOKEN)
  715. (rng-xsd-def-list-type 'IDREFS 'IDREF)
  716. (rng-xsd-def-list-type 'ENTITIES 'ENTITY)
  717. (put 'anyURI 'rng-xsd-convert '(rng-xsd-convert-any-uri))
  718. (put 'anyURI 'rng-xsd-length 'length)
  719. (put 'QName 'rng-xsd-convert '(rng-xsd-convert-qname))
  720. (put 'NOTATION 'rng-xsd-convert '(rng-xsd-convert-qname))
  721. (defconst rng-xsd-long-max "9223372036854775807")
  722. (defconst rng-xsd-long-min "-9223372036854775808")
  723. (defconst rng-xsd-int-max "2147483647")
  724. (defconst rng-xsd-int-min "-2147483648")
  725. (defconst rng-xsd-short-max "32767")
  726. (defconst rng-xsd-short-min "-32768")
  727. (defconst rng-xsd-byte-max "127")
  728. (defconst rng-xsd-byte-min "-128")
  729. (defconst rng-xsd-unsigned-long-max "18446744073709551615")
  730. (defconst rng-xsd-unsigned-int-max "4294967295")
  731. (defconst rng-xsd-unsigned-short-max "65535")
  732. (defconst rng-xsd-unsigned-byte-max "255")
  733. (rng-xsd-def-integer-type 'nonNegativeInteger "0" nil)
  734. (rng-xsd-def-integer-type 'positiveInteger "1" nil)
  735. (rng-xsd-def-integer-type 'nonPositiveInteger nil "0")
  736. (rng-xsd-def-integer-type 'negativeInteger nil "-1")
  737. (rng-xsd-def-integer-type 'long rng-xsd-long-min rng-xsd-long-max)
  738. (rng-xsd-def-integer-type 'int rng-xsd-int-min rng-xsd-int-max)
  739. (rng-xsd-def-integer-type 'short rng-xsd-short-min rng-xsd-short-max)
  740. (rng-xsd-def-integer-type 'byte rng-xsd-byte-min rng-xsd-byte-max)
  741. (rng-xsd-def-integer-type 'unsignedLong "0" rng-xsd-unsigned-long-max)
  742. (rng-xsd-def-integer-type 'unsignedInt "0" rng-xsd-unsigned-int-max)
  743. (rng-xsd-def-integer-type 'unsignedShort "0" rng-xsd-unsigned-short-max)
  744. (rng-xsd-def-integer-type 'unsignedByte "0" rng-xsd-unsigned-byte-max)
  745. (defun rng-xsd-def-date-time-type (name template)
  746. (put name 'rng-xsd-convert (list 'rng-xsd-convert-date-time
  747. (rng-xsd-make-date-time-regexp template)))
  748. (put name 'rng-xsd-less-than 'rng-xsd-date-time<))
  749. (rng-xsd-def-date-time-type 'dateTime "Y-M-DTt")
  750. (rng-xsd-def-date-time-type 'time "t")
  751. (rng-xsd-def-date-time-type 'date "Y-M-D")
  752. (rng-xsd-def-date-time-type 'gYearMonth "Y-M")
  753. (rng-xsd-def-date-time-type 'gYear "Y")
  754. (rng-xsd-def-date-time-type 'gMonthDay "--M-D")
  755. (rng-xsd-def-date-time-type 'gDay "---D")
  756. (rng-xsd-def-date-time-type 'gMonth "--M")
  757. (put 'duration 'rng-xsd-convert '(rng-xsd-convert-duration))
  758. (put 'duration 'rng-xsd-less-than 'rng-xsd-duration<)
  759. (provide 'rng-xsd)
  760. ;;; rng-xsd.el ends here