dchester / jsonpath Goto Github PK
View Code? Open in Web Editor NEWQuery and manipulate JavaScript objects with JSONPath expressions. Robust JSONPath engine for Node.js.
License: MIT License
Query and manipulate JavaScript objects with JSONPath expressions. Robust JSONPath engine for Node.js.
License: MIT License
value()
is documented as returning the new value if one is passed in. I thought it was a doc error, so I checked, and that is indeed what it does. But wouldn't it be more useful (and arguably more typical for such a function) to return the old value?
Array indices larger than 1 digit don't work in paths:
jp.query({
stuff: [1,2,3,4,5,6,7,8,9,10,11]
}, '$.stuff[10]');
Results in:
Error: Parse error on line 1:
$.stuff[10]
running this query throws path is undefined error:
'$..["prop1", "prop2"]'
if prop2 does not exist anywhere in the object being queried
The pre-bundled jsonpath.js file included in the node package will crash when attempting to use an array selector operation due to missing underscore functions.
Webpack has given "underscore" module index 9, which in the bundle is:
9:[function(require,module,exports){
},{}]
As this exports no content, the line
var _uniq = require('underscore').uniq;
sets _uniq to undefined, causing the crash when unique() is called on line 4855.
Setting a unexisting property with "value" method not work if the path points to an array element using a filter.
Object:
{
"list": [
{
"index": 0
}
]
}
jsonpath.value(obj, "$.list[0].value", "test");
test
jsonpath.value(obj, "$.list[?(@.index == 0)].value", "test");
undefined
I got Error: ENOENT, no such file or directory 'include/module.js' error message when using version 0.1.6. json
I cannot install via npm , if i do that I get this error:
npm ERR! Darwin 14.5.0
npm ERR! argv "/usr/local/Cellar/node/5.5.0/bin/node" "/usr/local/bin/npm" "install" "jsonpath"
npm ERR! node v5.5.0
npm ERR! npm v3.5.3
npm ERR! code ELIFECYCLE
npm ERR! [email protected] postinstall: node lib/aesprim.js > generated/aesprim-browser.js
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] postinstall script 'node lib/aesprim.js > generated/aesprim-browser.js'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the jsonpath package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node lib/aesprim.js > generated/aesprim-browser.js
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs jsonpath
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls jsonpath
npm ERR! There is likely additional logging output above.
npm ERR! Please include the following file with any support request:
Last path selector returns all
const jsonpath = require('jsonpath');
const store = {
"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
}
}
};
console.log(jsonpath.query(store, '$..book[-1:].title'));
All the books are pushed: [ 'Sayings of the Century', 'Sword of Honour', 'Moby Dick', 'The Lord of the Rings' ]
Currently after a parse error, parse.yy.ast is carrying left overs from the partially successful parse.
If the next path string has an identical "correct" prefix or the next path string has the same number of components or more, the bug goes unnoticed.
Example:
test('parser ast is reinitialized after parse() throws', function() {
assert.throws(function() { var path = jp.parse('store.book...') })
var path = jp.parse('$..price');
assert.deepEqual(path, [
{ "expression": { "type": "root", "value": "$" } },
{ "expression": { "type": "identifier", "value": "price" }, "operation": "member", "scope": "descendant"}
])
});
// Notice left-over component: { expression: { type: 'identifier', value: 'book' }, ... }
Given this object:
{
"store": {
"books": [
{
"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
}
}
}
I would expect that these would be equivalent:
jsonpath.query(jsObj, '$.store.books[2]')
jsonpath.query(jsObj, '$.store.books')[2]
It turns out these are not equivalent; the first returns [{book2data}] and the second returns undefined. I was expecting to get {book2data} from both. It seems like the wrapping array creates the difference and I'm a bit confused as to what the expected behavior is.
Thanks for your thoughts!
Hi,
I noticed that grammar tries to parse expression lists of arbitrary length, but it actually doesn't work for lists longer than two expressions
Grammar also permits lists of two script expressions or filter expressions or even '*' but handler doesn't support those actions, only handlers for INTEGER, STRING_LITERAL and ARRAY_SLICE work.
for example ,if i want to select all the books whose isbn =0-553-21311-3
$..book[?(@.isbn='0-553-21311-3')]
it does not work
from IBM-Cloud/gp-js-flatten#18 by @JCEmmons
According to http://goessner.net/articles/JsonPath/ , bracket notation for a given path uses single quote, not double quote.
Would it be possible to have an option (or default) to a goessner-compatible stringify giving:
require('jsonpath').stringify(['$','π']); // => $['π']
…instead of $["π"]
?
Hi,
Given a structure like this:
[
{
"id": 1,
"tags": ["foo","bar"]
},
{
"id": 2,
"tags": ["bar","zot"]
}
]
How can I do a selection that selects the whole object if the tag array contains "foo"?
This way I only get the tags-arrays back:
'$..tags[?(@ === "foo")]'
My guess was:
'$..[?(@.tags[?(@property === "foo")])]'
But that gives me
Error in the given query: Lexical error on line 1. Unrecognized text.
...perty === "foo")])]
-----------------------^
This is what I want back from the query:
[
{
"id": 1,
"tags": ["foo","bar"]
}
]
Any help would be greatly appreciated.
I'm coding an application that using Electron, and I'm also using webpack to compile my code.
But when using jsonpath, webpack shows a warning in console:
WARNING in ./~/jsonpath/lib/grammar.js
[0] Critical dependencies:
[0] 4:0-7 require function is used in a way in which dependencies cannot be statically extracted
[0] 4:18-25 require function is used in a way in which dependencies cannot be statically extracted
[0] @ ./~/jsonpath/lib/grammar.js 4:0-7 4:18-25
In Electron's console, there's an error:
fs.js:977Uncaught Error: EBADF: bad file descriptor, fstat
fs.fstatSync @ fs.js:977
tryStatSync @ fs.js:462
fs.readFileSync @ fs.js:510
fs.readFileSync @ ELECTRON_ASAR.js:500
(anonymous function) @ grammar.js:104
__webpack_require__ @ bootstrap 31da7ee…:531
fn @ bootstrap 31da7ee…:62
(anonymous function) @ parser.js:1
__webpack_require__ @ bootstrap 31da7ee…:531
fn @ bootstrap 31da7ee…:62
(anonymous function) @ index.js:3
__webpack_require__ @ bootstrap 31da7ee…:531
fn @ bootstrap 31da7ee…:62
(anonymous function) @ index.js:1
__webpack_require__ @ bootstrap 31da7ee…:531
fn @ bootstrap 31da7ee…:62
(anonymous function) @ index.js:12
__webpack_require__ @ bootstrap 31da7ee…:531
fn @ bootstrap 31da7ee…:62
(anonymous function) @ appContainer.js:8
__webpack_require__ @ bootstrap 31da7ee…:531
fn @ bootstrap 31da7ee…:62
(anonymous function) @ shell.js:13
__webpack_require__ @ bootstrap 31da7ee…:531
fn @ bootstrap 31da7ee…:62
(anonymous function) @ bootstrap 31da7ee…:554
__webpack_require__ @ bootstrap 31da7ee…:531
(anonymous function) @ bootstrap 31da7ee…:554
(anonymous function) @ bootstrap 31da7ee…:554
When I dig into it, here's the code that causing the error:
moduleInclude: fs.readFileSync(require.resolve("../include/module.js")),
actionInclude: fs.readFileSync(require.resolve("../include/action.js"))
It's in lib/grammar.js
Here's some code in my js which using jsonpath.
import jsonpath from 'jsonpath';
class Point {
...
jsonpath.query(this.object, this.path);
...
}
In webpack's config, target
is set to electron
, so it won't change require
function, because Electron already offer one.
Objects using string representations of integers as their keys are not correctly parsed. The integer key seems to be ignored as a valid path member. An example will make the issue clear:
const jp = require('jsonpath')
const library = {
"books": {
"1": {
"author": "Herman Melville",
"title": "Moby Dick"
},
"2": {
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings"
}
}
}
jp.query(library, '$.books.1.author')
// returns []
// but
const letterLibrary = {
"books": {
"a": {
"author": "Herman Melville",
"title": "Moby Dick"
},
"b": {
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings"
}
}
}
jp.query(letterLibrary, '$.books.a.author')
// returns [ 'Herman Melville' ]
Hi,
is there a way i can return nodes where a substring is matched.. like
$..[?(@.task=~/Cov.*/i)]
i have tried the above in various combinations but does not seem to return anything.
data:
[{'item': 'bar', 'group': 'cov001'},{'item': 'foo', 'group': 'cov002'},{'item': 'gee', 'group': 'cog001'}]
I have been trying to integrate jsonpath into my webpack project, but I'm getting blocked the following error:
Uncaught ReferenceError: Invalid left-hand side in assignment
It appears the error is coming from the following line in grammar.js when it tries to stub out require.resolve:
require.resolve = require.resolve || function() {}
The above line of code is rewritten by webpack into this, which is invalid:
!(function webpackMissingModule() { var e = new Error("Cannot find module \".\""); e.code = 'MODULE_NOT_FOUND'; throw e; }()).resolve = !(function webpackMissingModule() { var e = new Error("Cannot find module \".\""); e.code = 'MODULE_NOT_FOUND'; throw e; }()).resolve || function() {}
For reference, I am using webpack v2.2.0-rc.3
I want to directly include the js file and use it. Is it possible?
jp.query
is extremely helpful, but sometimes one needs (and expects) to find only 1 value (for example, when searching by ID). In those cases jp.query
is wasting precious time iterating over all items, when it could return as soon as a match is found.
This could vastly improve performance whit big sets of data.
when i have a data structure like
{
city1: ['BJ'],
city2: 'BJ'
}
when i use jsonpath to get the json value,
$.city1 it will return ['BJ']
$.city2 it will return ['BJ'] as well,
then the question come out, how could i juddge the element type is a String or is an Array?
Current identifier string contains
identifier: "[a-zA-Z_]+[a-zA-Z0-9_]*"
which leads to
$.status.dev-01
-------------^
Expecting 'DOT', 'DOT_DOT', '[', got 'INTEGER'
which is wrong as long as "dev-01" key is valid.
https://github.com/defunctzombie/commonjs-assert is used by the package -- but is not in package.json. (yarn tells me it is in node_modules because
info This module exists because "grunt-browserify#browserify" depends on it.
). Presumably should be added to package.json?
const x = {a: 1};
jp.query(x, 'a')
// returns 1
jp.value(x, 'a', 2);
// returns 2, sets key 'a' to 2 in x
jp.value(x, 'b', 2);
// Error: couldn't understand path
jp.query(x, 'b')
// returns []
jp.value(x, '$..b', 2);
// returns 2 and sets key 'b' to 2 in x
I would prefer to be able to leave the '$' off -- which mostly works -- as it seems redundant. But it seems to be necessary using "value" if the location does not yet exist.
Hi
There is a handler for member-descendant-identifier which helps resolve queries like $..author, which shows all paths where the author key exists from the root node, https://github.com/dchester/jsonpath/blob/master/lib/handlers.js#L45. But if we put the author in quotes, $..['author'], it has no handler (subscript-descendant-string_literal) to resolve it, though the handler is similar. My example is of course very simple, and there was probably a good reason why this is not supported. Just curious to know what that is.
Thanks
When parsing this erroneous path: '$...id'
(and others like it), the result is not a friendly parse error, but a TypeError from somewhere within jsonpath.
> var jp = require('jsonpath')
> jp.parse('$...id')
TypeError: Cannot read property 'initialize' of undefined
at Object.parser.yy.parseError (/Users/wasyl/Projects/chap/chaplain/node_modules/jsonpath/lib/parser.js:10:18)
at Object.parse (/Users/wasyl/Projects/chap/chaplain/node_modules/jsonpath/generated/parser.js:224:22)
at JSONPath.parse (/Users/wasyl/Projects/chap/chaplain/node_modules/jsonpath/lib/index.js:19:22)
...
Adding an if in that line checking if parser.yy.ast
is present before calling initialize()
on it seems to fix that, but I'm not 100% sure that's the right fix.
It would make it easier for me to properly attribute some code that I copied.
Also without the year and full name filled in, it isn't clear to me that the license is valid
How about a command line tool for extracting data via jsonpath? It could be similar to: https://stedolan.github.io/jq/
Hi
I have used this plugin for json traverse. Getting invalid calling object error in IE11 alone.
Found this line causing error
function _is_string(obj) {
return toString.call(obj) == '[object String]';
}
Fixed by changing code like this
function _is_string(obj) {
var toString = Object.prototype.toString;
return toString.call(obj) == '[object String]';
}
Please verify from your end. Maybe it will help others
Hi,
if I use jsonpath in the browser with require.js it works as expected. As soon as I run r.js optimizer it throwing the following error:
Mismatches anonymous define() module
I don't know why, but I have the strange felling that there is a error in the UMD. The require.js page states out, that this error can occur under the following situations: source
Be sure to load all scripts that call define() via the RequireJS API. Do not manually code script tags in HTML to load scripts that have define() calls in them.
If you manually code an HTML script tag, be sure it only includes named modules, and that an anonymous module that will have the same name as one of the modules in that file is not loaded.
If the problem is the use of loader plugins or anonymous modules but the RequireJS optimizer is not used for file bundling, use the RequireJS optimizer.
If the problem is the var define lint approach, use /*global define */ (no space before "global") comment style instead.
About the first 3 points I am pretty sure that they are not the case, because the lib is working without the optimizer. The last part I tried, but I can not find any documentation about the "global define" comment. Do you know, how I can use this lib in combination with the r.js optimizer?
Thanks and regards,
Jan
'value'-method does not set a new value:
jsonpath.value({
"list": [
{
"index": 0,
"value": "default"
},
{
"index": 1,
"value": "default"
}
]
}, "$.list[?(@.index == 1)].value", "test");
'default'
Hey,
I tried to use the library where the library was created in a different scope than the tested object. This can happen in situation where using different frames for the require of the library and the tested object. In such situations the library fails. I suggest changing "x instanceof Array" to "Array.isArray(x)" and "x instanceof Object" to "typeof x === 'object'
I noticed that this example is incorrect:
JSONPath | Description |
---|---|
$..book[(@.length-1)] |
The third book via script subscript |
It is not the third book - it is the last book. The third book would be:
JSONPath | Description |
---|---|
$..book[(@.length-2)] |
The third book via script subscript |
How can I apply multiple search criteria?
In this example I'd like to get the name
of the author where the type is participant
and the primary
is false
.
var book = {
authors: [
{
type: 'participant',
primary: 'false',
name: 'John'
},
{
type: 'author',
primary: 'true',
name: 'Fred'
}
]
}
I tried this but to no success
console.log('mars = ', jsonpath.value(book, '$.book.auhors[?(@.type=="participant"),(@.primary=="false")]'));
I’m not sure if this is intentional, but while a path of '$'
— i.e. the root object — works fine with jp.query()
, jp.paths()
, jp.nodes()
, jp.parse()
, and jp.value()
when not setting a new value, it causes an error for other methods. That makes sense for jp.parent()
(although returning null
or undefined
might be friendlier than throwing an error), but it would be nice if jp.apply()
and setting a new value with jp.value()
worked too.
var jp = require('jsonpath')
let o = { foo: 'things' }
jp.value(o, '$') // returns { foo: 'things' }
let newO = { bar: 'baz' }
jp.value(o, '$', newO) // throws error “couldn’t understand path” in jp._normalize()
You can test this example on RunKit: https://runkit.com/embed/f3g7kw86i0z6
I realise that using jsonpath
with a path of '$'
is redundant, but wondered whether this behaviour was expected or not.
infinite loop bug with when step arg is defined
i += step
causing the loop termination condition to never firei != end
is again never firedAdd test to cover scenario: "$.store.book[0:4:2]"
Given a JSON such as:
[
{
"type": ["a", "b"]
},
{
"type": ["c"]
}
]
I can't figure out how to get all nodes where type=='c'? Is there a 'contains value' operator or something like that?
Thanks.
Hi, I was trying to use this module as a dependency in another Node project, but when I ran Browserify in that project it resulted in the error Uncaught TypeError: require.resolve is not a function
.
Eventually I found the additional options needed for jsonpath
:
Lines 16 to 26 in 855ddc0
Lines 39 to 46 in 855ddc0
It would help to document this to prevent confusion for anyone else using jsonpath
as a dependency in a Node project they plan to Browserify.
How can I reverse filter objects? Say, for example, the example data from the README of this repo. How can I filter all objects that don't have an isbn
property?
I tried $..[?(@.isbn==undefined)]
but that doesn't seem to be working.
obj = {}
jp.values(obj,'$."a.b"', 1)
Throws an error:
$."a.b"
---^
Expecting 'STAR', 'IDENTIFIER', 'SCRIPT_EXPRESSION', 'INTEGER', 'END', '[', got 'QQ_STRING'
Expected:
console.log(obj)
// {'a.b': 1}
There seems to be an unhandled error case:
jp.query({key: 'value'}, 42);
throws
TypeError: undefined is not a function
instead of returning an error (like when the second parameter is null
).
This is more of a feature request.
I am trying to achieve the following:
var template = {
message: 'Hello {{$.name}}! You have {{$.messages.length}} new messages.'
};
var data = {
name: 'Alice',
messages: [{/*...*/}, {/*...*/}, {/*...*/}]
};
var renderedMessage = jp.render(template, data);
// { "message": "Hello Alice! You have 3 new messages." }
The {{ }}
delimitors and the method name jp.render
are of course for illustration purposes.
Would this kind of usage be within the scope of this library?
Given the 'store' test .json file
{ "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
}
}
}
Using union for querying inexistent identifiers works fine for out of range indices
$.store.book[0,1,2,3,151]['title','author','price']
But throws an undefined variable error when one of the string identifiers doesn't exists
$.store.book[0,1,2,3]['title','author','price','fruit']
throws
TypeError: Cannot read property 'path' of undefined
at lib/handlers.js:248:27
at _.uniq._.unique (node_modules/underscore/underscore.js:516:24)
at unique (lib/handlers.js:246:10)
at Handlers.subscript-child-union (lib/handlers.js:86:12)
at lib/index.js:137:21
at Array.forEach (native)
at lib/index.js:134:14
at Array.forEach (native)
at JSONPath.nodes (lib/index.js:128:8)
at Context.<anonymous> (test/query.js:273:22)
The current jison being required has itself a broken nomnom (0.4.3) requirement that breaks shrinkwrap:
npm install jsonpath --save
npm shrinkwrap
npm ERR! Error: Problems were encountered
npm ERR! Please correct and try again.
npm ERR! missing: findit@>=0.0.3 <0.1, required by [email protected]
npm ERR! missing: source@>=0.0.3 <0.1, required by [email protected]
npm ERR! missing: es5-shim@>=1.0.0, required by [email protected]
npm ERR! missing: coffee-script@>=1.1.1 <1.2, required by [email protected]
npm ERR! missing: hashish@>=0.0.2, required by [email protected]
This is because nomnom erroneously includes a copy of browserify (but doesn't put it in the package).
If property name in the json includes a ":", it fails parsing, tried quoting and escaping
"d:Id": [
"xxxxxxx"
]
content[0].d:Id[0]
------------^
pecting 'DOT', 'DOT_DOT', '[', got 'ARRAY_SLICE'
Currently, we use this syntax to make filters:
$..book[?(@.price<30 && @.category=="fiction")]
I wonder if we can have a more concise syntax like this one:
$..book[@price<30 && @category=="fiction"]
It's more natural, right?
Hi, I'm going to build a part of my nodejs application using this module. I hope it fits my needs. I have a pretty big tree in json. If I query the first book $..book[0]
I would like to exclude specific fields, for example the price
. Like this result
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century"
}
In XPath there are ways, how about here?
var db = {
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
}
}
};
Hi - firstly, thanks for the work on this - it looks like it will be a very useful library for us.
I am trying to get it running with jspm - which like browserify has issues with the require.resolve. I have sorted this for aesprim.js by just including the modified version of the library instead (not perfect but does the trick for now).
With grammar.js it does not appear that the moduleInclude: & actionInclude: parameters that use require.resolve are used anywhere currently - are these historical, or there for future use, or am I just overlooking their purpose? Some basic testing seems to indicate that things work ok without these properties, but would be good to know what is likely to break without them.
Thanks
Glen
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.