UNPKG

json-q

Version:

Retrieves values from JSON objects (and JavaScript objects) by css-selector-like query (includes attribute filters and array flattening).

151 lines (107 loc) 4.65 kB
# json-q Retrieves values from JSON objects (and JavaScript objects) by css-selector-like query (includes attribute filters and array flattening). [![Coverage Status](https://coveralls.io/repos/github/artemdudkin/json-q/badge.svg?branch=master)](https://coveralls.io/github/artemdudkin/json-q?branch=master) [![Build Status](https://api.travis-ci.org/artemdudkin/json-q.svg?branch=master)](https://api.travis-ci.org/artemdudkin/json-q.svg?branch=master) _I am not clever enough to use XPath over objects (via [jsonpath](https://www.npmjs.com/package/jsonpath), [jsonata](https://www.npmjs.com/package/jsonata), [JSONPath](https://github.com/s3u/JSONPath), [ObjectPath](http://objectpath.org/) or [DefiantJs](http://defiantjs.com/)), while I like CSS selectors. [JSONSelect](https://www.npmjs.com/package/JSONSelect) looks abandoned, [json-query](https://www.npmjs.com/package/json-query) looks overcomplicated; so I created more simple query language (inspired by CSS attribute selectors)._ ## Example ```js const {get} = require('json-q'); const data = { a:{ b:[ {name:'xxx',c:{d:1}}, {name:'yyy',c:{d:2}} ] } }; get(data, "a b[.c.d=1] name"); //=> ['xxx'] ``` ## API ### `get(object, selector, opt)` Returns array of all fields of _object_ from any level of nesting that satisfies _selector_ (with expansions via _opt_). About selectors: - **"a"**   means: get value of all fields named "a" from all nested level of given object - **".a"** means: get value of field named "a" from first level of given object (i.e. object["a"]) - **"a b"** means: get all values of all fields "b", that are nested of field "a", that can be at any level of given object - **".a.b"** means: get field "b", that is direct descendant of field "a" from first level of given object (i.e. object.a.b) About filters: - you can add filter of any depth at any level like this: **"a.b[x.y=23] c"** - combination of filters **"[.x=23][.y=3]"** means "items heaving field x=23 AND field y=3" - you can use [attr] [attr=value] [attr~=value] [attr|=value] [attr^=value] [attr$=value] [attr*=value] [attr=value] - just like CSS attribute filters do About pseudos: - do you remember CSS pseudo-classes? All that :focus, :active, :hover etc.? Pretty useless for objects, even :empty and :first-child, but it is a good concept to add user-defined (parameterless) functions. - you can add it anywhere: **"a b:empty.c"** - look at :empty and see the section about expansions Another thing - I consider array as multiple values of field, so 1. arrays of arrays become flat, i.e. {a:[[1], [2,3]]} becomes {a:[1, 2, 3]}} 2. you can not address array items by index, i.e. ```js var data = { a:{ b:{ c:[1,2] } } }; get(data, ".a.b.c"); //=> [1,2] get(data, ".a.b.c.0"); //=> [] var data = { a:{ b:[ {c:1}, {c:2}  ] } } get(data, ".a.b.c"); //=> [1,2] also ``` ## Escaping Special Characters There are no strings now. So if you have special symbols at field names then you should escape it - I mean dot, colon, square brackets and space symbols (i.e. " .:[]"). ```js var data = { "a:c":{ x:[1,2] } }; get(data, "a:c"); //=> Error "Pseudo 'c' not found." get(data, "a\\:c"); //=> {x:[1, 2]} ``` ## Expansions (i.e. opt param at get) You can add your own filter or pseudo (or re-define existing one). The difference between them is that filter can only filter (obviously) while pseudo can do anything with intermediate result - i.e. delete, add, change (at any depth) objects at result array. For instance, new filter for [a!=some value] ```js var d = [{a:{name:1}}, {a:{name:2}}] var p = "a[name!=1]"; get( d, p, { operator : { "!=" : function(complexFieldValue, value){ return true_if_one_is_true(complexFieldValue, value, (a,b)=>{return a!=b;}); }, } }); // => [{name:2}] ``` And pseudo for add "abc" string to all fields names at any level (dont ask me what for) ```js var d = [{a:{b:1}}, {a:{c:2}}] var p = "a:abc.cabc"; get( d, p, { pseudo : { "abc" : function(arrValue){ return arrValue.map(value => { deep_iterate(value, (_obj) => { for(var i in _obj) { if (typeof _obj[i] !== 'object') { _obj[i+'abc'] = _obj[i]; delete _obj[i]; } } }); return value; }) }, } }); // => [2] ``` ## Browser Please use index.min.js at browser (IE9+ and other modern browsers) ## License MIT