├── .travis.yml ├── .gitignore ├── src ├── json_path.clj └── json_path │ ├── match.clj │ ├── parser.clj │ └── walker.clj ├── project.clj ├── CHANGELOG.md ├── LICENSE ├── README.md └── test ├── json_path └── test │ ├── regression_test.clj │ ├── json_path_test.clj │ ├── parser_test.clj │ └── walker_test.clj ├── Clojure_json-path.yaml └── regression_suite.yaml /.travis.yml: -------------------------------------------------------------------------------- 1 | language: clojure 2 | script: lein midje 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | /target 3 | .lein-failures 4 | .lein-deps-sum 5 | /pom.xml.asc 6 | *.diff 7 | -------------------------------------------------------------------------------- /src/json_path.clj: -------------------------------------------------------------------------------- 1 | (ns json-path 2 | [:require [json-path.parser :as parser] 3 | [json-path.match :as m] 4 | [json-path.walker :as walker]]) 5 | 6 | (defn query [path object] 7 | (walker/walk (parser/parse-path path) {:root (m/root object)})) 8 | 9 | (defn at-path [path object] 10 | (walker/map# :value (query path object))) 11 | -------------------------------------------------------------------------------- /src/json_path/match.clj: -------------------------------------------------------------------------------- 1 | (ns json-path.match) 2 | 3 | (defrecord Match [path value]) 4 | 5 | (defn root [value] 6 | (->Match [] value)) 7 | 8 | (defn with-context 9 | ([key value context] (->Match (vec (concat (:path context) [key])) 10 | value))) 11 | 12 | (defn create [value path] 13 | (->Match path value)) 14 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject json-path "2.2.0" 2 | :description "JSON Path for Clojure data structures" 3 | :url "http://github.com/gga/json-path" 4 | :license {:name "The MIT License" 5 | :url "http://opensource.org/licenses/MIT" 6 | :distribution :repo} 7 | :dependencies [[org.clojure/clojure "1.10.1"]] 8 | :profiles {:dev {:dependencies [[midje "1.9.6"] 9 | [org.clojure/data.json "0.2.7"] 10 | [io.forward/yaml "1.0.11"]] 11 | :plugins [[lein-midje "3.2.1"]]}}) 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.2.0 2 | ### Added 3 | - Support for boolean expressions (https://github.com/gga/json-path/pull/16) 4 | 5 | ## 2.1.0 6 | ### Added 7 | - Support for nested array selection (https://github.com/gga/json-path/pull/14) 8 | - Support for numbers in filters (e.g. `$[?(@.key>42)]`) 9 | 10 | ## 2.0.0 11 | ### Added 12 | - Support for negative array indexing (e.g. `-1`) 13 | 14 | ### Changed 15 | - Correctly handle array values for wildcards and recursive descend (https://github.com/gga/json-path/issues/13) 16 | 17 | ## 1.0.1 18 | ### Added 19 | - Support for namespaced keywords (#11) 20 | 21 | ## 1.0.0 22 | ### Added 23 | - Filtering supported on map structures 24 | - Filtering for non-nil values (e.g. `$.books[?(@.isbn)]`) 25 | - `query` method to retrieve key path alongside matches (#4) 26 | 27 | ### Changed 28 | - `$.key` will not match elements in `[{:key "foo"}, {:key "bar"}]` anymore. The correct query for this would be `$[*].key` (#8). 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011> Giles Alexander 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # json-path 2 | 3 | An implementation of the [JsonPath][jp] spec for Clojure. 4 | 5 | It doesn't provide a full implementation. The following syntactic 6 | elements are supported. 7 | 8 | * `$`: Select the root of the object. 9 | * `.`: Descend to a single child. 10 | * `..`: Recursive descent to select all children. 11 | * `*` and ``: Select the child objects matching a name, or all 12 | immediate children when using `*`. Unlike in JavaScript, the `name` 13 | can contain hyphens (`-`). This is convenient as Clojure data 14 | structures often use hyphens in keys. 15 | * `[]` and `[*]`: Select either a specific element of an 16 | array, or all elements of an array. 17 | * `[?()]`: Filter to select objects that match an 18 | expression. Supports all equality operators (`=`, `!=`, `<`, `<=`, 19 | `>`, `>=`) and can use `@` to refer to objects from the current 20 | object. 21 | 22 | See [`test/json_path/test/json_path_test.clj`][eg] for more examples. 23 | 24 | For a comparison to other implementations see the 25 | [json-path-comparison project][comp]. 26 | 27 | ## Missing 28 | 29 | Notable features missing from the JsonPath spec are multiple array 30 | indices (`[,]`),array slicing (`[start:end:step]`) and arbitrary 31 | script expressions (`[(...)]`). Also, the set of expression operators 32 | should probably be expanded. 33 | 34 | ## Future Work 35 | 36 | `json-path` will never support the arbitrary script expressions 37 | feature. That's just a plain bad idea. 38 | 39 | JsonPath is missing a parent operator. This is necessary for 40 | performing cousin operations. I propose using `^` as the parent 41 | operator. It would be used anywhere that the `.` child operator could 42 | be used. 43 | 44 | The supported expression operators should be expanded. And as 45 | arbitrary script expressions won't be supported, functions for 46 | operations like length should be added. 47 | 48 | ## Usage 49 | 50 | Accepts standard Clojure data structures: maps and sequences. Assumes 51 | that maps contains keywords for the child objects. 52 | 53 | ```clj 54 | (require 'json-path) 55 | 56 | (json-path/at-path "$.foo" {:foo {:bar "Hello, world!"}}) 57 | ; => {:bar "Hello, world!"} 58 | 59 | (->> (json-path/query "$..bar" {:foo {:bar "Hello"}}) 60 | (map :path)) 61 | ; => ([:foo :bar]) 62 | ``` 63 | 64 | ## Contributors 65 | 66 | * [Giles Alexander](https://github.com/gga) 67 | * [Matthew Gertner](https://github.com/matthewgertner) 68 | * [Christoph Burgmer](https://github.com/cburgmer) 69 | * [Trevor Hartman](https://github.com/devth) 70 | * [Chris Oakman](https://github.com/oakmac) 71 | 72 | ## License 73 | 74 | Copyright (C) 2011 Giles Alexander 75 | 76 | Distributed under the MIT License. 77 | 78 | [jp]: http://goessner.net/articles/JsonPath/ 79 | [eg]: https://github.com/gga/json-path/blob/master/test/json_path/test/json_path_test.clj 80 | [comp]: https://cburgmer.github.io/json-path-comparison/ 81 | -------------------------------------------------------------------------------- /test/json_path/test/regression_test.clj: -------------------------------------------------------------------------------- 1 | (ns json-path.test.regression-test 2 | (:use [json-path]) 3 | (:require [yaml.core :as yaml] 4 | [clojure.data.json :as json] 5 | [clojure 6 | [test :refer :all]])) 7 | 8 | (defn queries_from_suite [suite-yaml] 9 | (:queries (yaml/from-file suite-yaml))) 10 | 11 | (defn- query-implementation-for [{:keys [selector document ordered]}] 12 | (let [current (json-path/at-path selector document)] 13 | (if (= ordered false) 14 | (sort-by json/write-str current) 15 | current))) 16 | 17 | (defn- expected-by-consensus [query] 18 | (if (contains? query :scalar-consensus) 19 | (:scalar-consensus query) 20 | (:consensus query))) 21 | 22 | (deftest regression 23 | (let [non-consensus-query-ids (->> (queries_from_suite "test/Clojure_json-path.yaml") 24 | (map :id) 25 | set)] 26 | (->> (queries_from_suite "test/regression_suite.yaml") 27 | (remove (fn [{id :id}] (contains? non-consensus-query-ids id))) 28 | (map (fn [{:keys [id] :as query}] 29 | (testing id 30 | (is (= (expected-by-consensus query) 31 | (query-implementation-for query)))))) 32 | doall))) 33 | 34 | (defn- report-result [current-result current-exception previous {:keys [id selector] :as query}] 35 | (println 36 | (format "Warning: implementation has changed for %s: %s (previous status %s)" 37 | id selector (:status previous))) 38 | (println "Old:") 39 | (if (= (:status previous) "error") 40 | (println " Error") 41 | (println (format" %s" (pr-str (:result previous))))) 42 | (println "New:") 43 | (if (some? current-exception) 44 | (println " Error") 45 | (println (format" %s" (pr-str current-result)))) 46 | (when-let [consensus (expected-by-consensus query)] 47 | (println "Consensus:") 48 | (println (format" %s" (pr-str consensus))))) 49 | 50 | ;; This section is for warning us if we are moving away from previously 51 | ;; recorded results which however are not backed by a consensus based 52 | ;; on https://github.com/cburgmer/json-path-comparison 53 | (deftest warning-on-changes-for-non-conforming-queries-based-on-consensus 54 | (let [all-queries (queries_from_suite "test/regression_suite.yaml") 55 | query-lookup (zipmap (map :id all-queries) 56 | all-queries)] 57 | (->> (queries_from_suite "test/Clojure_json-path.yaml") 58 | (map (fn [{:keys [id status result] :as previous}] 59 | (let [query (get query-lookup id)] 60 | (testing id 61 | (try 62 | (let [current-result (query-implementation-for query)] 63 | (when (or (= "error" status) 64 | (not= result current-result)) 65 | (report-result current-result nil previous query))) 66 | (catch Exception e 67 | (when (not= "error" 68 | status) 69 | (report-result nil e previous query)))))))) 70 | doall))) 71 | -------------------------------------------------------------------------------- /src/json_path/parser.clj: -------------------------------------------------------------------------------- 1 | (ns json-path.parser) 2 | 3 | (declare parse parse-expr) 4 | 5 | (defn extract-sub-tree [start end stream] 6 | (take-while #(not (= end %)) (drop-while #(= start %) stream))) 7 | 8 | (def boolean-ops 9 | {"&&" :and, "||" :or}) 10 | 11 | (def comparator-ops 12 | {"=" :eq, "!=" :neq, "<" :lt, "<=" :lt-eq, ">" :gt, ">=" :gt-eq}) 13 | 14 | (def boolean-ops-strings (set (keys boolean-ops))) 15 | (def comparator-ops-strings (set (keys comparator-ops))) 16 | 17 | (defn parse-boolean-expr [expr] 18 | (let [lhs (take-while #(not (boolean-ops-strings %)) expr) 19 | op (first (drop-while #(not (boolean-ops-strings %)) expr)) 20 | rhs (rest (drop-while #(not (boolean-ops-strings %)) expr))] 21 | [(boolean-ops op) (parse-expr lhs) (parse-expr rhs)])) 22 | 23 | (defn parse-comparator-expr [expr] 24 | (let [lhs (take-while #(not (comparator-ops-strings %)) expr) 25 | op (first (drop-while #(not (comparator-ops-strings %)) expr)) 26 | rhs (rest (drop-while #(not (comparator-ops-strings %)) expr))] 27 | [(comparator-ops op) (parse lhs) (parse rhs)])) 28 | 29 | (defn parse-expr [expr] 30 | (let [first-el (first expr)] 31 | (cond 32 | (some boolean-ops-strings expr) (parse-boolean-expr expr) 33 | (some (set (keys comparator-ops)) expr) (parse-comparator-expr expr) 34 | (= first-el "true") [:val true] 35 | (= first-el "false") [:val false] 36 | (= "\"" first-el) [:val (apply str (extract-sub-tree "\"" "\"" expr))] 37 | :else [:some (parse expr)]))) 38 | 39 | (defn parse-indexer [remaining] 40 | (let [next (first remaining)] 41 | (cond 42 | (= next "*") [:index "*"] 43 | (= "?(" next) [:filter (parse-expr (extract-sub-tree "?(" ")" (drop 1 remaining)))] 44 | :else [:index next]))) 45 | 46 | (defn parse-path-components [parts] 47 | (let [converter (fn [part] 48 | (let [path-cmds {"$" :root, "." :child, ".." :all-children, "@" :current}] 49 | (if (path-cmds part) 50 | [(path-cmds part)] 51 | [:key part])))] 52 | (vec (map converter parts)))) 53 | 54 | (defn parse [remaining] 55 | (let [next (first remaining)] 56 | (cond 57 | (empty? remaining) [] 58 | (re-matches #"\d+" next) [:val (Integer/parseInt next)] 59 | (re-matches #"\d+\.\d*" next) [:val (Double/parseDouble next)] 60 | (= next "true") [:val true] 61 | (= next "false") [:val false] 62 | (= "\"" next) [:val (apply str (extract-sub-tree "\"" "\"" remaining))] 63 | (= "[" next) (do 64 | (let [idx (parse-indexer (extract-sub-tree "[" "]" remaining)) 65 | rem (drop 1 (drop-while #(not (= "]" %)) remaining))] 66 | (if (not (empty? rem)) 67 | [:selector idx (parse rem)] 68 | [:selector idx]))) 69 | :else (do 70 | (let [pth (parse-path-components (extract-sub-tree "" "[" remaining)) 71 | rem (drop-while #(not (= "[" %)) remaining)] 72 | (if (not (empty? rem)) 73 | [:path pth (parse rem)] 74 | [:path pth])))))) 75 | 76 | (defn parse-path [path] 77 | (parse (re-seq #"<=|>=|\.\.|[.*$@\[\]\(\)\"=<>]|\d+|[\w-\/]+|\?\(|!=|&&|\|\||true|false" path))) 78 | -------------------------------------------------------------------------------- /test/json_path/test/json_path_test.clj: -------------------------------------------------------------------------------- 1 | (ns json-path.test.json-path-test 2 | [:use 3 | [json-path] 4 | [midje.sweet]]) 5 | 6 | (unfinished) 7 | 8 | (def keys-of-many-types 9 | [{:key 1} 10 | {:key 3} 11 | {:key "nice"} 12 | {:key true} 13 | {:key nil} 14 | {:key false} 15 | {:key {}} 16 | {:key []} 17 | {:key -1} 18 | {:key 0} 19 | {:key ""}]) 20 | 21 | (facts 22 | (at-path "$" ...json...) => ...json... 23 | (at-path "$.hello" {:hello "world"}) => "world" 24 | (at-path "$.hello.world" {:hello {:world "foo"}}) => "foo" 25 | (at-path "$..world" {:hello {:world "foo"}, 26 | :baz {:world "bar", 27 | :quuz {:world "zux"}}}) => ["foo", "bar", "zux"] 28 | (at-path "$.*.world" {:a {:world "foo"}, 29 | :b {:world "bar", 30 | :c {:world "baz"}}}) => ["foo", "bar"] 31 | (at-path "$.foo[*]" {:foo ["a", "b", "c"]}) => ["a", "b", "c"] 32 | (at-path "$[*]" {:foo 1 :bar [2 3]}) => [1 [2 3]] 33 | (at-path "$..*" {:foo 1 :bar [2 3]}) => [1 [2 3] 2 3] 34 | (at-path "$[-2]" [1 2 3]) => 2 35 | (at-path "$[?(@.bar<2)]" [{:bar 1} {:bar 2}]) => [{:bar 1}] 36 | (at-path "$.foo[?(@.bar=\"baz\")].hello" 37 | {:foo [{:bar "wrong" :hello "goodbye"} 38 | {:bar "baz" :hello "world"}]}) => ["world"] 39 | (at-path "$.foo[?(@.id=$.id)].text" 40 | {:id 45, :foo [{:id 12, :text "bar"}, 41 | {:id 45, :text "hello"}]}) => ["hello"] 42 | (at-path "$.foo[*].bar[*].baz" 43 | {:foo [{:bar [{:baz "hello"}]}]}) => ["hello"] 44 | ;; Filter expression with boolean and operator 45 | (at-path "$[?(@.key>42 && @.key<44)]" 46 | [{:key 42}, {:key 43}, {:key 44}]) => [{:key 43}] 47 | ;; Filter expression with boolean and operator and value false 48 | (at-path "$[?(@.key>0 && false)]" 49 | keys-of-many-types) => [] 50 | ;; Filter expression with boolean and operator and value true 51 | (at-path "$[?(@.key>0 && true)]" 52 | keys-of-many-types) => [{:key 1}, {:key 3}] 53 | ;; Filter expression with boolean or operator 54 | (at-path "$[?(@.key>43 || @.key<43)]" 55 | [{:key 42}, {:key 43}, {:key 44}]) => [{:key 42}, {:key 44}] 56 | ;; Filter expression with boolean or operator and value false 57 | (at-path "$[?(@.key>0 || false)]" 58 | keys-of-many-types) => [{:key 1}, {:key 3}] 59 | ;; Filter expression with boolean or operator and value true 60 | (at-path "$[?(@.key>0 || true)]" 61 | keys-of-many-types) => keys-of-many-types 62 | ;; Filter expression with value true 63 | (at-path "$[?(@.key)]" 64 | [{:some "some value"} 65 | {:key true} 66 | {:key false} 67 | {:key nil} 68 | {:key "value"} 69 | {:key ""} 70 | {:key 0} 71 | {:key 1} 72 | {:key -1} 73 | {:key 42} 74 | {:key {}} 75 | {:key []}]) 76 | => [{:key true} 77 | {:key false} 78 | {:key "value"} 79 | {:key ""} 80 | {:key 0} 81 | {:key 1} 82 | {:key -1} 83 | {:key 42} 84 | {:key {}} 85 | {:key []}]) 86 | ;; TODO: Filter expression with different grouped operators 87 | ;; NOTE: the parser will need to be updated in order to get this test to work 88 | ; (at-path "$[?(@.a && (@.b || @.c))]" 89 | ; [{:a true} 90 | ; {:a true, :b true} 91 | ; {:a true, :b true, :c true} 92 | ; {:b true, :c true} 93 | ; {:a true, :c true} 94 | ; {:c true} 95 | ; {:b true}]) 96 | ; => [{:a true, :b true} 97 | ; {:a true, :b true, :c true} 98 | ; {:a true, :c true}]) 99 | 100 | (facts 101 | (-> (query "$.hello" 102 | {:hello "world"}) 103 | :path) => [:hello] 104 | (-> (query "$" 105 | {:hello "world"}) 106 | :path) => [] 107 | (->> (query "$..world" {:baz {:world "bar", 108 | :quuz {:world "zux"}}}) 109 | (map :value)) => '("bar" "zux") 110 | (->> (query "$..world" {:baz {:world "bar", 111 | :quuz {:world "zux"}}}) 112 | (map :path)) => '([:baz :world] [:baz :quuz :world]) 113 | (->> (query "$.foo[*]" {:foo ["a", "b", "c"]}) 114 | (map :path)) => '([:foo 0] [:foo 1] [:foo 2]) 115 | (-> (query "$.hello" 116 | {:hello "world"}) 117 | :value) => "world" 118 | (-> (query "$.hello/world" 119 | {:hello/world "foo"}) 120 | :value) => "foo" 121 | (-> (query "$.hello/world.world/name" 122 | {:hello/world {:world/name "earth"}}) 123 | :value) => "earth" 124 | (->> (query "$.foo[?(@.bar=\"baz\")].hello" 125 | {:foo [{:bar "wrong" :hello "goodbye"} 126 | {:bar "baz" :hello "world"}]}) 127 | (map :path)) => '([:foo 1 :hello]) 128 | (->> (query "$[?(@.key>42 && @.key<44)]" 129 | [{:key 42}, {:key 43}, {:key 44}]) 130 | (map :value)) => [{:key 43}] 131 | (->> (query "$[?(@.key>43 || @.key<43)]" 132 | [{:key 42}, {:key 43}, {:key 44}]) 133 | (map :value)) => [{:key 42}, {:key 44}]) 134 | -------------------------------------------------------------------------------- /src/json_path/walker.clj: -------------------------------------------------------------------------------- 1 | (ns json-path.walker 2 | [:require [json-path.match :as m]]) 3 | 4 | (declare walk eval-expr) 5 | 6 | ;; 'and' and 'or' are macros in Clojure, so we wrap them in functions here so they 7 | ;; can be passed to apply and tested for equality 8 | (defn and* [a b] 9 | (and a b)) 10 | 11 | (defn or* [a b] 12 | (or a b)) 13 | 14 | (defn eval-bool-expr [comp-fn context operands] 15 | (boolean 16 | (apply 17 | (fn [a b] 18 | (cond 19 | ;; allow less-than, greater-than comparisons if both args are Numbers or Strings 20 | (and (contains? #{< <= > >=} comp-fn) 21 | (or (and (number? a) (number? b)) 22 | (and (string? a) (string? b)))) 23 | (comp-fn a b) 24 | 25 | ;; always allow equality comparisons as well as 'and' and 'or' 26 | (contains? #{= not= and* or*} comp-fn) 27 | (comp-fn a b) 28 | 29 | ;; else the two values cannot be compared: return false 30 | :else false)) 31 | (map #(eval-expr % context) operands)))) 32 | 33 | (def boolean-ops 34 | "expression operands that result in a boolean result" 35 | {:eq = 36 | :neq not= 37 | :lt < 38 | :lt-eq <= 39 | :gt > 40 | :gt-eq >= 41 | ;; NOTE: see comment above, these macros are wrapped as functions 42 | :and and* 43 | :or or*}) 44 | 45 | (defn eval-expr [[expr-type & operands :as expr] context] 46 | (cond 47 | (contains? boolean-ops expr-type) (eval-bool-expr (get boolean-ops expr-type) context operands) 48 | (= expr-type :some) (some? (:value (walk (first operands) context))) 49 | (= expr-type :val) (first operands) 50 | (= expr-type :path) (:value (walk expr context)))) 51 | 52 | (defn map# [func obj] 53 | (if (seq? obj) 54 | (->> obj 55 | (flatten) 56 | (map (partial map# func))) 57 | (func obj))) 58 | 59 | (defn- select-all [current-context] 60 | (let [obj (:value current-context)] 61 | (cond (map? obj) (map (fn [[k v]] (m/with-context k v current-context)) obj) 62 | (sequential? obj) (map-indexed (fn [idx child-obj] (m/with-context idx child-obj current-context)) obj) 63 | :else '()))) 64 | 65 | (defn select-by [[opcode & operands :as obj-spec] current-context] 66 | (if (= (first operands) "*") 67 | (select-all current-context) 68 | (let [obj (:value current-context) 69 | key (keyword (first operands))] 70 | (m/with-context key (key obj) current-context)))) 71 | 72 | (defn- obj-vals [current-context] 73 | (let [obj (:value current-context)] 74 | (cond 75 | (sequential? obj) (map-indexed (fn [idx child-obj] (m/with-context idx child-obj current-context)) obj) 76 | (map? obj) (->> obj 77 | (filter (fn [[k v]] (or (map? v) (sequential? v)))) 78 | (map (fn [[k v]] (m/with-context k v current-context)))) 79 | :else '()))) 80 | 81 | (defn- all-children [current-context] 82 | (let [children (mapcat all-children (obj-vals current-context))] 83 | (cons current-context children))) 84 | 85 | (defn walk-path [[next & parts] context] 86 | (cond 87 | (nil? next) (:current context) 88 | (= [:root] next) (walk-path parts (assoc context :current (:root context))) 89 | (= [:child] next) (walk-path parts context) 90 | (= [:current] next) (walk-path parts context) 91 | (= [:all-children] next) (->> (:current context) 92 | all-children 93 | (map #(walk-path parts (assoc context :current %))) 94 | flatten 95 | (remove #(nil? (:value %)))) 96 | (= :key (first next)) (map# #(walk-path parts (assoc context :current %)) (select-by next (:current context))))) 97 | 98 | (defn walk-selector [sel-expr context] 99 | (cond 100 | (= :index (first sel-expr)) (let [obj (:value (:current context)) 101 | sel (nth sel-expr 1)] 102 | (if (= "*" sel) 103 | (select-all (:current context)) 104 | (if (sequential? obj) 105 | (let [index (Integer/parseInt sel) 106 | effective-index (if (< index 0) 107 | (+ (count obj) index) 108 | index)] 109 | (m/with-context index (nth obj effective-index) (:current context))) 110 | (throw (Exception. "object must be an array."))))) 111 | (= :filter (first sel-expr)) (let [obj (:value (:current context)) 112 | children (if (map? obj) 113 | (map identity obj) 114 | (map-indexed (fn [i e] [i e]) obj))] 115 | (->> children 116 | (filter (fn [[key val]] (eval-expr (second sel-expr) (assoc context :current (m/root val))))) 117 | (map (fn [[key val]] (m/with-context key val (:current context)))))))) 118 | 119 | (defn walk [[opcode operand continuation :as expr] context] 120 | (let [down-obj (cond 121 | (= opcode :path) (walk-path operand context) 122 | (= opcode :selector) (walk-selector operand context) 123 | (= opcode :val) (eval-expr expr context) 124 | :else nil)] 125 | (if continuation 126 | (map# #(walk continuation (assoc context :current %)) down-obj) 127 | down-obj))) 128 | -------------------------------------------------------------------------------- /test/json_path/test/parser_test.clj: -------------------------------------------------------------------------------- 1 | (ns json-path.test.parser-test 2 | [:use [json-path.parser] 3 | [midje.sweet]]) 4 | 5 | (unfinished) 6 | 7 | (facts 8 | (extract-sub-tree 4 8 (range 4 10)) => [5 6 7]) 9 | 10 | (fact 11 | (parse-expr '("@" "." "foo" "=" "\"" "baz" "\"")) 12 | => 13 | [:eq [:path [[:current] [:child] [:key "foo"]]] [:val "baz"]]) 14 | 15 | (facts "comparator expressions should be parseable" 16 | (parse-expr '("\"" "bar" "\"" "!=" "\"" "bar" "\"")) => [:neq [:val "bar"] [:val "bar"]] 17 | (parse-expr '("\"" "bar" "\"" "<" "\"" "bar" "\"")) => [:lt [:val "bar"] [:val "bar"]] 18 | (parse-expr '("\"" "bar" "\"" "<=" "\"" "bar" "\"")) => [:lt-eq [:val "bar"] [:val "bar"]] 19 | (parse-expr '("\"" "bar" "\"" ">" "\"" "bar" "\"")) => [:gt [:val "bar"] [:val "bar"]] 20 | (parse-expr '("\"" "bar" "\"" ">=" "\"" "bar" "\"")) => [:gt-eq [:val "bar"] [:val "bar"]] 21 | (parse-expr '("\"" "bar" "\"" "=" "42")) => [:eq [:val "bar"] [:val 42]] 22 | (parse-expr '("\"" "bar" "\"" "=" "3.1415")) => [:eq [:val "bar"] [:val 3.1415]]) 23 | 24 | (facts "boolean expressions should be parseable" 25 | (parse-expr '("\"" "bar" "\"" "&&" "\"" "bar" "\"")) => [:and [:val "bar"] [:val "bar"]] 26 | (parse-expr '("\"" "bar" "\"" "&&" "true")) => [:and [:val "bar"] [:val true]] 27 | (parse-expr '("false" "&&" "\"" "bar" "\"")) => [:and [:val false] [:val "bar"]] 28 | (parse-expr '("\"" "bar" "\"" "||" "\"" "bar" "\"")) => [:or [:val "bar"] [:val "bar"]] 29 | (parse-expr '("\"" "bar" "\"" "=" "42" "&&" "\"" "bar" "\"")) => [:and [:eq [:val "bar"] [:val 42]] [:val "bar"]]) 30 | 31 | (fact 32 | (parse-indexer '("*")) => [:index "*"] 33 | (parse-indexer '("3")) => [:index "3"] 34 | (parse-indexer '("?(" "\"" "bar" "\"" "=" "\"" "bar" "\"" ")")) => [:filter [:eq [:val "bar"] [:val "bar"]]]) 35 | 36 | (facts 37 | (parse '("\"" "bar" "\"")) => [:val "bar"] 38 | (parse '("$")) => [:path [[:root]]] 39 | (parse '("$" "." "*")) => [:path [[:root] [:child] [:key "*"]]] 40 | (parse '("$" "." "foo" "[" "3" "]")) => [:path [[:root] [:child] [:key "foo"]] [:selector [:index "3"]]] 41 | (parse '("$" "[" "3" "]" "." "bar")) => [:path [[:root]] [:selector [:index "3"] [:path [[:child] [:key "bar"]]]]]) 42 | 43 | (facts 44 | (parse-path "") => [] 45 | (parse-path "$") => [:path [[:root]]] 46 | (parse-path "$.hello") => [:path [[:root] [:child] [:key "hello"]]] 47 | (parse-path "$.hello-world") => [:path [[:root] [:child] [:key "hello-world"]]] 48 | (parse-path "$.hello/world") => [:path [[:root] [:child] [:key "hello/world"]]] 49 | (parse-path "$.*") => [:path [[:root] [:child] [:key "*"]]] 50 | (parse-path "$..hello") => [:path [[:root] [:all-children] [:key "hello"]]] 51 | (parse-path "$.foo[3]") => [:path [[:root] [:child] [:key "foo"]] [:selector [:index "3"]]] 52 | (parse-path "foo[*]") => [:path [[:key "foo"]] [:selector [:index "*"]]] 53 | (parse-path "$[?(@.baz)]") => [:path [[:root]] 54 | [:selector [:filter [:some [:path [[:current] 55 | [:child] 56 | [:key "baz"]]]]]]] 57 | (parse-path "$[?(@.bar<2)]") => [:path [[:root]] 58 | [:selector [:filter [:lt 59 | [:path [[:current] 60 | [:child] 61 | [:key "bar"]]] 62 | [:val 2]]]]] 63 | (parse-path "$[?(@.bar>42 && @.bar<44)]") => [:path [[:root]] 64 | [:selector [:filter 65 | [:and 66 | [:gt 67 | [:path [[:current] 68 | [:child] 69 | [:key "bar"]]] 70 | [:val 42]] 71 | [:lt 72 | [:path [[:current] 73 | [:child] 74 | [:key "bar"]]] 75 | [:val 44]]]]]] 76 | (parse-path "$[?(@.bar>42 && true)]") => [:path [[:root]] 77 | [:selector [:filter 78 | [:and 79 | [:gt 80 | [:path [[:current] 81 | [:child] 82 | [:key "bar"]]] 83 | [:val 42]] 84 | [:val true]]]]] 85 | (parse-path "$[?(@.bar>42 || @.bar<44)]") => [:path [[:root]] 86 | [:selector [:filter 87 | [:or 88 | [:gt 89 | [:path [[:current] 90 | [:child] 91 | [:key "bar"]]] 92 | [:val 42]] 93 | [:lt 94 | [:path [[:current] 95 | [:child] 96 | [:key "bar"]]] 97 | [:val 44]]]]]] 98 | (parse-path "$.foo[?(@.bar=\"baz\")].hello") => [:path [[:root] [:child] [:key "foo"]] 99 | [:selector [:filter [:eq [:path [[:current] 100 | [:child] 101 | [:key "bar"]]] 102 | [:val "baz"]]] 103 | [:path [[:child] [:key "hello"]]]]]) 104 | 105 | (facts "equality tokens should be recognised" 106 | (parse-path "10!=11") => truthy 107 | (provided 108 | (parse (contains "!=")) => true) 109 | (parse-path "10=11") => truthy 110 | (provided 111 | (parse (contains "=")) => true) 112 | (parse-path "10<11") => truthy 113 | (provided 114 | (parse (contains "<")) => true) 115 | (parse-path "10<=11") => truthy 116 | (provided 117 | (parse (contains "<=")) => true) 118 | (parse-path "10>11") => truthy 119 | (provided 120 | (parse (contains ">")) => true) 121 | (parse-path "10>=11") => truthy 122 | (provided 123 | (parse (contains ">=")) => true)) 124 | -------------------------------------------------------------------------------- /test/json_path/test/walker_test.clj: -------------------------------------------------------------------------------- 1 | (ns json-path.test.walker-test 2 | [:require [json-path.match :as m]] 3 | [:use [json-path.walker] 4 | [midje.sweet]]) 5 | 6 | (unfinished) 7 | 8 | (facts "evaluate expressions" 9 | (eval-expr [:eq [:val "a"] [:val "b"]] {}) => falsey 10 | (eval-expr [:eq [:val "a"] [:val "a"]] {}) => truthy 11 | (eval-expr [:neq [:val "a"] [:val "b"]] {}) => truthy 12 | (eval-expr [:lt [:val 10] [:val 11]] {}) => truthy 13 | (eval-expr [:lt-eq [:val 10] [:val 10]] {}) => truthy 14 | (eval-expr [:gt [:val 10] [:val 9]] {}) => truthy 15 | (eval-expr [:gt-eq [:val 10] [:val 9]] {}) => truthy 16 | (eval-expr [:gt-eq [:val 10] [:val 10]] {}) => truthy 17 | (eval-expr [:path [[:key "foo"]]] {:current (m/root {:foo "bar"})}) => "bar" 18 | (eval-expr [:some [:path [[:current] [:child] [:key "foo"]]]] {:current (m/root {:foo "bar"})}) => truthy 19 | (eval-expr [:some [:path [[:current] [:child] [:key "foo"]]]] {:current (m/root {:foo nil})}) => falsey 20 | (eval-expr [:eq [:path [[:key "foo"]]] [:val "bar"]] {:current (m/root {:foo "bar"})}) => truthy 21 | 22 | (eval-expr [:val true] {}) => truthy 23 | (eval-expr [:val false] {}) => falsey 24 | 25 | ;; 'and' expressions 26 | (eval-expr [:and [:val true] [:val true]] {}) => truthy 27 | (eval-expr [:and [:val true] [:val false]] {}) => falsey 28 | (eval-expr [:and [:val false] [:val true]] {}) => falsey 29 | (eval-expr [:and [:val false] [:val false]] {}) => falsey 30 | (eval-expr [:and [:val true] [:val "bar"]] {}) => truthy 31 | (eval-expr [:and [:val "bar"] [:val false]] {}) => falsey 32 | (eval-expr [:and [:val true] [:lt [:val 10] [:val 11]]] {}) => truthy 33 | (eval-expr [:and [:val true] 34 | [:path [[:key "foo"]]]] {:current (m/root {:foo "bar"})}) => truthy 35 | (eval-expr [:and [:val true] 36 | [:path [[:key "foo"]]]] {:current (m/root {:foo nil})}) => falsey 37 | 38 | ;; 'or' expressions 39 | (eval-expr [:or [:val true] [:val true]] {}) => truthy 40 | (eval-expr [:or [:val true] [:val false]] {}) => truthy 41 | (eval-expr [:or [:val false] [:val true]] {}) => truthy 42 | (eval-expr [:or [:val false] [:val false]] {}) => falsey 43 | (eval-expr [:or [:val true] [:val "bar"]] {}) => truthy 44 | (eval-expr [:or [:val "bar"] [:val false]] {}) => truthy 45 | (eval-expr [:or [:val true] [:lt [:val 10] [:val 11]]] {}) => truthy 46 | (eval-expr [:or [:val false] 47 | [:path [[:key "foo"]]]] {:current (m/root {:foo "bar"})}) => truthy 48 | (eval-expr [:or [:val false] 49 | [:path [[:key "foo"]]]] {:current (m/root {:foo nil})}) => falsey) 50 | 51 | (facts 52 | (select-by [:key "hello"] (m/root {:hello "world"})) => (m/create "world" [:hello]) 53 | (select-by [:key "hello"] {:current [{:hello "foo"} {:hello "bar"}]}) => (m/create nil [:hello]) 54 | (select-by [:key "*"] (m/root {:hello "world"})) => (list (m/create "world" [:hello])) 55 | (select-by [:key "*"] (m/root {:hello "world" :foo "bar"})) => (list (m/create "world" [:hello]) (m/create "bar" [:foo])) 56 | (select-by [:key "*"] (m/root [{:hello "world"} {:foo "bar"}])) => (list (m/create {:hello "world"} [0]) (m/create {:foo "bar"} [1])) 57 | (select-by [:key "*"] {:current 1}) => '()) 58 | 59 | (facts 60 | (walk-path [[:root]] {:root (m/root ...root...), :current (m/root ...obj...)}) => (m/create ...root... []) 61 | (walk-path [[:root] [:child] [:key "foo"]] {:root (m/root {:foo "bar"})}) => (m/create "bar" [:foo]) 62 | (walk-path [[:all-children]] {:current (m/root {:foo "bar" :baz {:qux "zoo"}})}) => (list (m/create {:foo "bar" :baz {:qux "zoo"}} []) 63 | (m/create {:qux "zoo"} [:baz])) 64 | (walk-path [[:all-children] [:key "bar"]] 65 | {:current (m/root '([{:bar "hello"}]))}) => (list (m/create "hello" [0 0 :bar])) 66 | (walk-path [[:all-children] [:key "bar"]] 67 | {:current (m/root {:foo [{:bar "wrong"} 68 | {:bar "baz"}]})}) => (list (m/create "wrong" [:foo 0 :bar]) 69 | (m/create "baz" [:foo 1 :bar])) 70 | (walk-path [[:all-children] [:key "foo"]] 71 | {:current (m/root {:foo [{:foo "foo"}]})}) => (list (m/create [{:foo "foo"}] [:foo]) 72 | (m/create "foo" [:foo 0 :foo]))) 73 | 74 | (facts 75 | (walk-selector [:index "1"] {:current (m/root ["foo", "bar", "baz"])}) => (m/create "bar" [1]) 76 | (walk-selector [:index "-1"] {:current (m/root ["foo", "bar", "baz"])}) => (m/create "baz" [-1]) 77 | (walk-selector [:index "*"] {:current (m/root [:a :b])}) => (list (m/create :a [0]) (m/create :b [1])) 78 | (walk-selector [:index "*"] {:current (m/root {:foo "bar"})}) => (list (m/create "bar" [:foo])) 79 | (walk-selector [:index "*"] {:current (m/root 1)}) => '() 80 | (walk-selector [:filter [:eq [:path [[:current] [:child] [:key "bar"]]] [:val "baz"]]] 81 | {:current (m/root [{:bar "wrong"} {:bar "baz"}])}) => (list (m/create {:bar "baz"} [1])) 82 | (walk-selector [:filter [:eq [:path [[:current] [:child] [:key "bar"]]] [:val "baz"]]] 83 | {:current (m/root {:one {:bar "wrong"} :other {:bar "baz"}})}) => (list (m/create {:bar "baz"} [:other])) 84 | (walk-selector [:filter [:gt [:path [[:current] [:child] [:key "bar"]]] [:val 42]]] 85 | {:current (m/root [{:bar 41} {:bar 43}])}) => (list (m/create {:bar 43} [1]))) 86 | 87 | (fact "selecting places constraints on the shape of the object being selected from" 88 | (walk-selector [:index "1"] {:current (m/root {:foo "bar"})}) => (throws Exception)) 89 | 90 | (facts 91 | (walk [:path [[:root]]] {:root (m/root ...json...)}) => (m/create ...json... []) 92 | (walk [:path [[:child]]] {:current (m/root ...json...)}) => (m/create ...json... []) 93 | (walk [:path [[:current]]] {:current (m/root ...json...)}) => (m/create ...json... []) 94 | (walk [:path [[:key "foo"]]] {:current (m/root {:foo "bar"})}) => (m/create "bar" [:foo]) 95 | (walk [:path [[:all-children]]] 96 | {:current 97 | (m/root {:hello {:world "foo"}, 98 | :baz {:world "bar", 99 | :quuz {:world "zux"}}})}) => (list (m/create {:hello {:world "foo"}, 100 | :baz {:world "bar", :quuz {:world "zux"}}} 101 | []) 102 | (m/create {:world "foo"} 103 | [:hello]) 104 | (m/create {:world "bar", 105 | :quuz {:world "zux"}} 106 | [:baz]) 107 | (m/create {:world "zux"} 108 | [:baz :quuz])) 109 | (walk [:path [[:all-children]]] 110 | {:current 111 | (m/root (list {:hello {:world "foo"}} 112 | {:baz {:world "bar"}}))}) => (list (m/create [{:hello {:world "foo"}} 113 | {:baz {:world "bar"}}] 114 | []) 115 | (m/create {:hello {:world "foo"}} [0]) 116 | (m/create {:world "foo"} [0 :hello]) 117 | (m/create {:baz {:world "bar"}} [1]) 118 | (m/create {:world "bar"} [1 :baz])) 119 | (walk [:path [[:all-children]]] 120 | {:current (m/root "scalar")}) => (list (m/create "scalar" [])) 121 | (walk [:path [[:all-children] [:key "world"]]] 122 | {:current (m/root {:hello {:world "foo"}, 123 | :baz {:world "bar", 124 | :quuz {:world "zux"}}})}) => (list (m/create "foo" [:hello :world]) 125 | (m/create "bar" [:baz :world]) 126 | (m/create "zux" [:baz :quuz :world])) 127 | (walk [:selector [:index "1"]] {:current (m/root ["foo", "bar", "baz"])}) => (m/create "bar" [1]) 128 | (walk [:selector [:index "*"]] {:current (m/root [:a :b])}) => (list (m/create :a [0]) (m/create :b [1])) 129 | (walk [:selector [:index "*"] 130 | [:path [[:child] [:key "foo"]]]] 131 | {:current 132 | (m/root [{:foo 1} {:foo 2}])}) => (list (m/create 1 [0 :foo]) (m/create 2 [1 :foo])) 133 | (walk [:path [[:key "*"]]] {:current 1}) => '() 134 | (walk [:selector [:filter [:eq 135 | [:path [[:current] 136 | [:child] 137 | [:key "bar"]]] 138 | [:val "baz"]]]] 139 | {:current (m/root [{:bar "wrong"} {:bar "baz"}])}) => (list (m/create {:bar "baz"} [1])) 140 | (walk [:path [[:root] [:child] [:key "foo"]] 141 | [:selector [:filter [:eq 142 | [:path [[:current] 143 | [:child] 144 | [:key "bar"]]] 145 | [:val "baz"]]] 146 | [:path [[:child] [:key "hello"]]]]] 147 | {:root (m/root {:foo [{:bar "wrong" :hello "goodbye"} 148 | {:bar "baz" :hello "world"}]})}) => (list (m/create "world" [:foo 1 :hello])) 149 | (walk [:path [[:root]] 150 | [:selector [:filter [:some [:path [[:current] 151 | [:child] 152 | [:key "bar"]]]]]]] 153 | {:root (m/root {:hello "world" :foo {:bar "baz"}})}) => (list (m/create {:bar "baz"} [:foo]))) 154 | 155 | (facts "walking a nil object should be safe" 156 | (walk [:path [[:root]]] {:root (m/root nil)}) => (m/create nil []) 157 | (walk [:path [[:root] [:child] [:key "foo"]]] {:root (m/root {:bar "baz"})}) => (m/create nil [:foo]) 158 | (walk [:path [[:root] [:child] [:key "foo"] [:child] [:key "bar"]]] 159 | {:root (m/root {:foo {:baz "hello"}})}) => (m/create nil [:foo :bar])) 160 | -------------------------------------------------------------------------------- /test/Clojure_json-path.yaml: -------------------------------------------------------------------------------- 1 | # This file was generated by src/compile_implementation_report.sh from https://github.com/cburgmer/json-path-comparison/ 2 | 3 | # This file tracks all results of the given implementation for queries which the implementation either does not match 4 | # an existing consensus or where no consensus exists. 5 | # It can be used to track changes in the underlying implementation and complements the regression report. 6 | 7 | implementation: Clojure_json-path 8 | queries: 9 | - id: array_slice 10 | status: fail 11 | result: "second" 12 | - id: array_slice_on_exact_match 13 | status: fail 14 | result: "first" 15 | - id: array_slice_on_non_overlapping_array 16 | status: error 17 | - id: array_slice_on_object 18 | status: error 19 | - id: array_slice_on_partially_overlapping_array 20 | status: fail 21 | result: "second" 22 | - id: array_slice_with_large_number_for_end 23 | status: fail 24 | result: "third" 25 | - id: array_slice_with_large_number_for_end_and_negative_step 26 | status: open 27 | result: "third" 28 | - id: array_slice_with_large_number_for_start 29 | status: error 30 | - id: array_slice_with_large_number_for_start_end_negative_step 31 | status: error 32 | - id: array_slice_with_negative_start_and_end_and_range_of_-1 33 | status: fail 34 | result: 4 35 | - id: array_slice_with_negative_start_and_end_and_range_of_0 36 | status: fail 37 | result: 4 38 | - id: array_slice_with_negative_start_and_end_and_range_of_1 39 | status: fail 40 | result: 4 41 | - id: array_slice_with_negative_start_and_positive_end_and_range_of_-1 42 | status: fail 43 | result: 4 44 | - id: array_slice_with_negative_start_and_positive_end_and_range_of_0 45 | status: fail 46 | result: 4 47 | - id: array_slice_with_negative_start_and_positive_end_and_range_of_1 48 | status: fail 49 | result: 4 50 | - id: array_slice_with_negative_step 51 | status: open 52 | result: "forth" 53 | - id: array_slice_with_negative_step_and_start_greater_than_end 54 | status: open 55 | result: "first" 56 | - id: array_slice_with_negative_step_on_partially_overlapping_array 57 | status: error 58 | - id: array_slice_with_negative_step_only 59 | status: open 60 | result: "forth" 61 | - id: array_slice_with_open_end 62 | status: fail 63 | result: "second" 64 | - id: array_slice_with_open_end_and_negative_step 65 | status: open 66 | result: "forth" 67 | - id: array_slice_with_open_start 68 | status: fail 69 | result: "third" 70 | - id: array_slice_with_open_start_and_end 71 | status: error 72 | - id: array_slice_with_open_start_and_end_and_step_empty 73 | status: error 74 | - id: array_slice_with_open_start_and_end_on_object 75 | status: error 76 | - id: array_slice_with_open_start_and_negative_step 77 | status: open 78 | result: "third" 79 | - id: array_slice_with_positive_start_and_negative_end_and_range_of_-1 80 | status: fail 81 | result: 5 82 | - id: array_slice_with_positive_start_and_negative_end_and_range_of_0 83 | status: fail 84 | result: 5 85 | - id: array_slice_with_positive_start_and_negative_end_and_range_of_1 86 | status: fail 87 | result: 5 88 | - id: array_slice_with_range_of_-1 89 | status: fail 90 | result: "third" 91 | - id: array_slice_with_range_of_0 92 | status: fail 93 | result: "first" 94 | - id: array_slice_with_range_of_1 95 | status: fail 96 | result: "first" 97 | - id: array_slice_with_start_-1_and_open_end 98 | status: fail 99 | result: "third" 100 | - id: array_slice_with_start_-2_and_open_end 101 | status: fail 102 | result: "second" 103 | - id: array_slice_with_start_large_negative_number_and_open_end_on_short_array 104 | status: error 105 | - id: array_slice_with_step 106 | status: fail 107 | result: "first" 108 | - id: array_slice_with_step_0 109 | status: open 110 | result: "first" 111 | - id: array_slice_with_step_1 112 | status: fail 113 | result: "first" 114 | - id: array_slice_with_step_and_leading_zeros 115 | status: fail 116 | result: 10 117 | - id: array_slice_with_step_but_end_not_aligned 118 | status: fail 119 | result: "first" 120 | - id: array_slice_with_step_empty 121 | status: fail 122 | result: "second" 123 | - id: array_slice_with_step_only 124 | status: fail 125 | result: "third" 126 | - id: bracket_notation 127 | status: error 128 | - id: bracket_notation_after_recursive_descent 129 | status: error 130 | - id: bracket_notation_on_object_without_key 131 | status: error 132 | - id: bracket_notation_with_NFC_path_on_NFD_key 133 | status: error 134 | - id: bracket_notation_with_dot 135 | status: error 136 | - id: bracket_notation_with_double_quotes 137 | status: error 138 | - id: bracket_notation_with_empty_path 139 | status: error 140 | - id: bracket_notation_with_empty_string 141 | status: error 142 | - id: bracket_notation_with_empty_string_doubled_quoted 143 | status: error 144 | - id: bracket_notation_with_negative_number_on_short_array 145 | status: error 146 | - id: bracket_notation_with_number_-1_on_empty_array 147 | status: error 148 | - id: bracket_notation_with_number_after_dot_notation_with_wildcard_on_nested_arrays_with_different_length 149 | status: error 150 | - id: bracket_notation_with_number_on_object 151 | status: error 152 | - id: bracket_notation_with_number_on_short_array 153 | status: error 154 | - id: bracket_notation_with_number_on_string 155 | status: error 156 | - id: bracket_notation_with_quoted_array_slice_literal 157 | status: error 158 | - id: bracket_notation_with_quoted_closing_bracket_literal 159 | status: error 160 | - id: bracket_notation_with_quoted_current_object_literal 161 | status: error 162 | - id: bracket_notation_with_quoted_dot_literal 163 | status: error 164 | - id: bracket_notation_with_quoted_dot_wildcard 165 | status: error 166 | - id: bracket_notation_with_quoted_double_quote_literal 167 | status: error 168 | - id: bracket_notation_with_quoted_escaped_backslash 169 | status: error 170 | - id: bracket_notation_with_quoted_escaped_single_quote 171 | status: error 172 | - id: bracket_notation_with_quoted_number_on_object 173 | status: error 174 | - id: bracket_notation_with_quoted_root_literal 175 | status: error 176 | - id: bracket_notation_with_quoted_special_characters_combined 177 | status: error 178 | - id: bracket_notation_with_quoted_string_and_unescaped_single_quote 179 | status: error 180 | - id: bracket_notation_with_quoted_union_literal 181 | status: error 182 | - id: bracket_notation_with_quoted_wildcard_literal 183 | status: fail 184 | result: ["entry", "value"] 185 | - id: bracket_notation_with_quoted_wildcard_literal_on_object_without_key 186 | status: fail 187 | result: ["entry"] 188 | - id: bracket_notation_with_spaces 189 | status: error 190 | - id: bracket_notation_with_string_including_dot_wildcard 191 | status: error 192 | - id: bracket_notation_with_two_literals_separated_by_dot 193 | status: error 194 | - id: bracket_notation_with_two_literals_separated_by_dot_without_quotes 195 | status: error 196 | - id: bracket_notation_with_wildcard_after_array_slice 197 | status: fail 198 | result: [1, 2] 199 | - id: bracket_notation_without_quotes 200 | status: error 201 | - id: current_with_dot_notation 202 | status: open 203 | result: null 204 | - id: dot_bracket_notation 205 | status: error 206 | - id: dot_bracket_notation_with_double_quotes 207 | status: error 208 | - id: dot_bracket_notation_without_quotes 209 | status: error 210 | - id: dot_notation_after_array_slice 211 | status: fail 212 | result: "ey" 213 | - id: dot_notation_after_bracket_notation_after_recursive_descent 214 | status: error 215 | - id: dot_notation_after_bracket_notation_with_wildcard_on_some_matching 216 | status: fail 217 | result: [1, null] 218 | - id: dot_notation_after_filter_expression 219 | status: fail 220 | result: [] 221 | - id: dot_notation_after_recursive_descent_with_extra_dot 222 | status: open 223 | result: ["russian dolls", "something", "top", "value", {"key": "russian dolls"}] 224 | - id: dot_notation_after_union 225 | status: fail 226 | result: "ey" 227 | - id: dot_notation_after_union_with_keys 228 | status: error 229 | - id: dot_notation_with_double_quotes 230 | status: open 231 | result: null 232 | - id: dot_notation_with_double_quotes_after_recursive_descent 233 | status: open 234 | result: [] 235 | - id: dot_notation_with_empty_path 236 | status: fail 237 | result: {"": 9001, "''": "nice", "key": 42} 238 | - id: dot_notation_with_key_root_literal 239 | status: open 240 | result: {"$": "value"} 241 | - id: dot_notation_with_non_ASCII_key 242 | status: fail 243 | result: {"\u5c6c\u6027": "value"} 244 | - id: dot_notation_with_number 245 | status: open 246 | result: null 247 | - id: dot_notation_with_single_quotes 248 | status: open 249 | result: "value" 250 | - id: dot_notation_with_single_quotes_after_recursive_descent 251 | status: open 252 | result: ["russian dolls", "something", "top", "value", {"key": "russian dolls"}] 253 | - id: dot_notation_with_single_quotes_and_dot 254 | status: open 255 | result: "value" 256 | - id: dot_notation_with_space_padded_key 257 | status: open 258 | result: 2 259 | - id: dot_notation_with_wildcard_after_recursive_descent_on_null_value_array 260 | status: fail 261 | result: [40, 42] 262 | - id: dot_notation_without_dot 263 | status: fail 264 | result: 1 265 | - id: dot_notation_without_root 266 | status: open 267 | result: null 268 | - id: dot_notation_without_root_and_dot 269 | status: open 270 | result: null 271 | - id: empty 272 | status: open 273 | result: null 274 | - id: filter_expression_after_dot_notation_with_wildcard_after_recursive_descent 275 | status: error 276 | - id: filter_expression_after_recursive_descent 277 | status: open 278 | result: [2, 2, 2, 2, 2, [{"id": 2}, {"more": {"id": 2}}, {"id": {"id": 2}}, [{"id": 2}]], [{"id": 2}], {"more": {"id": 2}}] 279 | - id: filter_expression_on_object 280 | status: open 281 | result: [{"key": 1}] 282 | - id: filter_expression_with_addition 283 | status: open 284 | result: [{"key": 60}, {"key": 50}, {"key": 10}, {"key": -50}, {"key+50": 100}] 285 | - id: filter_expression_with_boolean_and_operator_and_value_false 286 | status: open 287 | result: [] 288 | - id: filter_expression_with_boolean_and_operator_and_value_true 289 | status: open 290 | result: [{"key": 1}, {"key": 3}] 291 | - id: filter_expression_with_boolean_or_operator_and_value_false 292 | status: open 293 | result: [{"key": 1}, {"key": 3}] 294 | - id: filter_expression_with_boolean_or_operator_and_value_true 295 | status: open 296 | result: [{"key": 1}, {"key": 3}, {"key": "nice"}, {"key": true}, {"key": null}, {"key": false}, {"key": {}}, {"key": []}, {"key": -1}, {"key": 0}, {"key": ""}] 297 | - id: filter_expression_with_bracket_notation 298 | status: error 299 | - id: filter_expression_with_bracket_notation_and_current_object_literal 300 | status: error 301 | - id: filter_expression_with_bracket_notation_with_-1 302 | status: open 303 | result: [null, null, null, null] 304 | - id: filter_expression_with_bracket_notation_with_number 305 | status: fail 306 | result: [null, null] 307 | - id: filter_expression_with_bracket_notation_with_number_on_object 308 | status: open 309 | result: [null, null] 310 | - id: filter_expression_with_current_object 311 | status: open 312 | result: ["some value", "value", 0, 1, -1, "", [], {}, false, true] 313 | - id: filter_expression_with_different_grouped_operators 314 | status: open 315 | result: [{"a": true, "b": true, "c": true}, {"a": true, "c": true}] 316 | - id: filter_expression_with_different_ungrouped_operators 317 | status: open 318 | result: [{"a": true, "b": true}, {"a": true, "b": true, "c": true}, {"a": true, "c": true}] 319 | - id: filter_expression_with_division 320 | status: open 321 | result: [{"key": 60}, {"key": 50}, {"key": 10}, {"key": -50}] 322 | - id: filter_expression_with_dot_notation_with_dash 323 | status: open 324 | result: [] 325 | - id: filter_expression_with_dot_notation_with_number 326 | status: open 327 | result: [] 328 | - id: filter_expression_with_dot_notation_with_number_on_array 329 | status: open 330 | result: [["first", "second", "third", "forth", "fifth"]] 331 | - id: filter_expression_with_empty_expression 332 | status: fail 333 | result: [] 334 | - id: filter_expression_with_equals 335 | status: open 336 | result: [{"key": null}, {"some": "value"}] 337 | - id: filter_expression_with_equals_array 338 | status: error 339 | - id: filter_expression_with_equals_array_for_array_slice_with_range_1 340 | status: error 341 | - id: filter_expression_with_equals_array_for_dot_notation_with_star 342 | status: error 343 | - id: filter_expression_with_equals_array_with_single_quotes 344 | status: error 345 | - id: filter_expression_with_equals_boolean_expression_value 346 | status: open 347 | result: [] 348 | - id: filter_expression_with_equals_false 349 | status: open 350 | result: [{"some": "some value"}, {"key": null}] 351 | - id: filter_expression_with_equals_null 352 | status: open 353 | result: [{"some": "some value"}, {"key": null}] 354 | - id: filter_expression_with_equals_number_for_array_slice_with_range_1 355 | status: error 356 | - id: filter_expression_with_equals_number_for_bracket_notation_with_star 357 | status: open 358 | result: [] 359 | - id: filter_expression_with_equals_number_for_dot_notation_with_star 360 | status: open 361 | result: [[1, 2], [2, 3], [1], [2], [1, 2, 3], 1, 2, 3] 362 | - id: filter_expression_with_equals_number_with_fraction 363 | status: open 364 | result: [] 365 | - id: filter_expression_with_equals_number_with_leading_zeros 366 | status: open 367 | result: [] 368 | - id: filter_expression_with_equals_object 369 | status: open 370 | result: [{"d": null}, "v"] 371 | - id: filter_expression_with_equals_on_array_of_numbers 372 | status: fail 373 | result: [null] 374 | - id: filter_expression_with_equals_on_object 375 | status: open 376 | result: [{"some": "value"}] 377 | - id: filter_expression_with_equals_on_object_with_key_matching_query 378 | status: open 379 | result: [2] 380 | - id: filter_expression_with_equals_string 381 | status: fail 382 | result: [{"key": null}, {"some": "value"}] 383 | - id: filter_expression_with_equals_string_in_NFC 384 | status: fail 385 | result: [] 386 | - id: filter_expression_with_equals_string_with_current_object_literal 387 | status: fail 388 | result: [] 389 | - id: filter_expression_with_equals_string_with_dot_literal 390 | status: fail 391 | result: [] 392 | - id: filter_expression_with_equals_string_with_single_quotes 393 | status: fail 394 | result: [] 395 | - id: filter_expression_with_equals_string_with_unicode_character_escape 396 | status: open 397 | result: [] 398 | - id: filter_expression_with_equals_true 399 | status: open 400 | result: [{"some": "some value"}, {"key": null}] 401 | - id: filter_expression_with_equals_with_path_and_path 402 | status: open 403 | result: [{"key2": 10}, {}, {"key1": null, "key2": null}, {"key1": null}, {"key2": null}, {"key2": 0}, {"key2": false}] 404 | - id: filter_expression_with_equals_with_root_reference 405 | status: open 406 | result: [{"key": 42}] 407 | - id: filter_expression_with_greater_than 408 | status: open 409 | result: [{"key": 43}, {"key": 42.0001}, {"key": 100}] 410 | - id: filter_expression_with_greater_than_or_equal 411 | status: open 412 | result: [{"key": 42}, {"key": 43}, {"key": 42.0001}, {"key": 100}] 413 | - id: filter_expression_with_in_array_of_values 414 | status: error 415 | - id: filter_expression_with_in_current_object 416 | status: open 417 | result: [] 418 | - id: filter_expression_with_less_than 419 | status: open 420 | result: [{"key": 0}, {"key": -1}, {"key": 41}, {"key": 41.9999}] 421 | - id: filter_expression_with_less_than_or_equal 422 | status: open 423 | result: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 41}, {"key": 41.9999}] 424 | - id: filter_expression_with_multiplication 425 | status: open 426 | result: [{"key": 60}, {"key": 50}, {"key": 10}, {"key": -50}, {"key*2": 100}] 427 | - id: filter_expression_with_negation_and_equals 428 | status: open 429 | result: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "43"}, {"key": "42"}, {"key": "41"}, {"key": "value"}, {"some": "value"}] 430 | - id: filter_expression_with_negation_and_less_than 431 | status: open 432 | result: [] 433 | - id: filter_expression_with_negation_and_without_value 434 | status: open 435 | result: [{"key": true}, {"key": false}, {"key": "value"}, {"key": ""}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": 42}, {"key": {}}, {"key": []}] 436 | - id: filter_expression_with_not_equals 437 | status: open 438 | result: [{"key": 0}, {"key": -1}, {"key": 1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "some"}, {"key": "42"}, {"key": null}, {"key": 420}, {"key": ""}, {"key": {}}, {"key": []}, {"key": [42]}, {"key": {"key": 42}}, {"key": {"some": 42}}, {"some": "value"}] 439 | - id: filter_expression_with_parent_axis_operator 440 | status: fail 441 | result: [] 442 | - id: filter_expression_with_regular_expression 443 | status: open 444 | result: [] 445 | - id: filter_expression_with_regular_expression_from_member 446 | status: open 447 | result: [{"pattern": "hello.*"}] 448 | - id: filter_expression_with_set_wise_comparison_to_scalar 449 | status: open 450 | result: [] 451 | - id: filter_expression_with_set_wise_comparison_to_set 452 | status: open 453 | result: [] 454 | - id: filter_expression_with_single_equal 455 | status: fail 456 | result: [{"key": 42}] 457 | - id: filter_expression_with_subfilter 458 | status: open 459 | result: [] 460 | - id: filter_expression_with_subpaths 461 | status: fail 462 | result: [] 463 | - id: filter_expression_with_subtraction 464 | status: open 465 | result: [{"key": 60}, {"key": 50}, {"key": 10}, {"key": -50}] 466 | - id: filter_expression_with_tautological_comparison 467 | status: open 468 | result: [] 469 | - id: filter_expression_with_triple_equal 470 | status: open 471 | result: [{"key": null}, {"some": "value"}] 472 | - id: filter_expression_with_value 473 | status: open 474 | result: [{"key": true}, {"key": false}, {"key": "value"}, {"key": ""}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": 42}, {"key": {}}, {"key": []}] 475 | - id: filter_expression_with_value_after_dot_notation_with_wildcard_on_array_of_objects 476 | status: open 477 | result: [] 478 | - id: filter_expression_with_value_after_recursive_descent 479 | status: open 480 | result: [{"id": 2}, {"id": 2}, {"id": 2}, {"id": 2}, {"id": {"id": 2}}] 481 | - id: filter_expression_with_value_false 482 | status: open 483 | result: [] 484 | - id: filter_expression_with_value_from_recursive_descent 485 | status: open 486 | result: [] 487 | - id: filter_expression_with_value_null 488 | status: open 489 | result: [] 490 | - id: filter_expression_with_value_true 491 | status: open 492 | result: [1, 3, "nice", true, null, false, {}, [], -1, 0, ""] 493 | - id: filter_expression_without_parens 494 | status: error 495 | - id: filter_expression_without_value 496 | status: open 497 | result: [{"key": true}, {"key": false}, {"key": "value"}, {"key": ""}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": 42}, {"key": {}}, {"key": []}] 498 | - id: function_sum 499 | status: open 500 | result: null 501 | - id: parens_notation 502 | status: fail 503 | result: null 504 | - id: recursive_descent 505 | status: open 506 | result: [0, 1, [0, 1], [{"a": {"b": "c"}}, [0, 1]], {"a": {"b": "c"}}, {"b": "c"}] 507 | - id: recursive_descent_after_dot_notation 508 | status: open 509 | result: [0, 1, [0, 1], {"complex": "string", "primitives": [0, 1]}] 510 | - id: script_expression 511 | status: error 512 | - id: union 513 | status: fail 514 | result: "first" 515 | - id: union_with_duplication_from_array 516 | status: fail 517 | result: "a" 518 | - id: union_with_duplication_from_object 519 | status: error 520 | - id: union_with_filter 521 | status: open 522 | result: [{"key": 1}, {"key": 2}] 523 | - id: union_with_keys 524 | status: error 525 | - id: union_with_keys_after_array_slice 526 | status: error 527 | - id: union_with_keys_after_bracket_notation 528 | status: error 529 | - id: union_with_keys_after_dot_notation_with_wildcard 530 | status: error 531 | - id: union_with_keys_after_recursive_descent 532 | status: error 533 | - id: union_with_keys_on_object_without_key 534 | status: error 535 | - id: union_with_numbers_in_decreasing_order 536 | status: fail 537 | result: 5 538 | - id: union_with_repeated_matches_after_dot_notation_with_wildcard 539 | status: open 540 | result: ["string", false] 541 | - id: union_with_slice_and_number 542 | status: open 543 | result: 2 544 | - id: union_with_spaces 545 | status: fail 546 | result: "first" 547 | - id: union_with_wildcard_and_number 548 | status: fail 549 | result: ["first", "second", "third", "forth", "fifth"] 550 | -------------------------------------------------------------------------------- /test/regression_suite.yaml: -------------------------------------------------------------------------------- 1 | # This file was generated by src/compile_regression_suite.sh from 2 | # https://github.com/cburgmer/json-path-comparison/ 3 | # You probably don't want to change this manually. 4 | 5 | # This file contains all queries implemented by the comparison and holds all 6 | # consensus results where such a consensus exist. 7 | # It can be used to track regressions in implementations. This file can be 8 | # complemented with the report specifically generated for each implementation. 9 | 10 | # If a query can possibly return only one element, the consensus calls out both 11 | # possible response types found in implementations: an array with one element 12 | # and just the element ("scalar-consensus"). 13 | # If a query has no match, the consensus calls out the specific NOT_FOUND 14 | # response as returned by some implementations ("not-found-consensus"). If this 15 | # coincides with a query that could possibly only return one match, it also 16 | # calls out that possible answer ("scalar-not-found-consensus"). 17 | # In all cases you should pick the response type that matches your 18 | # implementation. 19 | # 20 | # The consensus is not always a valid JSON document. In the case that the 21 | # consensus is that a query is not supported it will contain the string 22 | # "NOT_SUPPORTED". 23 | 24 | queries: 25 | - id: array_slice 26 | selector: "$[1:3]" 27 | document: ["first", "second", "third", "forth", "fifth"] 28 | consensus: ["second", "third"] 29 | - id: array_slice_on_exact_match 30 | selector: "$[0:5]" 31 | document: ["first", "second", "third", "forth", "fifth"] 32 | consensus: ["first", "second", "third", "forth", "fifth"] 33 | - id: array_slice_on_non_overlapping_array 34 | selector: "$[7:10]" 35 | document: ["first", "second", "third"] 36 | consensus: [] 37 | not-found-consensus: NOT_FOUND 38 | - id: array_slice_on_object 39 | selector: "$[1:3]" 40 | document: {":": 42, "more": "string", "a": 1, "b": 2, "c": 3, "1:3": "nice"} 41 | consensus: [] 42 | not-found-consensus: NOT_FOUND 43 | - id: array_slice_on_partially_overlapping_array 44 | selector: "$[1:10]" 45 | document: ["first", "second", "third"] 46 | consensus: ["second", "third"] 47 | - id: array_slice_with_large_number_for_end 48 | selector: "$[2:113667776004]" 49 | document: ["first", "second", "third", "forth", "fifth"] 50 | consensus: ["third", "forth", "fifth"] 51 | - id: array_slice_with_large_number_for_end_and_negative_step 52 | selector: "$[2:-113667776004:-1]" 53 | document: ["first", "second", "third", "forth", "fifth"] 54 | - id: array_slice_with_large_number_for_start 55 | selector: "$[-113667776004:2]" 56 | document: ["first", "second", "third", "forth", "fifth"] 57 | consensus: ["first", "second"] 58 | - id: array_slice_with_large_number_for_start_end_negative_step 59 | selector: "$[113667776004:2:-1]" 60 | document: ["first", "second", "third", "forth", "fifth"] 61 | - id: array_slice_with_negative_start_and_end_and_range_of_-1 62 | selector: "$[-4:-5]" 63 | document: [2, "a", 4, 5, 100, "nice"] 64 | consensus: [] 65 | not-found-consensus: NOT_FOUND 66 | - id: array_slice_with_negative_start_and_end_and_range_of_0 67 | selector: "$[-4:-4]" 68 | document: [2, "a", 4, 5, 100, "nice"] 69 | consensus: [] 70 | not-found-consensus: NOT_FOUND 71 | - id: array_slice_with_negative_start_and_end_and_range_of_1 72 | selector: "$[-4:-3]" 73 | document: [2, "a", 4, 5, 100, "nice"] 74 | consensus: [4] 75 | - id: array_slice_with_negative_start_and_positive_end_and_range_of_-1 76 | selector: "$[-4:1]" 77 | document: [2, "a", 4, 5, 100, "nice"] 78 | consensus: [] 79 | not-found-consensus: NOT_FOUND 80 | - id: array_slice_with_negative_start_and_positive_end_and_range_of_0 81 | selector: "$[-4:2]" 82 | document: [2, "a", 4, 5, 100, "nice"] 83 | consensus: [] 84 | not-found-consensus: NOT_FOUND 85 | - id: array_slice_with_negative_start_and_positive_end_and_range_of_1 86 | selector: "$[-4:3]" 87 | document: [2, "a", 4, 5, 100, "nice"] 88 | consensus: [4] 89 | - id: array_slice_with_negative_step 90 | selector: "$[3:0:-2]" 91 | document: ["first", "second", "third", "forth", "fifth"] 92 | - id: array_slice_with_negative_step_and_start_greater_than_end 93 | selector: "$[0:3:-2]" 94 | document: ["first", "second", "third", "forth", "fifth"] 95 | - id: array_slice_with_negative_step_on_partially_overlapping_array 96 | selector: "$[7:3:-1]" 97 | document: ["first", "second", "third", "forth", "fifth"] 98 | - id: array_slice_with_negative_step_only 99 | selector: "$[::-2]" 100 | document: ["first", "second", "third", "forth", "fifth"] 101 | - id: array_slice_with_open_end 102 | selector: "$[1:]" 103 | document: ["first", "second", "third", "forth", "fifth"] 104 | consensus: ["second", "third", "forth", "fifth"] 105 | - id: array_slice_with_open_end_and_negative_step 106 | selector: "$[3::-1]" 107 | document: ["first", "second", "third", "forth", "fifth"] 108 | - id: array_slice_with_open_start 109 | selector: "$[:2]" 110 | document: ["first", "second", "third", "forth", "fifth"] 111 | consensus: ["first", "second"] 112 | - id: array_slice_with_open_start_and_end 113 | selector: "$[:]" 114 | document: ["first", "second"] 115 | consensus: ["first", "second"] 116 | - id: array_slice_with_open_start_and_end_and_step_empty 117 | selector: "$[::]" 118 | document: ["first", "second"] 119 | consensus: ["first", "second"] 120 | - id: array_slice_with_open_start_and_end_on_object 121 | selector: "$[:]" 122 | document: {":": 42, "more": "string"} 123 | consensus: [] 124 | not-found-consensus: NOT_FOUND 125 | - id: array_slice_with_open_start_and_negative_step 126 | selector: "$[:2:-1]" 127 | document: ["first", "second", "third", "forth", "fifth"] 128 | - id: array_slice_with_positive_start_and_negative_end_and_range_of_-1 129 | selector: "$[3:-4]" 130 | document: [2, "a", 4, 5, 100, "nice"] 131 | consensus: [] 132 | not-found-consensus: NOT_FOUND 133 | - id: array_slice_with_positive_start_and_negative_end_and_range_of_0 134 | selector: "$[3:-3]" 135 | document: [2, "a", 4, 5, 100, "nice"] 136 | consensus: [] 137 | not-found-consensus: NOT_FOUND 138 | - id: array_slice_with_positive_start_and_negative_end_and_range_of_1 139 | selector: "$[3:-2]" 140 | document: [2, "a", 4, 5, 100, "nice"] 141 | consensus: [5] 142 | - id: array_slice_with_range_of_-1 143 | selector: "$[2:1]" 144 | document: ["first", "second", "third", "forth"] 145 | consensus: [] 146 | not-found-consensus: NOT_FOUND 147 | - id: array_slice_with_range_of_0 148 | selector: "$[0:0]" 149 | document: ["first", "second"] 150 | consensus: [] 151 | not-found-consensus: NOT_FOUND 152 | - id: array_slice_with_range_of_1 153 | selector: "$[0:1]" 154 | document: ["first", "second"] 155 | consensus: ["first"] 156 | - id: array_slice_with_start_-1_and_open_end 157 | selector: "$[-1:]" 158 | document: ["first", "second", "third"] 159 | consensus: ["third"] 160 | - id: array_slice_with_start_-2_and_open_end 161 | selector: "$[-2:]" 162 | document: ["first", "second", "third"] 163 | consensus: ["second", "third"] 164 | - id: array_slice_with_start_large_negative_number_and_open_end_on_short_array 165 | selector: "$[-4:]" 166 | document: ["first", "second", "third"] 167 | consensus: ["first", "second", "third"] 168 | - id: array_slice_with_step 169 | selector: "$[0:3:2]" 170 | document: ["first", "second", "third", "forth", "fifth"] 171 | consensus: ["first", "third"] 172 | - id: array_slice_with_step_0 173 | selector: "$[0:3:0]" 174 | document: ["first", "second", "third", "forth", "fifth"] 175 | - id: array_slice_with_step_1 176 | selector: "$[0:3:1]" 177 | document: ["first", "second", "third", "forth", "fifth"] 178 | consensus: ["first", "second", "third"] 179 | - id: array_slice_with_step_and_leading_zeros 180 | selector: "$[010:024:010]" 181 | document: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] 182 | consensus: [10, 20] 183 | - id: array_slice_with_step_but_end_not_aligned 184 | selector: "$[0:4:2]" 185 | document: ["first", "second", "third", "forth", "fifth"] 186 | consensus: ["first", "third"] 187 | - id: array_slice_with_step_empty 188 | selector: "$[1:3:]" 189 | document: ["first", "second", "third", "forth", "fifth"] 190 | consensus: ["second", "third"] 191 | - id: array_slice_with_step_only 192 | selector: "$[::2]" 193 | document: ["first", "second", "third", "forth", "fifth"] 194 | consensus: ["first", "third", "fifth"] 195 | - id: bracket_notation 196 | selector: "$['key']" 197 | document: {"key": "value"} 198 | consensus: ["value"] 199 | scalar-consensus: "value" 200 | - id: bracket_notation_after_recursive_descent 201 | selector: "$..[0]" 202 | document: ["first", {"key": ["first nested", {"more": [{"nested": ["deepest", "second"]}, ["more", "values"]]}]}] 203 | ordered: false 204 | consensus: ["deepest", "first nested", "first", "more", {"nested": ["deepest", "second"]}] 205 | - id: bracket_notation_on_object_without_key 206 | selector: "$['missing']" 207 | document: {"key": "value"} 208 | consensus: [] 209 | scalar-consensus: null 210 | not-found-consensus: NOT_FOUND 211 | scalar-not-found-consensus: NOT_FOUND 212 | - id: bracket_notation_with_NFC_path_on_NFD_key 213 | selector: "$['ü']" 214 | document: {"u\u0308": 42} 215 | consensus: [] 216 | scalar-consensus: null 217 | not-found-consensus: NOT_FOUND 218 | scalar-not-found-consensus: NOT_FOUND 219 | - id: bracket_notation_with_dot 220 | selector: "$['two.some']" 221 | document: {"one": {"key": "value"}, "two": {"some": "more", "key": "other value"}, "two.some": "42"} 222 | consensus: ["42"] 223 | scalar-consensus: "42" 224 | - id: bracket_notation_with_double_quotes 225 | selector: "$[\"key\"]" 226 | document: {"key": "value"} 227 | consensus: ["value"] 228 | scalar-consensus: "value" 229 | - id: bracket_notation_with_empty_path 230 | selector: "$[]" 231 | document: {"": 42, "''": 123, "\"\"": 222} 232 | consensus: NOT_SUPPORTED 233 | - id: bracket_notation_with_empty_string 234 | selector: "$['']" 235 | document: {"": 42, "''": 123, "\"\"": 222} 236 | consensus: [42] 237 | scalar-consensus: 42 238 | - id: bracket_notation_with_empty_string_doubled_quoted 239 | selector: "$[\"\"]" 240 | document: {"": 42, "''": 123, "\"\"": 222} 241 | consensus: [42] 242 | scalar-consensus: 42 243 | - id: bracket_notation_with_negative_number_on_short_array 244 | selector: "$[-2]" 245 | document: ["one element"] 246 | consensus: [] 247 | scalar-consensus: null 248 | not-found-consensus: NOT_FOUND 249 | scalar-not-found-consensus: NOT_FOUND 250 | - id: bracket_notation_with_number 251 | selector: "$[2]" 252 | document: ["first", "second", "third", "forth", "fifth"] 253 | consensus: ["third"] 254 | scalar-consensus: "third" 255 | - id: bracket_notation_with_number_-1 256 | selector: "$[-1]" 257 | document: ["first", "second", "third"] 258 | consensus: ["third"] 259 | scalar-consensus: "third" 260 | - id: bracket_notation_with_number_-1_on_empty_array 261 | selector: "$[-1]" 262 | document: [] 263 | consensus: [] 264 | scalar-consensus: null 265 | not-found-consensus: NOT_FOUND 266 | scalar-not-found-consensus: NOT_FOUND 267 | - id: bracket_notation_with_number_0 268 | selector: "$[0]" 269 | document: ["first", "second", "third", "forth", "fifth"] 270 | consensus: ["first"] 271 | scalar-consensus: "first" 272 | - id: bracket_notation_with_number_after_dot_notation_with_wildcard_on_nested_arrays_with_different_length 273 | selector: "$.*[1]" 274 | document: [[1], [2, 3]] 275 | consensus: [3] 276 | - id: bracket_notation_with_number_on_object 277 | selector: "$[0]" 278 | document: {"0": "value"} 279 | consensus: [] 280 | scalar-consensus: null 281 | not-found-consensus: NOT_FOUND 282 | scalar-not-found-consensus: NOT_FOUND 283 | - id: bracket_notation_with_number_on_short_array 284 | selector: "$[1]" 285 | document: ["one element"] 286 | consensus: [] 287 | scalar-consensus: null 288 | not-found-consensus: NOT_FOUND 289 | scalar-not-found-consensus: NOT_FOUND 290 | - id: bracket_notation_with_number_on_string 291 | selector: "$[0]" 292 | document: "Hello World" 293 | consensus: [] 294 | scalar-consensus: null 295 | not-found-consensus: NOT_FOUND 296 | scalar-not-found-consensus: NOT_FOUND 297 | - id: bracket_notation_with_quoted_array_slice_literal 298 | selector: "$[':']" 299 | document: {":": "value", "another": "entry"} 300 | consensus: ["value"] 301 | scalar-consensus: "value" 302 | - id: bracket_notation_with_quoted_closing_bracket_literal 303 | selector: "$[']']" 304 | document: {"]": 42} 305 | consensus: [42] 306 | scalar-consensus: 42 307 | - id: bracket_notation_with_quoted_current_object_literal 308 | selector: "$['@']" 309 | document: {"@": "value", "another": "entry"} 310 | consensus: ["value"] 311 | scalar-consensus: "value" 312 | - id: bracket_notation_with_quoted_dot_literal 313 | selector: "$['.']" 314 | document: {".": "value", "another": "entry"} 315 | consensus: ["value"] 316 | scalar-consensus: "value" 317 | - id: bracket_notation_with_quoted_dot_wildcard 318 | selector: "$['.*']" 319 | document: {"key": 42, ".*": 1, "": 10} 320 | consensus: [1] 321 | scalar-consensus: 1 322 | - id: bracket_notation_with_quoted_double_quote_literal 323 | selector: "$['\"']" 324 | document: {"\"": "value", "another": "entry"} 325 | consensus: ["value"] 326 | scalar-consensus: "value" 327 | - id: bracket_notation_with_quoted_escaped_backslash 328 | selector: "$['\\\\']" 329 | document: {"\\": "value"} 330 | - id: bracket_notation_with_quoted_escaped_single_quote 331 | selector: "$['\\'']" 332 | document: {"'": "value"} 333 | - id: bracket_notation_with_quoted_number_on_object 334 | selector: "$['0']" 335 | document: {"0": "value"} 336 | consensus: ["value"] 337 | scalar-consensus: "value" 338 | - id: bracket_notation_with_quoted_root_literal 339 | selector: "$['$']" 340 | document: {"$": "value", "another": "entry"} 341 | consensus: ["value"] 342 | scalar-consensus: "value" 343 | - id: bracket_notation_with_quoted_special_characters_combined 344 | selector: "$[':@.\"$,*\\'\\\\']" 345 | document: {":@.\"$,*'\\": 42} 346 | - id: bracket_notation_with_quoted_string_and_unescaped_single_quote 347 | selector: "$['single'quote']" 348 | document: {"single'quote": "value"} 349 | consensus: NOT_SUPPORTED 350 | - id: bracket_notation_with_quoted_union_literal 351 | selector: "$[',']" 352 | document: {",": "value", "another": "entry"} 353 | consensus: ["value"] 354 | scalar-consensus: "value" 355 | - id: bracket_notation_with_quoted_wildcard_literal 356 | selector: "$['*']" 357 | document: {"*": "value", "another": "entry"} 358 | ordered: false 359 | consensus: ["value"] 360 | scalar-consensus: "value" 361 | - id: bracket_notation_with_quoted_wildcard_literal_on_object_without_key 362 | selector: "$['*']" 363 | document: {"another": "entry"} 364 | consensus: [] 365 | scalar-consensus: null 366 | not-found-consensus: NOT_FOUND 367 | scalar-not-found-consensus: NOT_FOUND 368 | - id: bracket_notation_with_spaces 369 | selector: "$[ 'a' ]" 370 | document: {" a": 1, "a": 2, " a ": 3, "a ": 4, " 'a' ": 5, " 'a": 6, "a' ": 7, " \"a\" ": 8, "\"a\"": 9} 371 | consensus: [2] 372 | scalar-consensus: 2 373 | - id: bracket_notation_with_string_including_dot_wildcard 374 | selector: "$['ni.*']" 375 | document: {"nice": 42, "ni.*": 1, "mice": 100} 376 | consensus: [1] 377 | scalar-consensus: 1 378 | - id: bracket_notation_with_two_literals_separated_by_dot 379 | selector: "$['two'.'some']" 380 | document: {"one": {"key": "value"}, "two": {"some": "more", "key": "other value"}, "two.some": "42", "two'.'some": "43"} 381 | consensus: NOT_SUPPORTED 382 | - id: bracket_notation_with_two_literals_separated_by_dot_without_quotes 383 | selector: "$[two.some]" 384 | document: {"one": {"key": "value"}, "two": {"some": "more", "key": "other value"}, "two.some": "42"} 385 | consensus: NOT_SUPPORTED 386 | - id: bracket_notation_with_wildcard_after_array_slice 387 | selector: "$[0:2][*]" 388 | document: [[1, 2], ["a", "b"], [0, 0]] 389 | consensus: [1, 2, "a", "b"] 390 | - id: bracket_notation_with_wildcard_after_dot_notation_after_bracket_notation_with_wildcard 391 | selector: "$[*].bar[*]" 392 | document: [{"bar": [42]}] 393 | consensus: [42] 394 | - id: bracket_notation_with_wildcard_after_recursive_descent 395 | selector: "$..[*]" 396 | document: {"key": "value", "another key": {"complex": "string", "primitives": [0, 1]}} 397 | ordered: false 398 | consensus: ["string", "value", 0, 1, [0, 1], {"complex": "string", "primitives": [0, 1]}] 399 | - id: bracket_notation_with_wildcard_on_array 400 | selector: "$[*]" 401 | document: ["string", 42, {"key": "value"}, [0, 1]] 402 | consensus: ["string", 42, {"key": "value"}, [0, 1]] 403 | - id: bracket_notation_with_wildcard_on_empty_array 404 | selector: "$[*]" 405 | document: [] 406 | consensus: [] 407 | not-found-consensus: NOT_FOUND 408 | - id: bracket_notation_with_wildcard_on_empty_object 409 | selector: "$[*]" 410 | document: {} 411 | consensus: [] 412 | not-found-consensus: NOT_FOUND 413 | - id: bracket_notation_with_wildcard_on_null_value_array 414 | selector: "$[*]" 415 | document: [40, null, 42] 416 | consensus: [40, null, 42] 417 | - id: bracket_notation_with_wildcard_on_object 418 | selector: "$[*]" 419 | document: {"some": "string", "int": 42, "object": {"key": "value"}, "array": [0, 1]} 420 | ordered: false 421 | consensus: ["string", 42, [0, 1], {"key": "value"}] 422 | - id: bracket_notation_without_quotes 423 | selector: "$[key]" 424 | document: {"key": "value"} 425 | consensus: NOT_SUPPORTED 426 | - id: current_with_dot_notation 427 | selector: "@.a" 428 | document: {"a": 1} 429 | - id: dot_bracket_notation 430 | selector: "$.['key']" 431 | document: {"key": "value", "other": {"key": [{"key": 42}]}} 432 | - id: dot_bracket_notation_with_double_quotes 433 | selector: "$.[\"key\"]" 434 | document: {"key": "value", "other": {"key": [{"key": 42}]}} 435 | - id: dot_bracket_notation_without_quotes 436 | selector: "$.[key]" 437 | document: {"key": "value", "other": {"key": [{"key": 42}]}} 438 | consensus: NOT_SUPPORTED 439 | - id: dot_notation 440 | selector: "$.key" 441 | document: {"key": "value"} 442 | consensus: ["value"] 443 | scalar-consensus: "value" 444 | - id: dot_notation_after_array_slice 445 | selector: "$[0:2].key" 446 | document: [{"key": "ey"}, {"key": "bee"}, {"key": "see"}] 447 | consensus: ["ey", "bee"] 448 | - id: dot_notation_after_bracket_notation_after_recursive_descent 449 | selector: "$..[1].key" 450 | document: {"k": [{"key": "some value"}, {"key": 42}], "kk": [[{"key": 100}, {"key": 200}, {"key": 300}], [{"key": 400}, {"key": 500}, {"key": 600}]], "key": [0, 1]} 451 | ordered: false 452 | consensus: [200, 42, 500] 453 | - id: dot_notation_after_bracket_notation_with_wildcard 454 | selector: "$[*].a" 455 | document: [{"a": 1}, {"a": 1}] 456 | consensus: [1, 1] 457 | - id: dot_notation_after_bracket_notation_with_wildcard_on_one_matching 458 | selector: "$[*].a" 459 | document: [{"a": 1}] 460 | consensus: [1] 461 | - id: dot_notation_after_bracket_notation_with_wildcard_on_some_matching 462 | selector: "$[*].a" 463 | document: [{"a": 1}, {"b": 1}] 464 | consensus: [1] 465 | - id: dot_notation_after_filter_expression 466 | selector: "$[?(@.id==42)].name" 467 | document: [{"id": 42, "name": "forty-two"}, {"id": 1, "name": "one"}] 468 | consensus: ["forty-two"] 469 | - id: dot_notation_after_recursive_descent 470 | selector: "$..key" 471 | document: {"object": {"key": "value", "array": [{"key": "something"}, {"key": {"key": "russian dolls"}}]}, "key": "top"} 472 | ordered: false 473 | consensus: ["russian dolls", "something", "top", "value", {"key": "russian dolls"}] 474 | - id: dot_notation_after_recursive_descent_after_dot_notation 475 | selector: "$.store..price" 476 | document: {"store": {"book": [{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99}], "bicycle": {"color": "red", "price": 19.95}}} 477 | ordered: false 478 | consensus: [12.99, 19.95, 22.99, 8.95, 8.99] 479 | - id: dot_notation_after_recursive_descent_with_extra_dot 480 | selector: "$...key" 481 | document: {"object": {"key": "value", "array": [{"key": "something"}, {"key": {"key": "russian dolls"}}]}, "key": "top"} 482 | ordered: false 483 | - id: dot_notation_after_union 484 | selector: "$[0,2].key" 485 | document: [{"key": "ey"}, {"key": "bee"}, {"key": "see"}] 486 | consensus: ["ey", "see"] 487 | - id: dot_notation_after_union_with_keys 488 | selector: "$['one','three'].key" 489 | document: {"one": {"key": "value"}, "two": {"k": "v"}, "three": {"some": "more", "key": "other value"}} 490 | consensus: ["value", "other value"] 491 | - id: dot_notation_on_array 492 | selector: "$.key" 493 | document: [0, 1] 494 | consensus: [] 495 | scalar-consensus: null 496 | not-found-consensus: NOT_FOUND 497 | scalar-not-found-consensus: NOT_FOUND 498 | - id: dot_notation_on_array_value 499 | selector: "$.key" 500 | document: {"key": ["first", "second"]} 501 | consensus: [["first", "second"]] 502 | scalar-consensus: ["first", "second"] 503 | - id: dot_notation_on_array_with_containing_object_matching_key 504 | selector: "$.id" 505 | document: [{"id": 2}] 506 | consensus: [] 507 | scalar-consensus: null 508 | not-found-consensus: NOT_FOUND 509 | scalar-not-found-consensus: NOT_FOUND 510 | - id: dot_notation_on_empty_object_value 511 | selector: "$.key" 512 | document: {"key": {}} 513 | consensus: [{}] 514 | scalar-consensus: {} 515 | - id: dot_notation_on_null_value 516 | selector: "$.key" 517 | document: {"key": null} 518 | consensus: [null] 519 | scalar-consensus: null 520 | - id: dot_notation_on_object_without_key 521 | selector: "$.missing" 522 | document: {"key": "value"} 523 | consensus: [] 524 | scalar-consensus: null 525 | not-found-consensus: NOT_FOUND 526 | scalar-not-found-consensus: NOT_FOUND 527 | - id: dot_notation_with_dash 528 | selector: "$.key-dash" 529 | document: {"key": 42, "key-": 43, "-": 44, "dash": 45, "-dash": 46, "": 47, "key-dash": "value", "something": "else"} 530 | consensus: ["value"] 531 | scalar-consensus: "value" 532 | - id: dot_notation_with_double_quotes 533 | selector: "$.\"key\"" 534 | document: {"key": "value", "\"key\"": 42} 535 | - id: dot_notation_with_double_quotes_after_recursive_descent 536 | selector: "$..\"key\"" 537 | document: {"object": {"key": "value", "\"key\"": 100, "array": [{"key": "something", "\"key\"": 0}, {"key": {"key": "russian dolls"}, "\"key\"": {"\"key\"": 99}}]}, "key": "top", "\"key\"": 42} 538 | ordered: false 539 | - id: dot_notation_with_empty_path 540 | selector: "$." 541 | document: {"key": 42, "": 9001, "''": "nice"} 542 | consensus: NOT_SUPPORTED 543 | - id: dot_notation_with_key_named_in 544 | selector: "$.in" 545 | document: {"in": "value"} 546 | consensus: ["value"] 547 | scalar-consensus: "value" 548 | - id: dot_notation_with_key_named_length 549 | selector: "$.length" 550 | document: {"length": "value"} 551 | consensus: ["value"] 552 | scalar-consensus: "value" 553 | - id: dot_notation_with_key_named_length_on_array 554 | selector: "$.length" 555 | document: [4, 5, 6] 556 | consensus: [] 557 | scalar-consensus: null 558 | not-found-consensus: NOT_FOUND 559 | scalar-not-found-consensus: NOT_FOUND 560 | - id: dot_notation_with_key_named_null 561 | selector: "$.null" 562 | document: {"null": "value"} 563 | consensus: ["value"] 564 | scalar-consensus: "value" 565 | - id: dot_notation_with_key_named_true 566 | selector: "$.true" 567 | document: {"true": "value"} 568 | consensus: ["value"] 569 | scalar-consensus: "value" 570 | - id: dot_notation_with_key_root_literal 571 | selector: "$.$" 572 | document: {"$": "value"} 573 | - id: dot_notation_with_non_ASCII_key 574 | selector: "$.屬性" 575 | document: {"\u5c6c\u6027": "value"} 576 | consensus: ["value"] 577 | scalar-consensus: "value" 578 | - id: dot_notation_with_number 579 | selector: "$.2" 580 | document: ["first", "second", "third", "forth", "fifth"] 581 | - id: dot_notation_with_number_-1 582 | selector: "$.-1" 583 | document: ["first", "second", "third", "forth", "fifth"] 584 | consensus: [] 585 | scalar-consensus: null 586 | not-found-consensus: NOT_FOUND 587 | scalar-not-found-consensus: NOT_FOUND 588 | - id: dot_notation_with_number_on_object 589 | selector: "$.2" 590 | document: {"a": "first", "2": "second", "b": "third"} 591 | consensus: ["second"] 592 | scalar-consensus: "second" 593 | - id: dot_notation_with_single_quotes 594 | selector: "$.'key'" 595 | document: {"key": "value", "'key'": 42} 596 | - id: dot_notation_with_single_quotes_after_recursive_descent 597 | selector: "$..'key'" 598 | document: {"object": {"key": "value", "'key'": 100, "array": [{"key": "something", "'key'": 0}, {"key": {"key": "russian dolls"}, "'key'": {"'key'": 99}}]}, "key": "top", "'key'": 42} 599 | ordered: false 600 | - id: dot_notation_with_single_quotes_and_dot 601 | selector: "$.'some.key'" 602 | document: {"some.key": 42, "some": {"key": "value"}, "'some.key'": 43} 603 | - id: dot_notation_with_space_padded_key 604 | selector: "$. a " 605 | document: {" a": 1, "a": 2, " a ": 3, "": 4} 606 | - id: dot_notation_with_wildcard_after_dot_notation_after_dot_notation_with_wildcard 607 | selector: "$.*.bar.*" 608 | document: [{"bar": [42]}] 609 | consensus: [42] 610 | - id: dot_notation_with_wildcard_after_dot_notation_with_wildcard_on_nested_arrays 611 | selector: "$.*.*" 612 | document: [[1, 2, 3], [4, 5, 6]] 613 | consensus: [1, 2, 3, 4, 5, 6] 614 | - id: dot_notation_with_wildcard_after_recursive_descent 615 | selector: "$..*" 616 | document: {"key": "value", "another key": {"complex": "string", "primitives": [0, 1]}} 617 | ordered: false 618 | consensus: ["string", "value", 0, 1, [0, 1], {"complex": "string", "primitives": [0, 1]}] 619 | - id: dot_notation_with_wildcard_after_recursive_descent_on_null_value_array 620 | selector: "$..*" 621 | document: [40, null, 42] 622 | ordered: false 623 | consensus: [40, 42, null] 624 | - id: dot_notation_with_wildcard_after_recursive_descent_on_scalar 625 | selector: "$..*" 626 | document: 42 627 | ordered: false 628 | consensus: [] 629 | not-found-consensus: NOT_FOUND 630 | - id: dot_notation_with_wildcard_on_array 631 | selector: "$.*" 632 | document: ["string", 42, {"key": "value"}, [0, 1]] 633 | consensus: ["string", 42, {"key": "value"}, [0, 1]] 634 | - id: dot_notation_with_wildcard_on_empty_array 635 | selector: "$.*" 636 | document: [] 637 | consensus: [] 638 | not-found-consensus: NOT_FOUND 639 | - id: dot_notation_with_wildcard_on_empty_object 640 | selector: "$.*" 641 | document: {} 642 | consensus: [] 643 | not-found-consensus: NOT_FOUND 644 | - id: dot_notation_with_wildcard_on_object 645 | selector: "$.*" 646 | document: {"some": "string", "int": 42, "object": {"key": "value"}, "array": [0, 1]} 647 | ordered: false 648 | consensus: ["string", 42, [0, 1], {"key": "value"}] 649 | - id: dot_notation_without_dot 650 | selector: "$a" 651 | document: {"a": 1, "$a": 2} 652 | consensus: NOT_SUPPORTED 653 | - id: dot_notation_without_root 654 | selector: ".key" 655 | document: {"key": "value"} 656 | - id: dot_notation_without_root_and_dot 657 | selector: "key" 658 | document: {"key": "value"} 659 | - id: empty 660 | selector: "" 661 | document: {"a": 42, "": 21} 662 | - id: filter_expression_after_dot_notation_with_wildcard_after_recursive_descent 663 | selector: "$..*[?(@.id>2)]" 664 | document: [{"complext": {"one": [{"name": "first", "id": 1}, {"name": "next", "id": 2}, {"name": "another", "id": 3}, {"name": "more", "id": 4}], "more": {"name": "next to last", "id": 5}}}, {"name": "last", "id": 6}] 665 | ordered: false 666 | - id: filter_expression_after_recursive_descent 667 | selector: "$..[?(@.id==2)]" 668 | document: {"id": 2, "more": [{"id": 2}, {"more": {"id": 2}}, {"id": {"id": 2}}, [{"id": 2}]]} 669 | ordered: false 670 | - id: filter_expression_on_object 671 | selector: "$[?(@.key)]" 672 | document: {"key": 42, "another": {"key": 1}} 673 | - id: filter_expression_with_addition 674 | selector: "$[?(@.key+50==100)]" 675 | document: [{"key": 60}, {"key": 50}, {"key": 10}, {"key": -50}, {"key+50": 100}] 676 | - id: filter_expression_with_boolean_and_operator 677 | selector: "$[?(@.key>42 && @.key<44)]" 678 | document: [{"key": 42}, {"key": 43}, {"key": 44}] 679 | consensus: [{"key": 43}] 680 | - id: filter_expression_with_boolean_and_operator_and_value_false 681 | selector: "$[?(@.key>0 && false)]" 682 | document: [{"key": 1}, {"key": 3}, {"key": "nice"}, {"key": true}, {"key": null}, {"key": false}, {"key": {}}, {"key": []}, {"key": -1}, {"key": 0}, {"key": ""}] 683 | - id: filter_expression_with_boolean_and_operator_and_value_true 684 | selector: "$[?(@.key>0 && true)]" 685 | document: [{"key": 1}, {"key": 3}, {"key": "nice"}, {"key": true}, {"key": null}, {"key": false}, {"key": {}}, {"key": []}, {"key": -1}, {"key": 0}, {"key": ""}] 686 | - id: filter_expression_with_boolean_or_operator 687 | selector: "$[?(@.key>43 || @.key<43)]" 688 | document: [{"key": 42}, {"key": 43}, {"key": 44}] 689 | consensus: [{"key": 42}, {"key": 44}] 690 | - id: filter_expression_with_boolean_or_operator_and_value_false 691 | selector: "$[?(@.key>0 || false)]" 692 | document: [{"key": 1}, {"key": 3}, {"key": "nice"}, {"key": true}, {"key": null}, {"key": false}, {"key": {}}, {"key": []}, {"key": -1}, {"key": 0}, {"key": ""}] 693 | - id: filter_expression_with_boolean_or_operator_and_value_true 694 | selector: "$[?(@.key>0 || true)]" 695 | document: [{"key": 1}, {"key": 3}, {"key": "nice"}, {"key": true}, {"key": null}, {"key": false}, {"key": {}}, {"key": []}, {"key": -1}, {"key": 0}, {"key": ""}] 696 | - id: filter_expression_with_bracket_notation 697 | selector: "$[?(@['key']==42)]" 698 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"some": "value"}] 699 | consensus: [{"key": 42}] 700 | - id: filter_expression_with_bracket_notation_and_current_object_literal 701 | selector: "$[?(@['@key']==42)]" 702 | document: [{"@key": 0}, {"@key": 42}, {"key": 42}, {"@key": 43}, {"some": "value"}] 703 | consensus: [{"@key": 42}] 704 | - id: filter_expression_with_bracket_notation_with_-1 705 | selector: "$[?(@[-1]==2)]" 706 | document: [[2, 3], ["a"], [0, 2], [2]] 707 | - id: filter_expression_with_bracket_notation_with_number 708 | selector: "$[?(@[1]=='b')]" 709 | document: [["a", "b"], ["x", "y"]] 710 | consensus: [["a", "b"]] 711 | - id: filter_expression_with_bracket_notation_with_number_on_object 712 | selector: "$[?(@[1]=='b')]" 713 | document: {"1": ["a", "b"], "2": ["x", "y"]} 714 | - id: filter_expression_with_current_object 715 | selector: "$[?(@)]" 716 | document: ["some value", null, "value", 0, 1, -1, "", [], {}, false, true] 717 | - id: filter_expression_with_different_grouped_operators 718 | selector: "$[?(@.a && (@.b || @.c))]" 719 | document: [{"a": true}, {"a": true, "b": true}, {"a": true, "b": true, "c": true}, {"b": true, "c": true}, {"a": true, "c": true}, {"c": true}, {"b": true}] 720 | - id: filter_expression_with_different_ungrouped_operators 721 | selector: "$[?(@.a && @.b || @.c)]" 722 | document: [{"a": true, "b": true}, {"a": true, "b": true, "c": true}, {"b": true, "c": true}, {"a": true, "c": true}, {"a": true}, {"b": true}, {"c": true}, {"d": true}, {}] 723 | - id: filter_expression_with_division 724 | selector: "$[?(@.key/10==5)]" 725 | document: [{"key": 60}, {"key": 50}, {"key": 10}, {"key": -50}, {"key/10": 5}] 726 | - id: filter_expression_with_dot_notation_with_dash 727 | selector: "$[?(@.key-dash == 'value')]" 728 | document: [{"key-dash": "value"}] 729 | - id: filter_expression_with_dot_notation_with_number 730 | selector: "$[?(@.2 == 'second')]" 731 | document: [{"a": "first", "2": "second", "b": "third"}] 732 | - id: filter_expression_with_dot_notation_with_number_on_array 733 | selector: "$[?(@.2 == 'third')]" 734 | document: [["first", "second", "third", "forth", "fifth"]] 735 | - id: filter_expression_with_empty_expression 736 | selector: "$[?()]" 737 | document: [1, {"key": 42}, "value", null] 738 | consensus: NOT_SUPPORTED 739 | - id: filter_expression_with_equals 740 | selector: "$[?(@.key==42)]" 741 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "some"}, {"key": "42"}, {"key": null}, {"key": 420}, {"key": ""}, {"key": {}}, {"key": []}, {"key": [42]}, {"key": {"key": 42}}, {"key": {"some": 42}}, {"some": "value"}] 742 | - id: filter_expression_with_equals_array 743 | selector: "$[?(@.d==[\"v1\",\"v2\"])]" 744 | document: [{"d": ["v1", "v2"]}, {"d": ["a", "b"]}, {"d": "v1"}, {"d": "v2"}, {"d": {}}, {"d": []}, {"d": null}, {"d": -1}, {"d": 0}, {"d": 1}, {"d": "['v1','v2']"}, {"d": "['v1', 'v2']"}, {"d": "v1,v2"}, {"d": "[\"v1\", \"v2\"]"}, {"d": "[\"v1\",\"v2\"]"}] 745 | - id: filter_expression_with_equals_array_for_array_slice_with_range_1 746 | selector: "$[?(@[0:1]==[1])]" 747 | document: [[1, 2, 3], [1], [2, 3], 1, 2] 748 | - id: filter_expression_with_equals_array_for_dot_notation_with_star 749 | selector: "$[?(@.*==[1,2])]" 750 | document: [[1, 2], [2, 3], [1], [2], [1, 2, 3], 1, 2, 3] 751 | - id: filter_expression_with_equals_array_with_single_quotes 752 | selector: "$[?(@.d==['v1','v2'])]" 753 | document: [{"d": ["v1", "v2"]}, {"d": ["a", "b"]}, {"d": "v1"}, {"d": "v2"}, {"d": {}}, {"d": []}, {"d": null}, {"d": -1}, {"d": 0}, {"d": 1}, {"d": "['v1','v2']"}, {"d": "['v1', 'v2']"}, {"d": "v1,v2"}, {"d": "[\"v1\", \"v2\"]"}, {"d": "[\"v1\",\"v2\"]"}] 754 | - id: filter_expression_with_equals_boolean_expression_value 755 | selector: "$[?((@.key<44)==false)]" 756 | document: [{"key": 42}, {"key": 43}, {"key": 44}] 757 | - id: filter_expression_with_equals_false 758 | selector: "$[?(@.key==false)]" 759 | document: [{"some": "some value"}, {"key": true}, {"key": false}, {"key": null}, {"key": "value"}, {"key": ""}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": 42}, {"key": {}}, {"key": []}] 760 | - id: filter_expression_with_equals_null 761 | selector: "$[?(@.key==null)]" 762 | document: [{"some": "some value"}, {"key": true}, {"key": false}, {"key": null}, {"key": "value"}, {"key": ""}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": 42}, {"key": {}}, {"key": []}] 763 | - id: filter_expression_with_equals_number_for_array_slice_with_range_1 764 | selector: "$[?(@[0:1]==1)]" 765 | document: [[1, 2, 3], [1], [2, 3], 1, 2] 766 | - id: filter_expression_with_equals_number_for_bracket_notation_with_star 767 | selector: "$[?(@[*]==2)]" 768 | document: [[1, 2], [2, 3], [1], [2], [1, 2, 3], 1, 2, 3] 769 | - id: filter_expression_with_equals_number_for_dot_notation_with_star 770 | selector: "$[?(@.*==2)]" 771 | document: [[1, 2], [2, 3], [1], [2], [1, 2, 3], 1, 2, 3] 772 | - id: filter_expression_with_equals_number_with_fraction 773 | selector: "$[?(@.key==-0.123e2)]" 774 | document: [{"key": -12.3}, {"key": -0.123}, {"key": -12}, {"key": 12.3}, {"key": 2}, {"key": "-0.123e2"}] 775 | - id: filter_expression_with_equals_number_with_leading_zeros 776 | selector: "$[?(@.key==010)]" 777 | document: [{"key": "010"}, {"key": "10"}, {"key": 10}, {"key": 0}, {"key": 8}] 778 | - id: filter_expression_with_equals_object 779 | selector: "$[?(@.d=={\"k\":\"v\"})]" 780 | document: [{"d": {"k": "v"}}, {"d": {"a": "b"}}, {"d": "k"}, {"d": "v"}, {"d": {}}, {"d": []}, {"d": null}, {"d": -1}, {"d": 0}, {"d": 1}, {"d": "[object Object]"}, {"d": "{\"k\": \"v\"}"}, {"d": "{\"k\":\"v\"}"}, "v"] 781 | - id: filter_expression_with_equals_on_array_of_numbers 782 | selector: "$[?(@==42)]" 783 | document: [0, 42, -1, 41, 43, 42.0001, 41.9999, null, 100] 784 | consensus: [42] 785 | - id: filter_expression_with_equals_on_array_without_match 786 | selector: "$[?(@.key==43)]" 787 | document: [{"key": 42}] 788 | consensus: [] 789 | not-found-consensus: NOT_FOUND 790 | - id: filter_expression_with_equals_on_object 791 | selector: "$[?(@.key==42)]" 792 | document: {"a": {"key": 0}, "b": {"key": 42}, "c": {"key": -1}, "d": {"key": 41}, "e": {"key": 43}, "f": {"key": 42.0001}, "g": {"key": 41.9999}, "h": {"key": 100}, "i": {"some": "value"}} 793 | - id: filter_expression_with_equals_on_object_with_key_matching_query 794 | selector: "$[?(@.id==2)]" 795 | document: {"id": 2} 796 | - id: filter_expression_with_equals_string 797 | selector: "$[?(@.key==\"value\")]" 798 | document: [{"key": "some"}, {"key": "value"}, {"key": null}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": ""}, {"key": {}}, {"key": []}, {"key": "valuemore"}, {"key": "morevalue"}, {"key": ["value"]}, {"key": {"some": "value"}}, {"key": {"key": "value"}}, {"some": "value"}] 799 | consensus: [{"key": "value"}] 800 | - id: filter_expression_with_equals_string_in_NFC 801 | selector: "$[?(@.key==\"Motörhead\")]" 802 | document: [{"key": "something"}, {"key": "Mot\u00f6rhead"}, {"key": "mot\u00f6rhead"}, {"key": "Motorhead"}, {"key": "Motoo\u0308rhead"}, {"key": "motoo\u0308rhead"}] 803 | consensus: [{"key": "Mot\u00f6rhead"}] 804 | - id: filter_expression_with_equals_string_with_current_object_literal 805 | selector: "$[?(@.key==\"hi@example.com\")]" 806 | document: [{"key": "some"}, {"key": "value"}, {"key": "hi@example.com"}] 807 | consensus: [{"key": "hi@example.com"}] 808 | - id: filter_expression_with_equals_string_with_dot_literal 809 | selector: "$[?(@.key==\"some.value\")]" 810 | document: [{"key": "some"}, {"key": "value"}, {"key": "some.value"}] 811 | consensus: [{"key": "some.value"}] 812 | - id: filter_expression_with_equals_string_with_single_quotes 813 | selector: "$[?(@.key=='value')]" 814 | document: [{"key": "some"}, {"key": "value"}] 815 | consensus: [{"key": "value"}] 816 | - id: filter_expression_with_equals_string_with_unicode_character_escape 817 | selector: "$[?(@.key==\"Mot\\u00f6rhead\")]" 818 | document: [{"key": "something"}, {"key": "Mot\u00f6rhead"}, {"key": "mot\u00f6rhead"}, {"key": "Motorhead"}, {"key": "Motoo\u0308rhead"}, {"key": "motoo\u0308rhead"}] 819 | - id: filter_expression_with_equals_true 820 | selector: "$[?(@.key==true)]" 821 | document: [{"some": "some value"}, {"key": true}, {"key": false}, {"key": null}, {"key": "value"}, {"key": ""}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": 42}, {"key": {}}, {"key": []}] 822 | - id: filter_expression_with_equals_with_path_and_path 823 | selector: "$[?(@.key1==@.key2)]" 824 | document: [{"key1": 10, "key2": 10}, {"key1": 42, "key2": 50}, {"key1": 10}, {"key2": 10}, {}, {"key1": null, "key2": null}, {"key1": null}, {"key2": null}, {"key1": 0, "key2": 0}, {"key1": 0}, {"key2": 0}, {"key1": -1, "key2": -1}, {"key1": "", "key2": ""}, {"key1": false, "key2": false}, {"key1": false}, {"key2": false}, {"key1": true, "key2": true}, {"key1": [], "key2": []}, {"key1": {}, "key2": {}}, {"key1": {"a": 1, "b": 2}, "key2": {"b": 2, "a": 1}}] 825 | - id: filter_expression_with_equals_with_root_reference 826 | selector: "$.items[?(@.key==$.value)]" 827 | document: {"value": 42, "items": [{"key": 10}, {"key": 42}, {"key": 50}]} 828 | - id: filter_expression_with_greater_than 829 | selector: "$[?(@.key>42)]" 830 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "43"}, {"key": "42"}, {"key": "41"}, {"key": "value"}, {"some": "value"}] 831 | - id: filter_expression_with_greater_than_or_equal 832 | selector: "$[?(@.key>=42)]" 833 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "43"}, {"key": "42"}, {"key": "41"}, {"key": "value"}, {"some": "value"}] 834 | - id: filter_expression_with_in_array_of_values 835 | selector: "$[?(@.d in [2, 3])]" 836 | document: [{"d": 1}, {"d": 2}, {"d": 1}, {"d": 3}, {"d": 4}] 837 | - id: filter_expression_with_in_current_object 838 | selector: "$[?(2 in @.d)]" 839 | document: [{"d": [1, 2, 3]}, {"d": [2]}, {"d": [1]}, {"d": [3, 4]}, {"d": [4, 2]}] 840 | - id: filter_expression_with_less_than 841 | selector: "$[?(@.key<42)]" 842 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "43"}, {"key": "42"}, {"key": "41"}, {"key": "value"}, {"some": "value"}] 843 | - id: filter_expression_with_less_than_or_equal 844 | selector: "$[?(@.key<=42)]" 845 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "43"}, {"key": "42"}, {"key": "41"}, {"key": "value"}, {"some": "value"}] 846 | - id: filter_expression_with_multiplication 847 | selector: "$[?(@.key*2==100)]" 848 | document: [{"key": 60}, {"key": 50}, {"key": 10}, {"key": -50}, {"key*2": 100}] 849 | - id: filter_expression_with_negation_and_equals 850 | selector: "$[?(!(@.key==42))]" 851 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "43"}, {"key": "42"}, {"key": "41"}, {"key": "value"}, {"some": "value"}] 852 | - id: filter_expression_with_negation_and_less_than 853 | selector: "$[?(!(@.key<42))]" 854 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "43"}, {"key": "42"}, {"key": "41"}, {"key": "value"}, {"some": "value"}] 855 | - id: filter_expression_with_negation_and_without_value 856 | selector: "$[?(!@.key)]" 857 | document: [{"some": "some value"}, {"key": true}, {"key": false}, {"key": null}, {"key": "value"}, {"key": ""}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": 42}, {"key": {}}, {"key": []}] 858 | - id: filter_expression_with_not_equals 859 | selector: "$[?(@.key!=42)]" 860 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "some"}, {"key": "42"}, {"key": null}, {"key": 420}, {"key": ""}, {"key": {}}, {"key": []}, {"key": [42]}, {"key": {"key": 42}}, {"key": {"some": 42}}, {"some": "value"}] 861 | - id: filter_expression_with_parent_axis_operator 862 | selector: "$[*].bookmarks[?(@.page == 45)]^^^" 863 | document: [{"title": "Sayings of the Century", "bookmarks": [{"page": 40}]}, {"title": "Sword of Honour", "bookmarks": [{"page": 35}, {"page": 45}]}, {"title": "Moby Dick", "bookmarks": [{"page": 3035}, {"page": 45}]}] 864 | consensus: NOT_SUPPORTED 865 | - id: filter_expression_with_regular_expression 866 | selector: "$[?(@.name=~/hello.*/)]" 867 | document: [{"name": "hullo world"}, {"name": "hello world"}, {"name": "yes hello world"}, {"name": "HELLO WORLD"}, {"name": "good bye"}] 868 | - id: filter_expression_with_regular_expression_from_member 869 | selector: "$[?(@.name=~/@.pattern/)]" 870 | document: [{"name": "hullo world"}, {"name": "hello world"}, {"name": "yes hello world"}, {"name": "HELLO WORLD"}, {"name": "good bye"}, {"pattern": "hello.*"}] 871 | - id: filter_expression_with_set_wise_comparison_to_scalar 872 | selector: "$[?(@[*]>=4)]" 873 | document: [[1, 2], [3, 4], [5, 6]] 874 | - id: filter_expression_with_set_wise_comparison_to_set 875 | selector: "$.x[?(@[*]>=$.y[*])]" 876 | document: {"x": [[1, 2], [3, 4], [5, 6]], "y": [3, 4, 5]} 877 | - id: filter_expression_with_single_equal 878 | selector: "$[?(@.key=42)]" 879 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "some"}, {"key": "42"}, {"key": null}, {"key": 420}, {"key": ""}, {"key": {}}, {"key": []}, {"key": [42]}, {"key": {"key": 42}}, {"key": {"some": 42}}, {"some": "value"}] 880 | consensus: NOT_SUPPORTED 881 | - id: filter_expression_with_subfilter 882 | selector: "$[?(@.a[?(@.price>10)])]" 883 | document: [{"a": [{"price": 1}, {"price": 3}]}, {"a": [{"price": 11}]}, {"a": [{"price": 8}, {"price": 12}, {"price": 3}]}, {"a": []}] 884 | - id: filter_expression_with_subpaths 885 | selector: "$[?(@.address.city=='Berlin')]" 886 | document: [{"address": {"city": "Berlin"}}, {"address": {"city": "London"}}] 887 | consensus: [{"address": {"city": "Berlin"}}] 888 | - id: filter_expression_with_subtraction 889 | selector: "$[?(@.key-50==-100)]" 890 | document: [{"key": 60}, {"key": 50}, {"key": 10}, {"key": -50}, {"key-50": -100}] 891 | - id: filter_expression_with_tautological_comparison 892 | selector: "$[?(1==1)]" 893 | document: [1, 3, "nice", true, null, false, {}, [], -1, 0, ""] 894 | - id: filter_expression_with_triple_equal 895 | selector: "$[?(@.key===42)]" 896 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "some"}, {"key": "42"}, {"key": null}, {"key": 420}, {"key": ""}, {"key": {}}, {"key": []}, {"key": [42]}, {"key": {"key": 42}}, {"key": {"some": 42}}, {"some": "value"}] 897 | - id: filter_expression_with_value 898 | selector: "$[?(@.key)]" 899 | document: [{"some": "some value"}, {"key": true}, {"key": false}, {"key": null}, {"key": "value"}, {"key": ""}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": 42}, {"key": {}}, {"key": []}] 900 | - id: filter_expression_with_value_after_dot_notation_with_wildcard_on_array_of_objects 901 | selector: "$.*[?(@.key)]" 902 | document: [{"some": "some value"}, {"key": "value"}] 903 | - id: filter_expression_with_value_after_recursive_descent 904 | selector: "$..[?(@.id)]" 905 | document: {"id": 2, "more": [{"id": 2}, {"more": {"id": 2}}, {"id": {"id": 2}}, [{"id": 2}]]} 906 | ordered: false 907 | - id: filter_expression_with_value_false 908 | selector: "$[?(false)]" 909 | document: [1, 3, "nice", true, null, false, {}, [], -1, 0, ""] 910 | - id: filter_expression_with_value_from_recursive_descent 911 | selector: "$[?(@..child)]" 912 | document: [{"key": [{"child": 1}, {"child": 2}]}, {"key": [{"child": 2}]}, {"key": [{}]}, {"key": [{"something": 42}]}, {}] 913 | - id: filter_expression_with_value_null 914 | selector: "$[?(null)]" 915 | document: [1, 3, "nice", true, null, false, {}, [], -1, 0, ""] 916 | - id: filter_expression_with_value_true 917 | selector: "$[?(true)]" 918 | document: [1, 3, "nice", true, null, false, {}, [], -1, 0, ""] 919 | - id: filter_expression_without_parens 920 | selector: "$[?@.key==42]" 921 | document: [{"key": 0}, {"key": 42}, {"key": -1}, {"key": 1}, {"key": 41}, {"key": 43}, {"key": 42.0001}, {"key": 41.9999}, {"key": 100}, {"key": "some"}, {"key": "42"}, {"key": null}, {"key": 420}, {"key": ""}, {"key": {}}, {"key": []}, {"key": [42]}, {"key": {"key": 42}}, {"key": {"some": 42}}, {"some": "value"}] 922 | consensus: NOT_SUPPORTED 923 | - id: filter_expression_without_value 924 | selector: "$[?(@.key)]" 925 | document: [{"some": "some value"}, {"key": true}, {"key": false}, {"key": null}, {"key": "value"}, {"key": ""}, {"key": 0}, {"key": 1}, {"key": -1}, {"key": 42}, {"key": {}}, {"key": []}] 926 | - id: function_sum 927 | selector: "$.data.sum()" 928 | document: {"data": [1, 2, 3, 4]} 929 | - id: parens_notation 930 | selector: "$(key,more)" 931 | document: {"key": 1, "some": 2, "more": 3} 932 | consensus: NOT_SUPPORTED 933 | - id: recursive_descent 934 | selector: "$.." 935 | document: [{"a": {"b": "c"}}, [0, 1]] 936 | ordered: false 937 | - id: recursive_descent_after_dot_notation 938 | selector: "$.key.." 939 | document: {"some key": "value", "key": {"complex": "string", "primitives": [0, 1]}} 940 | ordered: false 941 | - id: root 942 | selector: "$" 943 | document: {"key": "value", "another key": {"complex": ["a", 1]}} 944 | consensus: [{"another key": {"complex": ["a", 1]}, "key": "value"}] 945 | scalar-consensus: {"another key": {"complex": ["a", 1]}, "key": "value"} 946 | - id: root_on_scalar 947 | selector: "$" 948 | document: 42 949 | consensus: [42] 950 | scalar-consensus: 42 951 | - id: root_on_scalar_false 952 | selector: "$" 953 | document: false 954 | consensus: [false] 955 | scalar-consensus: false 956 | - id: root_on_scalar_true 957 | selector: "$" 958 | document: true 959 | consensus: [true] 960 | scalar-consensus: true 961 | - id: script_expression 962 | selector: "$[(@.length-1)]" 963 | document: ["first", "second", "third", "forth", "fifth"] 964 | consensus: NOT_SUPPORTED 965 | - id: union 966 | selector: "$[0,1]" 967 | document: ["first", "second", "third"] 968 | consensus: ["first", "second"] 969 | - id: union_with_duplication_from_array 970 | selector: "$[0,0]" 971 | document: ["a"] 972 | consensus: ["a", "a"] 973 | - id: union_with_duplication_from_object 974 | selector: "$['a','a']" 975 | document: {"a": 1} 976 | consensus: [1, 1] 977 | - id: union_with_filter 978 | selector: "$[?(@.key<3),?(@.key>6)]" 979 | document: [{"key": 1}, {"key": 8}, {"key": 3}, {"key": 10}, {"key": 7}, {"key": 2}, {"key": 6}, {"key": 4}] 980 | - id: union_with_keys 981 | selector: "$['key','another']" 982 | document: {"key": "value", "another": "entry"} 983 | consensus: ["value", "entry"] 984 | - id: union_with_keys_after_array_slice 985 | selector: "$[:]['c','d']" 986 | document: [{"c": "cc1", "d": "dd1", "e": "ee1"}, {"c": "cc2", "d": "dd2", "e": "ee2"}] 987 | consensus: ["cc1", "dd1", "cc2", "dd2"] 988 | - id: union_with_keys_after_bracket_notation 989 | selector: "$[0]['c','d']" 990 | document: [{"c": "cc1", "d": "dd1", "e": "ee1"}, {"c": "cc2", "d": "dd2", "e": "ee2"}] 991 | consensus: ["cc1", "dd1"] 992 | - id: union_with_keys_after_dot_notation_with_wildcard 993 | selector: "$.*['c','d']" 994 | document: [{"c": "cc1", "d": "dd1", "e": "ee1"}, {"c": "cc2", "d": "dd2", "e": "ee2"}] 995 | consensus: ["cc1", "dd1", "cc2", "dd2"] 996 | - id: union_with_keys_after_recursive_descent 997 | selector: "$..['c','d']" 998 | document: [{"c": "cc1", "d": "dd1", "e": "ee1"}, {"c": "cc2", "child": {"d": "dd2"}}, {"c": "cc3"}, {"d": "dd4"}, {"child": {"c": "cc5"}}] 999 | ordered: false 1000 | consensus: ["cc1", "cc2", "cc3", "cc5", "dd1", "dd2", "dd4"] 1001 | - id: union_with_keys_on_object_without_key 1002 | selector: "$['missing','key']" 1003 | document: {"key": "value", "another": "entry"} 1004 | consensus: ["value"] 1005 | - id: union_with_numbers_in_decreasing_order 1006 | selector: "$[4,1]" 1007 | document: [1, 2, 3, 4, 5] 1008 | consensus: [5, 2] 1009 | - id: union_with_repeated_matches_after_dot_notation_with_wildcard 1010 | selector: "$.*[0,:5]" 1011 | document: {"a": ["string", null, true], "b": [false, "string", 5.4]} 1012 | - id: union_with_slice_and_number 1013 | selector: "$[1:3,4]" 1014 | document: [1, 2, 3, 4, 5] 1015 | - id: union_with_spaces 1016 | selector: "$[ 0 , 1 ]" 1017 | document: ["first", "second", "third"] 1018 | consensus: ["first", "second"] 1019 | - id: union_with_wildcard_and_number 1020 | selector: "$[*,1]" 1021 | document: ["first", "second", "third", "forth", "fifth"] 1022 | consensus: NOT_SUPPORTED 1023 | --------------------------------------------------------------------------------