Creating JSON formatted data from Active4D
Ajax is the foundation of dynamic Web 2.0 sites. The de facto standard for returning data to an Ajax request is JSON. To help you (and me) transform 4D data types into JSON format, I threw together a library (a4d.json) which will become part of the standard release.
Using the library
The easiest way to use the library is to create a JSON "object" like this:
Once you have a JSON object, you can add values to it directly or from a selection or RowSet.
Adding values from a selection
It is trivially easy to add one or more fields from a selection of records as JSON data. After establishing the selection of records you want in the order you want, you first need to create a map of JSON field names to 4D field or table pointers, like this:
$map := new collection("id"; ->[contacts]id; "name"; ->[contacts]fullname; \\
"recnum"; ->[contacts]; "company"; ->[company]name)
Note that if you pass a table pointer, the current record number for that table will be added to the JSON data. Note that we can also include fields from related tables as long as their is an auto relation between the main table and the related table. Once we create the map, we then call addSelection(), which has the following syntax:
addSelection($inTable; $inCountField; $inDataField {; $inMap = "" {; $inStart = 1 {; $inLimit = -1}}})
Before explaining this, here's an example:
$json := a4d.json.new
get auto relations($mto; $otm)
auto relate(true) // turn many-to-one auto relations on so we can get the related [company] record
$json->addSelection(->[contacts]; "count"; "rows"; $map)
auto relate($mto; $otm)<
This will add two fields to the $json object:
- "count" will contain the number of records in the selection of [contacts]
- "rows" will be an array, the elements of which are objects which contain one item for each field specified in $map
So a call to $json->toJSON would return something like this:
{"count":2,"rows":[{"id":"001","name":"Tiny Tim","recnum":1,"company":"TT Enterprises},{"id":"002","name":"Paul Bunyan","recnum":2,"company":"PB, Inc."}]}
Note that $inMap is optional in the call to addSelection(). If you don't pass it, or pass an empty string, a map is constructed which maps all of the fields in the table. Usually you will not want to do this.
Limiting the selection
Since you often need to batch large datasets, the addSelection() method makes it easy to get only the portion of the data you are interested in through the last two parameters:
- $inStart - If this is passed in, then the records returned will start with that index.
- $inLimit - If passed in and >= 0, then the number of records added is limited to this number.
Let's look at a common use case. The user selects a dataset of 70 records, but you want to display 10 at a time. The starting record index is passed in the query parameter "bst" and the batch size is passed in "bsz". In that case we would call addSelection() like this:
$start := max of(num(_query{"bst"}); 1) // if "bst" not present, defaults to 1
$size := min of(num(_query{"bsz"}); -1) // if "bsz" not present, defaults to -1
$json->addSelection(->[contacts]; "count"; "rows"; $map; $start; $size)
It couldn't get much easier!
Adding values from a RowSet
If you are using RowSets instead of raw selections, you use the addRowSet() method instead of the addSelection() method:
addRowSet($inRowSet; $inCountField; $inDataField {; $inMap = "" {; $inStart = 1 {; $inLimit = -1}}})
The behavior of addRowSet() is exactly analogous to addSelection(), with the following differences:
- You pass a RowSet instead of a table pointer.
- If $inMap is not passed, a map is constructed that maps the RowSet virtual column names to JSON field names.
- If $inMap is passed, it must be a semicolon-delimited list of <JSON field>:<RowSet virtual column> pairs.
For example, let's assume we only want to return the RowSet columns "id" and "name", and we want the JSON field name to be "nm" instead of "name". In that case we would pass the following map:
Again, it couldn't get much easier!
Adding values directly
For all value types except arrays, use the add() method, passing the key and value like this:
$json->add("name"; "Bob")
$json->add("age"; 27)
$json->add("employed"; true)
$json->add("birthdate"; !08/27/1931!)
$json->add("data"; $c)
To add an array, use the addArray() method:
$json->addArray("children"; $myArray)
Because the add() and addArray() methods return the JSON object, you can actually chain several calls together like this:
$json->add("name"; "Bob")->add("age"; 27)->addArray("children"; $myArray)->add("employed"; true)
Adding collections
One extra option available when adding collections is a filter, which allows to selectively include or excluded certain items from the collection. The filter is passed as a string argument after the collection, and behaves as follows:
- If the filter begins with "#", it performs an exclusion, i.e. all items that match the filter are excluded.
- Otherwise only items that match the filter are included.
- If the first character after the optional # is "/", it is considered a regular expression pattern and regex matching is done.
- Otherwise simple string comparison is performed.
So, for example, if we only wanted to add collection items beginning with "foo", we would do this:
$json->add("data"; $c; "foo@")
On the other hand, if we wanted to exclude all items that begin with "x_", we would do this:
$json->add("data"; $c; "#x_@")
Returning the JSON data
When you are finally ready to return the JSON formatted data from Active4D to the calling request, use the toJSON() method like this:
Where to get it
You can download the library here. Hope this helps with your Web 2.0 programming!
Comments (0)
You don't have permission to comment on this page.