CSS Selectors for JSON - GistLabs/mechanize GitHub Wiki
CSS Selectors, a JSON query language
CSS Selectors are an elegant mix of simplicity and power. They are also nearly ubiquitous to everyone involved in web development. This page describes how CSS Selectors are made available to searching JSON.
Examples
"doc": {
"uri": "/id/42",
"rel": "self",
"next": {
"uri": "/id/43",
"about": {
"href": "a"
}
},
"prev": {
"uri": "/id/41",
"about": {
"href": "a"
}
},
"line-items": [
{ "uri": "/item/{id}", "types": "type1", "id": "3d4"},
{ "uri": "/item/{id}", "types": "type1 type2", "id": "ab2"},
{ "uri": "/item/{id}", "types": "type3", "id": "54e"}
]
}
Here are some examples of applying CCS Selectors to this JSON:
- find
next
.getAttribute("uri") is/id/43
- find
doc next
is same result asnext
in this case - findAll
[href]
size is2
, the "about" nodes - find
doc
.findprev
.getAttribute("uri") is/id/41
- findAll
doc line-items[types~="type1"]
size is2
- findAll
doc line-items[types~="type2"]
size is1
Flexibility Built-in
One important reason to use a query language to find content in a document type is the flexibility it enable for evolvable systems.
Consider the following CSS Selector: doc line-items[types~="type2"]
. This will function exactly the same even if the JSON document was restructured like this:
"doc": {
"_links": [
{"rel": "self", "uri": "/id/42"},
{"rel": "next", "uri": "/id/43", "about": {"href": "a"}},
{"rel": "prev", "uri": "/id/41", "about": {"href": "a"}}
],
"_properties": [
{"line-items": [
{ "uri": "/item/{id}", "types": "type1", "id": "3d4"},
{ "uri": "/item/{id}", "types": "type1 type2", "id": "ab2"},
{ "uri": "/item/{id}", "types": "type3", "id": "54e"}
]}
]
}
Not all of the selectors are quite so flexible. Notice that doc next
would need to be changed, perhaps to doc [rel="next"]
. For hyperlink definitions see Finding JSON Links to learn how we handle this flexibility.
The benefit is in creating extra degrees of freedom for the server/producer to evolve and change, without causing breaking changes to clients/consumers.
Implementation
This implementation is is based on a wrapping object model around a standard JSON parser.
- The object model is based on nodes with simple attributes and children nodes. See AbstractNode.java. This model does obscure the JSON array, treating it like an ordered list of named child objects.
- The CSS Selectors is implemented by modifying the css-selectors library to make use of an adapter [CssNodeHelper.java](https://github.com/GistLabs/mechanize/blob/master/src/main/java/com/gistlabs/mechanize/document/node/CssNodeHelper.java(https://github.com/GistLabs/mechanize/blob/master/src/main/java/com/gistlabs/mechanize/document/node/CssNodeHelper.java).
- The JSON parser is simply JSON in Java, chosen to be stand-alone and simple.
No efforts at optimization have been undertaken, instead all focus is on testing ideas for merit.