5.4 OPC UA JSON

5.4.1 General

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 built-in types.

The JSON format is defined in IETF 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.

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 is 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 identifies some the artefacts which can be removed to meet the needs of cloud applications. Applications, such as JavaScript Clients, which use the DataEncoding for communication with other OPC UA applications require the artefacts.

The CompactEncoding omits all fields in Structure values with a value equal to the default value for the type. The VerboseEncoding includes all of these fields.

The CompactEncoding and VerboseEncoding replace the ReversibleEncoding and NonReversibleEncoding. The differences are described in Annex H. The VerboseEncoding also supports the RawData mode defined in OPC 10000-14. In RawData mode, encoders shall omit the following fields:

UaType (see 5.4.2.17 and 5.4.2.18);

UaTypeId (see 5.4.2.16);

Decoders may not be able to process streams encoding in RawData mode unless they have access to the associated metadata. These fields are not omitted when serialization uses abstract DataTypes such as Structure (i.e. ExtensionObject) or BaseDataType (i.e. Variant). OPC 10000-14 specifies the behaviour if a Publisher is misconfigured with metadata that uses abstract DataTypes.

5.4.2 Built-in Types

5.4.2.1 General

Any value for a nullable Built-In type that is NULL shall be encoded as the JSON literal ‘null’ if the value is an element of a JSON array. If the NULL value is for a field within a JSON object, the field shall be omitted when using the CompactEncoding. When using the VerboseEncoding, the field is encoded as the JSON literal ‘null’.

Any non-nullable built-in type shall be encoded if it is an element of an array. When using the CompactEncoding, the field of a Structure or Union is omitted if value is equal to the default value for the built-in type.

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.

5.4.2.2 Boolean

A Boolean value shall be encoded as the JSON literal ‘true’ or ‘false’.

5.4.2.3 Integer

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).

5.4.2.4 Floating-point

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.

5.4.2.5 String

String values shall be encoded as JSON strings.

Any characters which are not allowed in JSON strings are escaped using the rules defined in IETF 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.

5.4.2.6 DateTime

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 required 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.

5.4.2.7 Guid

Guid values shall be formatted as described in 5.1.3 and encoded as a JSON string.

5.4.2.8 ByteString

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 IETF RFC 8259.

5.4.2.9 XmlElement

XmlElement value shall be encoded as a String as described in 5.4.2.5.

5.4.2.10 NodeId

NodeId values shall be encoded as a JSON string using the format defined in 5.1.12. NodeIds in NamespaceIndex 0 use the <identifier> form. All other NodeIds use the <namespace-uri> form.

The first abnormal state occurs when the encoder cannot map a NamespaceIndex to a NamespaceUri. In this case, the encoder shall encode the NamespaceIndex using the <namespace-index> form. The decoder shall pass this NamespaceIndex to the application.

The second abnormal state occurs when the decoder cannot convert a NamespaceUri to a NamespaceIndex. If this occurs the decoder shall set the NamespaceIndex to 0, the IdType to String and the Identifier to the JSON string.

5.4.2.11 ExpandedNodeId

ExpandedNodeId values shall be encoded as a JSON string using the format defined in 5.1.12. The NodeId portion of the ExpandedNodeId uses the rules from 5.4.2.10.ExpandedNodeIds with a ServerIndex of 0 are encoded using the <node-id> form. All other ExpandedNodeIds use the <server-uri> form unless the first abnormal state occurs as described below.

The first abnormal state occurs when the encoder cannot map a ServerIndex to a ServerUri. In this case, the encoder shall encode the ServerIndex using the <server-index> form. The decoder shall pass this ServerIndex to the application.

The second abnormal state occurs when the decoder cannot convert a ServerUri to a ServerIndex. If this occurs the decoder shall set the ServerIndex to 0, the NamespaceIndex to 0, the IdType to String and the Identifier to the JSON string.

When the ServerIndex is 0, decoders shall replace a NamespaceUri with a NamespaceIndex when a mapping exists or if a mapping can be created. If no mapping exists or one cannot be created the NamespaceUri is stored in the NamespaceUri field of the ExpandedNodeId.

5.4.2.12 StatusCode

StatusCode values shall be encoded as a JSON object with the fields defined in Table 37.

Table 37 – JSON Object Definition for a StatusCode
NameDescription
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 "BadInvalidArgument".

Any InfoBits in the StatusCode are ignored when looking up the symbol.

If the string literal is not known to the encoder the field is omitted.

The field is omitted in the CompactEncoding.

The field is omitted if the numeric code is 0 (Good).

