This function imports and exports data in JavaScript Object Notation (JSON) Data Interchange Format1.
JSON supports a limited number of data types and there is not a direct correspondence between JSON and APL data structures. In particular:
These differences are catered for in various ways as discussed below.
If specified, X must be a numeric scalar with the value 0 (import JSON) or 1 (export JSON). If X is not specified and Y is a character array, X is assumed to be 0 (import); otherwise it is assumed to be 1 (export).
Other options for ⎕JSON are Format, Compact, Null, HighRank and Dialect which are specified using the Variant operator ⍠.
The Dialect Variant option is either 'JSON' (the default) or 'JSON5'. The latter enables JSON5 extensions on import and export.
Y is a character vector or matrix in JSON format. There is an implied newline character between each row of a matrix.
The content of the result R depends upon the Format variant which may be 'D' (the default) or 'M'.
If Format is 'D' (which stands for "data") the JSON described by Y is converted to APL object(s) and R is an array or a namespace containing arrays and sub-namespaces.
If Format is 'M' (which stands for "matrix") the result R is a matrix whose columns contain the following:
[;1] | depth |
[;2] | name (for JSON object members) |
[;3] | value |
[;4] | JSON type (integer: see below) |
Table 45: JSON data types are as follows:
Type | Description |
---|---|
1 | Object |
2 | Array |
3 | Numeric |
4 | String |
5 | Null |
6 | No APL equivalent (represented by character string) |
7 | JavaScript Object (export only) |
The JSON standard says that members of a JSON object should have unique names and that different implementations behave differently when there are duplicates. Dyalog handles duplicate names as follows:
⍴JSON 18 19 JSON { "a": { "b": [ "string 1", "string 2" ], "c": true, "d": { "e": false, "f⍺": [ "string 3", 123, 1000.2, null ] } } }
j←⎕JSON JSON j #.[JSON object] j.⎕NL 9 a j.a.⎕NL 2 b c j.a.b ┌────────┬────────┐ │string 1│string 2│ └────────┴────────┘ j.a.c ┌────┐ │true│ └────┘ j.a.⎕NL 9 d j.a.d.⎕NL 2 ⍝ Note that f⍺ is an invalid APL name e ⍙f⍙9082⍙ j.a.d.e ┌─────┐ │false│ └─────┘ j.a.d.⍙f⍙9082⍙ ┌────────┬───┬──────┬──────┐ │string 3│123│1000.2│┌────┐│ │ │ │ ││null││ │ │ │ │└────┘│ └────────┴───┴──────┴──────┘
(⎕JSON⍠'M')JSON ┌─┬──┬────────┬─┐ │0│ │ │1│ ├─┼──┼────────┼─┤ │1│a │ │1│ ├─┼──┼────────┼─┤ │2│b │ │2│ ├─┼──┼────────┼─┤ │3│ │string 1│4│ ├─┼──┼────────┼─┤ │3│ │string 2│4│ ├─┼──┼────────┼─┤ │2│c │┌────┐ │6│ │ │ ││true│ │ │ │ │ │└────┘ │ │ ├─┼──┼────────┼─┤ │2│d │ │1│ ├─┼──┼────────┼─┤ │3│e │┌─────┐ │6│ │ │ ││false│ │ │ │ │ │└─────┘ │ │ ├─┼──┼────────┼─┤ │3│f⍺│ │2│ ├─┼──┼────────┼─┤ │4│ │string 3│4│ ├─┼──┼────────┼─┤ │4│ │123 │3│ ├─┼──┼────────┼─┤ │4│ │1000.2 │3│ ├─┼──┼────────┼─┤ │4│ │┌────┐ │5│ │ │ ││null│ │ │ │ │ │└────┘ │ │ └─┴──┴────────┴─┘
Y is the data to be exported as JSON and may be an array, a namespace or a matrix representation of JSON such as would have been produced by JSON Import with Format 'M'. Y is interpreted according to the Format variant which may be 'D' (the default) or 'M'.
⎕JSON will signal DOMAIN ERROR if Y is incompatible with the specified (or implied) value of Format.
If Format is M, the data values in Y[;3] must correspond precisely with the JSON types specified in Y[;4]as specified in the following table.
Y[;4] (Type) | Y[;3] (Value) |
---|---|
1 | Empty array |
2 | Empty array |
3 | Numeric scalar |
4 | Character vector |
5 | Null |
6 | Enclosed character vector |
7 | Enclose character vector |
R is a character vector whose content depends upon the value of the Compact variant.
Compact | Description |
---|---|
0 | The JSON text is padded with spaces and new lines for readability. |
1 | The JSON text is compacted into its minimal form.. |
The HighRank variant option may be used to instruct ⎕JSON to pre-process higher rank arrays into a form that can be represented by JSON. Note that if necessary, the transformation is applied recursively throughout the high-rank array(s) specified by Y.
HighRank | Description |
---|---|
'Split' | High rank data is split into nested vectors. |
'Error' | Higher rank data is rejected (DOMAIN ERROR) |
The name of any namespace member that begins with ⍙ and otherwise conforms to the conversion format used for JSON object names will be demangled.
j ⍝ See above #.[JSON object] ⍴JS←1 ⎕JSON j 94 JS {"a":{"b":["string 1","string 2"],"c":true,"d":{"e":false,"f⍺":["string 3",123,1000.2,null]}}} 1(⎕JSON⍠'Compact' 0) j { "a": { "b": [ "string 1", "string 2" ], "c": true, "d": { "e": false, "f⍺": [ "string 3", 123, 1000.2, null ] } } }
If there are any mis-matches between the values in Y[;3] and the types in Y[;4], ⎕JSON will signal DOMAIN ERROR and report the first row where there is a mis-match (⎕IO sensitive) as illustrated in the following example.
M←(⎕JSON⍠'Format' 'M')'{"values": [ 75, 300 ]}' M ┌─┬──────┬───┬─┐ │0│ │ │1│ ├─┼──────┼───┼─┤ │1│values│ │2│ ├─┼──────┼───┼─┤ │2│ │75 │3│ ├─┼──────┼───┼─┤ │2│ │300│3│ └─┴──────┴───┴─┘ M[3;3]←⊂'75' ⍝ character not numeric M ⍝ but looks the same as before ┌─┬──────┬───┬─┐ │0│ │ │1│ ├─┼──────┼───┼─┤ │1│values│ │2│ ├─┼──────┼───┼─┤ │2│ │75 │3│ ├─┼──────┼───┼─┤ │2│ │300│3│ └─┴──────┴───┴─┘ 1 (⎕JSON⍠ 'Format' 'M')M DOMAIN ERROR: Value does not match the specified type in row 3 1(⎕JSON⍠'Format' 'M')M ∧
d ┌─────┬─────────────────────────┐ │1 2 │ABC │ │A B │DEF │ ├─────┼─────────────────────────┤ │1 2 3│1 0.5 │ │4 5 6│0.3333333333 0.25 │ │ │ │ │ │0.2 0.1666666667│ │ │0.1428571429 0.125 │ └─────┴─────────────────────────┘ 1 ⎕JSON d DOMAIN ERROR: JSON export: the right argument cannot be converted (⎕IO=1) 1 ⎕JSON d ∧ 1 (⎕JSON⍠'HighRank' 'Split') d [[[[1,2],"AB"],["ABC","DEF"]],[[[1,2,3],[4,5,6]],...
The following example illustrates how JavaScript objects may be exported.
In the example, the object is a JavaScript function which is specified by the contents of an enclosed character vector. Note that in this case Dyalog performs no validation of the code itself.
'Slider' ⎕NS '' Slider.range←⊂'true' ⍝ Note the ⊂ Slider.min←0 Slider.max←500 Slider.values←75 300 fn1←' function( event, ui ) {' fn2←'$( "#amount" ).val( "$" + ui.values[ 0 ] +' fn2,←' " - $" + ui.values[ 1 ] );}' Slider.slide←,/fn1 fn2 ⍝ Enclosed character vec
⍴JS←1 ⎕JSON Slider 159 JS {"max":500,"min":0,"range":true,"slide": function( event, ui ) {$( \"#amount\" ).val( \"$\" + ui.values[ 0 ] + \" - $\" + ui.values[ 1 ] );},"values":[75,300]}
When Dyalog converts from JSON to APL data, and a member of a JSON object has a name which is not a valid APL name, it is renamed.
In this example, the JSON describes an object containing two numeric items, one named a (which is a valid APL name) and the other named 2a (which is not):
{"a": 1, "2a": 2}
When this JSON is imported as an APL namespace using ⎕JSON, Dyalog converts the name 2a to a valid APL name. The name mangling algorithm creates a name beginning with ⍙.
(⎕JSON'{"a": 1, "2a": 2}').⎕NL 2 a ⍙2a
When Dyalog exports JSON it performs the reverse name mangling, so:
1 ⎕JSON ⎕JSON'{"a": 1, "2a": 2}' {"a":1,"2a":2}
Should you need to create and decode these names directly,7162⌶ provides the same name mangling and un-mangling operations. See JSON Translate Name.
0(7162⌶)'2a' ⍙2a 1(7162⌶)'⍙2a' 2a