($and/ <== DO NOT REMOVE - switch for preventing MathML interpretation of dollar signs on this page)

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

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.

  1. 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 ")".

  2. 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:

  1. URIs as peer roots: This use case was designed for XDI discovery and a simpler solution was found.

  2. SHA schemes: These will be addressed in CID (Cryptographic ID) schemes to be defined in either the XDI Schemes or XDI Cryptographic Mechanisms specs.


CategoryProposal CategoryGraphModel CategoryCurrent

XdiAbnf (last edited 2015-10-19 02:14:32 by drummond)