The recommended string literals are defined in A.2.

5.4.2.13 DiagnosticInfo

DiagnosticInfo values shall be encoded as a JSON object with the fields shown in Table 38.

Table 38 – JSON Object Definition for a DiagnosticInfo
NameData TypeDescription
SymbolicIdInt32

A symbolic name for the status code.

The default value is -1.

It is not encoded if the value is -1.

NamespaceUriInt32

A namespace that qualifies the symbolic id.

The default value is -1.

It is not encoded if the value is -1.

LocaleInt32

The locale used for the localized text.

The default value is -1.

It is not encoded if the value is -1.

LocalizedTextInt32

A human readable summary of the status code.

The default value is -1.

It is not encoded if the value is -1.

AdditionalInfoString

Detailed application specific diagnostic information.

The default value is null.

It is not encoded if the value is null.

InnerStatusCodeStatusCode

A status code provided by an underlying system.

The default value is Good.

It is not encoded if the value is Good.

InnerDiagnosticInfoDiagnosticInfo

Diagnostic info associated with the inner status code.

The default value is null.

It is not encoded if the value is null.

The SymbolicId, NamespaceUri, Locale and LocalizedText fields are encoded as JSON numbers which reference the StringTable contained in the ResponseHeader.

DiagnosticInfo is recursive and unlimited recursion could result in stack overflow errors even if the message size is less than the maximum allowed. Decoders shall support at least 4 recursion levels and are not expected to support more than 10. Decoders shall report an error if the number of recursion levels exceeds what it supports.

5.4.2.14 QualifiedName

QualifiedName values shall be encoded as a JSON string using the format defined in 5.1.12.

The form with the NamespaceIndex is not allowed unless there is an encoding error. This can occur when the encoder cannot map a NamespaceIndex to a NamespaceUri. In this case, the encoder shall encode the NamespaceIndex using the <namespace-index> form. The decoder shall pass this NamespaceIndex to the application.

A second abnormal state occurs when the decoder cannot convert a NamespaceUri to a NamespaceIndex. If this occurs the decoder shall set the NamespaceIndex to 0 and the Name to the raw JSON string that includes the NamespaceUri that cannot be decoded.

5.4.2.15 LocalizedText

LocalizedText values shall be encoded as a JSON object with the fields shown in Table 39.

Table 39 – JSON Object Definition for a LocalizedText
NameDescription
Locale

The Locale portion of LocalizedText values shall be encoded as a JSON string.

The field is not encoded if it is null or empty.

Text

The Text portion of LocalizedText values shall be encoded as a JSON string.

The field is not encoded if it is null or empty.

5.4.2.16 ExtensionObject

The ExtensionObject is encoded as a JSON object as described in:

Structure (see 5.4.6);

Structure with optional fields (see 5.4.7);

Union (see 5.4.8);

with the UaTypeId field inserted into the JSON object.

Decoders shall report decoding errors to the application if a JSON object has multiple fields with the same name.

The UaEncoding and UaBody fields are only used when UA Binary or UA XML encoded Structures are serialized. Only the fields in Table 40 are present if these fields are used.

The JSON object fields used for an ExtensionObject are in Table 40.

Table 40 – JSON Object Fields used for an ExtensionObject
NameDescription
UaTypeId

A NodeId formatted using the rules in 5.4.2.10.

This is the NodeId of a DataType Node.

UaEncoding

A JSON number that represents the format of the UaBody field.

A value of 1 indicates UA Binary data is encoded in the UaBody field.

A value of 2 indicates UA XML data is encoded in the UaBody field.

This field is omitted for JSON encoded Structures.

UaBody

A ByteString containing an UA Binary or UA XML encoded Structure.

This field is omitted for JSON encoded Structures.

Encoders, when allowed by the DevelopmentPlatform, should write the UaTypeId first. Decoders shall accept the UaTypeId in any position.

The default value for an ExtensionObject is serialized as an empty JSON object in the VerboseEncoding and omitted in the CompactEncoding.

5.4.2.17 Variant

Variant values shall be encoded as a JSON object with the fields shown in Table 41.

Table 41 – JSON Object Definition for a Variant
NameDescription
UaTypeThe built-in type for the value contained in the Body (see Table 1) encoded as JSON number.
Value

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 JSON array containing all elements. The mapping of a multidimensional array to a flat list is described in 5.2.2.16.

The field is not encoded if the value is a NULL for nullable built-in types (see Table 1).

DimensionsThe dimensions of the array encoded as a JSON array of JSON numbers.

