Forgot the schema:
default namespace = "urn:ietf:params:xml:ns:vcard-4.0"
# Value types \text = element text { text } text-list = \text+ uri = element uri { xsd:anyURI } date = element date { xsd:string { pattern = "\d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d" } } time = element time { xsd:string { pattern = "(\d\d(\d\d(\d\d)?)?|-\d\d(\d\d?)|--\d\d)" ~ "(Z|[+-]\d\d(\d\d)?)?" } } date-time = element date-time { xsd:string { pattern = "(\d{8}|--\d{4}|---\d\d)T\d\d(\d\d(\d\d)?)?" ~ "(Z|[+-]\d\d(\d\d)?)?" } } date-and-or-time = date | date-time | time timestamp = element timestamp { xsd:string { pattern = "\d{8}T\d{6}(Z|[+-]\d\d(\d\d)?)?" } } boolean = element boolean { xsd:boolean } integer = element integer { xsd:integer } float = element float { xsd:float } binary = element binary { xsd:base64Binary } language-tag = element language-tag { xsd:string { pattern = "([a-z]{2,3}((-[a-z]{3}){0,3})?|[a-z]{4,8})" ~ "(-[a-z]{4})?(-([a-z]{2}|\d{3}))?" ~ "(-([0-9a-z]{5,8}|\d[0-9a-z]{3}))*" ~ "(-[0-9a-wyz](-[0-9a-z]{2,8})+)*(-x(-[0-9a-z]{1,8})+)?|" ~ "x(-[0-9a-z]{1,8})+|[a-z]{1,3}(-[0-9a-z]{2,8}){1,2}" } } data = (element type { xsd:string { pattern = "[A-Za-z\d!#$&.+-^_]{1,127}/" ~ "[A-Za-z\d!#$&.+-^_]{1,127}" } }, binary) | uri
# Parameters language = element language { language-tag }? pref = element pref { xsd:integer { minInclusive = "1" maxInclusive = "100" } }? pid = element pid { xsd:string { pattern = "\d+(.\d+)?" } }?
# Properties source = element source { pid, pref, uri } name = element name { \text } kind = element kind { element individual { empty } | element group { empty } | element org { empty } | element location { empty } } fn = element fn { language, pid, pref, \text } n = element n { language, element surname { text-list }, element given { text-list },
element prefix { text-list }, element suffix { text-list } } nickname = element nickname { language, pid, pref, text-list } photo = element photo { pid, pref, data } bday = element bday { date-and-or-time | \text } dday = element dday { date-and-or-time | \text } birth = element birth { language, \text } death = element death { language, \text } anniversary = element anniversary { date-and-or-time | \text } sex = element sex { "0" | "1" | "2" | "9" } adr = element adr { language, element geo { uri }?, element tz { \text | uri }?, pid, pref, element pobox { text-list }, element ext { text-list }, element street { text-list }, element locality { text-list }, element region { text-list }, element code { text-list }, element country { text-list } } label = element label { language, pid, pref, \text } tel = element tel { element type { element text { empty }?, element voice { empty }?, element fax { empty }?, element cell { empty }?, element video { empty }?, element pager { empty }? }?, pid, pref, uri } email = element email { pid, pref, \text } impp = element impp { pid, pref, uri } lang = element lang { pid, pref, language-tag } tz = element tz { pid, pref, (\text | uri) } geo = element geo { pid, pref, uri } title = element title { language, pid, pref, \text } role = element role { language, pid, pref, \text }
logo = element logo { language, pid, pref, data } org = element org { language, pid, pref, text-list } member = element member { pid, pref, uri } related = element related { element type { element parent { empty } | element child { empty } | element sibling { empty } | element spouse { empty } | element family { empty } | element friend { empty } | element supervisor { empty } | element supervisee { empty } | element assistant { empty } | element colleague { empty } | element agent { empty } | element emergency { empty } }?, pid, pref, (uri | \text) } categories = element categories { pid, pref, \text } note = element note { language, pid, pref, \text } prodid = element prodid { \text } rev = element rev { timestamp } sort-string = element sort-string { \text } sound = element sound { language, pid, pref, data } uid = element uid { uri } clientpidmap = element clientpidmap { element sourceid { xsd:positiveInteger }, uri } url = element url { pid, pref, uri } class = element class { element PUBLIC { empty } | element PRIVATE { empty } | element CONFIDENTIAL { empty } } key = element key { pid, pref, data } fburl = element fburl { pid, pref, uri } caladruri = element caladruri { pid, pref, uri } caluri = element caluri { pid, pref, uri }
# Top-level grammar group-property = fn | nickname | photo | adr | label | tel | email | impp | lang | tz | geo | title | role | logo | org | related | categories | note | sound | url | key | fburl | caladruri | caluri any-property = group-property | source | name | kind | n | bday | dday | birth | death | anniversary | sex | member | prodid | rev | sort-string | uid | clientpidmap | class start = element vcard { (any-property | element group { attribute name { text }, group-property* })* }