ParseJSON

Release:

 • 4.6 •  5.0 •  5.1 •  5.2 •  5.3 •  5.4 •   •  6.0 •  6.1 •  6.2 •  6.3 •  6.4 •  6.5 •  6.6 •  7.0 •  7.1

New to Analytica 5.0


ParseJSON( json, schema, flags )

Parses «json» text into Analytica data structures without using a schema. Usually, you will obtain the «json» text from a call to ReadFromUrl (a web-service call) or ReadTextFile.

JavaScript Object Notation (JSON) is a widely used lightweight data-interchange format. It is easy for humans and machines to read and write. Nowadays it is a standard in nearly every modern webservice.

The Analytica data structures for the result, as well as the structure of the «schema», have changed in 7.0 to be much easier to use. If you load a model from an earlier release, a legacy parameter is added,

ParseJSON( json, Legacy: True )

which forces the older behavior for backward compatibility. To see that behavior, select 6.6 or earlier on the release bar at the top of this page.

Parameters

  • «json»: A JSON-formatted text to parse.
  • «schema»: (Optional) The identifier of a Struct object. If omitted, defaults to _JSON.
  • «flags»: (optional) A bit field of flags that control various aspects of parsing. Bit settings are
    • 1 = During schema-free parsing, create local indexes .Dim1, .Dim2, ... for arrays. Without this, each level of an array is returned as a reference to a list.

The following parameters are deprecated, but will show up when a legacy model that uses ParseJSON is loaded into Analytica 7.0 or later (to preserve backward compatibility).

  • «legacy»: (optional) Set to True to use the older, pre-7.0 data structures and «objectSchema».
  • «objectSchema»: (optional) Used only for legacy models. Hidden parameter, but you might see it in a legacy model.

Model with these examples

The examples that appear on this page are in this example model:

Download: ParseJSON examples on docs.ana

Parsing without a schema

The top-level item in a JSON text document should be a JSON object, for example:

Variable json1 
Definition: 
    '{ "title" : "1984",
       "author" : "George Orwell",
       "year" : 1949,
       "pages" : 336,
       "paperback" : true
     }'

Here is the result of parsing that JSON text without providing a schema:

ParseJSON(json1)
ParseJSON 7.0 result topLevel.png

This depicts an instance of the built-in Struct named _JSON. Double click on the «_JSON» cell to see its internals.

ParseJSON 7.0 result secondLevel.png

These members contain the data. If you save the result of ParseJSON(json1) in a variable named json1_parse1, you can access the values using, e.g.,

json1_parse1 -> author

which returns "George Orwell".

JSON with nested objects and no schema

With a JSON document containing nested objects, it creates local indexes at each level. To prevent the indexes from combining into a rectangular array, it places each member object in a reference.

Variable json2 
Definition: 
    '{ "title" : "1984",
       "author" : { "first" : "George", "last" : "Orwell" },
       "year" : 1949,
       "pages" : 336,
       "paperback" : true
     }'
Variable parse2 := ParseJSON(json2)
parse2 → (after clicking into the top «_JSON»):
ParseJSON 7.0 parse2 secondLevel.png

and after double clicking the «_JSON» on 'author:

ParseJSON 7.0 parse2 author.png

In other expression, you can now access the author's last name as

parse2->author->last

Reading JSON arrays

With no schema, ParseJSON does not map array data to existing indexes that you might have. There are two ways to read that depending on whether you set the «flags» parameter. By default, if you don't specify «flags», it returns arrays as lists and any nested array data to references to lists (to avoid having the implicit dimensions combine with other indexes).

Variable json3 := '{ "data": [ [ 1,2], [3,4], [5,6] ] }'
Variable parse3 := ParseJSON(json3) (after drilling down by double-clicking the «_JSON»):
ParseJSON 7.0 parse3.png

The [...] indicates that the data member holds a list. Next, double click on the [...] to drill down further so see the contents of the list.

ParseJSON 7.0 parse3 data.png

Each nested list becomes a reference to a list. This preserves the list structure of the JSON. The reference is necessary because Analytica doesn't allow lists of lists -- this would result in a multi-D array with more than one unnamed dimension. Drilling down into the second «ref» we see the list contents.

ParseJSON 7.0 parse3 data 2.png

If you set used «flags» to 1, ParseJSON creates local indexes, named .Dim1, .Dim2, etc., for each nesting level in «json», and produces a multi-dimensional array without nesting.

Variable parse3b := ParseJSON(json3, flags:1)
parse3->data
ParseJSON3a.png

Parsing with a schema

