15

I have been looking at JSONPath and though it seems pretty well done, I wonder if anyone has worked with it and can comment on its usability, or can recommend alternatives? What would be really slick is if there was a plugin for JQuery that did something like this. I have been searching the plugins and coming up empty handed. Anyway, before I spend time getting to know JSONPath (which has some aspects I am not keen on), or before I reinvent wheels, I thought I'd see if anyone had an angle on this...

To give you an idea what I mean, imagine this Javascript object:

var Characters=[
        {
            id: "CuriousGeorge",
            species:"Monkey",
            mood: "curious",
            appendage: [
                { 
                    type: "hand",
                    side: "left",
                    holding: [ 
                        { id: "Banana" } 
                    ]
                },
                { 
                    type: "hand",
                    side: "right",
                    holding: []
                }, 
                { 
                    type: "foot",
                    side: "left",
                    holding: []
                },
                { 
                    type: "foot",
                    side: "right",
                    holding: [ 
                        { id: "YellowHat" },
                        { id: "Keys" }
                    ]
                }
            ]
        },
        {
            id: "ManInYellowHat",
            species: "Human",
            mood: "angry",
            //...ok, you get it...
        }
    ]

Wouldn't it be great to get to of some of the deeper objects by something like Jquery selectors?

var banana=SomeUtility("Characters holding #Banana").get(0);
var leftHands=SomeUtility("Characters appendage[type=hand][side=left]").get();

