File: README.md

package info (click to toggle)
ruby-jsonpath 1.1.5-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 332 kB
  • sloc: ruby: 1,831; makefile: 4
file content (301 lines) | stat: -rw-r--r-- 7,333 bytes parent folder | download
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# JsonPath

This is an implementation of http://goessner.net/articles/JsonPath/.

## What is JsonPath?

JsonPath is a way of addressing elements within a JSON object. Similar to xpath
of yore, JsonPath lets you traverse a json object and manipulate or access it.

## Usage

### Command-line

There is stand-alone usage through the binary `jsonpath`

    jsonpath [expression] (file|string)

    If you omit the second argument, it will read stdin, assuming one valid JSON
    object per line. Expression must be a valid jsonpath expression.

### Library

To use JsonPath as a library simply include and get goin'!

```ruby
require 'jsonpath'

json = <<-HERE_DOC
{"store":
  {"bicycle":
    {"price":19.95, "color":"red"},
    "book":[
      {"price":8.95, "category":"reference", "title":"Sayings of the Century", "author":"Nigel Rees"},
      {"price":12.99, "category":"fiction", "title":"Sword of Honour", "author":"Evelyn Waugh"},
      {"price":8.99, "category":"fiction", "isbn":"0-553-21311-3", "title":"Moby Dick", "author":"Herman Melville","color":"blue"},
      {"price":22.99, "category":"fiction", "isbn":"0-395-19395-8", "title":"The Lord of the Rings", "author":"Tolkien"}
    ]
  }
}
HERE_DOC
```

Now that we have a JSON object, let's get all the prices present in the object.
We create an object for the path in the following way.

```ruby
path = JsonPath.new('$..price')
```

Now that we have a path, let's apply it to the object above.

```ruby
path.on(json)
# => [19.95, 8.95, 12.99, 8.99, 22.99]
```

Or reuse it later on some other object (thread safe) ...

```ruby
path.on('{"books":[{"title":"A Tale of Two Somethings","price":18.88}]}')
# => [18.88]
```

You can also just combine this into one mega-call with the convenient
`JsonPath.on` method.

```ruby
JsonPath.on(json, '$..author')
# => ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "Tolkien"]
```

Of course the full JsonPath syntax is supported, such as array slices

```ruby
JsonPath.new('$..book[::2]').on(json)
# => [
#      {"price" => 8.95, "category" => "reference", "title" => "Sayings of the Century", "author" => "Nigel Rees"},
#      {"price" => 8.99, "category" => "fiction", "isbn" => "0-553-21311-3", "title" => "Moby Dick", "author" => "Herman Melville","color" => "blue"},
#    ]
```

...and evals, including those with conditional operators

```ruby
JsonPath.new("$..price[?(@ < 10)]").on(json)
# => [8.95, 8.99]

JsonPath.new("$..book[?(@['price'] == 8.95 || @['price'] == 8.99)].title").on(json)
# => ["Sayings of the Century", "Moby Dick"]

JsonPath.new("$..book[?(@['price'] == 8.95 && @['price'] == 8.99)].title").on(json)
# => []
```

There is a convenience method, `#first` that gives you the first element for a
JSON object and path.

```ruby
JsonPath.new('$..color').first(json)
# => "red"
```

As well, we can directly create an `Enumerable` at any time using `#[]`. 

```ruby
enum = JsonPath.new('$..color')[json]
# => #<JsonPath::Enumerable:...>
enum.first
# => "red"
enum.any?{ |c| c == 'red' }
# => true
```

For more usage examples and variations on paths, please visit the tests. There
are some more complex ones as well.

### Querying ruby data structures

If you have ruby hashes with symbolized keys as input, you
can use `:use_symbols` to make JsonPath work fine on them too:

```ruby
book = { title: "Sayings of the Century" }

JsonPath.new('$.title').on(book)
# => []

JsonPath.new('$.title', use_symbols: true).on(book)
# => ["Sayings of the Century"]
```

JsonPath also recognizes objects responding to `dig` (introduced
in ruby 2.3), and therefore works out of the box with Struct,
OpenStruct, and other Hash-like structures:

```ruby
book_class = Struct.new(:title)
book = book_class.new("Sayings of the Century")

JsonPath.new('$.title').on(book)
# => ["Sayings of the Century"]
```

JsonPath is able to query pure ruby objects and uses `__send__`
on them. The option is enabled by default in JsonPath 1.x, but
we encourage to enable it explicitly:

```ruby
book_class = Class.new{ attr_accessor :title }
book = book_class.new
book.title = "Sayings of the Century"

JsonPath.new('$.title', allow_send: true).on(book)
# => ["Sayings of the Century"]
```

### Other available options

By default, JsonPath does not return null values on unexisting paths.
This can be changed using the `:default_path_leaf_to_null` option

```ruby
JsonPath.new('$..book[*].isbn').on(json)
# => ["0-553-21311-3", "0-395-19395-8"]

JsonPath.new('$..book[*].isbn', default_path_leaf_to_null: true).on(json)
# => [nil, nil, "0-553-21311-3", "0-395-19395-8"]
```

When JsonPath returns a Hash, you can ask to symbolize its keys
using the `:symbolize_keys` option

```ruby
JsonPath.new('$..book[0]').on(json)
# => [{"category" => "reference", ...}]

JsonPath.new('$..book[0]', symbolize_keys: true).on(json)
# => [{category: "reference", ...}]
```

### Selecting Values

It's possible to select results once a query has been defined after the query. For
example given this JSON data:

```bash
{
    "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
            }
        ]
}
```

... and this query:

```ruby
"$.store.book[*](category,author)"
```

... the result can be filtered as such:

```bash
[
   {
      "category" : "reference",
      "author" : "Nigel Rees"
   },
   {
      "category" : "fiction",
      "author" : "Evelyn Waugh"
   }
]
```

### Manipulation

If you'd like to do substitution in a json object, you can use `#gsub`
or `#gsub!` to modify the object in place.

```ruby
JsonPath.for('{"candy":"lollipop"}').gsub('$..candy') {|v| "big turks" }.to_hash
```

The result will be

```ruby
{'candy' => 'big turks'}
```

If you'd like to remove all nil keys, you can use `#compact` and `#compact!`.
To remove all keys under a certain path, use `#delete` or `#delete!`. You can
even chain these methods together as follows:

```ruby
json = '{"candy":"lollipop","noncandy":null,"other":"things"}'
o = JsonPath.for(json).
  gsub('$..candy') {|v| "big turks" }.
  compact.
  delete('$..other').
  to_hash
# => {"candy" => "big turks"}
```

### Fetch all paths

To fetch all possible paths in given json, you can use `fetch_all_path`` method.

data:

```bash
{
    "store": {
        "book": [
            {
                "category": "reference",
                "author": "Nigel Rees"
            },
            {
                "category": "fiction",
                "author": "Evelyn Waugh"
            }
        ]
}
```

... and this query:

```ruby
JsonPath.fetch_all_path(data)
```

... the result will be:

```bash
["$", "$.store", "$.store.book", "$.store.book[0].category", "$.store.book[0].author", "$.store.book[0]", "$.store.book[1].category", "$.store.book[1].author", "$.store.book[1]"]
```



# Contributions

Please feel free to submit an Issue or a Pull Request any time you feel like
you would like to contribute. Thank you!

## Running an individual test

```ruby
ruby -Ilib:../lib test/test_jsonpath.rb --name test_wildcard_on_intermediary_element_v6
```