A schema describes the data structure of a Java Script object, and the Structs and indexes in your model you want to map to.

JSON object schemas

The acceptable JSON structure and final representation is described by a Struct. The Parameter declarations determine which fields are allow, which data types are allowed in each field, how JSON lists map onto existing indexes, and which Structs are used for nested JSON objects. For example, consider this json2 data again:

    '{ "title" : "1984",
       "author" : { "first" : "George", "last" : "Orwell" },
       "year" : 1949,
       "pages" : 336,
       "paperback" : true
     }'

This JavaScript has a top-level object (Book) and a nested object (PersonName). We could use the following Struct to encode the schema:

Struct Book( title: text atom; 
             author: Person atom ; 
             year, pages: Number atom ; 
             paperback : Boolean atom 
)
Struct Person( first, last : Text atom )
Variable parse4 ::= ParseJSON( json2, Book )
ParseJSON 7.0 Book 1.png

The result is now an instance of the Book struct instead of the generic _JSON struct. Double-click on «Book» to view the internals.

ParseJSON 7.0 Book 2.png

The author field is now an instance of the Person struct. After double-clicking on «_Person»,

ParseJSON 7.0 Book 3.png

You can access the field values as, for example,

parse4->author->first

Member qualifiers in schema

Each parameter of a Struct may specify a data type or a dimensionality or (or neither or both).

Data types

The data types corresponding to JSON data types are:

  • Boolean
  • Number
  • Text
  • The name of a Struct.
  • orNull -- this can be combined with any of the above.

When a data type is specified, an error issue when the data provided by the JSON is inconsistent with the declared type. If no data type is specified, then any data type is accepted for that field. In this case, there is no schema for that field, so any JSON objects that appear will produce an instance of the _JSON struct.

Array dimensions

A parameter can declare a dimensionality, which may include any of the following:

  • Atom
  • [ ] -- this is synonymous with Atom
  • [ I, J, K ] -- one or more indexes in brackets
  • List -- must be 1-D
    • List of «type» -- Specifies the schema and type for list items

If you omit any dimensionality declaration, then it accepts a non-list (consistent with any data type specified) or a list or nested list, with the elements consistent with any specified data type. If the JSON has a list at that point, it returns a list, with a nested list returned as a reference to a list. If you specify flags:1 then instead of using lists of references to lists, nested lists will be returned as a multi-D array using local indexes named .Dim1, .Dim2, etc.

You can have it create a local index with a specified name and with the required length by using an index parameter in your Struct schema. The index parameter doesn't appear in your JSON, but it will appear as a member of your resulting struct by default (the value is a handle to the index), or you can qualify the index parameter with nonMember to omit it as a member of the struct.

Struct Club_with_members( members : Person[ Member_ID ] ; Member_Id : Index )

Variable json4 ::=

Definition:
 '{ "members" : 
          [ 
             { "first":"Lonnie", "last":"Chrisman"}, 
             { "first":"Peter", "last":"Moore"}, 
             { "first":"Max", "last":"Henrion"} 
          ]
  }'
Variable parse_to_Club ::= ParseJSON( json4, Club_with_members )
ParseJSON 7.0 Club with members 1.png
ParseJSON 7.0 Club with members 2.png
ParseJSON 7.0 Club with members 3.png

Excess parameters

You can tag a parameter with the Optional keyword to accept a JSON object that is missing a specific field. But if this is all you do, it will still reject JSON objects that have names not mentioned at all in the Struct's parameters.

If you want to accept fields that are not listed explicitly in your Struct's parameters, you can use an excess parameter. For example, our earlier person example could be made to accept any additional fields for the person by declaring is:

Struct Person( first, last : Text atom ; ... )

The ... parameter catches any fields other than first and last that appear. Notice that the ellipsis here is the name of the last parameter (not to be confused as the ellipsis qualifier that is used to the right of the colon to declare a parameter to be a repeated parameter.

If you want to tolerate them without an error, but not make them members of the result, use

Struct Person( first, last : Text atom ; ... : nonMember )

You can also restrict any excess fields that appear to have a specific data type or dimensionality. For example, to allow only atomic (non-list) field, you could use

Struct Person( first, last : Text atom ; ... : atom )

History

  • The ParseJSON function was introduced into the Analytica Enterprise edition in Analytica 5.0.
  • Made available to the Free and Professional editions in Analytica 6.6.
  • Changed in Analytica 7.0 to parse JSON objects to Structs, and to use the Struct's declaration as the schema. This turned out to be dramatically easier to understand and work with than the legacy schema, so the legacy schema was deprecated.

See Also

Comments


You are not allowed to post comments.