Files
cloud-cap-samples/odata/etc/odata-url.abnf
2021-02-01 09:37:06 +01:00

1189 lines
49 KiB
ABNF

;------------------------------------------------------------------------------
; odata-abnf-construction-rules
;------------------------------------------------------------------------------
;
; OData Version 4.0 Plus Errata 03
; OASIS Standard incorporating Approved Errata 03
; 02 June 2016
; Copyright (c) OASIS Open 2016. All Rights Reserved.
; Source: http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/abnf/
; Link to latest version of narrative specification: http://docs.oasis-open.org/odata/odata/v4.0/errata03/odata-v4.0-errata03-part1-protocol-complete.html
;
; Technical Committee:
; OASIS Open Data Protocol (OData) TC
; https://www.oasis-open.org/committees/odata
;
; Chairs:
; - Barbara Hartel (barbara.hartel@sap.com), SAP SE
; - Ram Jeyaraman (Ram.Jeyaraman@microsoft.com), Microsoft
;
; Editors:
; - Ralf Handl (ralf.handl@sap.com), SAP SE
; - Michael Pizzo (mikep@microsoft.com), Microsoft
; - Martin Zurmuehl (martin.zurmuehl@sap.com), SAP SE
;
; Additional artifacts:
; This grammar is one component of a Work Product which consists of:
; - OData Version 4.0 Part 1: Protocol
; - OData Version 4.0 Part 2: URL Conventions
; - OData Version 4.0 Part 3: Common Schema Definition Language (CSDL)
; - OData ABNF Construction Rules Version 4.0 (this document)
; - OData ABNF Test Cases
; - OData Core Vocabulary
; - OData Capabilities Vocabulary
; - OData Measures Vocabulary
; - OData Metadata Service Entity Model
; - OData EDMX XML Schema
; - OData EDM XML Schema
;
; Related work:
; This work product is related to the following two Work Products, each of
; which define alternate formats for OData payloads
; - OData Atom Format Version 4.0
; - OData JSON Format Version 4.0
; This specification replaces or supersedes:
; - None
;
; Declared XML namespaces:
; - http://docs.oasis-open.org/odata/ns/edmx
; - http://docs.oasis-open.org/odata/ns/edm
;
; Abstract:
; The Open Data Protocol (OData) enables the creation of REST-based data
; services, which allow resources, identified using Uniform Resource
; Identifiers (URLs) and defined in a data model, to be published and
; edited by Web clients using simple HTTP messages. This document defines
; the URL syntax for requests and the serialization format for primitive
; literals in request and response payloads.
;
; Overview:
; This grammar uses the ABNF defined in RFC5234 with one extension: literals
; enclosed in single quotes (e.g. '$metadata') are treated case-sensitive.
;
; The following rules assume that URIs have been percent-encoding normalized
; as described in section 6.2.2.2 of RFC3986
; (http://tools.ietf.org/html/rfc3986#section-6.2.2.2)
; before applying the grammar to them, i.e. all characters in the unreserved
; set (see rule "unreserved" below) are plain literals and NOT
; percent-encoded.
;
; For characters outside the unreserved set the rules explicitly state
; whether the percent-encoded representation is treated identical to the
; plain literal representation.
;
; One prominent example is the single quote that delimits OData primitive
; type literals: %27 and ' are treated identically, so a single quote within
; a string literal is "encoded" as two consecutive single quotes in either
; literal or percent-encoded representation.
;
; Contents:
; 1. Resource Path
; 2. Query Options
; 3. Context URL Fragments
; 4. Expressions
; 5. JSON format for function parameters
; 6. Names and identifiers
; 7. Literal Data Values
; 8. Header values
; 9. Punctuation
;
; A. URI syntax [RFC3986]
; B. IRI syntax [RFC3986]
; C. ABNF core definitions [RFC5234]
;
;------------------------------------------------------------------------------
dummyStartRule = odataUri / header / primitiveValue ; just to please the test parser
;------------------------------------------------------------------------------
odataUri = serviceRoot [ odataRelativeUri ]
serviceRoot = ( "https" / "http" ) ; Note: case-insensitive
"://" host [ ":" port ]
"/" *( segment-nz "/" )
odataRelativeUri = '$batch' ; Note: case-sensitive!
/ '$entity' "?" entityOptions
/ '$entity' "/" qualifiedEntityTypeName "?" entityCastOptions
/ '$metadata' [ "?" format ] [ context ]
/ resourcePath [ "?" queryOptions ]
;------------------------------------------------------------------------------
; 1. Resource Path
;------------------------------------------------------------------------------
resourcePath = entitySetName [ collectionNavigation ]
/ singletonEntity [ singleNavigation ]
/ actionImportCall
/ entityColFunctionImportCall [ collectionNavigation ]
/ entityFunctionImportCall [ singleNavigation ]
/ complexColFunctionImportCall [ complexColPath ]
/ complexFunctionImportCall [ complexPath ]
/ primitiveColFunctionImportCall [ primitiveColPath ]
/ primitiveFunctionImportCall [ primitivePath ]
/ crossjoin
/ '$all' [ "/" qualifiedEntityTypeName ]
collectionNavigation = [ "/" qualifiedEntityTypeName ] [ collectionNavPath ]
collectionNavPath = keyPredicate [ singleNavigation ]
/ boundOperation
/ count
/ ref
keyPredicate = simpleKey / compoundKey ;/ keyPathSegments
simpleKey = OPEN ( parameterAlias / keyPropertyValue ) CLOSE
compoundKey = OPEN keyValuePair *( COMMA keyValuePair ) CLOSE
keyValuePair = ( primitiveKeyProperty / keyPropertyAlias ) EQ ( parameterAlias / keyPropertyValue )
keyPropertyValue = primitiveLiteral
keyPropertyAlias = odataIdentifier
;keyPathSegments = 1*( "/" keyPathLiteral )
;keyPathLiteral = *pchar
singleNavigation = [ "/" qualifiedEntityTypeName ]
[ "/" propertyPath
/ boundOperation
/ ref
/ value ; request the media resource of a media entity
]
propertyPath = entityColNavigationProperty [ collectionNavigation ]
/ entityNavigationProperty [ singleNavigation ]
/ complexColProperty [ complexColPath ]
/ complexProperty [ complexPath ]
/ primitiveColProperty [ primitiveColPath ]
/ primitiveProperty [ primitivePath ]
/ streamProperty [ boundOperation ]
primitiveColPath = count / boundOperation
primitivePath = value / boundOperation
complexColPath = [ "/" qualifiedComplexTypeName ]
[ count / boundOperation ]
complexPath = [ "/" qualifiedComplexTypeName ]
[ "/" propertyPath
/ boundOperation
]
count = '/$count'
ref = '/$ref'
value = '/$value'
; boundOperation segments can only be composed if the type of the previous segment
; matches the type of the first parameter of the action or function being called.
; Note that the rule name reflects the return type of the function.
boundOperation = "/" ( boundActionCall
/ boundEntityColFunctionCall [ collectionNavigation ]
/ boundEntityFunctionCall [ singleNavigation ]
/ boundComplexColFunctionCall [ complexColPath ]
/ boundComplexFunctionCall [ complexPath ]
/ boundPrimitiveColFunctionCall [ primitiveColPath ]
/ boundPrimitiveFunctionCall [ primitivePath ]
)
actionImportCall = actionImport
boundActionCall = namespace "." action
; with the added restriction that the binding parameter MUST be either an entity or collection of entities
; and is specified by reference using the URI immediately preceding (to the left) of the boundActionCall
; The following boundXxxFunctionCall rules have the added restrictions that
; - the function MUST support binding, and
; - the binding parameter type MUST match the type of resource identified by the
; URI immediately preceding (to the left) of the boundXxxFunctionCall, and
; - the functionParameters MUST NOT include the bindingParameter.
boundEntityFunctionCall = namespace "." entityFunction functionParameters
boundEntityColFunctionCall = namespace "." entityColFunction functionParameters
boundComplexFunctionCall = namespace "." complexFunction functionParameters
boundComplexColFunctionCall = namespace "." complexColFunction functionParameters
boundPrimitiveFunctionCall = namespace "." primitiveFunction functionParameters
boundPrimitiveColFunctionCall = namespace "." primitiveColFunction functionParameters
entityFunctionImportCall = entityFunctionImport functionParameters
entityColFunctionImportCall = entityColFunctionImport functionParameters
complexFunctionImportCall = complexFunctionImport functionParameters
complexColFunctionImportCall = complexColFunctionImport functionParameters
primitiveFunctionImportCall = primitiveFunctionImport functionParameters
primitiveColFunctionImportCall = primitiveColFunctionImport functionParameters
functionParameters = OPEN [ functionParameter *( COMMA functionParameter ) ] CLOSE
functionParameter = parameterName EQ ( parameterAlias / primitiveLiteral )
parameterName = odataIdentifier
parameterAlias = AT odataIdentifier
crossjoin = '$crossjoin' OPEN
entitySetName *( COMMA entitySetName )
CLOSE
;------------------------------------------------------------------------------
; 2. Query Options
;------------------------------------------------------------------------------
queryOptions = queryOption *( "&" queryOption )
queryOption = systemQueryOption
/ aliasAndValue
/ customQueryOption
entityOptions = *( entityIdOption "&" ) id *( "&" entityIdOption )
entityIdOption = format
/ customQueryOption
entityCastOptions = *( entityCastOption "&" ) id *( "&" entityCastOption )
entityCastOption = entityIdOption
/ expand
/ select
id = '$id' EQ IRI-in-query
systemQueryOption = deltatoken
/ expand
/ filter
/ format
/ id
/ inlinecount
/ orderby
/ search
/ select
/ skip
/ skiptoken
/ top
expand = '$expand' EQ expandItem *( COMMA expandItem )
expandItem = STAR [ ref / OPEN levels CLOSE ]
/ expandPath
[ ref [ OPEN expandRefOption *( SEMI expandRefOption ) CLOSE ]
/ count [ OPEN expandCountOption *( SEMI expandCountOption ) CLOSE ]
/ OPEN expandOption *( SEMI expandOption ) CLOSE
]
expandPath = [ ( qualifiedEntityTypeName / qualifiedComplexTypeName ) "/" ]
*( ( complexProperty / complexColProperty ) "/" [ qualifiedComplexTypeName "/" ] )
( STAR / navigationProperty [ "/" qualifiedEntityTypeName ] )
expandCountOption = filter
/ search
expandRefOption = expandCountOption
/ orderby
/ skip
/ top
/ inlinecount
expandOption = expandRefOption
/ select
/ expand
/ levels
levels = '$levels' EQ ( oneToNine *DIGIT / 'max' )
filter = '$filter' EQ boolCommonExpr
orderby = '$orderby' EQ orderbyItem *( COMMA orderbyItem )
orderbyItem = commonExpr [ RWS ( 'asc' / 'desc' ) ]
skip = '$skip' EQ 1*DIGIT
top = '$top' EQ 1*DIGIT
format = '$format' EQ
( "atom"
/ "json"
/ "xml"
/ 1*pchar "/" 1*pchar ; <a data service specific value indicating a
) ; format specific to the specific data service> or
; <An IANA-defined [IANA-MMT] content type>
inlinecount = '$count' EQ booleanValue
search = '$search' EQ BWS searchExpr
searchExpr = ( OPEN BWS searchExpr BWS CLOSE
/ searchTerm
) [ searchOrExpr
/ searchAndExpr
]
searchOrExpr = RWS 'OR' RWS searchExpr
searchAndExpr = RWS [ 'AND' RWS ] searchExpr
searchTerm = [ 'NOT' RWS ] ( searchPhrase / searchWord )
searchPhrase = quotation-mark 1*qchar-no-AMP-DQUOTE quotation-mark
searchWord = 1*ALPHA ; Actually: any character from the Unicode categories L or Nl,
; but not the words AND, OR, and NOT
select = '$select' EQ selectItem *( COMMA selectItem )
selectItem = STAR
/ allOperationsInSchema
/ [ ( qualifiedEntityTypeName / qualifiedComplexTypeName ) "/" ]
( selectProperty
/ qualifiedActionName
/ qualifiedFunctionName
)
selectProperty = primitiveProperty
/ primitiveColProperty
/ navigationProperty
/ selectPath [ "/" selectProperty ]
selectPath = ( complexProperty / complexColProperty ) [ "/" qualifiedComplexTypeName ]
allOperationsInSchema = namespace "." STAR
; The parameterNames uniquely identify the bound function overload
; only if it has overloads.
qualifiedActionName = namespace "." action
qualifiedFunctionName = namespace "." function [ OPEN parameterNames CLOSE ]
; The names of all non-binding parameters, separated by commas
parameterNames = parameterName *( COMMA parameterName )
deltatoken = '$deltatoken' EQ 1*( qchar-no-AMP )
skiptoken = '$skiptoken' EQ 1*( qchar-no-AMP )
aliasAndValue = parameterAlias EQ parameterValue
parameterValue = arrayOrObject
/ commonExpr
customQueryOption = customName [ EQ customValue ]
customName = qchar-no-AMP-EQ-AT-DOLLAR *( qchar-no-AMP-EQ )
customValue = *( qchar-no-AMP )
;------------------------------------------------------------------------------
; 3. Context URL Fragments
;------------------------------------------------------------------------------
context = "#" contextFragment
contextFragment = 'Collection($ref)'
/ '$ref'
/ 'Collection(Edm.EntityType)'
/ 'Collection(Edm.ComplexType)'
/ singletonEntity [ navigation *( containmentNavigation ) [ "/" qualifiedEntityTypeName ] ] [ selectList ]
/ qualifiedTypeName [ selectList ]
/ entitySet ( '/$deletedEntity' / '/$link' / '/$deletedLink' )
/ entitySet keyPredicate "/" contextPropertyPath [ selectList ]
/ entitySet [ selectList ] [ '/$entity' / '/$delta' ]
entitySet = entitySetName *( containmentNavigation ) [ "/" qualifiedEntityTypeName ]
containmentNavigation = keyPredicate [ "/" qualifiedEntityTypeName ] navigation
navigation = *( "/" complexProperty [ "/" qualifiedComplexTypeName ] ) "/" navigationProperty
selectList = OPEN selectListItem *( COMMA selectListItem ) CLOSE
selectListItem = STAR ; all structural properties
/ allOperationsInSchema
/ [ qualifiedEntityTypeName "/" ]
( qualifiedActionName
/ qualifiedFunctionName
/ selectListProperty
)
selectListProperty = primitiveProperty
/ primitiveColProperty
/ navigationProperty [ '+' ] [ selectList ]
/ selectPath [ "/" selectListProperty ]
contextPropertyPath = primitiveProperty
/ primitiveColProperty
/ complexColProperty
/ complexProperty [ [ "/" qualifiedComplexTypeName ] "/" contextPropertyPath ]
;------------------------------------------------------------------------------
; 4. Expressions
;------------------------------------------------------------------------------
; Note: a boolCommonExpr is also a commonExpr, e.g. sort by Boolean
commonExpr = ( primitiveLiteral
/ parameterAlias
/ arrayOrObject
/ rootExpr
/ firstMemberExpr
/ functionExpr
/ negateExpr
/ methodCallExpr
/ parenExpr
/ castExpr
)
[ addExpr
/ subExpr
/ mulExpr
/ divExpr
/ modExpr
]
boolCommonExpr = ( isofExpr
/ boolMethodCallExpr
/ notExpr
/ commonExpr
[ eqExpr
/ neExpr
/ ltExpr
/ leExpr
/ gtExpr
/ geExpr
/ hasExpr
]
/ boolParenExpr
) [ andExpr / orExpr ]
rootExpr = '$root/' ( entitySetName keyPredicate / singletonEntity ) [ singleNavigationExpr ]
firstMemberExpr = memberExpr
/ inscopeVariableExpr [ "/" memberExpr ]
memberExpr = [ qualifiedEntityTypeName "/" ]
( propertyPathExpr
/ boundFunctionExpr
)
propertyPathExpr = ( entityColNavigationProperty [ collectionNavigationExpr ]
/ entityNavigationProperty [ singleNavigationExpr ]
/ complexColProperty [ complexColPathExpr ]
/ complexProperty [ complexPathExpr ]
/ primitiveColProperty [ collectionPathExpr ]
/ primitiveProperty [ primitivePathExpr ]
/ streamProperty [ primitivePathExpr ]
)
inscopeVariableExpr = implicitVariableExpr
/ lambdaVariableExpr ; only allowed inside a lambdaPredicateExpr
implicitVariableExpr = '$it' ; references the unnamed outer variable of the query
lambdaVariableExpr = odataIdentifier
collectionNavigationExpr = [ "/" qualifiedEntityTypeName ]
[ keyPredicate [ singleNavigationExpr ]
/ collectionPathExpr
]
singleNavigationExpr = "/" memberExpr
complexColPathExpr = [ "/" qualifiedComplexTypeName ]
[ collectionPathExpr ]
collectionPathExpr = count
/ "/" boundFunctionExpr
/ "/" anyExpr
/ "/" allExpr
complexPathExpr = [ "/" qualifiedComplexTypeName ]
[ "/" propertyPathExpr
/ "/" boundFunctionExpr
]
primitivePathExpr = "/" boundFunctionExpr
boundFunctionExpr = functionExpr ; boundFunction segments can only be composed if the type of the
; previous segment matches the type of the first function parameter
functionExpr = namespace "."
( entityColFunction functionExprParameters [ collectionNavigationExpr ]
/ entityFunction functionExprParameters [ singleNavigationExpr ]
/ complexColFunction functionExprParameters [ complexColPathExpr ]
/ complexFunction functionExprParameters [ complexPathExpr ]
/ primitiveColFunction functionExprParameters [ collectionPathExpr ]
/ primitiveFunction functionExprParameters [ primitivePathExpr ]
)
functionExprParameters = OPEN [ functionExprParameter *( COMMA functionExprParameter ) ] CLOSE
functionExprParameter = parameterName EQ ( parameterAlias / parameterValue )
anyExpr = 'any' OPEN BWS [ lambdaVariableExpr BWS COLON BWS lambdaPredicateExpr ] BWS CLOSE
allExpr = 'all' OPEN BWS lambdaVariableExpr BWS COLON BWS lambdaPredicateExpr BWS CLOSE
lambdaPredicateExpr = boolCommonExpr ; containing at least one lambdaVariableExpr
methodCallExpr = indexOfMethodCallExpr
/ toLowerMethodCallExpr
/ toUpperMethodCallExpr
/ trimMethodCallExpr
/ substringMethodCallExpr
/ concatMethodCallExpr
/ lengthMethodCallExpr
/ yearMethodCallExpr
/ monthMethodCallExpr
/ dayMethodCallExpr
/ hourMethodCallExpr
/ minuteMethodCallExpr
/ secondMethodCallExpr
/ fractionalsecondsMethodCallExpr
/ totalsecondsMethodCallExpr
/ dateMethodCallExpr
/ timeMethodCallExpr
/ roundMethodCallExpr
/ floorMethodCallExpr
/ ceilingMethodCallExpr
/ distanceMethodCallExpr
/ geoLengthMethodCallExpr
/ totalOffsetMinutesMethodCallExpr
/ minDateTimeMethodCallExpr
/ maxDateTimeMethodCallExpr
/ nowMethodCallExpr
boolMethodCallExpr = endsWithMethodCallExpr
/ startsWithMethodCallExpr
/ containsMethodCallExpr
/ intersectsMethodCallExpr
containsMethodCallExpr = 'contains' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
startsWithMethodCallExpr = 'startswith' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
endsWithMethodCallExpr = 'endswith' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
lengthMethodCallExpr = 'length' OPEN BWS commonExpr BWS CLOSE
indexOfMethodCallExpr = 'indexof' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
substringMethodCallExpr = 'substring' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS [ COMMA BWS commonExpr BWS ] CLOSE
toLowerMethodCallExpr = 'tolower' OPEN BWS commonExpr BWS CLOSE
toUpperMethodCallExpr = 'toupper' OPEN BWS commonExpr BWS CLOSE
trimMethodCallExpr = 'trim' OPEN BWS commonExpr BWS CLOSE
concatMethodCallExpr = 'concat' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
yearMethodCallExpr = 'year' OPEN BWS commonExpr BWS CLOSE
monthMethodCallExpr = 'month' OPEN BWS commonExpr BWS CLOSE
dayMethodCallExpr = 'day' OPEN BWS commonExpr BWS CLOSE
hourMethodCallExpr = 'hour' OPEN BWS commonExpr BWS CLOSE
minuteMethodCallExpr = 'minute' OPEN BWS commonExpr BWS CLOSE
secondMethodCallExpr = 'second' OPEN BWS commonExpr BWS CLOSE
fractionalsecondsMethodCallExpr = 'fractionalseconds' OPEN BWS commonExpr BWS CLOSE
totalsecondsMethodCallExpr = 'totalseconds' OPEN BWS commonExpr BWS CLOSE
dateMethodCallExpr = 'date' OPEN BWS commonExpr BWS CLOSE
timeMethodCallExpr = 'time' OPEN BWS commonExpr BWS CLOSE
totalOffsetMinutesMethodCallExpr = 'totaloffsetminutes' OPEN BWS commonExpr BWS CLOSE
minDateTimeMethodCallExpr = 'mindatetime' OPEN BWS CLOSE
maxDateTimeMethodCallExpr = 'maxdatetime' OPEN BWS CLOSE
nowMethodCallExpr = 'now' OPEN BWS CLOSE
roundMethodCallExpr = 'round' OPEN BWS commonExpr BWS CLOSE
floorMethodCallExpr = 'floor' OPEN BWS commonExpr BWS CLOSE
ceilingMethodCallExpr = 'ceiling' OPEN BWS commonExpr BWS CLOSE
distanceMethodCallExpr = 'geo.distance' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
geoLengthMethodCallExpr = 'geo.length' OPEN BWS commonExpr BWS CLOSE
intersectsMethodCallExpr = 'geo.intersects' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
boolParenExpr = OPEN BWS boolCommonExpr BWS CLOSE
parenExpr = OPEN BWS commonExpr BWS CLOSE
andExpr = RWS 'and' RWS boolCommonExpr
orExpr = RWS 'or' RWS boolCommonExpr
eqExpr = RWS 'eq' RWS commonExpr
neExpr = RWS 'ne' RWS commonExpr
ltExpr = RWS 'lt' RWS commonExpr
leExpr = RWS 'le' RWS commonExpr
gtExpr = RWS 'gt' RWS commonExpr
geExpr = RWS 'ge' RWS commonExpr
hasExpr = RWS 'has' RWS enum
addExpr = RWS 'add' RWS commonExpr
subExpr = RWS 'sub' RWS commonExpr
mulExpr = RWS 'mul' RWS commonExpr
divExpr = RWS 'div' RWS commonExpr
modExpr = RWS 'mod' RWS commonExpr
negateExpr = "-" BWS commonExpr
notExpr = 'not' RWS boolCommonExpr
isofExpr = 'isof' OPEN BWS [ commonExpr BWS COMMA BWS ] qualifiedTypeName BWS CLOSE
castExpr = 'cast' OPEN BWS [ commonExpr BWS COMMA BWS ] qualifiedTypeName BWS CLOSE
;------------------------------------------------------------------------------
; 5. JSON format for function parameters
;------------------------------------------------------------------------------
; Note: the query part of a URI needs to be partially percent-decoded before
; applying these rules, see comment at the top of this file
;------------------------------------------------------------------------------
arrayOrObject = complexColInUri
/ complexInUri
/ rootExprCol
/ primitiveColInUri
complexColInUri = begin-array
[ complexInUri *( value-separator complexInUri ) ]
end-array
complexInUri = begin-object
[ ( annotationInUri
/ primitivePropertyInUri
/ complexPropertyInUri
/ collectionPropertyInUri
/ navigationPropertyInUri
)
*( value-separator
( annotationInUri
/ primitivePropertyInUri
/ complexPropertyInUri
/ collectionPropertyInUri
/ navigationPropertyInUri
)
)
]
end-object
collectionPropertyInUri = ( quotation-mark primitiveColProperty quotation-mark
name-separator
primitiveColInUri
)
/ ( quotation-mark complexColProperty quotation-mark
name-separator
complexColInUri
)
primitiveColInUri = begin-array
[ primitiveLiteralInJSON *( value-separator primitiveLiteralInJSON ) ]
end-array
complexPropertyInUri = quotation-mark complexProperty quotation-mark
name-separator
complexInUri
annotationInUri = quotation-mark AT namespace "." termName quotation-mark
name-separator
( complexInUri / complexColInUri / primitiveLiteralInJSON / primitiveColInUri )
primitivePropertyInUri = quotation-mark primitiveProperty quotation-mark
name-separator
primitiveLiteralInJSON
navigationPropertyInUri = singleNavPropInJSON
/ collectionNavPropInJSON
singleNavPropInJSON = quotation-mark entityNavigationProperty quotation-mark
name-separator
rootExpr
collectionNavPropInJSON = quotation-mark entityColNavigationProperty quotation-mark
name-separator
rootExprCol
rootExprCol = begin-array
[ rootExpr *( value-separator rootExpr ) ]
end-array
; JSON syntax: adapted to URI restrictions from [RFC4627]
begin-object = BWS ( "{" / "%7B" ) BWS
end-object = BWS ( "}" / "%7D" ) BWS
begin-array = BWS ( "[" / "%5B" ) BWS
end-array = BWS ( "]" / "%5D" ) BWS
quotation-mark = DQUOTE / "%22"
name-separator = BWS COLON BWS
value-separator = BWS COMMA BWS
primitiveLiteralInJSON = stringInJSON
/ numberInJSON
/ 'true'
/ 'false'
/ 'null'
stringInJSON = quotation-mark *charInJSON quotation-mark
charInJSON = qchar-unescaped
/ qchar-JSON-special
/ escape ( quotation-mark
/ escape
/ ( "/" / "%2F" ) ; solidus U+002F - literal form is allowed in the query part of a URL
/ 'b' ; backspace U+0008
/ 'f' ; form feed U+000C
/ 'n' ; line feed U+000A
/ 'r' ; carriage return U+000D
/ 't' ; tab U+0009
/ 'u' 4HEXDIG ; U+XXXX
)
qchar-JSON-special = SP / ":" / "{" / "}" / "[" / "]" ; some agents put these unencoded into the query part of a URL
escape = "\" / "%5C" ; reverse solidus U+005C
numberInJSON = [ "-" ] int [ frac ] [ exp ]
int = "0" / ( oneToNine *DIGIT )
frac = "." 1*DIGIT
exp = "e" [ "-" / "+" ] 1*DIGIT
;------------------------------------------------------------------------------
; 6. Names and identifiers
;------------------------------------------------------------------------------
singleQualifiedTypeName = qualifiedEntityTypeName
/ qualifiedComplexTypeName
/ qualifiedTypeDefinitionName
/ qualifiedEnumTypeName
/ primitiveTypeName
qualifiedTypeName = singleQualifiedTypeName
/ 'Collection' OPEN singleQualifiedTypeName CLOSE
qualifiedEntityTypeName = namespace "." entityTypeName
qualifiedComplexTypeName = namespace "." complexTypeName
qualifiedTypeDefinitionName = namespace "." typeDefinitionName
qualifiedEnumTypeName = namespace "." enumerationTypeName
; an alias is just a single-part namespace
namespace = namespacePart *( "." namespacePart )
namespacePart = odataIdentifier
entitySetName = odataIdentifier
singletonEntity = odataIdentifier
entityTypeName = odataIdentifier
complexTypeName = odataIdentifier
typeDefinitionName = odataIdentifier
enumerationTypeName = odataIdentifier
enumerationMember = odataIdentifier
termName = odataIdentifier
; Note: this pattern is overly restrictive, the normative definition is type TSimpleIdentifier in OData EDM XML Schema
odataIdentifier = identifierLeadingCharacter *127identifierCharacter
identifierLeadingCharacter = ALPHA / "_" ; plus Unicode characters from the categories L or Nl
identifierCharacter = ALPHA / "_" / DIGIT ; plus Unicode characters from the categories L, Nl, Nd, Mn, Mc, Pc, or Cf
primitiveTypeName = 'Edm.' ( 'Binary'
/ 'Boolean'
/ 'Byte'
/ 'Date'
/ 'DateTimeOffset'
/ 'Decimal'
/ 'Double'
/ 'Duration'
/ 'Guid'
/ 'Int16'
/ 'Int32'
/ 'Int64'
/ 'SByte'
/ 'Single'
/ 'Stream'
/ 'String'
/ 'TimeOfDay'
/ abstractSpatialTypeName [ concreteSpatialTypeName ]
)
abstractSpatialTypeName = 'Geography'
/ 'Geometry'
concreteSpatialTypeName = 'Collection'
/ 'LineString'
/ 'MultiLineString'
/ 'MultiPoint'
/ 'MultiPolygon'
/ 'Point'
/ 'Polygon'
primitiveProperty = primitiveKeyProperty / primitiveNonKeyProperty
primitiveKeyProperty = odataIdentifier
primitiveNonKeyProperty = odataIdentifier
primitiveColProperty = odataIdentifier
complexProperty = odataIdentifier
complexColProperty = odataIdentifier
streamProperty = odataIdentifier
navigationProperty = entityNavigationProperty / entityColNavigationProperty
entityNavigationProperty = odataIdentifier
entityColNavigationProperty = odataIdentifier
action = odataIdentifier
actionImport = odataIdentifier
function = entityFunction
/ entityColFunction
/ complexFunction
/ complexColFunction
/ primitiveFunction
/ primitiveColFunction
entityFunction = odataIdentifier
entityColFunction = odataIdentifier
complexFunction = odataIdentifier
complexColFunction = odataIdentifier
primitiveFunction = odataIdentifier
primitiveColFunction = odataIdentifier
entityFunctionImport = odataIdentifier
entityColFunctionImport = odataIdentifier
complexFunctionImport = odataIdentifier
complexColFunctionImport = odataIdentifier
primitiveFunctionImport = odataIdentifier
primitiveColFunctionImport = odataIdentifier
;------------------------------------------------------------------------------
; 7. Literal Data Values
;------------------------------------------------------------------------------
; in URLs
primitiveLiteral = nullValue ; plain values up to int64Value
/ booleanValue
/ guidValue
/ dateValue
/ dateTimeOffsetValue
/ timeOfDayValue
/ decimalValue
/ doubleValue
/ singleValue
/ sbyteValue
/ byteValue
/ int16Value
/ int32Value
/ int64Value
/ string ; single-quoted
/ duration ; all others are quoted and prefixed
/ binary
/ enum
/ geographyCollection
/ geographyLineString
/ geographyMultiLineString
/ geographyMultiPoint
/ geographyMultiPolygon
/ geographyPoint
/ geographyPolygon
/ geometryCollection
/ geometryLineString
/ geometryMultiLineString
/ geometryMultiPoint
/ geometryMultiPolygon
/ geometryPoint
/ geometryPolygon
; in Atom and JSON message bodies and CSDL DefaultValue attributes
primitiveValue = booleanValue
/ guidValue
/ durationValue
/ dateValue
/ dateTimeOffsetValue
/ timeOfDayValue
/ enumValue
/ fullCollectionLiteral
/ fullLineStringLiteral
/ fullMultiPointLiteral
/ fullMultiLineStringLiteral
/ fullMultiPolygonLiteral
/ fullPointLiteral
/ fullPolygonLiteral
/ decimalValue
/ doubleValue
/ singleValue
/ sbyteValue
/ byteValue
/ int16Value
/ int32Value
/ int64Value
/ binaryValue
; also valid are:
; - any XML string for strings in Atom and CSDL documents
; - any JSON string for JSON documents
nullValue = 'null'
; base64url encoding according to http://tools.ietf.org/html/rfc4648#section-5
binary = "binary" SQUOTE binaryValue SQUOTE
binaryValue = *(4base64char) [ base64b16 / base64b8 ]
base64b16 = 2base64char ( 'A' / 'E' / 'I' / 'M' / 'Q' / 'U' / 'Y' / 'c' / 'g' / 'k' / 'o' / 's' / 'w' / '0' / '4' / '8' ) [ "=" ]
base64b8 = base64char ( 'A' / 'Q' / 'g' / 'w' ) [ "==" ]
base64char = ALPHA / DIGIT / "-" / "_"
booleanValue = "true" / "false"
decimalValue = [SIGN] 1*DIGIT ["." 1*DIGIT]
doubleValue = decimalValue [ "e" [SIGN] 1*DIGIT ] / nanInfinity ; IEEE 754 binary64 floating-point number (15-17 decimal digits)
singleValue = doubleValue ; IEEE 754 binary32 floating-point number (6-9 decimal digits)
nanInfinity = 'NaN' / '-INF' / 'INF'
guidValue = 8HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 12HEXDIG
byteValue = 1*3DIGIT ; numbers in the range from 0 to 255
sbyteValue = [ sign ] 1*3DIGIT ; numbers in the range from -128 to 127
int16Value = [ sign ] 1*5DIGIT ; numbers in the range from -32768 to 32767
int32Value = [ sign ] 1*10DIGIT ; numbers in the range from -2147483648 to 2147483647
int64Value = [ sign ] 1*19DIGIT ; numbers in the range from -9223372036854775808 to 9223372036854775807
string = SQUOTE *( SQUOTE-in-string / pchar-no-SQUOTE ) SQUOTE
SQUOTE-in-string = SQUOTE SQUOTE ; two consecutive single quotes represent one within a string literal
dateValue = year "-" month "-" day
dateTimeOffsetValue = year "-" month "-" day "T" hour ":" minute [ ":" second [ "." fractionalSeconds ] ] ( "Z" / sign hour ":" minute )
duration = "duration" SQUOTE durationValue SQUOTE
durationValue = [ sign ] "P" [ 1*DIGIT "D" ] [ "T" [ 1*DIGIT "H" ] [ 1*DIGIT "M" ] [ 1*DIGIT [ "." 1*DIGIT ] "S" ] ]
; the above is an approximation of the rules for an xml dayTimeDuration.
; see the lexical representation for dayTimeDuration in http://www.w3.org/TR/xmlschema11-2#dayTimeDuration for more information
timeOfDayValue = hour ":" minute [ ":" second [ "." fractionalSeconds ] ]
oneToNine = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
zeroToFiftyNine = ( "0" / "1" / "2" / "3" / "4" / "5" ) DIGIT
year = [ "-" ] ( "0" 3DIGIT / oneToNine 3*DIGIT )
month = "0" oneToNine
/ "1" ( "0" / "1" / "2" )
day = "0" oneToNine
/ ( "1" / "2" ) DIGIT
/ "3" ( "0" / "1" )
hour = ( "0" / "1" ) DIGIT
/ "2" ( "0" / "1" / "2" / "3" )
minute = zeroToFiftyNine
second = zeroToFiftyNine
fractionalSeconds = 1*12DIGIT
enum = qualifiedEnumTypeName SQUOTE enumValue SQUOTE
enumValue = singleEnumValue *( COMMA singleEnumValue )
singleEnumValue = enumerationMember / enumMemberValue
enumMemberValue = int64Value
geographyCollection = geographyPrefix SQUOTE fullCollectionLiteral SQUOTE
fullCollectionLiteral = sridLiteral collectionLiteral
collectionLiteral = "Collection(" geoLiteral *( COMMA geoLiteral ) CLOSE
geoLiteral = collectionLiteral
/ lineStringLiteral
/ multiPointLiteral
/ multiLineStringLiteral
/ multiPolygonLiteral
/ pointLiteral
/ polygonLiteral
geographyLineString = geographyPrefix SQUOTE fullLineStringLiteral SQUOTE
fullLineStringLiteral = sridLiteral lineStringLiteral
lineStringLiteral = "LineString" lineStringData
lineStringData = OPEN positionLiteral 1*( COMMA positionLiteral ) CLOSE
geographyMultiLineString = geographyPrefix SQUOTE fullMultiLineStringLiteral SQUOTE
fullMultiLineStringLiteral = sridLiteral multiLineStringLiteral
multiLineStringLiteral = "MultiLineString(" [ lineStringData *( COMMA lineStringData ) ] CLOSE
geographyMultiPoint = geographyPrefix SQUOTE fullMultiPointLiteral SQUOTE
fullMultiPointLiteral = sridLiteral multiPointLiteral
multiPointLiteral = "MultiPoint(" [ pointData *( COMMA pointData ) ] CLOSE
geographyMultiPolygon = geographyPrefix SQUOTE fullMultiPolygonLiteral SQUOTE
fullMultiPolygonLiteral = sridLiteral multiPolygonLiteral
multiPolygonLiteral = "MultiPolygon(" [ polygonData *( COMMA polygonData ) ] CLOSE
geographyPoint = geographyPrefix SQUOTE fullPointLiteral SQUOTE
fullPointLiteral = sridLiteral pointLiteral
sridLiteral = "SRID" EQ 1*5DIGIT SEMI
pointLiteral ="Point" pointData
pointData = OPEN positionLiteral CLOSE
positionLiteral = doubleValue SP doubleValue ; longitude, then latitude
geographyPolygon = geographyPrefix SQUOTE fullPolygonLiteral SQUOTE
fullPolygonLiteral = sridLiteral polygonLiteral
polygonLiteral = "Polygon" polygonData
polygonData = OPEN ringLiteral *( COMMA ringLiteral ) CLOSE
ringLiteral = OPEN positionLiteral *( COMMA positionLiteral ) CLOSE
; Within each ringLiteral, the first and last positionLiteral elements MUST be an exact syntactic match to each other.
; Within the polygonData, the ringLiterals MUST specify their points in appropriate winding order.
; In order of traversal, points to the left side of the ring are interpreted as being in the polygon.
geometryCollection = geometryPrefix SQUOTE fullCollectionLiteral SQUOTE
geometryLineString = geometryPrefix SQUOTE fullLineStringLiteral SQUOTE
geometryMultiLineString = geometryPrefix SQUOTE fullMultiLineStringLiteral SQUOTE
geometryMultiPoint = geometryPrefix SQUOTE fullMultiPointLiteral SQUOTE
geometryMultiPolygon = geometryPrefix SQUOTE fullMultiPolygonLiteral SQUOTE
geometryPoint = geometryPrefix SQUOTE fullPointLiteral SQUOTE
geometryPolygon = geometryPrefix SQUOTE fullPolygonLiteral SQUOTE
geographyPrefix = "geography"
geometryPrefix = "geometry"
;------------------------------------------------------------------------------
; 8. Header values
;------------------------------------------------------------------------------
header = content-id
/ odata-entityid
/ odata-isolation
/ odata-maxversion
/ odata-version
/ prefer
content-id = "Content-ID" ":" OWS 1*unreserved
odata-entityid = "OData-EntityID" ":" OWS IRI-in-header
odata-isolation = "OData-Isolation" ":" OWS "snapshot"
odata-maxversion = "OData-MaxVersion" ":" OWS 1*DIGIT "." 1*DIGIT
odata-version = "OData-Version" ":" OWS "4.0"
prefer = "Prefer" ":" OWS preference *( COMMA preference )
preference = allowEntityReferencesPreference
/ callbackPreference
/ continueOnErrorPreference
/ includeAnnotationsPreference
/ maxpagesizePreference
/ respondAsyncPreference
/ returnPreference
/ trackChangesPreference
/ waitPreference
; and everything allowed by http://tools.ietf.org/html/draft-snell-http-prefer-18
; / token [ EQ-h word ] *( OWS ";" [ OWS parameter ] )
allowEntityReferencesPreference = "odata.allow-entityreferences"
callbackPreference = "odata.callback" OWS ";" OWS "url" EQ-h DQUOTE URI DQUOTE
continueOnErrorPreference = "odata.continue-on-error"
includeAnnotationsPreference = "odata.include-annotations" EQ-h DQUOTE annotationsList DQUOTE
annotationsList = annotationIdentifier *(COMMA annotationIdentifier)
annotationIdentifier = [ excludeOperator ]
( STAR
/ namespace "." ( termName / STAR )
)
[ "#" odataIdentifier ]
excludeOperator = "-"
maxpagesizePreference = "odata.maxpagesize" EQ-h oneToNine *DIGIT
respondAsyncPreference = "respond-async"
returnPreference = "return" EQ-h ( 'representation' / 'minimal' )
trackChangesPreference = "odata.track-changes"
waitPreference = "wait" EQ-h 1*DIGIT
;parameter = token [ EQ-h word ]
;word = token / quoted-string
;token = 1*tchar
;tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
; / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
; / DIGIT / ALPHA
;quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
;qdtext = %x21 / %x23-5B / %x5D-7E / obs-text / OWS
obs-text = %x80-FF
;quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
OWS = *( SP / HTAB ) ; "optional" whitespace
BWS-h = *( SP / HTAB ) ; "bad" whitespace in header values
EQ-h = BWS-h EQ BWS-h
;------------------------------------------------------------------------------
; 9. Punctuation
;------------------------------------------------------------------------------
RWS = 1*( SP / HTAB / "%20" / "%09" ) ; "required" whitespace
BWS = *( SP / HTAB / "%20" / "%09" ) ; "bad" whitespace
AT = "@" / "%40"
COLON = ":" / "%3A"
COMMA = "," / "%2C"
EQ = "="
SIGN = "+" / "%2B" / "-"
SEMI = ";" / "%3B"
STAR = "*" / "%2A"
SQUOTE = "'" / "%27"
OPEN = "(" / "%28"
CLOSE = ")" / "%29"
;------------------------------------------------------------------------------
; A. URI syntax [RFC3986]
;------------------------------------------------------------------------------
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
; / path-empty
;URI-reference = URI / relative-ref
;absolute-URI = scheme ":" hier-part [ "?" query ]
;relative-ref = relative-part [ "?" query ] [ "#" fragment ]
;relative-part = "//" authority path-abempty
; / path-absolute
; / path-noscheme
; / path-empty
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
authority = [ userinfo "@" ] host [ ":" port ]
userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
host = IP-literal / IPv4address / reg-name
port = *DIGIT
IP-literal = "[" ( IPv6address / IPvFuture ) "]"
IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
IPv6address = 6( h16 ":" ) ls32
/ "::" 5( h16 ":" ) ls32
/ [ h16 ] "::" 4( h16 ":" ) ls32
/ [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
/ [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
/ [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
/ [ *4( h16 ":" ) h16 ] "::" ls32
/ [ *5( h16 ":" ) h16 ] "::" h16
/ [ *6( h16 ":" ) h16 ] "::"
h16 = 1*4HEXDIG
ls32 = ( h16 ":" h16 ) / IPv4address
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
dec-octet = "1" 2DIGIT ; 100-199
/ "2" %x30-34 DIGIT ; 200-249
/ "25" %x30-35 ; 250-255
/ %x31-39 DIGIT ; 10-99
/ DIGIT ; 0-9
reg-name = *( unreserved / pct-encoded / sub-delims )
;path = path-abempty ; begins with "/" or is empty
; / path-absolute ; begins with "/" but not "//"
; / path-noscheme ; begins with a non-colon segment
; / path-rootless ; begins with a segment
; / path-empty ; zero characters
path-abempty = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
;path-noscheme = segment-nz-nc *( "/" segment )
path-rootless = segment-nz *( "/" segment )
;path-empty = ""
segment = *pchar
segment-nz = 1*pchar
;segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) ; non-zero-length segment without any colon ":"
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
query = *( pchar / "/" / "?" )
fragment = *( pchar / "/" / "?" )
pct-encoded = "%" HEXDIG HEXDIG
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
;reserved = gen-delims / sub-delims
;gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
;sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
sub-delims = "$" / "&" / "'" / "=" / other-delims
other-delims = "!" / "(" / ")" / "*" / "+" / "," / ";"
pchar-no-SQUOTE = unreserved / pct-encoded-no-SQUOTE / other-delims / "$" / "&" / "=" / ":" / "@"
pct-encoded-no-SQUOTE = "%" ( "0" / "1" / "3" / "4" / "5" / "6" / "8" / "9" / A-to-F ) HEXDIG
/ "%" "2" ( "0" / "1" / "2" / "3" / "4" / "5" / "6" / "8" / "9" / A-to-F )
qchar-no-AMP = unreserved / pct-encoded / other-delims / ":" / "@" / "/" / "?" / "$" / "'" / "="
qchar-no-AMP-EQ = unreserved / pct-encoded / other-delims / ":" / "@" / "/" / "?" / "$" / "'"
qchar-no-AMP-EQ-AT-DOLLAR = unreserved / pct-encoded / other-delims / ":" / "/" / "?" / "'"
qchar-unescaped = unreserved / pct-encoded-unescaped / other-delims / ":" / "@" / "/" / "?" / "$" / "'" / "="
pct-encoded-unescaped = "%" ( "0" / "1" / "3" / "4" / "6" / "7" / "8" / "9" / A-to-F ) HEXDIG
/ "%" "2" ( "0" / "1" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / A-to-F )
/ "%" "5" ( DIGIT / "A" / "B" / "D" / "E" / "F" )
qchar-no-AMP-DQUOTE = qchar-unescaped
/ escape ( escape / quotation-mark )
;------------------------------------------------------------------------------
; B. IRI syntax [RFC3987]
;------------------------------------------------------------------------------
; Note: these are over-generous stubs, for the actual patterns refer to RFC3987
;------------------------------------------------------------------------------
IRI-in-header = 1*( VCHAR / obs-text )
IRI-in-query = 1*qchar-no-AMP
;------------------------------------------------------------------------------
; C. ABNF core definitions [RFC5234]
;------------------------------------------------------------------------------
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39
HEXDIG = DIGIT / A-to-F
A-to-F = "A" / "B" / "C" / "D" / "E" / "F"
DQUOTE = %x22
SP = %x20
HTAB = %x09
;WSP = SP / HTAB
;LWSP = *(WSP / CRLF WSP)
VCHAR = %x21-7E
;CHAR = %x01-7F
;LOCTET = %x00-FF
;CR = %x0D
;LF = %x0A
;CRLF = CR LF
;BIT = "0" / "1"
;------------------------------------------------------------------------------
; End of odata-abnf-construction-rules
;------------------------------------------------------------------------------