1# RELAX NG Schema for vCard in XML
2# Extract from RFC6351.
3# Erratum 2994 applied.
4# Erratum 3047 applied.
5# Erratum 3008 applied.
6# Erratum 4247 applied.
7
8default namespace = "urn:ietf:params:xml:ns:vcard-4.0"
9
10### Section 3.3: vCard Format Specification
11#
12# 3.3
13iana-token = xsd:string { pattern = "[a-zA-Z0-9\-]+" }
14x-name = xsd:string { pattern = "x-[a-zA-Z0-9\-]+" }
15
16### Section 4: Value types
17#
18# 4.1
19value-text = element text { text }
20value-text-list = value-text+
21
22# 4.2
23value-uri = element uri { xsd:anyURI }
24
25# 4.3.1
26value-date = element date {
27    xsd:string { pattern = "\d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d" }
28  }
29
30# 4.3.2
31value-time = element time {
32    xsd:string { pattern = "(\d\d(\d\d(\d\d)?)?|-\d\d(\d\d)?|--\d\d)"
33                         ~ "(Z|[+\-]\d\d(\d\d)?)?" }
34  }
35
36# 4.3.3
37value-date-time = element date-time {
38    xsd:string { pattern = "(\d{8}|--\d{4}|---\d\d)T\d\d(\d\d(\d\d)?)?"
39                         ~ "(Z|[+\-]\d\d(\d\d)?)?" }
40  }
41
42# 4.3.4
43value-date-and-or-time = value-date | value-date-time | value-time
44
45# 4.3.5
46value-timestamp = element timestamp {
47    xsd:string { pattern = "\d{8}T\d{6}(Z|[+\-]\d\d(\d\d)?)?" }
48  }
49
50# 4.4
51value-boolean = element boolean { xsd:boolean }
52
53# 4.5
54value-integer = element integer { xsd:integer }
55
56# 4.6
57value-float = element float { xsd:float }
58
59# 4.7
60value-utc-offset = element utc-offset {
61    xsd:string { pattern = "[+\-]\d\d(\d\d)?" }
62  }
63
64# 4.8
65value-language-tag = element language-tag {
66    xsd:string { pattern = "([a-z]{2,3}((-[a-z]{3}){0,3})?|[a-z]{4,8})"
67                         ~ "(-[a-z]{4})?(-([a-z]{2}|\d{3}))?"
68                         ~ "(-([0-9a-z]{5,8}|\d[0-9a-z]{3}))*"
69                         ~ "(-[0-9a-wyz](-[0-9a-z]{2,8})+)*"
70                         ~ "(-x(-[0-9a-z]{1,8})+)?|x(-[0-9a-z]{1,8})+|"
71                         ~ "[a-z]{1,3}(-[0-9a-z]{2,8}){1,2}" }
72  }
73
74### Section 5: Parameters
75#
76# 5.1
77param-language = element language { value-language-tag }?
78
79# 5.2
80param-pref = element pref {
81    element integer {
82      xsd:integer { minInclusive = "1" maxInclusive = "100" }
83    }
84  }?
85
86# 5.4
87param-altid = element altid { value-text }?
88
89# 5.5
90param-pid = element pid {
91    element text { xsd:string { pattern = "\d+(\.\d+)?" } }+
92  }?
93
94# 5.6
95param-type = element type { element text { "work" | "home" }+ }?
96
97# 5.7
98param-mediatype = element mediatype { value-text }?
99
100# 5.8
101param-calscale = element calscale { element text { "gregorian" } }?
102
103# 5.9
104param-sort-as = element sort-as { value-text+ }?
105
106# 5.10
107param-geo = element geo { value-uri }?
108
109# 5.11
110param-tz = element tz { value-text | value-uri }?
111
112### Section 6: Properties
113#
114# 6.1.3
115property-source = element source {
116    element parameters { param-altid, param-pid, param-pref,
117                         param-mediatype }?,
118    value-uri
119  }
120
121# 6.1.4
122property-kind = element kind {
123    element text { "individual" | "group" | "org" | "location" |
124                   x-name | iana-token }*
125  }
126
127# 6.2.1
128property-fn = element fn {
129    element parameters { param-language, param-altid, param-pid,
130                         param-pref, param-type }?,
131    value-text
132  }
133
134# 6.2.2
135property-n = element n {
136    element parameters { param-language, param-sort-as, param-altid }?,
137    element surname { text }+,
138    element given { text }+,
139    element additional { text }+,
140    element prefix { text }+,
141    element suffix { text }+
142  }
143
144# 6.2.3
145property-nickname = element nickname {
146    element parameters { param-language, param-altid, param-pid,
147                         param-pref, param-type }?,
148    value-text-list
149  }
150
151# 6.2.4
152property-photo = element photo {
153    element parameters { param-altid, param-pid, param-pref, param-type,
154                         param-mediatype }?,
155    value-uri
156  }
157
158# 6.2.5
159property-bday = element bday {
160    element parameters { param-altid, param-calscale }?,
161    (value-date-and-or-time | value-text)
162  }
163
164# 6.2.6
165property-anniversary = element anniversary {
166    element parameters { param-altid, param-calscale }?,
167    (value-date-and-or-time | value-text)
168  }
169
170# 6.2.7
171property-gender = element gender {
172    element sex { "" | "M" | "F" | "O" | "N" | "U" },
173    element identity { text }?
174  }
175
176# 6.3.1
177param-label = element label { value-text }?
178property-adr = element adr {
179    element parameters { param-language, param-altid, param-pid,
180                         param-pref, param-type, param-geo, param-tz,
181                         param-label }?,
182    element pobox { text }+,
183    element ext { text }+,
184    element street { text }+,
185    element locality { text }+,
186    element region { text }+,
187    element code { text }+,
188    element country { text }+
189  }
190
191# 6.4.1
192property-tel = element tel {
193    element parameters {
194      param-altid,
195      param-pid,
196      param-pref,
197      element type {
198        element text { "work" | "home" | "text" | "voice"
199                     | "fax" | "cell" | "video" | "pager"
200                     | "textphone" | x-name | iana-token }+
201      }?,
202      param-mediatype
203    }?,
204    (value-text | value-uri)
205  }
206
207# 6.4.2
208property-email = element email {
209    element parameters { param-altid, param-pid, param-pref,
210                         param-type }?,
211    value-text
212  }
213
214# 6.4.3
215property-impp = element impp {
216    element parameters { param-altid, param-pid, param-pref,
217                         param-type, param-mediatype }?,
218    value-uri
219  }
220
221# 6.4.4
222property-lang = element lang {
223    element parameters { param-altid, param-pid, param-pref,
224                         param-type }?,
225    value-language-tag
226  }
227
228# 6.5.1
229property-tz = element tz {
230    element parameters { param-altid, param-pid, param-pref,
231                         param-type, param-mediatype }?,
232    (value-text | value-uri | value-utc-offset)
233  }
234
235# 6.5.2
236property-geo = element geo {
237    element parameters { param-altid, param-pid, param-pref,
238                         param-type, param-mediatype }?,
239    value-uri
240  }
241
242# 6.6.1
243property-title = element title {
244    element parameters { param-language, param-altid, param-pid,
245                         param-pref, param-type }?,
246    value-text
247  }
248
249# 6.6.2
250property-role = element role {
251    element parameters { param-language, param-altid, param-pid,
252                         param-pref, param-type }?,
253    value-text
254  }
255
256# 6.6.3
257property-logo = element logo {
258    element parameters { param-language, param-altid, param-pid,
259                         param-pref, param-type, param-mediatype }?,
260    value-uri
261  }
262
263# 6.6.4
264property-org = element org {
265    element parameters { param-language, param-altid, param-pid,
266                         param-pref, param-type, param-sort-as }?,
267    value-text-list
268  }
269
270# 6.6.5
271property-member = element member {
272    element parameters { param-altid, param-pid, param-pref,
273                         param-mediatype }?,
274    value-uri
275  }
276
277# 6.6.6
278property-related = element related {
279    element parameters {
280      param-altid,
281      param-pid,
282      param-pref,
283      element type {
284        element text {
285          "work" | "home" | "contact" | "acquaintance" |
286          "friend" | "met" | "co-worker" | "colleague" | "co-resident" |
287          "neighbor" | "child" | "parent" | "sibling" | "spouse" |
288          "kin" | "muse" | "crush" | "date" | "sweetheart" | "me" |
289          "agent" | "emergency"
290        }+
291      }?,
292      param-mediatype
293    }?,
294    (value-uri | value-text)
295  }
296
297# 6.7.1
298property-categories = element categories {
299    element parameters { param-altid, param-pid, param-pref,
300                         param-type }?,
301    value-text-list
302  }
303
304# 6.7.2
305property-note = element note {
306    element parameters { param-language, param-altid, param-pid,
307                         param-pref, param-type }?,
308    value-text
309  }
310
311# 6.7.3
312property-prodid = element prodid { value-text }
313
314# 6.7.4
315property-rev = element rev { value-timestamp }
316
317# 6.7.5
318property-sound = element sound {
319    element parameters { param-language, param-altid, param-pid,
320                         param-pref, param-type, param-mediatype }?,
321    value-uri
322  }
323
324# 6.7.6
325property-uid = element uid { value-uri }
326
327# 6.7.7
328property-clientpidmap = element clientpidmap {
329    element sourceid { xsd:positiveInteger },
330    value-uri
331  }
332
333# 6.7.8
334property-url = element url {
335    element parameters { param-altid, param-pid, param-pref,
336                         param-type, param-mediatype }?,
337    value-uri
338  }
339
340# 6.8.1
341property-key = element key {
342    element parameters { param-altid, param-pid, param-pref,
343                         param-type, param-mediatype }?,
344    (value-uri | value-text)
345  }
346
347# 6.9.1
348property-fburl = element fburl {
349    element parameters { param-altid, param-pid, param-pref,
350                         param-type, param-mediatype }?,
351    value-uri
352  }
353
354# 6.9.2
355property-caladruri = element caladruri {
356    element parameters { param-altid, param-pid, param-pref,
357                         param-type, param-mediatype }?,
358    value-uri
359  }
360
361# 6.9.3
362property-caluri = element caluri {
363    element parameters { param-altid, param-pid, param-pref,
364                         param-type, param-mediatype }?,
365    value-uri
366  }
367
368# Top-level grammar
369property = property-adr | property-anniversary | property-bday
370         | property-caladruri | property-caluri | property-categories
371         | property-clientpidmap | property-email | property-fburl
372         | property-fn | property-geo | property-impp | property-key
373         | property-kind | property-lang | property-logo
374         | property-member | property-n | property-nickname
375         | property-note | property-org | property-photo
376         | property-prodid | property-related | property-rev
377         | property-role | property-gender | property-sound
378         | property-source | property-tel | property-title
379         | property-tz | property-uid | property-url
380start = element vcards {
381    element vcard {
382      (property
383       | element group {
384           attribute name { text },
385           property*
386         })+
387    }+
388  }
389