(This may qualify for worlds corniest code example, but hey, my kids just watched this. And I can't use real example because of NDA...)

...And, to make it more interesting, if I were to create such a thing, would anyone use it?

jwl
  • 10,268
  • 14
  • 53
  • 91
  • 1
    Adding a [json] tag seems appropriate. – Tomalak May 13 '09 at 16:51
  • Interesting question. An XPath equivalent for JSON would be a great thing, though the implementations I looked at (JSONPath and dojox.json.query) seem to use their own syntax for some reason I don't understand. – Tomalak May 13 '09 at 17:44
  • The dojo jsonquery is interesting but yes, the syntax is frankly bizarre and tries to accomplish a lot more than I want (and therefore clutters things up). I should look at it more closely though. I always steer clear of dojo simply because it seems overly sophisticated/complicated -- too much to learn to do something simple. That's just my personal impression – jwl May 14 '09 at 14:11

8 Answers8

6

Check out JSON Select - CSS-like selectors for JSON.

orad
  • 15,272
  • 23
  • 77
  • 113
4

Definitely would be a useful utility.

My opinion is that the best way to approach this would be to stay as similar as possible to css selectors, as you indicate. I'd recommend looking under the hood at jquery's implementation of selectors.

I would suggest something like

var banana = object.function(jsonObect, "holding #Banana");
var leftHands = object.function(jsonObject, "appendage[type=hand][side=left]");

instead of your usage examples.

I'm not sure how the upcoming native json support will affect this...

cofiem
  • 1,384
  • 1
  • 17
  • 29
  • Yes, passing in the object will make sense. I did some hacking on this last night and am encouraged by the possibilities.... more to come! – jwl May 14 '09 at 14:05
  • Please check out my answer, I have created a prototype – jwl May 17 '09 at 15:10
4

OK, I have created a prototype for this, available here: http://code.google.com/p/jfunk/

It has already proven useful for me, so I will probably slowly improve and refactor it into something nice. But if I get good feedback, I can move more quickly. I would also welcome help.

jwl
  • 10,268
  • 14
  • 53
  • 91
  • nice. I just had a quick glance over the code. certainly got the core of the idea there - might be some possible tweaks to make it more efficient, but seems to work ok just now. I'll have a look at it in a week or two when I have some more time. – cofiem May 19 '09 at 14:04
  • yes, didn't have time to even think about efficiency-- other than to realize that DOM has some real advantages here. _but_ whatever tasks this is useful for may not be able to be efficiently implemented any other way... though that would argue for redesigning data... oh well, i think this will be useful – jwl May 19 '09 at 14:22
  • empty repo and no changes since early prototype stage? – Qrilka Nov 25 '11 at 18:40
  • @Qrilka, yes, you can find something in the downloads section http://code.google.com/p/jfunk/downloads/list, no proper repo though. there was really no interest in this project and my own need for it disappeared so... I dropped it. If you think it's a good idea I wouldn't mind handing it over. Although, I am tinkering around with node.js, and may decide I could somehow use this after all depending on how I create some data structures... – jwl Nov 28 '11 at 23:02
3

Try to using JSPath -- https://github.com/dfilatov/jspath.

JSPath is a domain-specific language (DSL) that enables you to navigate and find data within your JSON documents. Using JSPath, you can select items of JSON in order to retrieve the data they contain.

JSPath for JSON like an XPath for XML.

dfilatov
  • 191
  • 1
  • 3
2

I just wrote a clientside JS-lib that does just this - it makes it possible to query a JSON structure with XPath.

@jlarson - with "defiant.js", you can query your JSON structure like this (this lib extends the global JSON object):

JSON.search( Characters, '//*[id="Banana"]' );



This call will return an array with matching nodes AND those matches won't be detached from your original JSON object (same behaviour as when working with XML + XPath). To illustrate what I mean, here is a little pseudo(-ish) code:

var store = {
    "book": [
        {
            "id": 1,
            "price": 8.95,
            "title": "Sayings of the Century",
            "category": "reference",
            "author": "Nigel Rees"
        },
        {
            "id": 2,
            "price": 22.99,
            "title": "The Lord of the Rings",
            "category": "fiction",
            "author": "J. R. R. Tolkien",
            "isbn": "0-395-19395-8"
         }
    ]
};

var b1 = JSON.search( store, '//book[1]' );
b1[0].isbn = '12345';

console.log( store.book[0].isbn );
// 12345

This lib is thus far for browser and clientside but I've plans to re-write it for NodeJS eventually. Check out the Xpath evaluator here; that demonstrates the functionality. There are also pre-written Xpath expressions as well:

http://defiantjs.com/#xpath_evaluator

You can find the lib at Github:
https://github.com/hbi99/defiant.js

Finally, there is a little more functionality in "defiant.js" and if you're interested, you'll hopefully read about it over there (http://defiant.com)

I hope you'll find it useful.

Hakan Bilgin
  • 1,113
  • 12
  • 11
2

Dojo's dojo.getObject has a facility that works loosely like this, where you can provide a path like "a.b.c" to the property you want to fetch.

Check it out:

http://api.dojotoolkit.org/jsdoc/1.3/dojo.getObject

I don't think it understands arrays quite that well and I think it is missing a full-featured selector language like the one you are suggesting.

As for usage, I've coded a selector language like the one you are suggesting, but for a client, and array addressing is very proprietary to their particular object structure.

I would definitely use a system like this if you were to make it, and perhaps even contribute if I saw an area I could help with.

Maciek
  • 3,322
  • 6
  • 28
  • 35
  • I hadn't found this one, interesting. I DEFINATELY feel the pain behind "Useful for longer api chains where you have to test each object in the chain", as I've many times had to write junk like var a=(b ? c ? d ? b.c.d : null : null : null); [though usually much uglier and including other conditions]. Still, this seems underwhelming overall... OK, definitely adding weight to creating a parallel Jquery-like library for Json/JavascriptObjects, though there will be obvious necessary differences, and I doubt performance will be as good... – jwl May 14 '09 at 16:08
  • Please check out my answer, I have created a prototype – jwl May 17 '09 at 15:10
1

Looks like there's a new option: jQuery-JSONPath. Seems to be exactly what you're asking for.

gregsdennis
  • 7,218
  • 3
  • 38
  • 71
0

Not exactly what you are looking for, but check out object-scan. It is a bit more verbose, but is much more powerful and supports more (complex) use cases. Here is an example of how one could use it

// const objectScan = require('object-scan');

const Characters = [{ id: 'CuriousGeorge', species: 'Monkey', mood: 'curious', appendage: [{ type: 'hand', side: 'left', holding: [{ id: 'Banana' }] }, { type: 'hand', side: 'right', holding: [] }, { type: 'foot', side: 'left', holding: [] }, { type: 'foot', side: 'right', holding: [{ id: 'YellowHat' }, { id: 'Keys' }] }] }, { id: 'ManInYellowHat', species: 'Human', mood: 'angry' }];

console.log(objectScan(['**.holding.id'], {
  useArraySelector: false,
  abort: true,
  rtn: 'parent',
  filterFn: ({ value }) => value === 'Banana'
})(Characters));
// => { id: 'Banana' }

console.log(objectScan(['**.appendage[*]'], {
  rtn: 'value',
  filterFn: ({ value }) => value.type === 'hand' && value.side === 'left'
})(Characters));
// => [ { type: 'hand', side: 'left', holding: [ { id: 'Banana' } ] } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.7.1"></script>

Disclaimer: I'm the author of object-scan

Make sure you check out the readme. It has a lot of examples in it.

vincent
  • 1,953
  • 3
  • 18
  • 24