|
| 1 | +# jsonpath |
| 2 | + |
| 3 | +This is a full implementation of [RFC 9535](https://datatracker.ietf.org/doc/rfc9535/) |
| 4 | + |
| 5 | +It is build to be webasm compatible. A playground application is also included. |
| 6 | + |
| 7 | +Everything within RFC9535 is in scope. Grammars outside RFC 9535 are not in scope. For using `=~` to dynamically represent a matched regex is not in scope. |
| 8 | + |
| 9 | +## Installation |
| 10 | + |
| 11 | +This application is included in the [speakeasy](https://github.com/speakeasy-api/speakeasy) CLI, but available as a stand-alone library. |
| 12 | + |
| 13 | +## ABNF grammar |
| 14 | + |
| 15 | +``` |
| 16 | + jsonpath-query = root-identifier segments |
| 17 | + segments = *(S segment) |
| 18 | +
|
| 19 | + B = %x20 / ; Space |
| 20 | + %x09 / ; Horizontal tab |
| 21 | + %x0A / ; Line feed or New line |
| 22 | + %x0D ; Carriage return |
| 23 | + S = *B ; optional blank space |
| 24 | + root-identifier = "$" |
| 25 | + selector = name-selector / |
| 26 | + wildcard-selector / |
| 27 | + slice-selector / |
| 28 | + index-selector / |
| 29 | + filter-selector |
| 30 | + name-selector = string-literal |
| 31 | +
|
| 32 | + string-literal = %x22 *double-quoted %x22 / ; "string" |
| 33 | + %x27 *single-quoted %x27 ; 'string' |
| 34 | +
|
| 35 | + double-quoted = unescaped / |
| 36 | + %x27 / ; ' |
| 37 | + ESC %x22 / ; \" |
| 38 | + ESC escapable |
| 39 | +
|
| 40 | + single-quoted = unescaped / |
| 41 | + %x22 / ; " |
| 42 | + ESC %x27 / ; \' |
| 43 | + ESC escapable |
| 44 | +
|
| 45 | + ESC = %x5C ; \ backslash |
| 46 | +
|
| 47 | + unescaped = %x20-21 / ; see RFC 8259 |
| 48 | + ; omit 0x22 " |
| 49 | + %x23-26 / |
| 50 | + ; omit 0x27 ' |
| 51 | + %x28-5B / |
| 52 | + ; omit 0x5C \ |
| 53 | + %x5D-D7FF / |
| 54 | + ; skip surrogate code points |
| 55 | + %xE000-10FFFF |
| 56 | +
|
| 57 | + escapable = %x62 / ; b BS backspace U+0008 |
| 58 | + %x66 / ; f FF form feed U+000C |
| 59 | + %x6E / ; n LF line feed U+000A |
| 60 | + %x72 / ; r CR carriage return U+000D |
| 61 | + %x74 / ; t HT horizontal tab U+0009 |
| 62 | + "/" / ; / slash (solidus) U+002F |
| 63 | + "\" / ; \ backslash (reverse solidus) U+005C |
| 64 | + (%x75 hexchar) ; uXXXX U+XXXX |
| 65 | +
|
| 66 | + hexchar = non-surrogate / |
| 67 | + (high-surrogate "\" %x75 low-surrogate) |
| 68 | + non-surrogate = ((DIGIT / "A"/"B"/"C" / "E"/"F") 3HEXDIG) / |
| 69 | + ("D" %x30-37 2HEXDIG ) |
| 70 | + high-surrogate = "D" ("8"/"9"/"A"/"B") 2HEXDIG |
| 71 | + low-surrogate = "D" ("C"/"D"/"E"/"F") 2HEXDIG |
| 72 | +
|
| 73 | + HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" |
| 74 | + wildcard-selector = "*" |
| 75 | + index-selector = int ; decimal integer |
| 76 | +
|
| 77 | + int = "0" / |
| 78 | + (["-"] DIGIT1 *DIGIT) ; - optional |
| 79 | + DIGIT1 = %x31-39 ; 1-9 non-zero digit |
| 80 | + slice-selector = [start S] ":" S [end S] [":" [S step ]] |
| 81 | +
|
| 82 | + start = int ; included in selection |
| 83 | + end = int ; not included in selection |
| 84 | + step = int ; default: 1 |
| 85 | + filter-selector = "?" S logical-expr |
| 86 | + logical-expr = logical-or-expr |
| 87 | + logical-or-expr = logical-and-expr *(S "||" S logical-and-expr) |
| 88 | + ; disjunction |
| 89 | + ; binds less tightly than conjunction |
| 90 | + logical-and-expr = basic-expr *(S "&&" S basic-expr) |
| 91 | + ; conjunction |
| 92 | + ; binds more tightly than disjunction |
| 93 | +
|
| 94 | + basic-expr = paren-expr / |
| 95 | + comparison-expr / |
| 96 | + test-expr |
| 97 | +
|
| 98 | + paren-expr = [logical-not-op S] "(" S logical-expr S ")" |
| 99 | + ; parenthesized expression |
| 100 | + logical-not-op = "!" ; logical NOT operator |
| 101 | + test-expr = [logical-not-op S] |
| 102 | + (filter-query / ; existence/non-existence |
| 103 | + function-expr) ; LogicalType or NodesType |
| 104 | + filter-query = rel-query / jsonpath-query |
| 105 | + rel-query = current-node-identifier segments |
| 106 | + current-node-identifier = "@" |
| 107 | + comparison-expr = comparable S comparison-op S comparable |
| 108 | + literal = number / string-literal / |
| 109 | + true / false / null |
| 110 | + comparable = literal / |
| 111 | + singular-query / ; singular query value |
| 112 | + function-expr ; ValueType |
| 113 | + comparison-op = "==" / "!=" / |
| 114 | + "<=" / ">=" / |
| 115 | + "<" / ">" |
| 116 | +
|
| 117 | + singular-query = rel-singular-query / abs-singular-query |
| 118 | + rel-singular-query = current-node-identifier singular-query-segments |
| 119 | + abs-singular-query = root-identifier singular-query-segments |
| 120 | + singular-query-segments = *(S (name-segment / index-segment)) |
| 121 | + name-segment = ("[" name-selector "]") / |
| 122 | + ("." member-name-shorthand) |
| 123 | + index-segment = "[" index-selector "]" |
| 124 | + number = (int / "-0") [ frac ] [ exp ] ; decimal number |
| 125 | + frac = "." 1*DIGIT ; decimal fraction |
| 126 | + exp = "e" [ "-" / "+" ] 1*DIGIT ; decimal exponent |
| 127 | + true = %x74.72.75.65 ; true |
| 128 | + false = %x66.61.6c.73.65 ; false |
| 129 | + null = %x6e.75.6c.6c ; null |
| 130 | + function-name = function-name-first *function-name-char |
| 131 | + function-name-first = LCALPHA |
| 132 | + function-name-char = function-name-first / "_" / DIGIT |
| 133 | + LCALPHA = %x61-7A ; "a".."z" |
| 134 | +
|
| 135 | + function-expr = function-name "(" S [function-argument |
| 136 | + *(S "," S function-argument)] S ")" |
| 137 | + function-argument = literal / |
| 138 | + filter-query / ; (includes singular-query) |
| 139 | + logical-expr / |
| 140 | + function-expr |
| 141 | + segment = child-segment / descendant-segment |
| 142 | + child-segment = bracketed-selection / |
| 143 | + ("." |
| 144 | + (wildcard-selector / |
| 145 | + member-name-shorthand)) |
| 146 | +
|
| 147 | + bracketed-selection = "[" S selector *(S "," S selector) S "]" |
| 148 | +
|
| 149 | + member-name-shorthand = name-first *name-char |
| 150 | + name-first = ALPHA / |
| 151 | + "_" / |
| 152 | + %x80-D7FF / |
| 153 | + ; skip surrogate code points |
| 154 | + %xE000-10FFFF |
| 155 | + name-char = name-first / DIGIT |
| 156 | +
|
| 157 | + DIGIT = %x30-39 ; 0-9 |
| 158 | + ALPHA = %x41-5A / %x61-7A ; A-Z / a-z |
| 159 | + descendant-segment = ".." (bracketed-selection / |
| 160 | + wildcard-selector / |
| 161 | + member-name-shorthand) |
| 162 | +
|
| 163 | + Figure 2: Collected ABNF of JSONPath Queries |
| 164 | +
|
| 165 | + Figure 3 contains the collected ABNF grammar that defines the syntax |
| 166 | + of a JSONPath Normalized Path while also using the rules root- |
| 167 | + identifier, ESC, DIGIT, and DIGIT1 from Figure 2. |
| 168 | +
|
| 169 | + normalized-path = root-identifier *(normal-index-segment) |
| 170 | + normal-index-segment = "[" normal-selector "]" |
| 171 | + normal-selector = normal-name-selector / normal-index-selector |
| 172 | + normal-name-selector = %x27 *normal-single-quoted %x27 ; 'string' |
| 173 | + normal-single-quoted = normal-unescaped / |
| 174 | + ESC normal-escapable |
| 175 | + normal-unescaped = ; omit %x0-1F control codes |
| 176 | + %x20-26 / |
| 177 | + ; omit 0x27 ' |
| 178 | + %x28-5B / |
| 179 | + ; omit 0x5C \ |
| 180 | + %x5D-D7FF / |
| 181 | + ; skip surrogate code points |
| 182 | + %xE000-10FFFF |
| 183 | +
|
| 184 | + normal-escapable = %x62 / ; b BS backspace U+0008 |
| 185 | + %x66 / ; f FF form feed U+000C |
| 186 | + %x6E / ; n LF line feed U+000A |
| 187 | + %x72 / ; r CR carriage return U+000D |
| 188 | + %x74 / ; t HT horizontal tab U+0009 |
| 189 | + "'" / ; ' apostrophe U+0027 |
| 190 | + "\" / ; \ backslash (reverse solidus) U+005C |
| 191 | + (%x75 normal-hexchar) |
| 192 | + ; certain values u00xx U+00XX |
| 193 | + normal-hexchar = "0" "0" |
| 194 | + ( |
| 195 | + ("0" %x30-37) / ; "00"-"07" |
| 196 | + ; omit U+0008-U+000A BS HT LF |
| 197 | + ("0" %x62) / ; "0b" |
| 198 | + ; omit U+000C-U+000D FF CR |
| 199 | + ("0" %x65-66) / ; "0e"-"0f" |
| 200 | + ("1" normal-HEXDIG) |
| 201 | + ) |
| 202 | + normal-HEXDIG = DIGIT / %x61-66 ; "0"-"9", "a"-"f" |
| 203 | + normal-index-selector = "0" / (DIGIT1 *DIGIT) |
| 204 | + ; non-negative decimal integer |
| 205 | +``` |
| 206 | + |
| 207 | +## Functions |
| 208 | + |
| 209 | + |
| 210 | + |
| 211 | +## Contributing |
| 212 | + |
0 commit comments