改进的标识符

JEP

6

作者

詹姆斯·萨耶维尼

状态

认可的

创建

2013年12月14日

最后更新

2013年12月15日

摘要

这个JEP建议对JMESPath进行语法修改,以改进JMESPath中使用的标识符。在这样做时,标识符语法规则中的几个不一致之处将得到修复,同时还有一种改进的语法,用于以与JSON字符串一致的方式指定unicode标识符。

动机

目前有两种方法可以指定标识符,即不带引号的规则:

identifier        = 1*char

引用的规则是:

identifier        =/ quote 1*(unescaped-char / escaped-quote) quote

这个 char 规则包含一组字符 not 必须引用:

char              = %x30-39 / ; 0-9
                    %x41-5A / ; A-Z
                    %x5F /    ; _
                    %x61-7A / ; a-z
                    %x7F-10FFFF

%x30-39 规则和 number 规则:

number            = ["-"]1*digit
digit             = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / "0"

使用哪条规则还不明确。给定一个字符串“123”,不清楚这是应该被解析为标识符还是数字。现有实现 不是 遵循这个规则(因为它是不明确的),所以应该更新语法以消除歧义,特别是,未加引号的标识符只能以字符开头 [a-zA-Z_] .

统一码

JMESPath通过 charunescaped-char 规则:

unescaped-char    = %x30-10FFFF
char              = %x30-39 / ; 0-9
                    %x41-5A / ; A-Z
                    %x5F /    ; _
                    %x61-7A / ; a-z
                    %x7F-10FFFF

但是,JSON支持转义unicode字符的语法。基本多语言平面(BMP)中的任何字符都可以用以下方式转义:

char = escape (%x75 4HEXDIG )  ; \uXXXX

类似于XPath支持XML中使用的数字字符引用的方式 (&#nnnn ),JMESPath应支持JSON中使用的相同转义序列。JSON还通过对UTF-16代理项对进行编码,为BMP之外的字符提供12个字符的转义序列。例如,代码点 U+1D11E 可以表示为 "\uD834\uDD1E" .

转义序列

考虑以下JSON对象:

{"foo\nbar": "baz"}

JMESPath表达式应该能够检索baz的值。对于当前的语法,必须依赖于环境输入控制字符(如换行符)的能力 (%x0A ). 这在某些环境中可能会出现问题。例如,在python中,这不是一个问题:

>>> jmespath_expression = "foo\nbar"

Python will interpret the sequence "\n" (%x5C %x6E) as the newline character %x0A. However, consider Bash:

$ foo --jmespath-expression "foo\nbar"

In this situation, bash will not interpret the "\n" (%x5C %x6E) sequence.

规范

这个 char 规则包含一组字符 not 必须被引用。不需要引用的新字符集将是:

unquoted-string   = (%x41-5A / %x61-7A / %x5F) *(%x30-39 / %x41-5A / %x5F / %x61-7A)

为了使标识符不被引用,它必须以 [A-Za-z_] ,则后面必须跟零或更多 [0-9A-Za-z_] .

未加引号的规则已更新,以说明所有JSON支持的转义序列:

quoted-string     =/ quote 1*(unescaped-char / escaped-char) quote

标识符的完整规则是:

identifier        = unquoted-string / quoted-string
unquoted-string   = (%x41-5A / %x61-7A / %x5F) *(  ; a-zA-Z_
                        %x30-39  /  ; 0-9
                        %x41-5A /  ; A-Z
                        %x5F    /  ; _
                        %x61-7A)   ; a-z
quoted-string     = quote 1*(unescaped-char / escaped-char) quote
unescaped-char    = %x20-21 / %x23-5B / %x5D-10FFFF
escape            = %x5C   ; Back slash: \
quote             = %x22   ; Double quote: '"'
escaped-char      = escape (
                        %x22 /          ; "    quotation mark  U+0022
                        %x5C /          ; \    reverse solidus U+005C
                        %x2F /          ; /    solidus         U+002F
                        %x62 /          ; b    backspace       U+0008
                        %x66 /          ; f    form feed       U+000C
                        %x6E /          ; n    line feed       U+000A
                        %x72 /          ; r    carriage return U+000D
                        %x74 /          ; t    tab             U+0009
                        %x75 4HEXDIG )  ; uXXXX                U+XXXX

理论基础

采用与JSON字符串相同的字符串规则将允许熟悉JSON语义的用户了解JMESPath标识符的工作方式。

这个变化也为jep3中提出的文本语法提供了很好的一致性。使用此模型,支持的文本字符串可以与带引号的标识符相同。

如果JMESPath添加了对基于文本值的过滤的支持,这也将允许语法以一致的方式增长。例如(请注意,这只是一个建议的语法,而不是一个正式的建议),给定的数据是:

{"foo": [{"✓": "✓"}, {"✓": "✗"}]}

现在可以使用以下JMESPath表达式::

foo[?"✓" = `✓`]
foo[?"\u2713" = `\u2713`]

作为常规属性,任何受支持的JSON字符串现在都是受支持的带引号的标识符。

影响

对于任何将数字解析为标识符的实现,以数字开头的标识符将不再有效,例如。 foo.0.1.2 .

有几个符合性测试,将必须更新作为这个JEP的结果。他们可以说一开始就错了。

basic.json

由于现在必须引用以数字开头的标识符,因此需要更改以下内容:

-            "expression": "foo.1",
+            "expression": "foo.\"1\"",
             "result": ["one", "two", "three"]
          },
          {
-            "expression": "foo.1[0]",
+            "expression": "foo.\"1\"[0]",
             "result": "one"
          },

同样,需要更改以下内容,因为未加引号的标识符不能以 - ::

-            "expression": "foo.-1",
+            "expression": "foo.\"-1\"",
             "result": "bar"
          }

escape.json

这个escape.json还有几个中间案件需要更新。这与更新的转义规则有关。每一个都会被解释。

-            "expression": "\"foo\nbar\"",
+            "expression": "\"foo\\nbar\"",
             "result": "newline"
          },

This has to be updated because a JSON parser will interpret the \n sequence as the newline character. The newline character is not allowed in a JMESPath identifier (note that the newline character %0A is not in any rule). In order for a JSON parser to create a sequence of %x5C %x6E, the JSON string must be \\n (%x5C %x5C %x6E).

-            "expression": "\"c:\\\\windows\\path\"",
+            "expression": "\"c:\\\\\\\\windows\\\\path\"",
             "result": "windows"
          },

上面的例子是一个更病态的逃跑案例。在这个例子中,我们有一个代表windows路径“c:\windowpath”的字符串。这里有两个级别的转义,一个在JSON解析器,一个在JMESPath解析器。JSON解析器将获取序列 "\"c:\\\\\\\\windows\\\\path\"" 然后创建字符串 "\"c:\\\\windows\\path\"" . JMESPath解析器将接受字符串 "\"c:\\\\windows\\path\"' 并且,应用它自己的转义规则,将查找名为 c:\\windows\path .