jsonpath 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +45 -0
- data/lib/jsonpath.rb +13 -11
- data/lib/jsonpath/enumerable.rb +16 -0
- data/lib/jsonpath/parser.rb +1 -1
- data/lib/jsonpath/version.rb +1 -1
- data/test/test_jsonpath.rb +76 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d49972014868528c0c690ecec0ec7d6e06056f14a803637d494c87ee3100de0
|
4
|
+
data.tar.gz: fbbb8f93028b2aac45f6727aba4e874c51db91bb599bc568ec62c94180595a91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60c7d6e4075b9ece68f6325d2b836f228b780304ac0ddafbfe2154668f07c10d4faee371135b9b9c55f7548a89a7f755d6536b4305e47f486112549c9b2711b1
|
7
|
+
data.tar.gz: cf72f327c8a3d12bb4780cf052846e9183218148dcf5e57fcddaeb0c1b86218f9a082d4b3cb7f7e38e390956176da71a954e855ae33436f9ce396a1eb73fd2f7
|
data/README.md
CHANGED
@@ -123,6 +123,51 @@ For more usage examples and variations on paths, please visit the tests. There a
|
|
123
123
|
end
|
124
124
|
```
|
125
125
|
|
126
|
+
### Selecting Values
|
127
|
+
|
128
|
+
It's possible to select results once a query has been defined after the query. For example given this JSON data:
|
129
|
+
|
130
|
+
```bash
|
131
|
+
{
|
132
|
+
"store": {
|
133
|
+
"book": [
|
134
|
+
{
|
135
|
+
"category": "reference",
|
136
|
+
"author": "Nigel Rees",
|
137
|
+
"title": "Sayings of the Century",
|
138
|
+
"price": 8.95
|
139
|
+
},
|
140
|
+
{
|
141
|
+
"category": "fiction",
|
142
|
+
"author": "Evelyn Waugh",
|
143
|
+
"title": "Sword of Honour",
|
144
|
+
"price": 12.99
|
145
|
+
}
|
146
|
+
]
|
147
|
+
}
|
148
|
+
```
|
149
|
+
|
150
|
+
... and this query:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
"$.store.book[*](category,author)"
|
154
|
+
```
|
155
|
+
|
156
|
+
... the result can be filtered as such:
|
157
|
+
|
158
|
+
```bash
|
159
|
+
[
|
160
|
+
{
|
161
|
+
"category" : "reference",
|
162
|
+
"author" : "Nigel Rees"
|
163
|
+
},
|
164
|
+
{
|
165
|
+
"category" : "fiction",
|
166
|
+
"author" : "Evelyn Waugh"
|
167
|
+
}
|
168
|
+
]
|
169
|
+
```
|
170
|
+
|
126
171
|
### Running an individual test
|
127
172
|
|
128
173
|
```ruby
|
data/lib/jsonpath.rb
CHANGED
@@ -10,7 +10,7 @@ require 'jsonpath/parser'
|
|
10
10
|
# JsonPath: initializes the class with a given JsonPath and parses that path
|
11
11
|
# into a token array.
|
12
12
|
class JsonPath
|
13
|
-
PATH_ALL = '$..*'
|
13
|
+
PATH_ALL = '$..*'
|
14
14
|
|
15
15
|
attr_accessor :path
|
16
16
|
|
@@ -19,21 +19,23 @@ class JsonPath
|
|
19
19
|
scanner = StringScanner.new(path.strip)
|
20
20
|
@path = []
|
21
21
|
until scanner.eos?
|
22
|
-
if token = scanner.scan(/\$\B|@\B|\*|\.\./)
|
22
|
+
if (token = scanner.scan(/\$\B|@\B|\*|\.\./))
|
23
23
|
@path << token
|
24
|
-
elsif token = scanner.scan(/[
|
24
|
+
elsif (token = scanner.scan(/[$@a-zA-Z0-9:{}_-]+/))
|
25
25
|
@path << "['#{token}']"
|
26
|
-
elsif token = scanner.scan(/'(.*?)'/)
|
26
|
+
elsif (token = scanner.scan(/'(.*?)'/))
|
27
27
|
@path << "[#{token}]"
|
28
|
-
elsif token = scanner.scan(/\[/)
|
28
|
+
elsif (token = scanner.scan(/\[/))
|
29
29
|
@path << find_matching_brackets(token, scanner)
|
30
|
-
elsif token = scanner.scan(/\]/)
|
30
|
+
elsif (token = scanner.scan(/\]/))
|
31
31
|
raise ArgumentError, 'unmatched closing bracket'
|
32
|
+
elsif (token = scanner.scan(/\(.*\)/))
|
33
|
+
@path << token
|
32
34
|
elsif scanner.scan(/\./)
|
33
35
|
nil
|
34
|
-
elsif token = scanner.scan(/[><=] \d+/)
|
36
|
+
elsif (token = scanner.scan(/[><=] \d+/))
|
35
37
|
@path.last << token
|
36
|
-
elsif token = scanner.scan(/./)
|
38
|
+
elsif (token = scanner.scan(/./))
|
37
39
|
begin
|
38
40
|
@path.last << token
|
39
41
|
rescue RuntimeError
|
@@ -46,13 +48,13 @@ class JsonPath
|
|
46
48
|
def find_matching_brackets(token, scanner)
|
47
49
|
count = 1
|
48
50
|
until count.zero?
|
49
|
-
if t = scanner.scan(/\[/)
|
51
|
+
if (t = scanner.scan(/\[/))
|
50
52
|
token << t
|
51
53
|
count += 1
|
52
|
-
elsif t = scanner.scan(/\]/)
|
54
|
+
elsif (t = scanner.scan(/\]/))
|
53
55
|
token << t
|
54
56
|
count -= 1
|
55
|
-
elsif t = scanner.scan(/[^\[\]]+/)
|
57
|
+
elsif (t = scanner.scan(/[^\[\]]+/))
|
56
58
|
token << t
|
57
59
|
elsif scanner.eos?
|
58
60
|
raise ArgumentError, 'unclosed bracket'
|
data/lib/jsonpath/enumerable.rb
CHANGED
@@ -28,6 +28,10 @@ class JsonPath
|
|
28
28
|
each(context, key, pos + 1, &blk) if node == @object
|
29
29
|
when /^\[(.*)\]$/
|
30
30
|
handle_wildecard(node, expr, context, key, pos, &blk)
|
31
|
+
when /\(.*\)/
|
32
|
+
keys = expr.gsub(/[()]/, '').split(',').map(&:strip)
|
33
|
+
new_context = filter_context(context, keys)
|
34
|
+
yield_value(blk, new_context, key)
|
31
35
|
end
|
32
36
|
|
33
37
|
if pos > 0 && @path[pos - 1] == '..' || (@path[pos - 1] == '*' && @path[pos] != '..')
|
@@ -40,6 +44,18 @@ class JsonPath
|
|
40
44
|
|
41
45
|
private
|
42
46
|
|
47
|
+
def filter_context(context, keys)
|
48
|
+
case context
|
49
|
+
when Hash
|
50
|
+
# TODO: Change this to `slice(*keys)` when ruby version support is > 2.4
|
51
|
+
context.select { |k| keys.include?(k) }
|
52
|
+
when Array
|
53
|
+
context.each_with_object([]) do |c, memo|
|
54
|
+
memo << c.select { |k| keys.include?(k) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
43
59
|
def handle_wildecard(node, expr, _context, _key, pos, &blk)
|
44
60
|
expr[1, expr.size - 2].split(',').each do |sub_path|
|
45
61
|
case sub_path[0]
|
data/lib/jsonpath/parser.rb
CHANGED
@@ -65,7 +65,7 @@ class JsonPath
|
|
65
65
|
elements = []
|
66
66
|
until scanner.eos?
|
67
67
|
if (t = scanner.scan(/\['[a-zA-Z@&*\/$%^?_]+'\]|\.[a-zA-Z0-9_]+[?!]?/))
|
68
|
-
elements << t.gsub(/[\[\]'
|
68
|
+
elements << t.gsub(/[\[\]'.]|\s+/, '')
|
69
69
|
elsif (t = scanner.scan(/(\s+)?[<>=!\-+][=~]?(\s+)?/))
|
70
70
|
operator = t
|
71
71
|
elsif (t = scanner.scan(/(\s+)?'?.*'?(\s+)?/))
|
data/lib/jsonpath/version.rb
CHANGED
data/test/test_jsonpath.rb
CHANGED
@@ -833,6 +833,82 @@ class TestJsonpath < MiniTest::Unit::TestCase
|
|
833
833
|
assert_equal [], JsonPath.on(json, "$.phoneNumbers[?(@[0].type == 'home')]")
|
834
834
|
end
|
835
835
|
|
836
|
+
def test_selecting_multiple_keys
|
837
|
+
json = '
|
838
|
+
{
|
839
|
+
"store": {
|
840
|
+
"book": [
|
841
|
+
{
|
842
|
+
"category": "reference",
|
843
|
+
"author": "Nigel Rees",
|
844
|
+
"title": "Sayings of the Century",
|
845
|
+
"price": 8.95
|
846
|
+
},
|
847
|
+
{
|
848
|
+
"category": "fiction",
|
849
|
+
"author": "Evelyn Waugh",
|
850
|
+
"title": "Sword of Honour",
|
851
|
+
"price": 12.99
|
852
|
+
}
|
853
|
+
]
|
854
|
+
}
|
855
|
+
}
|
856
|
+
'.to_json
|
857
|
+
|
858
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }, { 'category' => 'fiction', 'author' => 'Evelyn Waugh' }], JsonPath.on(json, '$.store.book[*](category,author)')
|
859
|
+
end
|
860
|
+
|
861
|
+
def test_selecting_multiple_keys_with_filter
|
862
|
+
json = '
|
863
|
+
{
|
864
|
+
"store": {
|
865
|
+
"book": [
|
866
|
+
{
|
867
|
+
"category": "reference",
|
868
|
+
"author": "Nigel Rees",
|
869
|
+
"title": "Sayings of the Century",
|
870
|
+
"price": 8.95
|
871
|
+
},
|
872
|
+
{
|
873
|
+
"category": "fiction",
|
874
|
+
"author": "Evelyn Waugh",
|
875
|
+
"title": "Sword of Honour",
|
876
|
+
"price": 12.99
|
877
|
+
}
|
878
|
+
]
|
879
|
+
}
|
880
|
+
}
|
881
|
+
'.to_json
|
882
|
+
|
883
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)](category,author)")
|
884
|
+
assert_equal [{ 'category' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( category, author )")
|
885
|
+
end
|
886
|
+
|
887
|
+
def test_selecting_multiple_keys_with_filter_with_space_in_catergory
|
888
|
+
json = '
|
889
|
+
{
|
890
|
+
"store": {
|
891
|
+
"book": [
|
892
|
+
{
|
893
|
+
"cate gory": "reference",
|
894
|
+
"author": "Nigel Rees",
|
895
|
+
"title": "Sayings of the Century",
|
896
|
+
"price": 8.95
|
897
|
+
},
|
898
|
+
{
|
899
|
+
"cate gory": "fiction",
|
900
|
+
"author": "Evelyn Waugh",
|
901
|
+
"title": "Sword of Honour",
|
902
|
+
"price": 12.99
|
903
|
+
}
|
904
|
+
]
|
905
|
+
}
|
906
|
+
}
|
907
|
+
'.to_json
|
908
|
+
|
909
|
+
assert_equal [{ 'cate gory' => 'reference', 'author' => 'Nigel Rees' }], JsonPath.on(json, "$.store.book[?(@['price'] == 8.95)]( cate gory, author )")
|
910
|
+
end
|
911
|
+
|
836
912
|
def example_object
|
837
913
|
{ 'store' => {
|
838
914
|
'book' => [
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonpath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Hull
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-06-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -158,7 +158,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
158
158
|
- !ruby/object:Gem::Version
|
159
159
|
version: '0'
|
160
160
|
requirements: []
|
161
|
-
|
161
|
+
rubyforge_project: jsonpath
|
162
|
+
rubygems_version: 2.7.3
|
162
163
|
signing_key:
|
163
164
|
specification_version: 4
|
164
165
|
summary: Ruby implementation of http://goessner.net/articles/JsonPath/
|