Contents
About
This is the proposed ABNF for XDI Core 1.0. It uses the ABNF syntax specified in RFC 5234.
The goal of the XDI TC is to keep this page current with any changes to the ABNF for XDI Core 1.0, so that it can serve as an easy Web reference.
Change Log
- 2015-10-18 - Drummond Reed and Joseph Boyle:
- Removed attr-terminal rule because, even though logically correct, the "greedy algorithm" of ABNF matched all attributes in an XDI address before reaching it.
- Renamed the XDI address sequence rules to use actual XDI address type names.
- Reordered a few of the rule groups in order to match a logical progression of headings in the XDI Core 1.0 spec.
2015-10-13 - Drummond Reed: added the relation-definition set of rules to support relation, domain, and range definition statements. See the Relations section of the Dictionary Patterns page).
- 2015-10-08 - Drummond Reed: fixed two small bugs:
peer-root-variable = "{" peer-root "}" ==> peer-root-variable = "{" peer-root-instance "}"
inner-root-variable = "{" inner-root "}" ==> inner-root-variable = "{" inner-root-instance "}"
- 2015-10-04 - Drummond Reed: post revised ABNF reflecting the changes proposed for XDI Core 1.0 Working Draft 05 based on having all sections finished.
- 2015-05-15 - Drummond Reed: correct entity cardinality in a peer root.
2015-04-05 - Drummond Reed: narrowed root-collection so it could only be a class (consistent with collection and attr-collection).
- 2015-03-19 - Drummond Reed: made revisions to close the first two open issues below.
2015-03-08 - Drummond Reed: started new comment log (see History for old log) to track changes in the ABNF starting with XDI Core 1.0 Working Draft 04. This new version: a) reflects the terminology being adopted starting in Working Draft 04, b) incorporates the StarShift proposal, and c) is intended for XDI statement format (the pure text format in which every XDI statement is expressed on its own line).
Proposed Collected ABNF for XDI Core 1.0 Working Draft 05
;***** XDI STATEMENTS SECTION ***** xdi-graph = *( xdi-statement / CRLF ) xdi-statement = contextual-statement / literal-statement / relational-statement contextual-statement = direct-contextual / inverse-contextual direct-contextual = peer-root-direct / inner-root-direct / entity-direct / attr-direct peer-root-direct = *peer-root "//" peer-root inner-root-direct = root-address "//" inner-root entity-direct = entity-address "//" entity attr-direct = attr-address "//" attr inverse-contextual = peer-root-inverse / inner-root-inverse / entity-inverse / attr-inverse peer-root-inverse = peer-root "/$is()/" *peer-root inner-root-inverse = inner-root "/$is()/" root-address entity-inverse = entity "/$is()/" entity-address attr-inverse = attr "/$is()/" attr-address literal-statement = entity-address 1*attr "/&/" value literal-var-statement = entity-address 1*attr "/{&}/" value-variable value-variable = "{" attr-class "}" relational-statement = direct-relational / inverse-relational / relation-definition direct-relational = xdi-address "/" 1*entity "/" xdi-address inverse-relational = xdi-address "/$is" 1*entity "/" xdi-address relation-definition = direct-domain / inverse-domain / direct-range / inverse-range direct-domain = direct-entity-domain / direct-attr-domain direct-entity-domain = root-address 1*definition "/(/)/" root-address 1*definition direct-attr-domain = root-address *definition 1*attr-definition "/(/)/" root-address 1*definition inverse-domain = inverse-entity-domain / inverse-attr-domain inverse-entity-domain = root-address 1*definition "/$is(/)/" root-address 1*definition inverse-attr-domain = root-address 1*definition "/$is(/)/" root-address *definition 1*attr-definition direct-range = direct-entity-range / direct-attr-range direct-entity-range = root-address 1*definition "/(/)#/" root-address 1*definition direct-attr-range = root-address 1*definition "/(/)#/" root-address *definition 1*attr-definition inverse-range = inverse-entity-range / inverse-attr-range inverse-entity-range = root-address 1*definition "/$is(/)#/" root-address 1*definition inverse-attr-range = root-address *definition 1*attr-definition "/$is(/)#/" root-address 1*definition ;***** XDI-ADDRESS SECTION ***** xdi-address = root-address / entity-address / attr-address / literal-address root-address = *peer-root *inner-root entity-address = root-address *entity attr-address = entity-address *attr literal-address = entity-address 1*attr "&" ;***** XDI-CONTEXTS SECTION ***** peer-root = peer-root-instance / peer-root-variable peer-root-instance = "(" entity ")" peer-root-variable = "{" peer-root-instance "}" inner-root = inner-root-instance / inner-root-variable inner-root-instance = inner-root-peer-root / inner-root-entity inner-root-peer-root = "(" *peer-root "/" *entity ")" inner-root-entity = "(" *entity "/" *entity ")" inner-root-variable = "{" inner-root-instance "}" entity = singleton / collection / definition / variable / meta-variable singleton = instance / class collection = "[" class "]" definition = "|" ( singleton / collection ) "|" variable = "{" ( singleton / collection / definition ) "}" meta-variable = "{" variable "}" instance = person / group / thing / ordinal person = "=" [ "!" ] [ "~" ] id-string group = "+" [ "!" ] [ "~" ] id-string thing = "*" [ "!" ] [ "~" ] id-string ordinal = "@" [ "!" ] [ "~" ] ordinal-string class = reserved-class / unreserved-class / "$" / "#" / "=" / "+" / "*" / "@" reserved-class = "$" xdi-name unreserved-class = "#" [ "~" ] id-string attr = attr-singleton / attr-collection / attr-definition / attr-variable / attr-meta-variable attr-singleton = attr-class / attr-instance attr-collection = "[" attr-class "]" attr-definition = "|" ( attr-singleton / attr-collection ) "|" attr-variable = "{" ( attr-singleton / attr-collection / attr-definition ) "}" attr-meta-variable = "{" attr-variable "}" attr-class = "<" class ">" attr-instance = "<" instance ">" ;***** XDI IDENTIFIERS SECTION ***** id-string = xdi-name / xdi-scheme / encap-iri ordinal-string = int / other-scheme xdi-name = name-char *( name-char / "_" / "-" / "." ) name-char = lower-alpha / DIGIT / %xA0-EFFFD / pct-encoded lower-alpha = %x61-7A ; a-z pct-encoded = "%" HEXDIG HEXDIG xdi-scheme = uuid-scheme / cid-scheme / other-scheme uuid-scheme = ":uuid:" 8HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 2HEXDIG 2HEXDIG "-" 12HEXDIG cid-scheme = ":cid-" 1*DIGIT ":" xdi-name other-scheme = ":" ( lower-alpha / DIGIT ) *( lower-alpha / DIGIT / "_" / "-" / "." ) ":" xdi-name encap-iri = "(" absolute-iri ")" absolute-iri = iri-scheme ":" 1*iri-char iri-scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) iri-char = safe-char / %xA0-EFFFD / pct-encoded safe-char = unreserved / reserved / gen-delims / safe-sub-delims unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" reserved = gen-delims / safe-sub-delims gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" safe-sub-delims = "!" / "$" / "&" / "(" / "*" / "+" / "," / ";" / "=" ; single quote & right paren removed ;***** JSON SECTION ***** ;JSON ABNF adapted from http://rfc7159.net/rfc7159 - How much whitespace do we want to allow? value = "false" / "null" / "true" / object / array / number / string object = begin-object [ member *( value-separator member ) ] end-object member = string name-separator value array = begin-array [ value *( value-separator value ) ] end-array begin-array = ws %x5B ws ; [ left square bracket begin-object = ws %x7B ws ; { left curly bracket end-array = ws %x5D ws ; ] right square bracket end-object = ws %x7D ws ; } right curly bracket name-separator = ws %x3A ws ; : colon value-separator = ws %x2C ws ; , comma number = [ "-" ] int [ frac ] [ exp ] exp = [ "e" / "E" ] [ "-" / "+" ] 1*DIGIT frac = "." 1*DIGIT int = "0" / ( %x31-39 *DIGIT ) ; no leading zeros string = quotation-mark *char quotation-mark ;backspace U+0008, form feed U+000C, line feed U+000A, CR U+000D, tab U+0009, any UTF-16 code unit (even illegal) char = unescaped / backslash ( quotation-mark / backslash / "/" / "b" / "f" / "n" / "r" / "t" / "u" 4HEXDIG ) backslash = %x5C ; \ reverse solidus U+005C quotation-mark = %x22 ; " quotation mark U+0022 ;any UTF-16 code unit except control characters, quotation mark, or backslash unescaped = %x20-21 / %x23-5B / %x5D-10FFFF ;if value must fit on one line ws = *( %x20 / %x09 / %x0A / %x0D ) ; Space / Horizontal tab / Line feed or New line / Carriage return ;***** STANDARD ABNF SECTION ***** ;Standard ABNF character classes ALPHA = %x41-5A / %x61-7A ; A-Z, a-z DIGIT = %x30-39 ; 0-9 HEXDIG = %x30-39 / %x41-46 / %x61-66 ; 0-9, a-f, A-F CRLF = %x0D / %x0A / ( %x0D %x0A )
Previous Collected ABNF for XDI Core 1.0 Working Draft 04 (2015-05-15)
;Statement ABNF uses root, entity, attr, attr-terminal, value, CRLF xdi-graph = xdi-statement *( CRLF xdi-statement ) xdi-statement = contextual-statement / relational-statement / literal-statement contextual-statement = direct-contextual / inverse-contextual direct-contextual = root-contextual / entity-contextual / attr-contextual root-contextual = *root "//" root entity-contextual = *root *entity "//" entity attr-contextual = *root *entity *attr "//" attr inverse-contextual = inverse-root-context / inverse-entity-context / inverse-attr-context inverse-root-context = root "/$is()/" *root inverse-entity-context = entity "/$is()/" *root *entity inverse-attr-context = attr "/$is()/" *root *entity *attr relational-statement = direct-relational / inverse-relational direct-relational = *root *entity *attr "/" 1*entity "/" *root *entity *attr [ attr-terminal "&" ] inverse-relational = *root *entity *attr [ attr-terminal "&" ] "/$is" 1*entity "/" *root *entity *attr literal-statement = *root *entity *attr attr-terminal "/&/" value ; value from JSON ABNF but is always rest of line ;Root ABNF uses entity, absolute-uri root = peer-root / inner-root / root-collection / root-definition / root-variable peer-root = "(" entity / absolute-uri ")" inner-root = "(" ( *peer-root / *entity ) "/" *entity ")" root-collection = "[(" class ")]" root-definition = "|" peer-root / inner-root / root-collection "|" root-variable = "{" peer-root / inner-root / root-collection / root-definition "}" ;Entity ABNF uses class, instance, authority entity = singleton / collection / definition / variable singleton = class / instance / authority collection = "[" class "]" definition = "|" class / authority / collection "|" variable = "{" singleton / collection / definition "}" ;Attribute ABNF uses class, instance, authority attr = attr-singleton / attr-collection / attr-definition / attr-variable attr-singleton = attr-class / attr-instance attr-collection = "[" attr-class "]" attr-definition = "|" attr-class / attr-authority / attr-collection "|" attr-variable = "{" attr-singleton / attr-collection / attr-definition "}" attr-class = "<" class ">" attr-instance = "<" instance ">" attr-authority = "<" authority ">" attr-terminal = attr-class / ( attr-collection attr-instance ) ;Type ABNF uses id-literal, xdi-name, int class = reserved / unreserved / "$" / "#" / "@" / "*" / "=" / "+" reserved = "$" xdi-name unreserved = "#" id-literal instance = ordered / unordered ordered = "@" [ "!" ] int ; int from JSON RFC 7159 unordered = "*" [ "!" ] id-literal authority = personal / legal personal = "=" [ "!" ] id-literal legal = "+" [ "!" ] id-literal ;Name ABNF use only standard character classes id-literal = xdi-name / xdi-scheme / external-ref xdi-scheme = uuid-scheme / ipv6-scheme / sha-scheme / sha3-scheme uuid-scheme = ":uuid:" 8HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 2HEXDIG 2HEXDIG "-" 12HEXDIG ;time-low,mid,high; clock-seq(-low); node ipv6-scheme = ":ipv6:" ipv6-literal ipv6-literal = ":ipv6:" 4HEXDIG 7*( ":" 4HEXDIG ) ;needs revision into canonical form per RFC 5952 sha-scheme = ":sha-" ( "224:" 7w32 / "256:" 8w32 / "384:" 12w32 / "512:" 16w32 / "512-224:" 7w32 / "512-256:" 8w32 ) sha3-scheme = ":sha3-" ( "224:" 7w32 / "256:" 8w32 / "384:" 12w32 / "512:" 16w32 ) w32 = 8HEXDIG external-ref = local-ref / uri-ref local-ref = "(" xdi-name ")" uri-ref = "(" absolute-uri ")" absolute-uri = uri-scheme ":" 1*uri-char uri-scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) xdi-name = global-name / local-name global-name = name-char *( name-char / "_" / "-" / "." ) local-name = "_" / "-" / "." *( name-char / "_" / "-" / "." ) name-char = ALPHA / DIGIT / %xA0-EFFFD ; safe-char = ALPHA / DIGIT / "$" / "-" / "_" / "." / "+" / "!" / "*" / "'" / "(" / ")" uri-char = safe-char / "%" HEXDIG HEXDIG ;uri-char = xdi-char / nonparen-delim / context-symbol / immutability-symbol ; "(" and ")" are excluded ;nonparen-delim = "/" / "?" / "[" / "]" / "'" / "," / ";" ; double quote included? ;context-symbol = "$" / "#" / "@" / "*" / "=" / "+" ;immutability-symbol = "!" ;JSON ABNF adapted from http://rfc7159.net/rfc7159 - How much whitespace do we want to allow? value = "false" / "null" / "true" / object / array / number / string object = begin-object [ member *( value-separator member ) ] end-object member = string name-separator value array = begin-array [ value *( value-separator value ) ] end-array begin-array = ws %x5B ws ; [ left square bracket begin-object = ws %x7B ws ; { left curly bracket end-array = ws %x5D ws ; ] right square bracket end-object = ws %x7D ws ; } right curly bracket name-separator = ws %x3A ws ; : colon value-separator = ws %x2C ws ; , comma number = [ "-" ] int [ frac ] [ exp ] exp = [ "e" / "E" ] [ "-" / "+" ] 1*DIGIT frac = "." 1*DIGIT int = "0" / ( %x31-39 *DIGIT ) ; no leading zeros string = quotation-mark *char quotation-mark char = unescaped / backslash ( quotation-mark / backslash / "/" / "b" / "f" / "n" / "r" / "t" / "u" 4HEXDIG ) ;backspace U+0008, form feed U+000C, line feed U+000A, CR U+000D, tab U+0009, any UTF-16 code unit (even illegal) backslash = %x5C ; \ reverse solidus U+005C quotation-mark = %x22 ; " quotation mark U+0022 unescaped = %x20-21 / %x23-5B / %x5D-10FFFF ;any UTF-16 code unit except control characters, quotation mark, or backslash ;ws = *( %x20 / %x09 ) ; Space / Horizontal tab : if value must fit on one line ws = *( %x20 / %x09 / %x0A / %x0D ) ; Space / Tab / LF or NL / CR ;Standard character classes ALPHA = %x41-5A / %x61-7A ; A-Z, a-z DIGIT = %x30-39 ; 0-9 HEXDIG = %x30-39 / %x41-46 / %x61-66 ; 0-9, a-f, A-F CRLF = %x0D / %x0A / ( %x0D %x0A )
Annotated ABNF
An XDI graph can be serialized as a list of statements (the first rule) or as a tree (see Serialization section).
An XDI graph node address must progress through roots (if any), then entities (if any), then attributes (if any). The rules for contextual statements express the constraint that the address resulting from the statement must follow this order.
If an XDI name includes non-ASCII characters, they SHOULD be limited to Unicode's Letter and Number character classes. XDI processors MAY but are not required to reject names containing non-ASCII characters of other Unicode character classes such as Space.
Names starting with period, hyphen, or underscore are reserved for local identifiers.
An XDI document is a sequence of Unicode characters and is intended only for encoding in Unicode encodings such as UTF-8 and UTF-16. Encoding in other encodings may result in character corruption and unpredictable results.
XDI processors are not required to check URIs for valid URI syntax. XDI parsers reading an URI (i.e. having found an open parenthesis followed by a string matching uri-scheme followed by a colon) MAY simply consider following characters part of the URI up to close parenthesis or end of line, but MUST allow matched ( ) pairs within the URI body in order to accommodate the phone number URI format.
The JSON value definition is intended to conform to JSON standards. The ABNF in RFC 7159 is authoritative and the JSON ABNF given here is just a readable equivalent given for the reader's convenience.
;While RFC 7159 allows whitespace between JSON tokens to be space, tab, CR, or LF, an XDI literal statement must be a single line, so CR or LF are not allowed as whitespace in JSON values in XDI literal statements.
XDI generators SHOULD produce JSON values without optional whitespace between tokens.
For historical reasons, the \uxxxx escape sequence expresses an UTF-16 code unit, implying a non-BMP character must be escaped as two code units, and allowing illegal escape sequences such as unpaired surrogates. This is not ideal, but following RFC 7159 we carry these rules forward for back compatibility. XDI processors MAY reject input with invalid UTF-16 code sequences but are not required to check.
Notes
The following documents decisions made for the XDI Core 1.0 Working Draft 04 ABNF that are no longer in the Working Draft 05 ABNF.
URIs as peer roots: On the 2015-03-13 TC telecon, we agreed to allow a "naked URI" as a peer root, e.g., (https://example.com) instead of requiring an external reference in the form (*(https://example.com))? The peer rule changed from "(" *entity ")" to "(" *entity / absolute-uri ")".
SHA schemes: On the 2015-03-13 TC telecon, we agreed to specify all SHA2 and SHA3 schemes (except the SHAKE schemes) as shown the SHA Wikipedia page.
Reasons these are no longer in the Working Draft 05 ABNF:
URIs as peer roots: This use case was designed for XDI discovery and a simpler solution was found.
SHA schemes: These will be addressed in CID (Cryptographic ID) schemes to be defined in either the XDI Schemes or XDI Cryptographic Mechanisms specs.