The JSON DataEncoding was developed to allow OPC UA applications to interoperate with web and enterprise software that use this format. The OPC UA JSON DataEncoding defines standard JSON representations for all OPC UA Built-In types.
The JSON format is defined in RFC 8259. It is partially self-describing because each field has a name encoded in addition to the value, however, JSON has no mechanism to qualify names with namespaces.
The JSON format does not have a published standard for a schema that can be used to describe the contents of a JSON document. However, the schema mechanisms defined in this document can be used to describe JSON documents. Specifically, the DataTypeDescription structure defined in OPC 10000-3 can define any JSON document that conforms to the rules described below.
Servers that support the JSON DataEncoding shall add DataTypeEncoding Nodes called “Default JSON” to all DataTypes which can be serialized with the JSON encoding. The NodeIds of these Nodes are defined by the information model which defines the DataType. These NodeIds are used in ExtensionObjects as described in 5.4.2.16.
There are two important use cases for the JSON encoding: Cloud applications which consume PubSub messages and JavaScript Clients (JSON is the preferred serialization format for JavaScript). For the Cloud application use case, the PubSub message needs to be self-contained which implies it cannot contain numeric references to an externally defined namespace table. Cloud applications also often rely on scripting languages to process the incoming messages so artefacts in the DataEncoding that exist to ensure fidelity during decoding are not necessary. For this reason, this DataEncoding defines a ‘non-reversible’ form which is designed to meet the needs of Cloud applications. Applications, such as JavaScript Clients, which use the DataEncoding for communication with other OPC UA applications use the normal or ‘reversible’ form. The differences, if any, between the reversible and non-reversible forms are described for each type.
Any value for a Built-In type that is NULL shall be encoded as the JSON literal ‘null’ if the value is an element of an array. If the NULL value is for a field within a Structure or Union, the field shall not be encoded.
Note that JSON objects are unordered sets of name-value pairs. When a Built-In type is encoded as a JSON object, the order of fields specified is not preserved.
A Boolean value shall be encoded as the JSON literal ‘true’ or ‘false’.
Integer values other than Int64 and UInt64 shall be encoded as a JSON number.
Int64 and UInt64 values shall be formatted as a decimal number encoded as a JSON string
(See the XML encoding of 64-bit values described in 5.3.1.3).
Normal Float and Double values shall be encoded as a JSON number.
Special floating-point numbers such as positive infinity (INF), negative infinity (-INF) and not-a-number (NaN) shall be represented by the values “Infinity”, “-Infinity” and “NaN” encoded as a JSON string. See 5.2.2.3 for more information on the different types of special floating-point numbers.
String values shall be encoded as JSON strings.
Any characters which are not allowed in JSON strings are escaped using the rules defined in RFC 8259.
Strings with embedded nulls (‘\u0000’) are not guaranteed to be interoperable because not all DevelopmentPlatforms can handle Strings with embedded nulls. For this reason, embedded nulls are not recommended. Encoders may encode Strings with embedded nulls. Decoders shall read all bytes in String; however, decoders may truncate the String at the first embedded null before passing it on to the application.
DateTime values shall be formatted as specified by ISO 8601-1 and encoded as a JSON string.
DateTime values which exceed the minimum or maximum values supported on a platform shall be encoded as “0001-01-01T00:00:00Z” or “9999-12-31T23:59:59Z” respectively. During decoding, these values shall be converted to the minimum or maximum values supported on the platform.
ISO 8601-1 DateType values may specify an arbitrary number of decimal places representing fractions of seconds. Encoders shall support as many decimal places needed to represent the full range of the DateTime type on their DevelopmentPlatform. Decoders may truncate decimal places that exceed the range supported by the DateTime type on their DevelopmentPlatform.
DateTime values equal to “0001-01-01T00:00:00Z” are considered to be NULL values.
Guid values shall be formatted as described in 5.1.3 and encoded as a JSON string.
ByteString values shall be formatted as a Base64 text and encoded as a JSON string.
Any characters which are not allowed in JSON strings are escaped using the rules defined in RFC 8259.
XmlElement value shall be encoded as a String as described in 5.4.2.5.
NodeId values shall be encoded as a JSON object with the fields defined in Table 31.
The abstract NodeId structure is defined in OPC 10000-3 and has three fields Id, IdType and NamespaceIndex. The representation of these abstract fields are described in the table.
Table 31 – JSON Object Definition for a NodeId
Name |
Description |
IdType |
The IdentifierType encoded as a JSON number. Allowed values are: 0 - UInt32 identifier encoded as a JSON number. 1 - A String identifier encoded as a JSON string. 2 - A Guid identifier encoded as described in 5.4.2.7. 3 - A ByteString identifier encoded as described in 5.4.2.8. This field is omitted for UInt32 identifiers. |
Id |
The identifier. The value of the IdType field specifies the encoding of this field. |
Namespace |
For reversible encoding this field is a JSON number with the NamespaceIndex. The field is omitted if the NamespaceIndex is 0. For non-reversible encoding this field is the JSON string containing the NamespaceUri associated with the NamespaceIndex unless the NamespaceIndex is 0. If the NamespaceIndex is 0 the field is omitted. |
ExpandedNodeId values shall be encoded as a JSON object with the fields defined in Table 32.
The abstract ExpandedNodeId structure is defined in OPC 10000-4 and has five fields Identifier, IdentifierType, NamespaceIndex, NamespaceUri and ServerIndex. The representation of these abstract fields are described in the table.
Table 32 – JSON Object Definition for an ExpandedNodeId
Name |
Description |
IdType |
The IdentifierType encoded as a JSON number. Allowed values are: 0 - UInt32 Identifier encoded as a JSON number. 1 - A String Identifier encoded as a JSON string. 2 - A Guid Identifier encoded as described in 5.4.2.7. 3 - A ByteString Identifier encoded as described in 5.4.2.8. This field is omitted for UInt32 identifiers. |
Id |
The Identifier. The value of the IdType field specifies the encoding of this field. |
Namespace |
For reversible encoding this field is a JSON string with the NamespaceUri if the NamespaceUri is specified. Otherwise, it is a JSON number with the NamespaceIndex. The field is omitted if the NamespaceIndex is 0. For non-reversible encoding this field is the JSON string containing the NamespaceUri or the NamespaceUri associated with the NamespaceIndex unless the NamespaceIndex is 0 or 1. If the NamespaceIndex is 0 the field is omitted. |
ServerUri |
For reversible encoding this field is a JSON number with the ServerIndex. The field is omitted if the ServerIndex is 0. For non-reversible encoding this field is the JSON string containing the ServerUri associated with the ServerIndex unless the ServerIndex is 0. If the ServerIndex is 0 the field is omitted. |
StatusCode values shall be encoded as a JSON number for the reversible encoding. If the StatusCode is Good (0) it is only encoded if it is an element of a JSON array.
For the non-reversible form, StatusCode values shall be encoded as a JSON object with the fields defined in Table 33.
Table 33 – JSON Object Definition for a StatusCode
Name |
Description |
Code |
The numeric code encoded as a JSON number. The Code is omitted if the numeric code is 0 (Good). |
Symbol |
The string literal associated with the numeric code encoded as JSON string. e.g. 0x80AB0000 has the associated literal “Bad_InvalidArgument”. The Symbol is omitted if the numeric code is 0 (Good). If the string literal is not known to the encoder the field is omitted. |
For the non-reversible encoding, a StatusCode of Good (0) it is only encoded if it is an element JSON array.
DiagnosticInfo values shall be encoded as a JSON object with the fields shown in Table 34.
Table 34 – JSON Object Definition for a DiagnosticInfo
Name |
Data Type |
Description |
SymbolicId |
Int32 |
A symbolic name for the status code. The default value is -1. |
NamespaceUri |
Int32 |
A namespace that qualifies the symbolic id. The default value is -1. |
Locale |
Int32 |
The locale used for the localized text. The default value is -1. |
LocalizedText |
Int32 |
A human readable summary of the status code. The default value is -1. |
AdditionalInfo |
String |
Detailed application specific diagnostic information. The default value is null. |
InnerStatusCode |
StatusCode |
A status code provided by an underlying system. The default value is Good. |
InnerDiagnosticInfo |
DiagnosticInfo |
Diagnostic info associated with the inner status code. The default value is null. |
Each field is encoded using the rules defined for the built-in type specified in the Data Type column. Fields should be omitted if the value is null or the default value for the field. If a field is not present the value shall be interpreted as the default value.
The SymbolicId, NamespaceUri, Locale and LocalizedText fields are encoded as JSON numbers which reference the StringTable contained in the ResponseHeader.
QualifiedName values shall be encoded as a JSON object with the fields shown in Table 35.
The abstract QualifiedName structure is defined in OPC 10000-3 and has two fields Name and NamespaceIndex. The NamespaceIndex is represented by the Uri field in the JSON object.
Table 35 – JSON Object Definition for a QualifiedName
Name |
Description |
Name |
The Name component of the QualifiedName. |
Uri |
For reversible encoding this field is a JSON number with the NamespaceIndex. The field is omitted if the NamespaceIndex is 0. For non-reversible encoding this field is the JSON string containing the NamespaceUri associated with the NamespaceIndex unless the NamespaceIndex is 0. If the NamespaceIndex is 0 the field is omitted. |
LocalizedText values shall be encoded as a JSON object with the fields shown in Table 36.
The abstract LocalizedText structure is defined in OPC 10000-3 and has two fields Text and Locale.
Table 36 – JSON Object Definition for a LocalizedText
Name |
Description |
Locale |
The Locale portion of LocalizedText values shall be encoded as a JSON string |
Text |
The Text portion of LocalizedText values shall be encoded as a JSON string. |
For the non-reversible form, LocalizedText value shall be encoded as a JSON string containing the Text component.
ExtensionObject values shall be encoded as a JSON object with the fields shown in Table 37.
Table 37 – JSON Object Definition for an ExtensionObject
Name |
Description |
TypeId |
The NodeId of a DataTypeEncoding Node or a DataType Node formatted using the rules in 5.4.2.10. |
Encoding |
The format of the Body field encoded as a JSON number. This value is 0 if the body is Structure encoded as a JSON object (see 5.4.6). This value is 1 if the body is a ByteString value encoded as a JSON string (see 5.4.2.8). This value is 2 if the body is a XmlElement value encoded as a JSON string (see 5.4.2.9). This field is omitted if the value is 0. |
Body |
Body of the ExtensionObject. The type of this field is specified by the Encoding field. If the Body is empty, the ExtensionObject is NULL and is omitted or encoded as a JSON null. |
For the non-reversible form, ExtensionObject values shall be encoded as a JSON value containing only the value of the Body field. The TypeId and Encoding fields are dropped.
Variant values shall be encoded as a JSON object with the fields shown in Table 38.
Table 38 – JSON Object Definition for a Variant
Name |
Description |
Type |
The Built-in type for the value contained in the Body (see Table 1) encoded as JSON number. If type is 0 (NULL) the Variant contains a NULL value and the containing JSON object shall be omitted or replaced by the JSON literal ‘null’ (when an element of a JSON array). |
Body |
If the value is a scalar, it is encoded using the rules for type specified for the Type. If the value is a one-dimensional array it is encoded as JSON array (see 5.4.5). Multi-dimensional arrays are encoded as a one-dimensional JSON array which is reconstructed using the value of the Dimensions field (see 5.2.2.16). |
Dimensions |
The dimensions of the array encoded as a JSON array of JSON numbers. The Dimensions are omitted for scalar and one-dimensional array values. |
For the non-reversible form, Variant values shall be encoded as a JSON value containing only the value of the Body field. The Type and Dimensions fields are dropped. Multi-dimensional arrays are encoded as a multi-dimensional JSON array as described in 5.4.5.
DataValue values shall be encoded as a JSON object with the fields shown in Table 39.
Table 39 – JSON Object Definition for a DataValue
Name |
Data Type |
Description |
Value |
Variant |
The value. |
Status |
StatusCode |
The status associated with the value. |
SourceTimestamp |
DateTime |
The source timestamp associated with the value. |
SourcePicoseconds |
UInt16 |
The number of 10 Picosecond intervals for the SourceTimestamp. |
ServerTimestamp |
DateTime |
The Server timestamp associated with the value. |
ServerPicoseconds |
UInt16 |
The number of 10 Picosecond intervals for the ServerTimestamp. |
If a field has a null or DefaultValue it is omitted. Each field is encoded using the rules defined for the built-in type specified in the Data Type column.
Decimal values shall be encoded as a JSON object with the fields in Table 40.
Table 40 – JSON Object Definition for a Decimal
Name |
Description |
Scale |
A JSON number with the scale applied to the Value. |
Value |
A JSON string with the Value encoded as a base-10 signed integer. (See the XML encoding of Integer values described in 5.3.1.3). |
See 5.1.10 for a description of the Scale and Value fields.
When encoding in a Variant, a Decimal value shall be encoded as an ExtensionObject with the JSON object in Table 40 as the Body. The TypeId shall be the NodeId of the Decimal DataType and the Encoding shall be 0.
Enumeration values shall be encoded as a JSON number for the reversible encoding.
For the non-reversible form, Enumeration values are encoded as a JSON string with the following format:
<name>_<value>
Where the name is the enumeration literal and the value is the numeric value.
If the literal is not known to the encoder, the numeric value is encoded as a JSON string.
If an Enumeration is encoded using the reversible encoding within a Variant, the Type field is Built-in Type Int32.
One dimensional Arrays shall be encoded as JSON arrays.
If an element is NULL, the element shall be encoded as the JSON literal ‘null’.
Otherwise, the element is encoded according to the rules defined for the type.
Multi-dimensional Arrays are encoded as nested JSON arrays. The outer array is the first dimension and the innermost array is the last dimension. For example, the following matrix
0 2 3 |
1 3 4 |
is encoded in JSON as
[ [0, 2, 3], [1, 3, 4] ]
Structures shall be encoded as JSON objects.
Note that JSON objects are unordered sets of name-value pairs. The order specified by the DataTypeDefinition is not preserved when a Structure is serialized in JSON.
Fields which are NULL or have a default value shall be encoded using the rules shown in Table 41.
Table 41 – JSON Encoding Rules for Structures
Field Value |
Reversible |
Non-Reversible |
NULL |
Omitted |
JSON null |
Default Value |
Omitted |
Default Value |
For example, instances of the structures:
struct Type2
{
Int32 A;
Int32 B;
Char* C;
};
struct Type1
{
Int32 X;
Int32 NoOfY;
Type2* Y;
Int32 Z;
};
The reversible encoding is represented in JSON as:
{
"X":1234,
"Y":[ { "A":1, "B":2, "C":"Hello" }, { "A":3, "B":4 } ],
"Z":5678
}
Where “C” is omitted from the second Type2 instance because it has a NULL value.
The non-reversible encoding is represented in JSON as:
{
"X":1234,
"Y":[ { "A":1, "B":2, "C":"Hello" }, { "A":3, "B":4, "C":null } ],
"Z":5678
}
Where “C” in the second Type2 instance has a JSON null value.
Structures with optional fields shall be encoded as JSON objects as shown in Table 42.
Note that JSON objects are unordered sets of name-value pairs. The order specified by the DataTypeDefinition is not preserved when a Structure is serialized in JSON. The EncodingMask may not appear as the first field.
Table 42 – JSON Object Definition for a Structures with Optional Fields
Name |
Description |
EncodingMask |
A bit mask indicating what fields are encoded in the structure (see 5.2.7) This mask is encoded as a JSON number. The bits are sequentially assigned to optional fields in the order that they are defined. This field is not encoded in the non-reversible form. |
<FieldName> |
The field in structure encoded according to the rules defined for their DataType. One entry may exist for each mandatory field and each optional field that is present. |
Fields which are NULL or have a default value shall be encoded using the rules shown in Table 43.
Table 43 – JSON Encoding Rules for Structures with Optional Fields
Field Value |
Field Type |
Reversible |
Non-Reversible |
NULL |
Mandatory |
Omitted |
JSON null |
Default Value |
Mandatory |
Omitted |
Default Value |
NULL |
Optional (Present) |
Omitted |
JSON null |
Default Value |
Optional (Present) |
Omitted |
Default Value |
NULL |
Optional (Omitted) |
Omitted |
Omitted |
Default Value |
Optional (Omitted) |
Omitted |
Omitted |
If a Structure with optional fields is subtyped, the subtypes extend the EncodingMask defined for the parent.
The following is an example of a structure with optional fields using C++ syntax:
struct TypeA
{
Int32 X;
Int32* O1;
SByte Y;
Int32* O2;
};
O1 and O2 are optional fields where a NULL indicates that the field is not present.
Assume that O1 is not specified and the value of O2 is 0.
The reversible encoding would be:
{ "EncodingMask": 2 "X": 1, "Y": 2 }
Where decoders would assign the default value of 0 to O2 since the mask bit is set even though the field was omitted (this is the behaviour defined for the Int32 DataType). Decoders would mark O1 as ‘not specified’.
The non-reversible encoding would be:
{ "X": 1, "Y": 2, "O2": 0 }
Where the EncodingMask is omitted.
Unions shall be encoded as JSON objects as shown in Table 44 for the reversible encoding.
Note that JSON objects are unordered sets of name-value pairs. The order specified by the DataTypeDefinition is not preserved when a Union is serialized in JSON. The SwitchField may not appear as the first field.
Table 44 – JSON Object Definition for a Union
Name |
Description |
SwitchField |
The identifier for the field in the Union which is encoded as a JSON number. The valid values for this field follow the conventions defined in 5.2.8. If the SwitchField value is its DefaultValue of 0, then the SwitchField and the Value field are not present. |
Value |
The value of the field encoded using the rules that apply to the data type. |
For the non-reversible form, Union values are encoded using the rule for the current value. If the SwitchField is 0 the Union is encoded as a JSON null value.
For example, instances of the union:
struct Union1
{
Byte Selector;
{
Int32 A;
Double B;
Char* C;
}
Value;
};
would be represented in reversible form as:
{ "SwitchField":2, "Value":3.1415 }
In non-reversible form, it is represented as:
3.1415
Messages are encoded ExtensionObjects (see 5.4.2.16).