# Foundations JSON API
API | Description |
---|---|
query | Perform query on JSON data object |
Schema.validate | Validate a data object as valid JSON and, optionally, against a JSON schema object. |
Schema.checkPropertyChange | Checks an object property for a valid value given its schema. |
Transformer.initialize | Register a template for transforming JSON data objects. |
Transformer.merge | Merge two different JSON data objects. |
Transformer.transform | Transform JSON data object(s) according to a set of named transforms in a registered template. |
Transformer.transformAndMerge | Transform JSON data according to a set of named transforms in a registered template and merge it with other JSON data. |
Including foundations.json in Your Code
To use foundations.json in your code:
-
Include the following two script tags in your app's Index.html file:
<script src="/usr/palm/frameworks/mojo/mojo.js" type="text/javascript" x-mojo-version="1"></script> <script src="/usr/palm/frameworks/mojoloader.js" type="text/javascript"></script>
-
Load and reference
foundations.json
in your JavaScript:var jsonlib = MojoLoader.require({name:"foundations.json", version: "1.0"}); var fjson = jsonlib["foundations.json"];
You can then reference methods using standard dot notation. For example (Schema.validate
):
Mojo.Log.info("FoundJSON: BadObj validate "+ JSON.stringify(fjson.Schema.validate(BadObj, jsonSchema)));
query
Performs a JSONQuery on a provided object and returns the results. This takes the form:
results = query(searchQuery, object);
If no object is provided (just a query), it returns a "compiled" function that evaluates objects according to the provided query. Compiled functions take the following form:
evaluator = query(searchQuery); results = evaluator(object);
JSONQuery provides a comprehensive set of data querying tools including filtering, recursive search, sorting, mapping, range selection, and powerful expressions with wildcard string comparisons and various operators. JSONQuery generally supersets JSONPath and provides syntax that matches and behaves like JavaScript where possible.
Supported Operators
JSONQuery evaluations begin with a provided object, which can be referenced with $
. From the starting object, various operators can be successively applied, each operating on the result of the last operation.
You can explicitly begin your query with $
, but it is not necessary, as it is implicitly auto-inserted. This allows you to start queries with operators. JSONQuery uses syntax that is similar to JavaScript (with a number of extra operators).
A simple query looks like this:
var data = {foo:"bar"}; var results = query("$.foo",data); // results == "bar"
For the code samples in the table below, assume the following initializations and data structure:
var jsonlib = MojoLoader.require({name:"foundations.json", version: "1.0"}); var fjson = jsonlib["foundations.json"]; var ItemPrices = [{ "Item" : "drink", "price" : 2}, { "Item" : "jacket", "price" : 22}, { "Item" : "shoes", "price" : 17}, { "Item" : "baseball", "price" : 6}, { "Item" : "bat", "price" : 4}, { "Item" : "book", "price" : 12} { "Item" : "BELL", "price" : 10}];
Operator | Description | Example/Output |
---|---|---|
.property |
Returns the indicated object property, behaving exactly like JavaScript. |
Mojo.Log.info("results = "+ fjson.query(".foo",{foo:"bar"})); results = bar |
[expression] | Returns the property name/index defined by the expression evaluation, behaving exactly like JavaScript. |
Get the value of Item for the second element:
Mojo.Log.info("FoundJSON : results = "+fjson.query("\[1\].Item", ItemPrices)); results = jacket |
[?expression] | Returns array items matching the expression. This operator does not need to be in brackets, you can simply use ?expression, but without "containment", no operators can be used afterwards. |
Get elements whose price is greater than 7:
Mojo.Log.info("results = "+ JSON.stringify(fjson.query("\[?price > 7\]", ItemPrices))); results = [{"Item":"jacket","price":22}, {"Item":"shoes","price":17}, {"Item":"book","price":12}, {"Item":"BELL","price":10}] |
[^?expression] | Same as [?expression] except that duplicate values/objects are removed from the result set | |
[/expression], [], |
Indicates a sort operation ("/" = ascending and "" = descending). Multiple comma-delimited sort expressions are possible for multiple sort orders (first being highest priority), i.e., [/LastName,/FirstName] .
|
Get items whose price is greater than 7, sort by Item: Mojo.Log.info("results = "+ JSON.stringify(fjson.query("\[?price > 7\]\[\/Item\]", ItemPrices))); results = [{"Item":"BELL","price":10}, {"Item":"book","price":12}, {"Item":"jacket","price":22}, {"Item":"shoes","price":17}] |
[=expression] | Performs a map operation on an array, creating a new array with each item being the evaluation of the expression for each item in the source array. |
Create an array of prices from ItemPrices:
Mojo.Log.info("results = "+ JSON.stringify(fjson.query("\[=price\]", ItemPrices))); results = [2,22,17,6,4,12,10] |
[start:end:step] | Performs an array slice/range operation, returning the elements from the optional start index to the optional end index, stepping by the optional step number. |
Get every other element:
Mojo.Log.info("results = "+ JSON.stringify(fjson.query("\[0:7:2\]", ItemPrices))); results = [{"Item":"drink","price":2}, {"Item":"shoes","price":17}, {"Item":"bat","price":4}, {"Item":"BELL","price":10}] |
[expr,expr] | This a union operator, returning an array of all the property/index values from the evaluation of the comma delimited expressions. | |
.* or [*] | This returns the values of all the properties of the current object. | |
$ | This is the root object, If a JSONQuery expression does not being with a $, it will be auto-inserted at the beginning. | |
@ |
This is the current object in filter, sort, and map expressions. Note that names are auto-converted to property references of the current object in expressions, but @ can be used for index access on the current object. The following queries are identical:
[?name='Fred'] [?@.name='Fred'] [?@['name']='Fred'] |
|
..property | Performs a recursive search for the given property name, returning an array of all values with such a property name in the current object and any sub-objects. | |
expr = expr | Performs a comparison (like JS's ==). When comparing to a string, the comparison string may contain wildcards * (matches any number of characters) and ? (matches any single character). |
Get all Items beginning with lowercase "b":
Mojo.Log.info("results = "+ JSON.stringify(fjson.query("\[?Item='b*'\]", ItemPrices))); results = [{"Item":"baseball","price":6}, {"Item":"bat","price":4}, {"Item":"book","price":12}] |
expr ~ expr | Compares strings without considering case. |
Get all items that start with the letter b, regardless of case. Mojo.Log.info("results = "+ JSON.stringify(fjson.query("\[?Item~'b*'\]", ItemPrices))); results = [{"Item":"baseball","price":6}, {"Item":"bat","price":4}, {"Item":"book","price":12}, {"Item":"BELL","price":10}] |
..[?expression] | This will perform a deep search filter operation on all the objects and subobjects of the current data. Rather than only searching an array, this will search property values, arrays, and their children. | |
$1,$2,$3, etc. | These are references to extra parameters passed to the query function or the evaluator function. |
Mojo.Log.info("results = "+ JSON.stringify(fjson.query("\[?Item=$1 & price=$2\]", ItemPrices,"book",12))); results = [{"Item":"book","price":12}] It can also be used in an evaluator function. var evaluator = fjson.query("\[?Item=$1 & price=$2\]"); Mojo.Log.info("results = "+ JSON.stringify(evaluator(ItemPrices,"book",12))); results = [{"Item":"book","price":12}] |
+, -, /, *, &, |, %, (, ), <, >, <=, >=, !=
|
These operators behave just as they do in JavaScript. |
Multiple operators can be used successively to create complex queries. For example, to find all the objects from the products
array with a price less than 15, sorted in descending order by rating, and showing only the first three items from the resultant list, we could do this query:
//** Query = $.products[?price < 20][\rating][0:3] var products = [{ "book" : "Color Purple", "price" : 21, "rating":8}, { "book" : "Obama", "price" : 12, "rating":4}, { "book" : "Pride and Prejudice", "price" : 17, "rating":6}, { "book" : "Winnie the Pooh", "price" : 22, "rating":9}, { "book" : "Crime and Punishment", "price" : 14, "rating":10}, { "book" : "Brothers Karamazov", "price" : 12, "rating":9} { "book" : "Anna Karenina", "price" : 10}, "rating":8]; Mojo.Log.info("results = "+ JSON.stringify(fjson.query("\[?price < 20\]\[\\rating\]\[0:3\]", products))); results = [{"book":"Crime and Punishment","price":14,"rating":10}, {"book":"Brothers Karamazov","price":12,"rating":9}, {"book":"Anna Karenina","price":10,"rating":8}]
Queries can use the regular operators to form general expressions based on more complex query operations. For example, to find the difference between the lowest priced item and the highest priced item in an array:
$.store.book[\price][0].price – $.store.book[/price][0].price
Syntax
query( {search query}, {JSON object});
Parameters
Argument | Required | Type | Description |
---|---|---|---|
query | Yes | string | Search query. |
JSON object | No | any | JSON search object. |
Schema.validate
You can use this API to determine if a JSON data object is valid JSON. Optionally, you can also validate it against a passed JSON schema object.
Syntax
Schema.validate( {instance object}, {schema object});
Parameters
Argument | Required | Type | Description |
---|---|---|---|
instance object | Yes | any | JSON data object. |
schema object | No | any | JSON schema object. |
Returns
{ valid : boolean, errors : [ { property : string, message : string } ] }
Argument | Required | Type | Description |
---|---|---|---|
valid | Yes | boolean | Is instance object valid according to schema flag. |
errors | Yes | array | Array of inline objects. Returns empty array ("[]") if no errors. |
errors[n].property | No | string | Property that had the error. |
errors[n].message | No | string | Error message |
Example
var jsonlib = MojoLoader.require({name:"foundations.json", version: "1.0"}); var fjson = jsonlib["foundations.json"]; var jsonSchema = {"id":"com.palm.schema.test:1", "type": "object", "properties" : { "_kind" : {"type": "string", "value":"com.palm.schema.test:1"}, "foo": {"type": "string", "description": "foo string"}, "bar": {"type": "string", "description": "bar string"}, "isMember": {"type": "boolean", "description" : "Is member flag" } } }; var BadObj = {"_kind":"com.palm.schema.test:1", "foo":"myFoo", "bar":"myBar", "isMember": "true"}; Mojo.Log.info("FoundJSON: BadObj validate "+ JSON.stringify(fjson.Schema.validate(BadObj, jsonSchema)));
Example Output
{"valid":false,"errors":[{"property":"isMember","message":"string value found, but a boolean is required"}]}
Schema.checkPropertyChange
Checks an object property for a valid value given its schema. Unlike the validate method, it assumes the passed schema object is valid.
Syntax
Schema.checkPropertyChange( {instance object}, {schema object}, "property");
Parameters
Argument | Required | Type | Description |
---|---|---|---|
instance object | Yes | any | JSON data object. |
schema object | Yes | any | JSON schema object. It is assumed this is valid. |
property | Yes | string | Name of schema property. |
Returns
{ valid : boolean, errors : [ { property : string, message : string } ] }
Argument | Required | Type | Description |
---|---|---|---|
valid | Yes | boolean | Is instance object valid according to schema flag. |
errors | Yes | array | Array of inline objects. Returns empty array ("[]") if no errors. |
errors[n].property | No | string | Property that had the error. |
errors[n].message | No | string | Error message |
Example
var jsonlib = MojoLoader.require({name:"foundations.json", version: "1.0"}); var fjson = jsonlib["foundations.json"]; var jsonSchema = {"id":"com.palm.schema.test:1", "type": "object", "properties" : { "_kind" : {"type": "string", "value":"com.palm.schema.test:1"}, "foo": {"type": "string", "description": "foo string"}, "bar": {"type": "string", "description": "bar string"}, "isMember": {"type": "boolean", "description" : "Is member flag" } } }; var BadObj = {"_kind":"com.palm.schema.test:1", "foo":"myFoo", "bar":"myBar", "isMember": "true"}; var GoodObj = {"_kind":"com.palm.schema.test:1", "foo":"myFoo", "bar":"myBar", "isMember": true}; Mojo.Log.info("FoundJSON: checkPropertyChange good object "+ JSON.stringify(fjson.Schema.checkPropertyChange(GoodObj, jsonSchema, "isMember"))); Mojo.Log.info("FoundJSON: checkPropertyChange bad object "+ JSON.stringify(fjson.Schema.checkPropertyChange(BadObj, jsonSchema, "isMember")));
Example Output
FoundJSON: checkPropertyChange good object {"valid":true,"errors":[]}, FoundJSON: checkPropertyChange bad object {"valid":false,"errors":[{"property":"isMember.isMember","message":"string value found, but a boolean is required"}]}
Transformer.initialize
Register a template containing a set of named transforms. This template is then used for all other operations.
Syntax
void initialize(template object);
Parameters
Argument | Required | Type | Description |
---|---|---|---|
template object | Yes | any | JSON object containing set of named transforms. |
Returns
None.
Example
var jsonlib = MojoLoader.require({name:"foundations.json", version: "1.0"}); var fjson = jsonlib["foundations.json"]; var myTransformer = new fjson.Transformer(); var template = { "user": { FirstName: "!{person.displayName}", LastName: "!{person.surname}", Country : "USA", State:"CA", Location: "!{person.building}" } }; myTransformer.initialize(template);
Transformer.merge
Merge two different JSON data objects.
Syntax
merge (olddata, newdata);
Parameters
Argument | Required | Type | Description |
---|---|---|---|
olddata | Yes | any | JSON data object(s) that are going to be merged with the new objects. |
newdata | Yes | any | JSON data object(s) that are going to be merged with old data. |
Returns
{ merged data }
Argument | Required | Type | Description |
---|---|---|---|
merged data | Yes | any | JSON data object(s)—old data object(s) merged with new data object(s). |
Example
var jsonlib = MojoLoader.require({name:"foundations.json", version: "1.0"}); var fjson = jsonlib["foundations.json"]; var myTransformer = new fjson.Transformer(); olddata = {"displayName": "Fred"}; newdata = {"street": "Main"}; Mojo.Log.info("FoundJSON: merge ="+ JSON.stringify(myTransformer.merge(olddata, newdata)));
Example Output
FoundJSON: merge ={"displayName":"Fred","street":"Main"},
Transformer.transform
Transform JSON data object(s) according to a set of named transforms in a registered template.
A simple template might look as follows:
{ "to": { name: "!{displayName}", type: "first" }
The !{...}
indicates a jsonPath expression that should be evaluated for the given data.
Syntax
transform (data);
Parameters
Argument | Required | Type | Description |
---|---|---|---|
data | Yes | any | JSON data object(s) that are going to be transformed given the set of named transforms in the last registered template. |
Returns
{ transformed data }
Example
var jsonlib = MojoLoader.require({name:"foundations.json", version: "1.0"}); var fjson = jsonlib["foundations.json"]; var myTransformer = new fjson.Transformer(); var template = { "user": { FirstName: "!{person.displayName}", LastName: "!{person.surname}", Country : "USA", State:"CA", Location: "!{person.building}" } }; myTransformer.initialize(template); var data = { "person": {"displayName" : "Fred", "surname" : "Flintstone", "building":"3-1" }}; Mojo.Log.info("FoundJSON: transform ="+ JSON.stringify(myTransformer.transform(data)));
Example Output
FoundJSON: transform ={"user":{"FirstName":"Fred","LastName":"Flintstone","Country":"USA","State":"CA","Location":"3-1"}}
Transformer.transformAndMerge
Transform the new data with the registered template and merge it with the old data.
Syntax
transformAndMerge (olddata, newdata);
Parameters
Argument | Required | Type | Description |
---|---|---|---|
olddata | Yes | any | JSON data object(s) that are going to be merged with the new objects. |
newdata | Yes | any | JSON data object(s) that are going to be transformed (if template registered) then merged with old data. |
Returns
{ merged data }
Argument | Required | Type | Description |
---|---|---|---|
merged data | Yes | any | JSON data object(s)—old data object(s) merged with new data object(s). |
Example
var jsonlib = MojoLoader.require({name:"foundations.json", version: "1.0"}); var fjson = jsonlib["foundations.json"]; var myTransformer = new fjson.Transformer(); var template = { "Address" : "!{street}"}; myTransformer.initialize(template); olddata = {"displayName": "Fred"}; newdata = {"street": "Main"}; Mojo.Log.info("FoundJSON: transformAndmerge ="+ JSON.stringify(myTransformer.transformAndMerge(olddata, newdata)));
Example Output
FoundJSON: transformAndMerge ={"displayName":"Fred","Address":"Main"},