Encoders, when allowed by the DevelopmentPlatform, should write the UaType first. Decoders shall accept the UaType field in any position.

5.4.2.18 DataValue

DataValue values shall be encoded as a JSON object with the fields shown in Table 42.

The DataValue adds additional fields to a Variant (see 5.4.2.17).

Table 42 – JSON Object Definition for a DataValue
NameData TypeDescription
UaTypeByteSee the UaType field in the Variant.
Value*See the Value field in the Variant.
DimensionsUInt32See the Dimensions field in the Variant.
StatusStatusCode

The status associated with the value.

Not encoded if the value is Good (0).

SourceTimestampDateTime

The source timestamp associated with the value.

Not encoded if the value is DateTime.MinValue.

SourcePicosecondsUInt16

The number of 10 Picosecond intervals for the SourceTimestamp.

Not encoded if the value is 0.

ServerTimestampDateTime

The Server timestamp associated with the value.

Not encoded if the value is DateTime.MinValue.

ServerPicosecondsUInt16

The number of 10 Picosecond intervals for the ServerTimestamp.

Not encoded if the value is 0.

5.4.3 Decimal

Decimal values shall be encoded as a JSON object with the fields in Table 43.

Table 43 – JSON Object Definition for a Decimal
NameDescription
ScaleA 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 43 as the Body. The TypeId shall be the NodeId of the Decimal DataType and the Encoding shall be 0.

5.4.4 Enumerations

5.4.4.1 Compact

Enumeration values shall be encoded as a JSON number.

When an Enumeration is encoded in a Variant the Type field is Int32.

5.4.4.2 Verbose

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.

When an Enumeration is encoded in a Variant the Type field is a Int32 and the value is encoded as a JSON number.

5.4.5 Arrays

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.

Multidimensional Arrays are encoded as JSON object with the fields defined in Table 44.

Table 44 – JSON Object Definition for an inline Matrix
NameDescription
ArrayMulti-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).
DimensionsThe dimensions of the array encoded as a JSON array of JSON numbers.

5.4.6 Structures

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 45.

Table 45 – JSON Encoding Rules for Structures
Field ValueCompactVerbose
NULLOmittedJSON null
Default ValueOmittedDefault 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 CompactEncoding 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 VerboseEncoding 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.

Code generators should ensure that the special field names (UaType, UaTypeId and EncodingMask) are not permitted in Structures.

5.4.7 Structures with optional fields

Structures with optional fields shall be encoded as JSON objects as shown in Table 46.

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 is not guaranteed to appear as the first field.

In the VerboseEncoding the bits in the EncodingMask are determined by the presence of a field in the JSON object. In the CompactEncoding, EncodingMask indicates which fields are specified because fields are omitted because they have a default value.

Table 46 – JSON Object Definition for a Structures with Optional Fields
NameDescription
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 omitted in the VerboseEncoding

<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 47.

Table 47 – JSON Encoding Rules for Structures with Optional Fields
Field ValueField TypeCompactVerbose
NULLMandatoryOmittedJSON null
Default ValueMandatoryOmittedDefault Value
NULLOptional (Present)OmittedJSON null
Default ValueOptional (Present)OmittedDefault Value
NULLOptional (Omitted)OmittedOmitted
Default ValueOptional (Omitted)OmittedOmitted

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 CompactEncoding 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 VerboseEncoding would be:

	 { "X": 1, "Y": 2, "O2": 0 }

Encoders, when allowed by the DevelopmentPlatform, should write the EncodingMask first. Decoders shall accept the EncodingMask in any position.

Code generators should ensure that the special field names (UaType, UaTypeId and EncodingMask) are not permitted in Structures with option field.

5.4.8 Unions

Unions shall be encoded as JSON objects as shown in Table 48.

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.

Table 48 – JSON Object Definition for a Union
NameDescription
SwitchField

This field is only present in the CompactEncoding.

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.

A Union with no field specified is encoded as an empty JSON object.

<FieldName>

The value of the field encoded using the rules that apply to the DataType.

The name of field in the JSON object is the name of the field in the DataTypeDefinition.

For example, instances of the union:

	struct Union1 
	{ 
	   Byte Selector; 
	
	   {
	   Int32 A; 
	   Double B; 
	   Char* C;
	   }
	   Value;
	}; 

would be represented in the CompactEncoding as:

	{ "SwitchField":2, "B":3.1415 }

and would be represented in the VerboseEncoding as:

	{ "B":3.1415 }

5.4.9 Messages

Messages are encoded as ExtensionObjects (see 5.4.2.16).