SPARQL Grammar

The SPARQL grammar covers both SPARQL Query and SPARQL Update.

SPARQL Request String

A SPARQL Request String is a SPARQL Query String or SPARQL Update String and it is a Unicode character string (c.f. section 6.1 String concepts of [Character Model for the World Wide Web 1.0: Fundamentals]) in the language defined by the following grammar.

A SPARQL Query String start at the QueryUnit production.

A SPARQL Update String start at the UpdateUnit production.

For compatibility with future versions of Unicode, the characters in this string may include Unicode codepoints that are unassigned as of the date of this publication (see Identifier and Pattern Syntax [Identifier and Pattern Syntax 4.1.0] section 4 Pattern Syntax). For productions with excluded character classes (for example [^<>'{}|^]), the characters are excluded from the range#x0 - #x10FFFF`.

Codepoint Escape Sequences

A SPARQL Query String is processed for codepoint escape sequences before parsing by the grammar defined in EBNF below. The codepoint escape sequences for a SPARQL query string are:

Escape Unicode code point
'\u'HEXHEXHEXHEX A Unicode code point in the range U+0 to U+FFFF inclusive corresponding to the encoded hexadecimal value.
'\U'HEXHEXHEXHEXHEXHEXHEXHEX A Unicode code point in the range U+0 to U+10FFFF inclusive corresponding to the encoded hexadecimal value.

where HEX is a hexadecimal character

HEX ::= [0-9] | [A-F] | [a-f]

Examples:

<ab\u00E9xy>        # Codepoint 00E9 is Latin small e with acute - é
\u03B1:a            # Codepoint x03B1 is Greek small alpha - α
a\u003Ab            # a:b -- codepoint x3A is colon

Codepoint escape sequences can appear anywhere in the query string. They are processed before parsing based on the grammar rules and so may be replaced by codepoints with significance in the grammar, such as ":" marking a prefixed name.

These escape sequences are not included in the grammar below. Only escape sequences for characters that would be legal at that point in the grammar may be given. For example, the variable "?x\u0020y" is not legal (\u0020 is a space and is not permitted in a variable name).

White Space

White space (production WS) is used to separate two terminals which would otherwise be (mis-)recognized as one terminal. Rule names below in capitals indicate where white space is significant; these form a possible choice of terminals for constructing a SPARQL parser. White space is significant in strings. Otherwise, white space is ignored between tokens.

For example:

?a<?b&&?c>?d

is the token sequence variable '?a', an IRI '<?b&&?c>', and variable '?d', not a expression involving the operator '&&' connecting two expression using '<' (less than) and '>' (greater than).

Comments

Comments in SPARQL queries take the form of '#', outside an IRI or string, and continue to the end of line (marked by characters 0x0D or 0x0A) or end of file if there is no end of line after the comment marker. Comments are treated as white space.

IRI References

Text matched by the IRIREF production and PrefixedName (after prefix expansion) production, after escape processing, must conform to the generic syntax of IRI references in section 2.2 of RFC 3987 "ABNF for IRI References and IRIs" [Internationalized Resource Identifiers (IRIs)]. For example, the IRIREF<abc#def> may occur in a SPARQL query string, but the IRIREF<abc##def> must not.

Base IRIs declared with the BASE keyword must be absolute IRIs. A prefix declared with the PREFIX keyword may not be re-declared in the same query. See section 4.1.1, Syntax of IRI Terms, for a description of BASE and PREFIX .

Blank Nodes and Blank Node Labels

Blank nodes can not be used in:

  • DELETE WHERE
  • DELETE DATA
  • a DeleteClause

in a SPARQL Update request.

Blank node labels are scoped to the SPARQL Request String in which they occur. Different uses of the same blank node label in a request string refer to the same blank node. Fresh blank nodes are generated for each request; blank nodes can not be referenced by label across requests.

The same blank node label can not be used in:

  • two basic graph patterns in a SPARQL Query
  • two WHERE clauses within a single SPARQL Update request
  • two INSERT DATA operations within a single SPARQL Update request

Note that the same blank node label can occur in different QuadPattern clauses in a SPARQL Update request.

Escape sequences in strings

In addition to the codepoint escape sequences, the following escape sequences any string production (e.g. STRING_LITERAL1, STRING_LITERAL2, STRING_LITERAL_LONG1, STRING_LITERAL_LONG2):

Escape Unicode code point
'\t' U+0009 (tab)
'\n' U+000A (line feed)
'\r' U+000D (carriage return)
'\b' U+0008 (backspace)
'\f' U+000C (form feed)
'\"' U+0022 (quotation mark, double quote mark)
"\'" U+0027 (apostrophe-quote, single quote mark)
'\\' U+005C (backslash)

Examples:

"abc\n"
"xy\rz"
'xy\tz'

Grammar

The EBNF notation used in the grammar is defined in Extensible Markup Language (XML) 1.1 [Extensible Markup Language (XML) 1.1] section 6 Notation.

Notes:

  1. Keywords are matched in a case-insensitive manner with the exception of the keyword 'a' which, in line with Turtle and N3, is used in place of the IRI rdf:type (in full, http://www.w3.org/1999/02/22-rdf-syntax-ns#type).
  2. Escape sequences are case sensitive.
  3. When tokenizing the input and choosing grammar rules, the longest match is chosen.
  4. The SPARQL grammar is LL(1) when the rules with uppercased names are used as terminals.
  5. There are two entry points into the grammar: QueryUnit for SPARQL queries, and UpdateUnit for SPARQL Update requests.
  6. In signed numbers, no white space is allowed between the sign and the number. The AdditiveExpression grammar rule allows for this by covering the two cases of an expression followed by a signed number. These produce an addition or subtraction of the unsigned number as appropriate.
  7. The tokens INSERT DATA, DELETE DATA, DELETE WHERE allow any amount of white space between the words. The single space version is used in the grammar for clarity.
  8. The QuadData and QuadPattern rules both use rule Quads. The rule QuadData, used in INSERT DATA and DELETE DATA, must not allow variables in the quad patterns.
  9. Blank node syntax is not allowed in DELETE WHERE, the DeleteClause for DELETE, nor in DELETE DATA.
  10. Rules for limiting the use of blank node labels are given in section 19.6.
  11. The number of variables in the variable list of VALUES block must be the same as the number of each list of associated values in the DataBlock.
  12. Variables introduced by AS in a SELECT clause must not already be in-scope.
  13. The variable assigned in a BIND clause must not be already in-use within the immediately preceding TriplesBlock within a GroupGraphPattern.
  14. Aggregate functions can be one of the built-in keywords for aggregates or a custom aggregate, which is syntactically a function call. Aggregate functions may only be used in SELECT, HAVING and ORDER BY clauses.
  15. Only custom aggregate functions use the DISTINCT keyword in a function call.
[1]   QueryUnit   ::=   Query
[2]   Query   ::=   Prologue
( SelectQuery | ConstructQuery | DescribeQuery | AskQuery )
ValuesClause
[3]   UpdateUnit   ::=   Update
[4]   Prologue   ::=   ( BaseDecl | PrefixDecl )*
[5]   BaseDecl   ::=   'BASE'IRIREF
[6]   PrefixDecl   ::=   'PREFIX'PNAME_NSIRIREF
[7]   SelectQuery   ::=   SelectClauseDatasetClause* WhereClauseSolutionModifier
[8]   SubSelect   ::=   SelectClauseWhereClauseSolutionModifierValuesClause
[9]   SelectClause   ::=   'SELECT' ( 'DISTINCT' | 'REDUCED' )? ( ( Var | ( '('Expression'AS'Var')' ) )+ | '*' )
[10]   ConstructQuery   ::=   'CONSTRUCT' ( ConstructTemplateDatasetClause* WhereClauseSolutionModifier | DatasetClause* 'WHERE''{'TriplesTemplate? '}'SolutionModifier )
[11]   DescribeQuery   ::=   'DESCRIBE' ( VarOrIri+ | '*' ) DatasetClause* WhereClause? SolutionModifier
[12]   AskQuery   ::=   'ASK'DatasetClause* WhereClauseSolutionModifier
[13]   DatasetClause   ::=   'FROM' ( DefaultGraphClause | NamedGraphClause )
[14]   DefaultGraphClause   ::=   SourceSelector
[15]   NamedGraphClause   ::=   'NAMED'SourceSelector
[16]   SourceSelector   ::=   iri
[17]   WhereClause   ::=   'WHERE'? GroupGraphPattern
[18]   SolutionModifier   ::=   GroupClause? HavingClause? OrderClause? LimitOffsetClauses?
[19]   GroupClause   ::=   'GROUP''BY'GroupCondition+
[20]   GroupCondition   ::=   BuiltInCall | FunctionCall | '('Expression ( 'AS'Var )? ')' | Var
[21]   HavingClause   ::=   'HAVING'HavingCondition+
[22]   HavingCondition   ::=   Constraint
[23]   OrderClause   ::=   'ORDER''BY'OrderCondition+
[24]   OrderCondition   ::=   ( ( 'ASC' | 'DESC' ) BrackettedExpression )
| ( Constraint | Var )
[25]   LimitOffsetClauses   ::=   LimitClauseOffsetClause? | OffsetClauseLimitClause?
[26]   LimitClause   ::=   'LIMIT'INTEGER
[27]   OffsetClause   ::=   'OFFSET'INTEGER
[28]   ValuesClause   ::=   ( 'VALUES'DataBlock )?
[29]   Update   ::=   Prologue ( Update1 ( ';'Update )? )?
[30]   Update1   ::=   Load | Clear | Drop | Add | Move | Copy | Create | InsertData | DeleteData | DeleteWhere | Modify
[31]   Load   ::=   'LOAD''SILENT'? iri ( 'INTO'GraphRef )?
[32]   Clear   ::=   'CLEAR''SILENT'? GraphRefAll
[33]   Drop   ::=   'DROP''SILENT'? GraphRefAll
[34]   Create   ::=   'CREATE''SILENT'? GraphRef
[35]   Add   ::=   'ADD''SILENT'? GraphOrDefault'TO'GraphOrDefault
[36]   Move   ::=   'MOVE''SILENT'? GraphOrDefault'TO'GraphOrDefault
[37]   Copy   ::=   'COPY''SILENT'? GraphOrDefault'TO'GraphOrDefault
[38]   InsertData   ::=   'INSERT DATA'QuadData
[39]   DeleteData   ::=   'DELETE DATA'QuadData
[40]   DeleteWhere   ::=   'DELETE WHERE'QuadPattern
[41]   Modify   ::=   ( 'WITH'iri )? ( DeleteClauseInsertClause? | InsertClause ) UsingClause* 'WHERE'GroupGraphPattern
[42]   DeleteClause   ::=   'DELETE'QuadPattern
[43]   InsertClause   ::=   'INSERT'QuadPattern
[44]   UsingClause   ::=   'USING' ( iri | 'NAMED'iri )
[45]   GraphOrDefault   ::=   'DEFAULT' | 'GRAPH'? iri
[46]   GraphRef   ::=   'GRAPH'iri
[47]   GraphRefAll   ::=   GraphRef | 'DEFAULT' | 'NAMED' | 'ALL'
[48]   QuadPattern   ::=   '{'Quads'}'
[49]   QuadData   ::=   '{'Quads'}'
[50]   Quads   ::=   TriplesTemplate? ( QuadsNotTriples'.'? TriplesTemplate? )*
[51]   QuadsNotTriples   ::=   'GRAPH'VarOrIri'{'TriplesTemplate? '}'
[52]   TriplesTemplate   ::=   TriplesSameSubject ( '.'TriplesTemplate? )?
[53]   GroupGraphPattern   ::=   '{' ( SubSelect | GroupGraphPatternSub ) '}'
[54]   GroupGraphPatternSub   ::=   TriplesBlock? ( GraphPatternNotTriples'.'? TriplesBlock? )*
[55]   TriplesBlock   ::=   TriplesSameSubjectPath ( '.'TriplesBlock? )?
[56]   GraphPatternNotTriples   ::=   GroupOrUnionGraphPattern | OptionalGraphPattern | MinusGraphPattern | GraphGraphPattern | ServiceGraphPattern | Filter | Bind | InlineData
[57]   OptionalGraphPattern   ::=   'OPTIONAL'GroupGraphPattern
[58]   GraphGraphPattern   ::=   'GRAPH'VarOrIriGroupGraphPattern
[59]   ServiceGraphPattern   ::=   'SERVICE''SILENT'? VarOrIriGroupGraphPattern
[60]   Bind   ::=   'BIND''('Expression'AS'Var')'
[61]   InlineData   ::=   'VALUES'DataBlock
[62]   DataBlock   ::=   InlineDataOneVar | InlineDataFull
[63]   InlineDataOneVar   ::=   Var'{'DataBlockValue* '}'
[64]   InlineDataFull   ::=   ( NIL | '('Var* ')' ) '{' ( '('DataBlockValue* ')' | NIL )* '}'
[65]   DataBlockValue   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral | 'UNDEF'
[66]   MinusGraphPattern   ::=   'MINUS'GroupGraphPattern
[67]   GroupOrUnionGraphPattern   ::=   GroupGraphPattern ( 'UNION'GroupGraphPattern )*
[68]   Filter   ::=   'FILTER'Constraint
[69]   Constraint   ::=   BrackettedExpression | BuiltInCall | FunctionCall
[70]   FunctionCall   ::=   iriArgList
[71]   ArgList   ::=   NIL | '(''DISTINCT'? Expression ( ','Expression )* ')'
[72]   ExpressionList   ::=   NIL | '('Expression ( ','Expression )* ')'
[73]   ConstructTemplate   ::=   '{'ConstructTriples? '}'
[74]   ConstructTriples   ::=   TriplesSameSubject ( '.'ConstructTriples? )?
[75]   TriplesSameSubject   ::=   VarOrTermPropertyListNotEmpty | TriplesNodePropertyList
[76]   PropertyList   ::=   PropertyListNotEmpty?
[77]   PropertyListNotEmpty   ::=   VerbObjectList ( ';' ( VerbObjectList )? )*
[78]   Verb   ::=   VarOrIri | 'a'
[79]   ObjectList   ::=   Object ( ','Object )*
[80]   Object   ::=   GraphNode
[81]   TriplesSameSubjectPath   ::=   VarOrTermPropertyListPathNotEmpty | TriplesNodePathPropertyListPath
[82]   PropertyListPath   ::=   PropertyListPathNotEmpty?
[83]   PropertyListPathNotEmpty   ::=   ( VerbPath | VerbSimple ) ObjectListPath ( ';' ( ( VerbPath | VerbSimple ) ObjectList )? )*
[84]   VerbPath   ::=   Path
[85]   VerbSimple   ::=   Var
[86]   ObjectListPath   ::=   ObjectPath ( ','ObjectPath )*
[87]   ObjectPath   ::=   GraphNodePath
[88]   Path   ::=   PathAlternative
[89]   PathAlternative   ::=   PathSequence ( '|'PathSequence )*
[90]   PathSequence   ::=   PathEltOrInverse ( '/'PathEltOrInverse )*
[91]   PathElt   ::=   PathPrimaryPathMod?
[92]   PathEltOrInverse   ::=   PathElt | '^'PathElt
[93]   PathMod   ::=   '?' | '*' | '+'
[94]   PathPrimary   ::=   iri | 'a' | '!'PathNegatedPropertySet | '('Path')'
[95]   PathNegatedPropertySet   ::=   PathOneInPropertySet | '(' ( PathOneInPropertySet ( '|'PathOneInPropertySet )* )? ')'
[96]   PathOneInPropertySet   ::=   iri | 'a' | '^' ( iri | 'a' )
[97]   Integer   ::=   INTEGER
[98]   TriplesNode   ::=   Collection | BlankNodePropertyList
[99]   BlankNodePropertyList   ::=   '['PropertyListNotEmpty']'
[100]   TriplesNodePath   ::=   CollectionPath | BlankNodePropertyListPath
[101]   BlankNodePropertyListPath   ::=   '['PropertyListPathNotEmpty']'
[102]   Collection   ::=   '('GraphNode+ ')'
[103]   CollectionPath   ::=   '('GraphNodePath+ ')'
[104]   GraphNode   ::=   VarOrTerm | TriplesNode
[105]   GraphNodePath   ::=   VarOrTerm | TriplesNodePath
[106]   VarOrTerm   ::=   Var | GraphTerm
[107]   VarOrIri   ::=   Var | iri
[108]   Var   ::=   VAR1 | VAR2
[109]   GraphTerm   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL
[110]   Expression   ::=   ConditionalOrExpression
[111]   ConditionalOrExpression   ::=   ConditionalAndExpression ( '||'ConditionalAndExpression )*
[112]   ConditionalAndExpression   ::=   ValueLogical ( '&&'ValueLogical )*
[113]   ValueLogical   ::=   RelationalExpression
[114]   RelationalExpression   ::=   NumericExpression ( '='NumericExpression | '!='NumericExpression | '<'NumericExpression | '>'NumericExpression | '<='NumericExpression | '>='NumericExpression | 'IN'ExpressionList | 'NOT''IN'ExpressionList )?
[115]   NumericExpression   ::=   AdditiveExpression
[116]   AdditiveExpression   ::=   MultiplicativeExpression ( '+'MultiplicativeExpression | '-'MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*'UnaryExpression ) | ( '/'UnaryExpression ) )* )*
[117]   MultiplicativeExpression   ::=   UnaryExpression ( '*'UnaryExpression | '/'UnaryExpression )*
[118]   UnaryExpression   ::=     '!'PrimaryExpression
| '+'PrimaryExpression
| '-'PrimaryExpression
| PrimaryExpression
[119]   PrimaryExpression   ::=   BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var
[120]   BrackettedExpression   ::=   '('Expression')'
[121]   BuiltInCall   ::=     Aggregate
| 'STR''('Expression')'
| 'LANG''('Expression')'
| 'LANGMATCHES''('Expression','Expression')'
| 'DATATYPE''('Expression')'
| 'BOUND''('Var')'
| 'IRI''('Expression')'
| 'URI''('Expression')'
| 'BNODE' ( '('Expression')' | NIL )
| 'RAND'NIL
| 'ABS''('Expression')'
| 'CEIL''('Expression')'
| 'FLOOR''('Expression')'
| 'ROUND''('Expression')'
| 'CONCAT'ExpressionList
| SubstringExpression
| 'STRLEN''('Expression')'
| StrReplaceExpression
| 'UCASE''('Expression')'
| 'LCASE''('Expression')'
| 'ENCODE_FOR_URI''('Expression')'
| 'CONTAINS''('Expression','Expression')'
| 'STRSTARTS''('Expression','Expression')'
| 'STRENDS''('Expression','Expression')'
| 'STRBEFORE''('Expression','Expression')'
| 'STRAFTER''('Expression','Expression')'
| 'YEAR''('Expression')'
| 'MONTH''('Expression')'
| 'DAY''('Expression')'
| 'HOURS''('Expression')'
| 'MINUTES''('Expression')'
| 'SECONDS''('Expression')'
| 'TIMEZONE''('Expression')'
| 'TZ''('Expression')'
| 'NOW'NIL
| 'UUID'NIL
| 'STRUUID'NIL
| 'MD5''('Expression')'
| 'SHA1''('Expression')'
| 'SHA256''('Expression')'
| 'SHA384''('Expression')'
| 'SHA512''('Expression')'
| 'COALESCE'ExpressionList
| 'IF''('Expression','Expression','Expression')'
| 'STRLANG''('Expression','Expression')'
| 'STRDT''('Expression','Expression')'
| 'sameTerm''('Expression','Expression')'
| 'isIRI''('Expression')'
| 'isURI''('Expression')'
| 'isBLANK''('Expression')'
| 'isLITERAL''('Expression')'
| 'isNUMERIC''('Expression')'
| RegexExpression
| ExistsFunc
| NotExistsFunc
[122]   RegexExpression   ::=   'REGEX''('Expression','Expression ( ','Expression )? ')'
[123]   SubstringExpression   ::=   'SUBSTR''('Expression','Expression ( ','Expression )? ')'
[124]   StrReplaceExpression   ::=   'REPLACE''('Expression','Expression','Expression ( ','Expression )? ')'
[125]   ExistsFunc   ::=   'EXISTS'GroupGraphPattern
[126]   NotExistsFunc   ::=   'NOT''EXISTS'GroupGraphPattern
[127]   Aggregate   ::=     'COUNT''(''DISTINCT'? ( '*' | Expression ) ')'
| 'SUM''(''DISTINCT'? Expression')'
| 'MIN''(''DISTINCT'? Expression')'
| 'MAX''(''DISTINCT'? Expression')'
| 'AVG''(''DISTINCT'? Expression')'
| 'SAMPLE''(''DISTINCT'? Expression')'
| 'GROUP_CONCAT''(''DISTINCT'? Expression ( ';''SEPARATOR''='String )? ')'
[128]   iriOrFunction   ::=   iriArgList?
[129]   RDFLiteral   ::=   String ( LANGTAG | ( '^^'iri ) )?
[130]   NumericLiteral   ::=   NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative
[131]   NumericLiteralUnsigned   ::=   INTEGER | DECIMAL | DOUBLE
[132]   NumericLiteralPositive   ::=   INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE
[133]   NumericLiteralNegative   ::=   INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE
[134]   BooleanLiteral   ::=   'true' | 'false'
[135]   String   ::=   STRING_LITERAL1 | STRING_LITERAL2 | STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2
[136]   iri   ::=   IRIREF | PrefixedName
[137]   PrefixedName   ::=   PNAME_LN | PNAME_NS
[138]   BlankNode   ::=   BLANK_NODE_LABEL | ANON

Productions for terminals:

[139]   IRIREF   ::=   '<' ([^<>"{}|^`\]-[#x00-#x20])* '>'
[140]   PNAME_NS   ::=   PN_PREFIX? ':'
[141]   PNAME_LN   ::=   PNAME_NSPN_LOCAL
[142]   BLANK_NODE_LABEL   ::=   '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
[143]   VAR1   ::=   '?' VARNAME
[144]   VAR2   ::=   '$' VARNAME
[145]   LANGTAG   ::=   '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)*
[146]   INTEGER   ::=   [0-9]+
[147]   DECIMAL   ::=   [0-9]* '.' [0-9]+
[148]   DOUBLE   ::=   [0-9]+ '.' [0-9]* EXPONENT | '.' ([0-9])+ EXPONENT | ([0-9])+ EXPONENT
[149]   INTEGER_POSITIVE   ::=   '+'INTEGER
[150]   DECIMAL_POSITIVE   ::=   '+'DECIMAL
[151]   DOUBLE_POSITIVE   ::=   '+'DOUBLE
[152]   INTEGER_NEGATIVE   ::=   '-'INTEGER
[153]   DECIMAL_NEGATIVE   ::=   '-'DECIMAL
[154]   DOUBLE_NEGATIVE   ::=   '-'DOUBLE
[155]   EXPONENT   ::=   [eE] [+-]? [0-9]+
[156]   STRING_LITERAL1   ::=   "'" ( ([^#x27#x5C#xA#xD]) | ECHAR )* "'"
[157]   STRING_LITERAL2   ::=   '"' ( ([^#x22#x5C#xA#xD]) | ECHAR )* '"'
[158]   STRING_LITERAL_LONG1   ::=   "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR ) )* "'''"
[159]   STRING_LITERAL_LONG2   ::=   '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR ) )* '"""'
[160]   ECHAR   ::=   '\' [tbnrf\"']
[161]   NIL   ::=   '(' WS* ')'
[162]   WS   ::=   #x20 | #x9 | #xD | #xA
[163]   ANON   ::=   '[' WS* ']'
[164]   PN_CHARS_BASE   ::=   [A-Z] | [a-z] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | [#x00F8-#x02FF] | [#x0370-#x037D] | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
[165]   PN_CHARS_U   ::=   PN_CHARS_BASE | '_'
[166]   VARNAME   ::=   ( PN_CHARS_U | [0-9] ) ( PN_CHARS_U | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] )*
[167]   PN_CHARS   ::=   PN_CHARS_U | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
[168]   PN_PREFIX   ::=   PN_CHARS_BASE ((PN_CHARS|'.')* PN_CHARS)?
[169]   PN_LOCAL   ::=   (PN_CHARS_U | ':' | [0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )?
[170]   PLX   ::=   PERCENT | PN_LOCAL_ESC
[171]   PERCENT   ::=   '%' HEXHEX
[172]   HEX   ::=   [0-9] | [A-F] | [a-f]
[173]   PN_LOCAL_ESC   ::=   '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?' | '#' | '@' | '%' )