The JSON Pointer was created to get the reference of properties in a JSON object. It has its own simple query system which helps you traverse the property tree. It is also "null-safe" you don't have to check if every single step in your path exists or no
npm install untold-json-pointer
npm install untold-json-pointer --save
`
Usage
For the purpose of this example we will write queries for the Character JSON object.
$3
First, import the json pointer library.
For the web:
`javascript
import JSONPointer from 'untold-json-pointer';
`
In node:
`javascript
const JSONPointer = require('untold-json-pointer');
`
Next, you should create a new instance from the JSON Pointer:
`javascript
const pointer = new JSONPointer();
`
Let's say you want to get the name property of the character object. You have 2 ways to do this. You can pass the string into the pointer:
`javascript
const result = pointer.executeQuery(character, '.name');
`
Or you can create a query object first
`javascript
const query = pointer.createQuery('.name');
const result = pointer.executeQuery(character, query);
`
The second aproach is useful when you want to execute the same query on different objects because you save time on parsing.
$3
The result object has the following methods and properties.
The _isQueryValid_ property tells you if the parser was able to process your query
`javascript
result.isQueryValid;
`
The _error_ property stores the error message from the parser if the _isQueryValid_ property is false
`javascript
result.error;
`
The _getAll()_ method returns all properties matching our query. The result is an array and every item in the array represents one of the properties. The length
of the array is empty if nothing matches your query. It becomes useful when we we are using the onEach operator which is represented by a _|_ character.
`javascript
result.getAll();
`
The _getSingle()_ method returns the first property which maches our query. The result is null if nothing matches our query. If you are only using paths and
indexers then you should always use this method because multiple results can only occure for filters.
`javascript
result.getSingle();
`
$3
Every member in the path are being identified with the '.' character. That's also true for the root member. You have to put the path parts between string
literals if they contain space character.
`javascript
const nameOfCharacter = pointer.executeQuery(character, '.name');
const nameOfWeapon = pointer.executeQuery(character, '.weapon.name');
const originalOwnerHasSpace = pointer.executeQuery(character, '.weapon."original owner');
console.log(nameOfCharacter.getSingle()); // 'Conan'
console.log(nameOfWeapon.getSingle()); // 'sword'
console.log(originalOwnerHasSpace.getSingle()); // 'Bob'
`
You don't have to worry about missing members in your JSON.
`javascript
const wrongPath = pointer.executeQuery(character, '.wrong.path');
console.log(wrongPath.getSingle()); // null
`
$3
Indexers are very similar to their JavaScript counterparts. You can use numbers or string to access members of an object.
`javascript
const nameOfTheFirstItem = pointer.executeQuery(character, '.items[0].name');
const nameOfTheWeapon = v.executeQuery(character, '.weapon["name"]');
console.log(nameOfTheFirstItem.getSingle()); // 'flask'
console.log(nameOfTheWeapon.getSingle()); // 'sword'
`
It is also null-safe so you don't have to worry about going out of bounds.
`javascript
const indexerOverLength = pointer.executeQuery(character, '.items[5].name');
console.log(indexerOverLength.getSingle()); // null
`
$3
It is possible to access every single item in an array at the same time. The _|_ operator iterates through the array and returns the specified property from
each element.
`javascript
const itemNames = pointer.executeQuery(character, '.items|name');
console.log(itemNames.getSingle()); // "flask"
console.log(itemNames.getAll()); // ["flask", "meat", "diamond", "golden key"]
`
When your query has a filter, you can start using the _getAll()_ and _setAll()_ methods because you can never be sure that it only matches one item.
$3
Filters can be very powerful because you can write a condition which will be executed against every single member of the array and identifies the matching ones.
Usually a filter looks like this: { lefthandSide operator righHandSide } The sides can be path or value. All of the regular javascript number and string
operators are available (<, <=, >, >=, ==, ===, !=, !==) and also we have a special operator for contains which is the ':' character.
`javascript
const itemsWhereWeightGreateThanOne = pointer.executeQuery(character, '.items{ .weight > 1}');
console.log(itemsWhereWeightGreateThanOne); // [{"name":"diamond","weight":2,"quantity":1,"equipped":false}]
`
The _true_, _false_, _null_ keywords are also avilable in the queries.
`javascript
const equipped = pointer.executeQuery(character, '.items{ .equipped == true}');
const notEquipped = pointer.executeQuery(character, '.items{ .equipped == true}');
const withoutPrice = pointer.executeQuery(character, '.items{ .price == null}');
`
$3
For simple queries you can use the _setSingle()_ method to set the value of the selected property.
`javascript
const result = pointer.executeQuery(character, '.name');
result.setSingle('Joe');
console.log(character.name); // "Joe"
`
If you are pointing to multiple items using the _|_ operator then the _setSingle()_ method will only update the first matching item. In that case you should use
the _setAll()_ method.
Built With
- TypeScript - The language being used
- PEGjs - Parse generator for the query
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please make sure to update tests as
appropriate.
Building the application:
`
npm run build
`
Generating types for TypeScript:
`
npm run build:types
`
Executing tests in chrome:
`
npm run test
`
Authors
- Krisztian Nagy - LinkedIn
License
MIT
`
``