diff --git a/language-reference-guide/docs/system-functions/json.md b/language-reference-guide/docs/system-functions/json.md
index ded2d77cfbb..5f69b9b4d21 100644
--- a/language-reference-guide/docs/system-functions/json.md
+++ b/language-reference-guide/docs/system-functions/json.md
@@ -9,98 +9,206 @@ search:
JSON Convert R←{X}⎕JSON Y
-This function imports and exports data in [JavaScript Object Notation](https://www.json.org/json-en.html) (JSON) Data Interchange Format.
+This function imports and exports data in [JavaScript Object Notation](https://www.json.org/json-en.html) (JSON) data interchange format.
-JSON supports a limited number of data types and there is not a direct correspondence between JSON and APL data structures. In particular:
+## Syntax
+
+If `X` is specified (that is, `⎕JSON` is called dyadically), it must be a numeric scalar with the value `0` for import or `1` for export.
+
+Examples
+
+Importing a JSON document to APL:
+```apl
+ 0 ⎕JSON'[1,-2,3]'
+1 ¯2 3
+```
+Exporting APL data to JSON:
+```apl
+ 1 ⎕JSON 1 ¯2 3
+[1,-2,3]
+```
+
+!!! Hint "Hints and Recommendations"
+ As a mnemonic, think of `X` as specifying the desired "JSON-ness": `0` means "no JSON", that is, converting away from JSON; `1` means "yes JSON", that is, converting towards JSON.
+
+If `X` is not specified (that is, `⎕JSON` is called monadically), its assumed value depends on `Y`: If `Y` is a character array, `X` is assumed to be `0`; otherwise it is assumed to be `1`.
+
+!!! Warning "Warning"
+ Dyalog Ltd strongly recommends that `X` should always be specified to avoid code that seemingly works, only to fail on specific values.
+
+`⎕JSON` has six [variant options](#variant-options): **Format**, **Compact**, **Null**, **HighRank**, **Charset**, and **Dialect**, specified using [`⍠`](../primitive-operators/variant.md). The principal option is **Format**.
+
+## Limitations
+
+JSON supports a limited number of data types, and there is no direct correspondence between JSON and APL data structures. In particular:
+
+- JSON does not support arrays with rank > 1.
+- JSON does not support nested scalars.
+- JSON includes Boolean values true and false which are distinct from numeric values 1 and 0; these have no direct APL equivalent.
+- JSON object members are named and these names might not be [valid names in APL](../../programming-reference-guide/introduction/names/).
+- The [JSON5](https://json5.org/) dialect includes numeric constants Infinity, -Infinity, and NaN, which have no direct APL equivalent.
-- JSON does not support arrays with rank >1.
-- JSON standard includes Boolean values true and false which are distinct from numeric values 1 and 0, and have no direct APL equivalent.
-- The [JSON5](https://json5.org/) standard includes numeric constants `Infinity`, `-Infinity`, `NaN` and `-NaN` which have no direct APL equivalent.
-- JSON object members are named and these names might not be valid names in APL.
-
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).
-
-Although this system function was designed with an optional left argument, it is strongly recommended that the argument should always be used.
-
-Other options for `⎕JSON` are `Format`, `Compact`, `Null`, `HighRank`, `Charset` and `Dialect` which are specified using `⍠` (see [Variant operator](../primitive-operators/variant.md)). The Principal Option is `Format`.
-
-The `Dialect` Variant option is either `'JSON'` (the default) or`'JSON5'`. The latter enables [JSON5](https://json5.org/) extensions on import and export.
-
-## JSON Import (`X` is `0`)
-`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 can 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.
-
-- JSON objects are created as APL namespaces.
-- JSON null is converted to the value specified by the `Null` variant, which may be either `⊂'null'` (the default) or `⎕NULL`.
-- JSON true and false and the JSON5 numeric constants `Infinity`, `-Infinity`, `NaN` and `-NaN` are converted to enclosed character vectors `⊂'true'`,`⊂'false'` and so forth.
-- If the JSON source contains object names which are not valid APL names they are converted to APL objects with mangled names. See [JSON Name Mangling](#json-name-mangling). `7162⌶` can be used to obtain the original name. See [JSON Translate Name](../primitive-operators/i-beam/json-translate-name.md)
-
-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) |
-
-- The representation of null, true and false are the same as for`Format 'D'`.
-- Object names are reported as specified in the JSON text; they are not mangled as they are for`Format 'D'`.
-
-| 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) |
-
-**Duplicate Names**
-
-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:
-
-- No error is generated.
-- For`Format 'D'`, the last member encountered is used and all previous members with the same name are discarded.
-- For`Format 'M'` all duplicate members are recorded in the result matrix.
-
-**Examples**
-
-```apl
- ⍴JSON
-18 19
- JSON
-{
- "a": {
- "b": [
- "string 1",
- "string 2"
- ],
- "c": true,
- "d": {
- "e": false,
- "f⍺": [
- "string 3",
- 123,
- 1000.2,
- null
- ]
- }
- }
-}
+## JSON Import
+
+If `X` is `0`, the JSON document `Y` is converted to the corresponding APL data `R`.
+
+`Y` is a character scalar, vector, or matrix in JSON format. There is an implied newline character between each row of a matrix.
+
+By default, `R` is APL data, possibly containing sub-arrays and/or sub-namespaces. If the variant option [**Format**](#variant-option-format) is set to `'M'`, `R` is instead a matrix that represents the JSON structure.
+
+The [JSON standard](https://www.rfc-editor.org/info/rfc8259/#section-4) states that members of a JSON object should have unique names and that implementations vary in how they treat duplicates. Dyalog does not error on duplicates, but their handling depends on the **Format** variant option.
+
+Example
+
+```apl
+ 0 ⎕JSON'[1,-2,3]'
+1 ¯2 3
```
-### Import as Data (`Format 'D'`)
+For details and more examples, see [Import to Data](#import-to-data) and [Import to Matrix](#import-to-matrix).
+
+## JSON Export
+
+If `X` is `1`, the APL data `Y` is converted to a corresponding JSON document `R`.
+
+`Y` is the data to be exported. By default, `Y` must be APL data that can be represented as JSON (subject to the [**HighRank**](#variant-option-highrank) variant option). If the [**Format**](#variant-option-format) variant option is set to `'M'`, `Y` must instead be a matrix representation such as would have been produced by importing JSON with **Format** being `'M'`. `⎕JSON` will signal `DOMAIN ERROR` if `Y` is incompatible with the specified (or implied) value of **Format**.
+
+`R` is a character vector whose content depends upon the values of the [**Compact**](#variant-option-compact), [**Dialect**](#variant-option-dialect), and [**Charset**](#variant-option-charset) variant options.
+
+Some JSON values lack a direct APL equivalent (true, false, null, JavaScript fragments), and some APL representations of datasets do not correspond to common JSON practice. Such cases are handled by [wrappers](#wrappers).
+
+Example
```apl
- j←0 ⎕JSON JSON
+ 1 ⎕JSON 1 ¯2 3
+[1,-2,3]
+```
+
+For details and more examples, see [Export from Data](#export-from-data) and [Export from Matrix](#export-from-matrix).
+
+## Name Mangling
+
+When `⎕JSON` converts a JSON document to APL data and a member of a JSON object has a name that is not a valid APL name, the member is renamed using a name mangling algorithm. This results in a name that begins with `⍙`. Any characters that cannot be part of an APL name are replaced with their [decimal Unicode code point](ucs.md#monadic-ucs) surrounded by `⍙`s.
+
+Example
+
+In this example, the JSON document 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 valid APL name):
+```json
+{"a": 1, "2a": 2}
+```
+
+When the object is imported (as a namespace), `⎕JSON` renames `2a` to a valid APL name:
+```apl
+ (0 ⎕JSON'{"a": 1, "2a": 2}').⎕NL 2
+a
+⍙2a
+```
+
+When the namespace is exported, `⎕JSON` reverses the mangling:
+```apl
+ 1 ⎕JSON (a:1 ⋄ ⍙2a:2)
+{"a":1,"2a":2}
+```
+
+Example
+
+This object has a member name with a character (`ý`; `⎕UCS 253`) that is not allowed in APL names:
+```json
+{"sýn":"vision"}
+```
+The `ý` is replaced with `⍙253⍙` ("253" is the Unicode decimal character code for this character):
+```apl
+ (0 ⎕JSON'{"sýn":"vision"}').⎕NL 2
+⍙s⍙253⍙n
+```
+
+### Name Mangling Algorithm
+
+[`7162⌶`](../primitive-operators/i-beam/json-translate-name.md) provides direct access to the name mangling algorithm.
+
+Example
+
+The above name translations are verified using `7162⌶`:
+```apl
+ 0(7162⌶)'2a' 'sýn'
+┌───┬────────┐
+│⍙2a│⍙s⍙253⍙n│
+└───┴────────┘
+ 1(7162⌶)'⍙2a' '⍙s⍙253⍙n'
+┌──┬───┐
+│2a│sýn│
+└──┴───┘
+```
+
+## Variant Options
+
+`⎕JSON` is controlled by six variant options. [](#variant-table) summarises each option's effect on import from JSON to APL (`X=0`) and export from APL to JSON (`X=1`). Each option is described in finer detail, with examples, below the table. Variant options specific to one direction are tolerated for the other direction even if they have no effect.
+
+Table: Variant options overview { #variant-table }
+
+| Variant Option | Value | Effect on Import | Effect on Export |
+|--------------------------------------------------------------------|:-------------------------------------:|-----------------------------------------------------|------------------|
+| [**Format**](#variant-option-format)
principal | `'D'`
default | `R` is APL data corresponding to `Y` | `Y` is APL data |
+|_- -_| `'M'` | `R` is an APL matrix encoding of `Y` | `Y` is a 4-column APL matrix as from import with `'M'` |
+| [**Dialect**](#variant-option-dialect) | `'JSON'`
default | Only strict JSON syntax is accepted | Only strict JSON syntax is produced |
+|_- -_| `'JSON5'` | [JSON5](https://json5.org/) extensions are accepted | JSON5 features are used to improve readability and editability, and/or shorten output |
+| [**Null**](#variant-option-null) | `⊂'null'`
default | JSON null becomes APL `⊂'null'` | APL `⊂'null'` becomes JSON null |
+|_- -_| `⎕NULL` | JSON null becomes APL `⎕NULL` | APL `⎕NULL` becomes JSON null |
+| [**Compact**](#variant-option-compact) | `1`
default | None | `R` has no whitespace outside quotes |
+|_- -_| `0` | None | `R` has whitespace for readability and, if **Dialect** is `'JSON5'`, trailing commas after final elements and members |
+| [**Charset**](#variant-option-charset) | `'Unicode'`
default | None | Unicode characters in `Y` are used when JSON standard allows |
+|_- -_| `'ASCII'` | None | Non-ASCII characters are converted to the hexadecimal form `\uNNNN`, and if **Dialect** is `'JSON5'`, also `\xNN` |
+| [**HighRank**](#variant-option-highrank) | `'Error'`
default | None | High-rank arrays are rejected |
+|_- -_| `'Split'` | None | High-rank arrays are split and [inverted table wrappers](#dataset-wrappers) accept text columns as matrices |
+
+### Variant Option: Format
+
+The **Format** variant option, the principal option, determines whether `⎕JSON` works with a direct APL representation of the data (`'D'` for "Data", the default) or with a four-column matrix that encodes the JSON structure (`'M'` for "Matrix") as nodes with depth, name, value, and type.
+
+#### Import to Data
+
+If **Format** is `'D'` (which stands for "Data", the default), the JSON document in `Y` is converted to the corresponding APL data `R`, possibly containing sub-arrays and/or sub-namespaces:
+
+- JSON arrays are converted into APL vectors.
+- JSON objects are converted into APL namespaces.
+- JSON null is converted into the specified (or implied) value of [**Null**](#variant-option-null) (`⊂'null'`, the default, or `⎕NULL`).
+- JSON true and false and, if the [**Dialect**](#variant-option-dialect) variant option is `'JSON5'`, the JSON5 numeric constants Infinity, -Infinity, and NaN, are converted to enclosed character vectors `⊂'true'`, `⊂'false'`, and so on.
+- If the JSON source contains object member names that are not valid APL names, they are converted to APL namespace members with [mangled names](#name-mangling). The original names can be obtained using [`7162⌶`](../primitive-operators/i-beam/json-translate-name.md).
+- If duplicate names are found, the last member encountered is used and all previous members with the same name are discarded.
+
+Examples
+
+The following JSON document is stored as the character vector `json`:
+```json
+{
+ "a": {
+ "b": [
+ "string 1",
+ "string 2"
+ ],
+ "c": true,
+ "d": {
+ "e": false,
+ "f⍺": [
+ "string 3",
+ 123,
+ 1000.2,
+ null
+ ]
+ }
+ }
+}
+```
+The JSON document is converted to APL data as a namespace:
+```apl
+ j←0 ⎕JSON json
j
#.[JSON object]
+```
+Listing the sub-namespace and its members:
+```apl
j.⎕NL 9
a
j.a.⎕NL 2
@@ -116,13 +224,12 @@ c
└────┘
j.a.⎕NL 9
d
- j.a.d.⎕NL 2 ⍝ Note that f⍺ is an invalid APL name
+```
+Note that `f⍺` is an invalid APL name:
+```apl
+ j.a.d.⎕NL 2
e
⍙f⍙9082⍙
- j.a.d.e
-┌─────┐
-│false│
-└─────┘
j.a.d.⍙f⍙9082⍙
┌────────┬───┬──────┬──────┐
│string 3│123│1000.2│┌────┐│
@@ -130,11 +237,75 @@ e
│ │ │ │└────┘│
└────────┴───┴──────┴──────┘
```
+The two ways to represent JSON nulls:
+```apl
+ 0 ⎕JSON'[null,2,3]'
+┌──────┬─┬─┐
+│┌────┐│2│3│
+││null││ │ │
+│└────┘│ │ │
+└──────┴─┴─┘
+ 0(⎕JSON⍠'Null'⎕NULL)'[null,2,3]'
+ [Null] 2 3
+```
+
+#### Import to Matrix
+
+If **Format** is `'M'` (which stands for "Matrix"), the JSON document `Y` is converted to a corresponding APL matrix `R` whose columns are as follows:
+
+Table: Import matrix columns { #import-matrix-table }
+
+| Column | Contents |
+|---------|----------------------------------|
+| `R[;1]` | Depth |
+| `R[;2]` | Name (for JSON object members) |
+| `R[;3]` | APL value |
+| `R[;4]` | [JSON type](#import-types-table) |
+
+The JSON types are as follows:
+
+Table: JSON types { #import-types-table }
+
+| `R[;4]` | `R[;3]` (APL value) | Corresponding JSON value |
+|---------|----------------------------------------|--------------------------|
+| `1` | Empty (contents are in following rows) | Object |
+| `2` | Empty (contents are in following rows) | Array |
+| `3` | Number | Number |
+| `4` | Character vector | String |
+| `5` | Specified by **Null** variant | Null |
+| `6` | Enclosed character vector | Lacking APL equivalent |
+
+Note that:
-### Import as Matrix (`Format 'M'`)
+- JSON null is converted into the specified (or implied) value of [**Null**](#variant-option-null); `⊂'null'` (the default) or `⎕NULL`.
+- JSON values that lack an APL equivalent, true and false, and, if **Dialect** is `'JSON5'`, the JSON5 numeric constants Infinity, -Infinity, and NaN, are converted to enclosed character vectors `⊂'true'`, `⊂'false'`, and so on.
+- Object member names are reported as specified in the JSON text; they are not mangled as when **Format** is `'D'`.
+- If duplicate names are found, all duplicate members are recorded in the result matrix.
+
+Example
+This example uses the character vector `json` from the previous example:
```apl
- (⎕JSON⍠'M')JSON
+ json
+{
+ "a": {
+ "b": [
+ "string 1",
+ "string 2"
+ ],
+ "c": true,
+ "d": {
+ "e": false,
+ "f⍺": [
+ "string 3",
+ 123,
+ 1000.2,
+ null
+ ]
+ }
+ }
+}
+ 0(⎕JSON⍠'M')json
┌─┬──┬────────┬─┐
│0│ │ │1│
├─┼──┼────────┼─┤
@@ -170,87 +341,77 @@ e
└─┴──┴────────┴─┘
```
-## JSON Export (`X` is `1`)
-
-`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 `Charset` variant option may be used to restrict the output to ASCII characters.
-
-| Charset | Description |
-|------------|-----------------|
-| 'Unicode' | All Unicode characters in `Y` are passed unchanged in the result `R`. |
-| 'ASCII' | Non-ASCII characters are converted to an encoded string of the form "\uNNNN" where "NNNN" is the upper-case hexadecimal value of the character in the Unicode system. For example, é (e-acute) is converted to "\u00E9". Furthermore, if the Dialect is JSON5, values less than hex 100 are converted to the form \xNN. |
-
-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.
-
-**Example**
-
-```apl
- 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]}}}
+#### Export from Data
- 1(⎕JSON⍠'Compact' 0) j
+If **Format** is `'D'` (which stands for "Data"), the APL value `Y` is converted to a corresponding JSON document `R` as follows:
-{
- "a": {
- "b": [
- "string 1",
- "string 2"
- ],
- "c": true,
- "d": {
- "e": false,
- "f⍺": [
- "string 3",
- 123,
- 1000.2,
- null
- ]
- }
- }
-}
+- APL vectors are converted to JSON arrays.
+- APL arrays of higher rank are recursively split if [**HighRank**](#variant-option-highrank) is `'Split'`, otherwise `⎕JSON` will signal `DOMAIN ERROR`.
+- APL namespaces are converted to JSON objects.
+- Enclosed vectors whose leading element is a wrapper code are interpreted as [wrappers](#wrappers) (mechanisms for special handling).
+- If a namespace member name appears to be mangled (has a form that would have been produced by [name mangling](#name-mangling)), it is demangled.
+
+Example
+
+```apl
+ ns←(
+ a:(
+ b:(
+ 'charvec 1'
+ 'charvec 2'
+ )
+ c:⊂'true'
+ d:(
+ e:⊂'false'
+ ⍙f⍙9082⍙:(
+ 'charvec 3'
+ 123
+ 1000.2
+ ⊂'null'
+ )
+ )
+ )
+ )
+ 1 ⎕JSON ns
+{"a":{"b":["charvec 1","charvec 2"],"c":true,"d":{"e":false,"f⍺":["charvec 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.
+#### Export from Matrix
+
+If **Format** is `'M'` (which stands for "Matrix"), the APL array `Y` is converted to a corresponding JSON document `R` and `Y` must be a matrix whose columns are as follows:
+
+Table: Export matrix columns { #export-matrix-table }
+
+| Column | Contents |
+|---------|---------------------------------|
+| `Y[;1]` | Depth |
+| `Y[;2]` | Name (for JSON object members) |
+| `Y[;3]` | APL value |
+| `Y[;4]` | [JSON type](#export-types-table) |
+
+The JSON types are as follows:
-**Example**
+Table: JSON types { #export-types-table }
-```apl
- M←(⎕JSON⍠'Format' 'M')'{"values": [ 75, 300 ]}'
- M
+| `Y[;4]` | `Y[;3]` (APL value) | Corresponding JSON value |
+|---------|---------------------------|--------------------------|
+| `1` | Empty array | Object |
+| `2` | Empty array | Array |
+| `3` | Numeric scalar | Number |
+| `4` | Character vector | String |
+| `5` | Null | Null |
+| `6` | Enclosed character vector | Lacking APL equivalent |
+| `7` | Enclosed character vector | [Raw text](#raw-text-wrapper) |
+
+The difference between JSON types `6` and `7` is that `7` allows any text but `6` only allows the special values that can be imported.
+
+If there are any mismatches 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 mismatch (`⎕IO` sensitive) as illustrated in the following example.
+
+Example
+
+```apl
+ m←0(⎕JSON⍠'M')'{"values": [ 75, 300 ]}'
+ m
┌─┬──────┬───┬─┐
│0│ │ │1│
├─┼──────┼───┼─┤
@@ -260,11 +421,11 @@ If there are any mis-matches between the values in `Y[;3]` and the types in `Y[;
├─┼──────┼───┼─┤
│2│ │300│3│
└─┴──────┴───┴─┘
-
- M[3;3]←⊂'75' ⍝ character not numeric
-
- M ⍝ but looks the same as before
-
+```
+To illustrate type mismatches, the above matrix is modified by replacing one number with a character vector that looks the same:
+```apl
+ m[3;3]←⊂'75'
+ m
┌─┬──────┬───┬─┐
│0│ │ │1│
├─┼──────┼───┼─┤
@@ -274,298 +435,398 @@ If there are any mis-matches between the values in `Y[;3]` and the types in `Y[;
├─┼──────┼───┼─┤
│2│ │300│3│
└─┴──────┴───┴─┘
-
- 1 (⎕JSON⍠ 'Format' 'M')M
+ 1(⎕JSON⍠'M')m
DOMAIN ERROR: JSON export: value does not match the specified type in row 3 (⎕IO=1)
- 1(⎕JSON⍠'Format' 'M')M
+ 1(⎕JSON⍠'M')m
∧
```
-**Charset Example**
+### Variant Option: Dialect
-```apl
- ns←⎕NS ''
- ns.dé←'DÉ'
- ns.dé
-DÉ
- ⎕JSON ns
-{"dé":"DÉ"}
- (⎕JSON⍠'Charset' 'ASCII')ns
-{"d\u00E9":"D\u00C9"}
-```
+If the **Dialect** variant option (default: `'JSON'`) is `'JSON5'`, [JSON5](https://json5.org/) extensions are enabled on import and export.
-**High Rank Example**
+On import, all JSON5 extensions are accepted.
+
+On export, the result is shortened by usage of identifiers without quotes, single quotes (`'`), and character escapes `\v` and of the form `\xNN` (for values less than hexadecimal 100, that is, `⎕UCS 256`). If [**Compact**](#variant-option-compact) is `0`, a trailing comma (`,`) is added after the last array element and object member.
+
+Examples
```apl
- 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]],...
+ 1 ⎕JSON(a:'é"')
+{"a":"é\""}
+ 1(⎕JSON⍠'Dialect' 'JSON5')(a:'é"')
+{a:'é"'}
+
+ 1(⎕JSON⍠'Charset' 'ASCII'⍠'Compact' 0)(a:'é"')
+{
+ "a": "\u00E9\""
+}
+ 1(⎕JSON⍠'Charset' 'ASCII'⍠'Compact' 0⍠'Dialect' 'JSON5')(a:'é"')
+{
+ a: '\xE9"',
+}
+
+ 0(⎕JSON⍠'Dialect' 'JSON5')['["a\'
+ 'bc",'
+ '//:)'
+ '+.1,'
+ '/**/'
+ '0xf]']
+┌───┬───┬──┐
+│abc│0.1│15│
+└───┴───┴──┘
```
-### Raw Text
+### Variant Option: Null
-An enclosed character vector is inserted into the result of JSON export as raw text. This feature may be used to export special JSON values such as `null`, `true` and `false`. Without the extra enclosure, the character vectors are exported as strings:
+The **Null** variant option selects how JSON null is represented in APL, and must be either `⊂'null'` (the default) or `⎕NULL`:
-**Example**
+- If **Null** is `⊂'null'`, `⎕NULL` causes `DOMAIN ERROR`.
+- If **Null** is `⎕NULL`, `⊂'null'` is still exported as null because it is interpreted as [raw text](#raw-text-wrapper).
+
+Examples
```apl
- ⎕JSON 'null' 'true' 'false'
-["null","true","false"]
- ⎕JSON ⊂¨'null' 'true' 'false'
-[null,true,false]
+ 0 ⎕JSON'[null,null]'
+┌──────┬──────┐
+│┌────┐│┌────┐│
+││null│││null││
+│└────┘│└────┘│
+└──────┴──────┘
+ 0(⎕JSON⍠'Null'⎕NULL)'[null,null]'
+ [Null] [Null]
+
+ 1 ⎕JSON ⎕NULL ⎕NULL
+DOMAIN ERROR: JSON export: item "[1]" of the right argument (⎕IO=1) cannot be converted
+ 1 ⎕JSON ⎕NULL ⎕NULL
+ ∧
+ 1(⎕JSON⍠'Null'⎕NULL)⎕NULL ⎕NULL
+[null,null]
```
-
-The same mechanism may be used to inject any raw text, although unless this is valid JSON it cannot then be re-imported.
-
-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.
-**Example**
+### Variant Option: Compact
-```apl
- 'Slider' ⎕NS ''
- Slider.range←⊂'true' ⍝ Note the ⊂
- Slider.min←0
- Slider.max←500
- Slider.values←75 300
+The **Compact** variant option can be used to generate JSON that is either dense (`1`, the default) or optimised for humans to read and edit (`0`).
- fn1←' function( event, ui ) {'
- fn2←'$( "#amount" ).val( "$" + ui.values[ 0 ] +'
- fn2,←' " - $" + ui.values[ 1 ] );}'
+If **Compact** is `0`:
- 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]}
-```
+- Line breaks are inserted after opening brackets `[` and `{` and before closing brackets `]` and `}`
+- Each array element and object member is on its own line, indented with two spaces relative to its container array or object
+- A space is inserted after `:` separating member name and value
+- If [**Dialect**](#variant-option-dialect) is `'JSON5'`, a trailing comma (`,`) is added after the last array element and object member
-### Wrappers
-
-A wrapper is an enclosed vector of the form:
+Example
+The following examples use this namespace as APL data:
```apl
- ⊂code special
+ ns←(
+ a:(
+ b:(
+ 'charvec 1'
+ 'charvec 2'
+ )
+ c:⊂'true'
+ d:(
+ e:⊂'false'
+ ⍙f⍙9082⍙:(
+ 'charvec 3'
+ 123
+ 1000.2
+ ⊂'null'
+ )
+ )
+ )
+ )
```
-
-The nature of the `special` data structure is identified within the wrapper by a leading numeric code. Code 1 is used to identify JSON values such as `null`, `true` and `false`. Codes 2, 3 and 4 are used to identify different forms of datasets.
-
-This wrapper mechanism has been chosen to identify special treatment because a scalar enclosure cannot be represented in JSON/JavaScript.
-
-A wrapper may be specified directly in the right argument to `⎕JSON` and/or as part of the array structure specified by the right argument, as a sub-array or in a namespace. This allows a special array to be processed appropriately as part of a general data structure that is to be rendered in JSON notation.
-
-**Wrappers for special JSON values**
-
-Wrappers may be used to export JSON special values such as `null`, `true` and `false` using code 1. This mechanism is supplementary to the use of enclosed character vectors. See **RawText** above.
-
-**Example**
-
+Conversion to compact JSON:
```apl
- ⎕JSON⊂¨(1 'null')(1 'true')(1 'false')
-[null,true,false]
+ ⍴json←1 ⎕JSON ns
+97
+ json
+{"a":{"b":["charvec 1","charvec 2"],"c":true,"d":{"e":false,"f⍺":["charvec 3",123,1000.2,null]}}}
+```
+Non-compact JSON takes more than twice as much space, but is more readable, and easier for humans to edit:
+```apl
+ ⍴json←1(⎕JSON⍠'Compact' 0)ns
+208
+ 1(⎕JSON⍠'Compact' 0)ns
+{
+ "a": {
+ "b": [
+ "charvec 1",
+ "charvec 2"
+ ],
+ "c": true,
+ "d": {
+ "e": false,
+ "f⍺": [
+ "charvec 3",
+ 123,
+ 1000.2,
+ null
+ ]
+ }
+ }
+}
```
-**Datasets**
+### Variant Option: Charset
-The term dataset is used here to mean a collection of data, usually presented in tabular form. Each named column represents a particular variable. Each row corresponds to a given member of the dataset in question. It lists values for each of the variables, such as height and weight of an object.
+The **Charset** variant option can be used to either allow Unicode in the generated JSON (`'Unicode'`, the default) or restrict the output to ASCII characters (`'ASCII'`). When necessary, characters are converted to the hexadecimal form `\uNNNN`. If [**Dialect**](#variant-option-dialect) is `'JSON5'`, the form `\xNN` is used for values up to hexadecimal `FF` (`⎕UCS 255`).
-Datasets are often represented in APL as a collection of variables.
+Example
```apl
- Fields←'Item' 'Price' 'Qty'
- Items←'Knife' 'Fork'
- Price←3 4
- Qty←23 45
+ ns←(dé:'DÉ')
+ ns.dé
+DÉ
+ 1 ⎕JSON ns
+{"dé":"DÉ"}
+ 1(⎕JSON⍠'Charset' 'ASCII')ns
+{"d\u00E9":"D\u00C9"}
```
-As an aside, note that using this scheme each variable represents an inverted index into the dataset and enables rapid searches.
+### Variant Option: HighRank
-```apl
- (Price<4)/Items
-┌─────┐
-│Knife│
-└─────┘
-```
+If **HighRank** is `'Error'` (the default), `⎕JSON` will signal a `DOMAIN ERROR` upon encountering any arrays in `Y` of rank higher than 1. If **HighRank** is `'Split'`, `⎕JSON` will recursively split any such arrays as necessary; in addition, [datasets](#dataset-wrappers) as inverted tables can have text columns represented as matrices.
-A conventional way to represent this dataset is as a matrix:
+Example
```apl
- Fields⍪⍉↑ Items Price Qty
+ d←[[1 2 ⋄ 'AB']['ABC' ⋄ 'DEF']
+ (2 3⍴⍳6) (2 2 2⍴×⍨⍳8) ]
+ d
+┌─────┬─────┐
+│1 2 │ABC │
+│A B │DEF │
+├─────┼─────┤
+│1 2 3│ 1 4│
+│4 5 6│ 9 16│
+│ │ │
+│ │25 36│
+│ │49 64│
+└─────┴─────┘
-┌─────┬─────┬───┐
-│Item │Price│Qty│
-├─────┼─────┼───┤
-│Knife│ 3 │23 │
-├─────┼─────┼───┤
-│Fork │ 4 │45 │
-└─────┴─────┴───┘
+ 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]],[[[1,4],[9,16]],[[25,36],[49,64]]]]]
```
-Another is as a 2-item vector containing the names of the fields and a matrix of their values:
+## Wrappers
-```apl
- (Fields (⍉↑Items Price Qty))
+A wrapper is an enclosed vector with the basic form `⊂wrapperCode wrapperData`. The `wrapperCode` can be omitted, and index vectors can be appended for data subsetting.
-┌────────────────┬────────────┐
-│┌────┬─────┬───┐│┌─────┬─┬──┐│
-││Item│Price│Qty│││Knife│3│23││
-│└────┴─────┴───┘│├─────┼─┼──┤│
-│ ││Fork │4│45││
-│ │└─────┴─┴──┘│
-└────────────────┴────────────┘
-```
+Some APL representations of datasets do not correspond to common JSON practice for datasets. A wrapper provides special handling if such an APL representation is encountered inside a nested scalar; nested were selected for this purpose because they cannot be represented in JSON or JavaScript.
-A third way retains the inverted nature of the data structure, storing the values as a vector. The advantage of this structure is that it consumes significantly less memory compared to the matrix forms, because numeric columns are stored as simple numeric vectors.
+A wrapper can be given directly as the right argument to `⎕JSON` or as part of the right argument's data structure (as a sub-array or in a sub-namespace). This allows a special array to be processed appropriately as part of a general data structure that is to be rendered as JSON.
-```apl
- (Fields (Items Price Qty))
+The structure of the special array is specified within the wrapper by a leading numeric code. Code `1` (the default) allows insertion of raw text, including JSON values such as null and true. Codes `2`, `3`, and `4` identify various representations of a *dataset*. The term *dataset* is used here to mean a collection of data, usually presented in tabular form. Each named column (also called a *field*) represents a particular variable. Each row (also called a *record*) corresponds to a given member of the dataset in question, listing its value for each of the variables, such as price and quantity of an item.
-┌────────────────┬────────────────────────┐
-│┌────┬─────┬───┐│┌────────────┬───┬─────┐│
-││Item│Price│Qty│││┌─────┬────┐│3 4│23 45││
-│└────┴─────┴───┘│││Knife│Fork││ │ ││
-│ ││└─────┴────┘│ │ ││
-│ │└────────────┴───┴─────┘│
-└────────────────┴────────────────────────┘
+In APL, a dataset is traditionally represented as a collection of variables:
+
+```apl
+ fields←'item' 'price' 'qty'
+ item←'Knife' 'Fork' 'Spoon'
+ price←3 4 5
+ qty←23 45 67
```
-In JSON, these three data structures are all expressed as follows:
+However, when a single array is needed, it is commonly represented as either a single mixed-type matrix that includes headers, a mixed-type matrix of values with a separate header vector, or an inverted table of values with a separate header vector.
+
+In JSON, a dataset is almost universally represented as an *array of objects* (JavaScript nomenclature for APL's *vector of namespaces*):
```json
[
- {
- "Item": "Knife",
- "Price": 3,
- "Qty": 23
- },
- {
- "Item": "Fork",
- "Price": 4,
- "Qty": 45
- }
+ {
+ "item": "Knife",
+ "price": 3,
+ "qty": 23
+ },
+ {
+ "item": "Fork",
+ "price": 4,
+ "qty": 45
+ },
+ {
+ "item": "Spoon",
+ "price": 5,
+ "qty": 67
+ }
]
```
-**Examples**
+The JSON structure can be represented in APL as:
```apl
- Fields,[1]↑[1]Items Price Qty
-
-┌─────┬─────┬───┐
-│Item │Price│Qty│
-├─────┼─────┼───┤
-│Knife│3 │23 │
-├─────┼─────┼───┤
-│Fork │4 │45 │
-└─────┴─────┴───┘
- ⎕JSON ⊂ 2 (Fields,[1]↑[1]Items Price Qty)
-[{"Item":"Knife","Price":3,"Qty":23},{"Item":"Fork","Price":4,"Qty":45}]
+ ⎕←fields{()⎕VSET(↑⍺)⍵}⍤1⍉↑item price qty
+ #.[Namespace] #.[Namespace] #.[Namespace]
```
-Note that if you omit the wrapper the operation fails:
+If such a representation is already used in an APL application, then no special handling is necessary to generate the corresponding JSON. However, transforming a dataset into a vector of namespaces, just for export to JSON, is cumbersome and can be expensive. `⎕JSON`'s wrapper codes `2`, `3`, and `4`, provide a quick and efficient way to transform the common APL representations of a dataset directly into a JSON array of objects.
-```apl
- ⎕JSON Fields,[1]↑[1]Items Price Qty)
+### Raw Text Wrapper
-DOMAIN ERROR: JSON export: the right argument cannot be converted (⎕IO=1)
-⎕JSON Fields,[1]↑[1]Items Price Qty)
-∧
+Special JSON values such as null, true and false do not directly correspond to specific APL values and, therefore, require special handling. This is provided by wrapper code `1`:
+
+```apl
+ 1 ⎕JSON 42 'text'(⊂1 'null')(⊂1 'true')(⊂1 'false')
+[42,"text",null,true,false]
+```
+As `1` is the default code number, it can be omitted:
+```apl
+ 1 ⎕JSON 42 'text'(⊂'null')(⊂'true')(⊂'false')
+[42,"text",null,true,false]
```
-**Further Examples**
+This feature can be used to inject any raw text, although unless it is valid JSON it cannot then be re-imported.
-```apl
- ⎕JSON ⊂ 3 ((↑[1]Items Price Qty)Fields)
-[{"Item":"Knife","Price":3,"Qty":23},{"Item":"Fork","Price":4,"Qty":45}]
+!!! Warning "Warning"
+ It is common practice to initialise a list using a scalar rather than a one-element vector. However, this will be interpreted as raw text if no subsequent elements are added:
+ ```apl
+ list←⊂'foo'
+ 1 ⎕JSON list
+ foo
+ 1 ⎕JSON list,'bar' 'baz'
+ ["foo","bar","baz"]
+ ```
+ It is, therefore, important to convert to a vector before initialising:
+ ```apl
+ list←,⊂'foo'
+ 1 ⎕JSON list
+ ["foo"]
+ ```
- ⎕JSON ⊂ 4 ((Items Price Qty)Fields)
-[{"Item":"Knife","Price":3,"Qty":23},{"Item":"Fork","Price":4,"Qty":45}]
-```
+Example
-Note that if you omit the wrapper, the operation generates a different result.
+This example illustrates how JavaScript objects can be exported; the object contains a JavaScript function that is specified by the contents of an enclosed character vector:
```apl
- ⎕JSON ((Items Price Qty)Fields)
-[[["Knife","Fork"],[3,4],[23,45]],["Item","Price","Qty"]]
+ slider←(
+ range:⊂'true'
+ min:0
+ max:500
+ values:75 300
+ slide:⊂'function(event,ui){$("#amount").val("$" + ui.values[0] + " - $" + ui.values[1]);}'
+ )
+ 1 ⎕JSON slider
+{"max":500,"min":0,"range":true,"slide":function(event,ui){$("#amount").val("$" + ui.values[0] + " - $" + ui.values[1]);},"values":[75,300]}
```
-**Selection**
+### Dataset Wrappers
-For codes 2, 3 and 4 the extension also provides the facility to optionally select elements of the dataset, so the array may contain 2, 3 or 4 items:
+Wrapper codes `2`, `3`, and `4` produce identical JSON output (an array of objects; the canonical JSON representation of a dataset), but each allows different APL representation of the dataset:
+
+Table: Wrapper codes { #wrapper-codes-table }
+
+| Code | Data | Advantage |
+|--------------|----------------------------------------------------------------------------------------|-----------|
+| `2` | Single mixed-type matrix (first row is header vector) | Preserves visual fidelity with a printed table |
+| `3` | Two-element nested vector: value matrix and header vector | Allows indexing into the rows and columns of the data |
+| `4` | Two-element nested vector: inverted table (vector of column vectors) and header vector | Less memory and faster lookups |
+
+For wrapper code `4`, if [**HighRank**](#variant-option-highrank) is `'Split'`, character columns can also be stored as character matrices rather than vectors of character vectors, providing even better performance, but `⎕JSON` will preserve trailing spaces.
+
+Examples
+
+The data arrays are defined as follows:
```apl
- ⊂(code dataset {records} {fields})
+ ⎕←singleMatrix←fields⍪⍉↑item price qty
+┌─────┬─────┬───┐
+│item │price│qty│
+├─────┼─────┼───┤
+│Knife│3 │23 │
+├─────┼─────┼───┤
+│Fork │4 │45 │
+├─────┼─────┼───┤
+│Spoon│5 │67 │
+└─────┴─────┴───┘
+ ⎕←valueMatrix←⍉↑item price qty
+┌─────┬─┬──┐
+│Knife│3│23│
+├─────┼─┼──┤
+│Fork │4│45│
+├─────┼─┼──┤
+│Spoon│5│67│
+└─────┴─┴──┘
+ ⎕←invertedTable←item price qty
+┌──────────────────┬─────┬────────┐
+│┌─────┬────┬─────┐│3 4 5│23 45 67│
+││Knife│Fork│Spoon││ │ │
+│└─────┴────┴─────┘│ │ │
+└──────────────────┴─────┴────────┘
+ ⎕←invertedTable2←↑¨item price qty
+┌─────┬─────┬────────┐
+│Knife│3 4 5│23 45 67│
+│Fork │ │ │
+│Spoon│ │ │
+└─────┴─────┴────────┘
+ ⎕←header←fields
+┌────┬─────┬───┐
+│item│price│qty│
+└────┴─────┴───┘
```
-where records and fields are integer indices that select which fields and which records are to be exported. The following example selects the first record and the first and third fields (Items and Qty)
+All wrapper invocations produce the same array of objects (except for trailing spaces when using a character matrix to represent a text field):
```apl
- ⎕JSON⊂4 ((Items Price Qty)Fields)1(1 3)
-[{"Item":"Knife","Qty":23}]
+ 1 ⎕JSON⊂2 singleMatrix
+[{"item":"Knife","price":3,"qty":23},{"item":"Fork","price":4,"qty":45},{"item":"Spoon","price":5,"qty":67}]
+ 1 ⎕JSON⊂3(valueMatrix header)
+[{"item":"Knife","price":3,"qty":23},{"item":"Fork","price":4,"qty":45},{"item":"Spoon","price":5,"qty":67}]
+ 1 ⎕JSON⊂4(invertedTable header)
+[{"item":"Knife","price":3,"qty":23},{"item":"Fork","price":4,"qty":45},{"item":"Spoon","price":5,"qty":67}]
+ 1(⎕JSON⍠'HighRank' 'Split')⊂4(invertedTable2 header)
+[{"item":"Knife","price":3,"qty":23},{"item":"Fork ","price":4,"qty":45},{"item":"Spoon","price":5,"qty":67}]
```
-**Namespaces and Sub-Arrays**
+Without their wrappers, each APL structure *can* be represented in JSON, though this is not a common way to represent a dataset:
-Wrappers in namespaces and sub-arrays are recognised for special treatment.
+```apl
+ 1(⎕JSON⍠'HighRank' 'Split')singleMatrix
+[["item","price","qty"],["Knife",3,23],["Fork",4,45],["Spoon",5,67]]
+ 1(⎕JSON⍠'HighRank' 'Split')valueMatrix header
+[[["Knife",3,23],["Fork",4,45],["Spoon",5,67]],["item","price","qty"]]
+ 1 ⎕JSON invertedTable header
+[[["Knife","Fork","Spoon"],[3,4,5],[23,45,67]],["item","price","qty"]]
+ 1(⎕JSON⍠'HighRank' 'Split')invertedTable2 header
+[[["Knife","Fork ","Spoon"],[3,4,5],[23,45,67]],["item","price","qty"]]
+```
-**Example**
+### Selection of a Subset
-```apl
- ns.Items←'Fork' 'Knife'
- ns.Price←3 4
- ns.Qty←23 45
- ns.(ds←⊂4(⌽('Item' 'Price' 'Qty')(Items Price Qty)))
- ⎕JSON ns
-{"Items":["Knife","Fork"],"Price":[3,4],"Qty":[23,45],"ds":[{"Item":"Knife","Price":3,"Qty":23},{"Item":"Fork","Price":4,"Qty":45}]}
+A subset of a dataset's records (rows) and fields (columns) can be selected, with each subset being specified as a vector of strictly ascending indices and `⊂⍬` meaning "all" records (and/or fields):
- a←'the' 'answer' 'is' 42
- a[3]←⊂ns.ds
- ⎕JSON a
-["the","answer",[{"Item":"Knife","Price":3,"Qty":23},{"Item":"Fork","Price":4,"Qty":45}],42]
-```
+Table: Wrappers forms for selecting dataset subsets { #subset-table }
-## JSON Name Mangling
+| Subset | Wrapper form |
+|--------------------|--------------------------------------------|
+| records | `⊂wrapperCode wrapperData recordIndices` |
+| fields | `⊂wrapperCode wrapperData(⊂⍬)fieldIndices` |
+| records and fields | `⊂wrapperCode wrapperData recordIndices fieldIndices` |
-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.
+Examples
-Example
+To select the second record (Fork):
-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):
```apl
-{"a": 1, "2a": 2}
+ 1 ⎕JSON⊂4(invertedTable header)2
+[{"item":"Fork","price":4,"qty":45}]
```
-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 `⍙`.
-```apl
- (⎕JSON'{"a": 1, "2a": 2}').⎕NL 2
-a
-⍙2a
-```
+To select the first and third fields (`item` and `qty`):
-When Dyalog exports JSON it performs the reverse *name mangling*, so:
```apl
- 1 ⎕JSON ⎕JSON'{"a": 1, "2a": 2}'
-{"a":1,"2a":2}
-
+ 1 ⎕JSON⊂4(invertedTable header)(⊂⍬)(1 3)
+[{"item":"Knife","qty":23},{"item":"Fork","qty":45},{"item":"Spoon","qty":67}]
```
-Should you need to create and decode these names directly,`7162⌶` provides the same name mangling and un-mangling operations. See [JSON Translate Name](../primitive-operators/i-beam/json-translate-name.md).
+To select the second record (Fork) and the first and third fields (`item` and `qty`):
+
```apl
- 0(7162⌶)'2a'
-⍙2a
- 1(7162⌶)'⍙2a'
-2a
+ 1 ⎕JSON⊂4(invertedTable header)2(1 3)
+[{"item":"Fork","qty":45}]
```