Mappings (normative)

Technical Data Formats

This document specifies the Asset Administration Shell in a technology-neutral format, UML. Different data formats are used or recommended to be used in the different life cycle phases of a product[1].

The Asset Administration Shell supports three widely used formats:

  • XML

  • JSON

  • RDF

Note: the mapping specifications and schemata for XML, JSON and RDF are part of https://github.com/admin-shell-io/aas-specs/tree/IDTA-01001-3-1_working.

Content Format Types

For different use case scenarios different formats are suitable to fulfill the needs. Besides technical formats like JSON and XML also different content formats are available.

Table 1. Format Types
Format Explanation

Normal

The standard serialization of the model element or child elements is applied.

Metadata

Only metadata of an element or child elements is returned; the value is not.

Value

Only the raw value of the model element or child elements is returned; it is commonly referred to as ValueOnly-serialization.

Reference

Only applicable to Referables. Only the reference to the found element is returned; potential child elements are ignored.

Path

Returns the idShort of the requested element and a list of idShortPath to child elements if the requested element is a Submodel, a SubmodelElementCollection, a SubmodelElementList, a AnnotatedRelationshipElement, or an Entity.

Encoding

Blobs require the following encoding: base64 string.

Text Serialization of Values of Type "Reference"

Grammar for Text Serialization Type "Reference"

Some mappings or serializations convert the type "Reference" into a single string. In this case, the following serialization is required:

Grammar:

<Reference> ::= ["[" <ReferenceType> [ "- " <referredSemanticId> " -" ] "]" ] <Key> {(", " <Key> }*

<ReferenceType> ::= "ExternalRef" | "ModelRef"     value of AAS:Reference/type

<SemanticId> ::= ["[" <ReferenceType> "]"] <Key> {(", " <Key> }*     value of AAS:Reference/referredSemanticId

<Key> ::= "(" <KeyType> ")" <KeyValue>

<KeyType> ::= value of AAS:Key/type

<KeyValue> ::= value of AAS:Key/value

Note 1: an IRI may also contain special symbols like "(", "," and "[". A blank is added before the new key or value to distinguish beginning and end of a new key.

Note 2: ReferenceType is optional. It is clear from the first key in the key chain whether the reference is a global or a model reference. The examples in this document therefore do not use this prefix.

Examples for Text Serialization Type "Reference"

Valid Examples:

External References:

(GlobalReference)0173-1#02-BAA120#008


[ExternalRef](GlobalReference)0173-1#02-BAA120#008


(GlobalReference)https://example.com/specification.html (FragmentReference)Hints

Model References:

(ConceptDescription)0173-1#02-BAA120#008


[ModelRef](ConceptDescription)0173-1#02-BAA120#008


(Submodel)https://example.com/aas/1/1/1234859590, (Property)Temperature


(Submodel)https://example.com/aas/1/1/1234859590, (SubmodelElementList)Documents, (SubmodelElementCollection)0, (MultiLanguageProperty)Title

Embedded Data Specifications

The document series "Specification Asset Administration Shell" predefines data specifications that can be used within an Asset Administration Shell to ensure interoperability (see Part 3 documents).

Consequently, some serializations or mappings support exactly the data descriptions defined in this specification, although the metamodel as such is more flexible and would also support proprietary data specifications.

In the case of restricted use of data specifications, we speak of "embedded data specifications". Figure 1 explains the realization: instead of a set of external global references to externally defined data specifications, a set of pairs consisting of an external global reference to a data specification and the data specification content itself are directly "embedded". Here, the data specification content belongs to the schema, while the data specification including its content are not part of the schema in the general concept.

Realization of Embedded Data Specifications
Figure 1. Realization of Embedded Data Specifications

Format "Metadata" (Metadata-Serialization)

Metadata objects are defined for scenarios where a client only wants to access the metadata of an object, but not the value. Metadata objects are used to reduce the payload response to a minimum and to avoid the recursive traversing through the data model when not needed. In many cases, a client is not interested in each child element or value of a resource, but only in the resource itself.

A metadata object does not contain any additional fields in relation to its full object representation, only some fields are left off. The left off fields are fields which could be requested by an own API call and may consist of a recursive or potentially large substructure. The serialization of a metadata object is the same as for the original full object, but without the left off fields.

For elements in the metamodel that are not listed in the table no "Metadata"-serialization is available.

Table 2. Metadata Attributes
Class Name Fields not available in metadata representation

Identifiables

AssetAdministrationShell

assetInformation, submodels

Submodel

submodelElements

SubmodelElements

SubmodelElementCollection

value

SubmodelElementList

value

Entity

statements, globalAssetId, specificAssetId

BasicEventElement

observed

Capability

 — 

Operation

 — 

DataElements

Property

value, valueId

MultilanguageProperty

value, valueId

Range

min, max

ReferenceElement

value

RelationshipElement

first, second

AnnotatedRelationshipElement

first, second, annotations

Blob

value, contentType

File

value, contentType

Example

The example shows a JSON serialization of an AssetAdministrationShell object in its full representation and how it looks like in a metadata representation.

Note: for editorial reasons, some fields which are the same for both representations are omitted.

Table 3. AssetAdministrationShell JSON Serialization Example
{
    "idShort": "TestAssetAdministrationShell",
    "description": [...],
    "id": {...},
     ...
    "derivedFrom": {...}
    "assetInformation": {...},
    "submodels": [...]
}
Table 4. AssetAdministrationShell Metadata JSON Serialization Example
{
  "idShort": "TestAssetAdministrationShell",
  "description": [...],
  "id": {...},
  ...
  "derivedFrom": {...}
}

Format "Value" (Value-Only Serialization) in JSON

Overview of Value-Only Serialization Attributes

In many cases, applications using data from Asset Administration Shells already know the Submodel regarding its structure, attributes, and semantics. Consequently, there is not always a need to receive the entire model information, which can be requested separately via Content modifier set to Metadata, in each request since it is constant most of the time. Instead, applications are most likely only interested in the values of the modelled data. Furthermore, having limited processing power or limited bandwidth, one use case of this format is to transfer data as efficiently as possible. Semantics and data might be split into two separate architecture building blocks. For example, a database would suit the needs for querying semantics, while a device would only provide the data at runtime. Two separate requests make it possible to build up a user interface (UI) and show new upcoming values highly efficiently.

Values are only available for

Capabilities are excluded from the serialization scope since only data containing elements are in the focus. They are consequently omitted in the serialization.

The following rules shall be adhered to when serializing a submodel, a submodel collection or a submodel element list with the format "Value"[2]:

  • A submodel or a submodel element collection is serialized as an unnamed JSON object.

  • A submodel element list is serialized as an JSON array.

  • A submodel element is considered a leaf submodel element if it does not contain other submodel elements. A leaf submodel element follows the rules for the different submodel elements considered in the serialization, as described below. If it is not a leaf element, the serialization rules must be transitively followed until the value is a leaf submodel element.

  • For each submodel element within the submodel, the submodel collection or submodel list:

    • Property is serialized as ${Property/idShort}: ${Property/value} where ${Property/value} is the JSON serialization of the respective property’s value in accordance with the data type to value mapping (see table after this section).

    • MultiLanguageProperty is serialized as named JSON object with ${MultiLanguageProperty/idShort} as the name of the containing JSON property. The JSON object contains an array of JSON objects for each language of the MultiLanguageProperty with the language as name and the corresponding localized string as value of the respective JSON property. The language name is defined as two chars according to ISO 639-1.

    • Range is serialized as named JSON object with $\{Range/idShort} as the name of the containing JSON property. The JSON object contains two JSON properties. The first is named "min". The second is named "max". Their corresponding values are $\{Range/min} and $\{Range/max}.

    • File and Blob are serialized as named JSON objects with $\{File/idShort} or $\{Blob/idShort}as the name of the containing JSON property. The JSON object contains two JSON properties. The first refers to the content type named $\{File/contentType} resp. $\{Blob/contentType}. The latter refers to the value named "value" $\{File/value} resp. $\{Blob/value}. The resulting ValueOnly object is indistinguishable whether it contains File or Blob attributes. Therefore, the receiver needs to take the type of the target resource into account. Since the receiver knows in advance if a File or a Blob SubmodelElement shall be manipulated, it can parse the transferred Value-Only object accordingly as a File or Blob object. For Blobs the value attribute is optional (in this case a Blob can be distinguished from a File).

    • SubmodelElementCollection is serialized as named JSON object with $\{SubmodelElementCollection/idShort} as the name of the containing JSON property. The elements contained within the struct are serialized according to their respective type with $\{SubmodelElement/idShort} as the name of the containing JSON property.

    • SubmodelElementList is serialized as a named JSON array with $\{SubmodelElementList/idShort} as the name of the containing JSON property. The elements in the JSON array are the ValueOnly serializations of the elements contained in the SubmodelElementList while preserving the order, i.e. index n in the JSON array is the ValueOnly serialization of the element at index n of the SubmodelElementList.

    • ReferenceElement is serialized as $\{ReferenceElement/idShort}: $\{ReferenceElement/value} where $\{ReferenceElement/value} is the serialization of the Reference class in format "Normal".

    • RelationshipElement is serialized as named JSON object with $\{RelationshipElement/idShort} as the name of the containing JSON property. The JSON object contains two JSON properties. The first is named "first". The second is named "second". Their corresponding values are $\{RelationshipElement/first} resp. $\{Relationship/second}. The values are serialized according to the serialization of a ReferenceElement (see above).

    • AnnotatedRelationshipElement is serialized according to the serialization of a RelationshipElement (see above). Additionally, a third named JSON object is introduced with "annotations" as the name of the containing JSON property. The value is $\{AnnotatedRelationshipElement/annotations}. The values of the array items are serialized depending on the type of the annotation data element. Annotations are optional.

    • Entity is serialized as named JSON object with $\{Entity/idShort} as the name of the containing JSON property. The JSON object contains four JSON properties. The first is named "statements" $\{Entity/statements} and contains an array of the serialized submodel elements according to their respective serialization mentioned in this clause. The second is named "globalAssetId" and the third "specificAssetIds". Either a "globalAssetId" value or a "specificAssetIds" value shall exist. The other attributes are optional. "globalAssetId" corresponds to a Reference (see above). "SpecificAssetIds" is an array of objects serializing SpecificAssetId. A single SpecificAssetId in the array corresponds to the serialization of the SpecificAssetId class in format "Normal". The forth property is named "entityType" and contains a string representation of $\{Entity/entityType}. Statements and the entityType are optional.

    • BasicEventElement is serialized as named JSON object with $\{BasicEventElement/idShort} as the name of the containing JSON property. The JSON object contains one JSON property named "observed" with the corresponding value of $\{BasicEventElement/observed} as the standard serialization of the Reference class.

The following rules shall be adhered to when serializing a single submodel element with the format "Value":

  • Property is serialized as ${Property/value} where ${Property/value} is serialized as described above.

  • MultiLanguageProperty is serialized as JSON object. The JSON object is serialized as described above.

  • Range is serialized as JSON object. The JSON object is serialized as described above.

  • File and Blob are serialized as JSON objects. The JSON object is serialized as described above.

  • ReferenceElement is serialized as ${ReferenceElement/value} where ${ReferenceElement/value} is is serialized as described above.

  • RelationshipElement is serialized as JSON object. The JSON object is serialized as described above.

  • AnnotatedRelationshipElement is serialized as JSON object. The JSON object is serialized as described above.

  • Entity is serialized as JSON object. The JSON object is serialized as described above.

  • BasicEventElement is serialized as JSON object. The JSON object is serialized as described above.

Submodel elements defined in the submodel other than the ones mentioned above are not subject to the Value-Only serialization.

Optional elements (like for example globalAssetId for an Entity submodel element) with no value shall be omitted in the serialization.

Data type to value mapping

The serialization of submodel element values is described in the following table. The left column "Data Type" shows the data types which can be used for submodel element values. The data types are defined according to the W3C XML Schema (https://www.w3.org/TR/xmlschema-2/#built-in-datatypes and https://www.w3.org/TR/xmlschema-2/#built-in-derived). "Value Range" further explains the possible range of data values for this data type. The right column comprises related examples of the serialization of submodel element values.

Table 5. Mapping of Data Types in ValueOnly-Serialization[3]
Data Type JSON Type Value Range Sample Values

Core Types

xs:string

string

Character string

"Hello world", "Καλημέρα κόσμε", "コンニチハ"

xs:boolean

boolean

true, false

true, false

xs:decimal

number

Arbitrary-precision decimal numbers

-1.23, 126789672374892739424.543233, 100000.00, 210

xs:integer

number

Arbitrary-size integer numbers

-1, 0, 126789675432332938792837429837429837429, 100000

IEEE-floating-point numbers

xs:double

number

64-bit floating point numbers

-1.0, -0.0, 0.0, 234.567e8, 234.567e+8, 234.567e-8

xs:float

number

32-bit floating point numbers

-1.0, -0.0, 0.0, 234.567e8, 234.567e+8, 234.567e-8

Time and data

xs:date

string

Dates (yyyy-mm-dd) with or without time zone

"2000-01-01","2000-01-01Z", "2000-01-01+12:05"

xs:time

string

Times (hh:mm:ss.sss…​) with or without time zone

"14:23:00", "14:23:00.527634Z", "14:23:00+03:00"

xs:dateTime

string

Date and time with or without time zone

"2000-01-01T14:23:00", "2000-01-01T14:23:00.66372+14:00"

xs:dateTimeStamp

string

Date and time with required time zone

"2000-01-01T14:23:00.66372+14:00"

Recurring and partial dates

xs:gYear

string

Gregorian calendar year

"2000", "2000+03:00"

xs:gMonth

string

Gregorian calendar month

"--04", "--04+03:00"

xs:gDay

string

Gregorian calendar day of the month

"---04", "---04+03:00"

xs:gYearMonth

string

Gregorian calendar year and month

"2000-01", "2000-01+03:00"

xs:gMonthDay

string

Gregorian calendar month and day

"--01-01", "--01-01+03:00"

xs:duration

string

Duration of time

"P30D", "-P1Y2M3DT1H", "PT1H5M0S"

xs:yearMonthDuration

string

Duration of time (months and years only)

"P10M", 'P5Y2M"

xs:dayTimeDuration

string

Duration of time (days, hours, minutes, seconds only)

"P30D", 'P1DT5H", 'PT1H5M0S"

Limited-range integer numbers

xs:byte

number

-128…+127 (8 bit)

-1, 0, 127

xs:short

number

-32768…+32767 (16 bit)

-1, 0, 32767

xs:int

number

2147483648…+2147483647 (32 bit)

-1, 0, 2147483647

xs:long

number

-9223372036854775808…+9223372036854775807 (64 bit)

-1, 0, 9223372036854775807

xs:unsignedByte

number

0…255 (8 bit)

0, 1, 255

xs:unsignedShort

number

0…65535 (16 bit)

0, 1, 65535

xs:unsignedInt

number

0…4294967295 (32 bit)

0, 1, 4294967295

xs:unsignedLong

number

0…18446744073709551615 (64 bit)

0, 1, 18446744073709551615

xs:positiveInteger

number

Integer numbers >0

1, 7345683746578364857368475638745

xs:nonNegativeInteger

number

Integer numbers ≥0

0, 1, 7345683746578364857368475638745

xs:negativeInteger

number

Integer numbers <0

-1, -23487263847628376482736487263847

xs:nonPositiveInteger

number

Integer numbers ≤0

-1, 0, -93845837498573987498798987394

Encoded binary data

xs:hexBinary

string

Hex-encoded binary data

"6b756d6f77617368657265"

xs:base64Binary

string

base64-encoded binary data

"a3Vtb3dhc2hlcmU="

Miscellaneous types

xs:anyURI

string

Absolute or relative URIs and IRIs

"http://customer.com/demo/aas/1/1/1234859590", "urn:example:company:1.0.0"

rdf:langString

string

Strings with language tags

"'Hello'@en", "'Hallo'@de"

Note: the examples are written in RDF/Turtle syntax, and only "Hello" and "Hallo" are the actual values.

The following types defined by the XSD and RDF specifications are explicitly omitted for serialization - they are not element of DataTypeDefXsd or DataTypeDefRdf:

xs:language, xs:normalizedString, xs:token, xs:NMTOKEN, xs:Name, xs:NCName, xs:QName, xs:ENTITY, xs:ID, xs:IDREF, xs:NOTATION, xs:IDREFS, xs:ENTITIES, xs:NMTOKENS, rdf:HTML and rdf:XMLLiteral.

Note 1: due to the limits in the representation of numbers in JSON, the maximum integer number that can be used without losing precision is 253-1 (defined as Number.MAX_SAFE_INTEGER). Even if the used data type would allow higher or lower values, they cannot be used if they cannot be represented in JSON. Affected data types are unbounded numeric types xs:decimal, xs:integer, xs:positiveInteger, xs:nonNegativeInteger, xs:negativeInteger, xs:nonPositiveInteger and the bounded type xs:unsignedLong. Other numeric types are not affected. [4]

Note 2: the ValueOnly-serialization uses JSON native data types, AAS in general uses XML Schema Built-in Datatypes for Simple Data Types and ValueDataType. In case of booleans, JSON accepts only literals true and false, whereas xs:boolean also accepts 1 and 0, respectively. In case of double, JSON number is used in ValueOnly, but JSON number does not support INF/-INF (positive Infinity/negative), which is supported by xs:double. Furthermore, NaN (Not a Number) is also not supported.

Note 3: language-tagged strings (rdf:langString) containing single quotes (‘) or double quotes (") are not supported.

Note 4: Roundtrip conversion from "Normal" to "ValueOnly" format may not result in the original payload because "Normal" is using string whereas "ValueOnly" is using the JSON type closest to the xsd datatype (see Table 5).

Example Value-Only serialization for a Submodel

The following example shows the JSON Value-Only serialization for a Submodel with name "Example" and two direct SubmodelElements "ProductClassifications" and "MaxRotationSpeed". "ProductClassifications" is represented by a SubmodelElementList with SubmodelElementCollections as its elements. Each of the SubmodelCollections has two mandatory elements "ProductClassificationSystem" and "ProductClassId" and one optional element "ProductClassificationVersion". All of these elements have data type "xs:string". "MaxRotationSpeed" is a property with data type "xs:int".

{ "ProductClassifications":
   [
    {
	"ProductClassificationSystem": "ECLASS",
	"ProductClassId": "27-01-88-77",
	"ProductClassificationVersion": "9.0"
    },
    {
	"ProductClassificationSystem": "IEC CDD",
	"ProductClassId": "0112/2///61987#ABA827#003"
    }
   ],
  "MaxRotationSpeed": 5000
}

The JSON Value-Only serialization for the element "ProductClassifications", a SubmodelElementList, within the submodel above looks like this:

   [
    {
	"ProductClassificationSystem": "ECLASS",
	"ProductClassId": "27-01-88-77",
	"ProductClassificationVersion": "9.0"
    },
    {
	"ProductClassificationSystem": "IEC CDD",
	"ProductClassId": "0112/2///61987#ABA827#003"
    }
   ]

The JSON Value-Only serialization for the first element, a SubmodelElementCollection, within the "ProductClassifications" list above looks like this:

{
	"ProductClassificationSystem": "ECLASS",
	"ProductClassId": "27-01-88-77",
	"ProductClassificationVersion": "9.0"
}

The JSON Value-Only serialization for the Property "MaxRotationSpeed" of the submodel above looks like this:

5000

The Format "Normal" in comparison to this Value-Only serialization of the property "MaxRotationSpeed" would look like this:

{
  "idShort": "MaxRotationSpeed",
  "semanticId": {
    "type": "ExternalReference",
    "keys": [
      {
        "type": "GlobalReference",
        "value": "0173-1#02-BAA120#008"
      }
    ]
  },
  "modelType": "Property",
  "valueType": "xs:int",
  "value": "5000"
}

Examples Value-Only serialization for all submodel element types

In the following examples for Value-Only serializations for all submodel element types are given.

For a single Property named "MaxRotationSpeed", the value-Only payload is minimized to the following (assuming its value is 5000):

  5000

For a SubmodelElementCollection named "ProductClassification" or being part of a list "ProductionClassifications", the Value-Only payload is minimized to the following, i.e. the name of the SubmodelElementCollection or its index in the list is not part of the Value-Only serialization:

{
	"ProductClassificationSystem": "ECLASS",
	"ProductClassId": "27-01-88-77",
	"ProductClassificationVersion": "9.0"
}

For a SubmodelElementList named "Authors" with string Properties as its value, the Value-Only payload is minimized to the following (values within a SubmodelElementList do not have idShort values)[5]:

[
    "Martha",
    "Jonathan",
    "Clark"
]

For a MultiLanguageProperty the Value-Only payload is minimized to the following:

[
    {"de": "Das ist ein deutscher Bezeichner"},
    {"en": "That's an English label"}
]

For a Range named "TorqueRange", the Value-Only payload is minimized to the following:

{
    "min": 3,
    "max": 15
}

For a ReferenceElement named "MaxRotationSpeedReference", the Value-Only payload is minimized to the following:

{
    "type": "ExternalReference",
    "keys": [
      {
        "type": "GlobalReference",
        "value": "0173-1#02-BAA120#008"
      }
    ]
}

For a File named "Document", the Value-Only payload is minimized to the following:

{
    "contentType": "application/pdf",
    "value": "SafetyInstructions.pdf"
}

For a Blob named "Library", there are two possibilities for the Value-Only payload. In case the Blob value - that can be very large - shall not be part of the payload, the payload is minimized to the following[6]:

{
    "contentType": "application/octet-stream"
}

In the second case the Blob value is part of the payload.[7], there is an additional attribute containing the base64-encoded value:

{
    "contentType": "application/octet-stream",
    "value": "VGhpcyBpcyBteSBibG9i"
}

For a RelationshipElement named "CurrentFlowsFrom", the Value-Only payload is minimized to the following:

{
    "first": {
      "type": "ModelReference",
      "keys": [
        {
          "type": "Submodel",
          "value": "http://customer.com/demo/aas/1/1/1234859590"
        },
        {
          "type": "Property",
          "value": "PlusPole"
        }
      ]
    },
    "second": {
      "type": "ModelReference",
      "keys": [
        {
          "type": "Submodel",
          "value": "http://customer.com/demo/aas/1/0/1234859123490"
        },
        {
          "type": "Property",
          "value": "MinusPole"
        }
      ]
    }
}

For an AnnotatedRelationshipElement named "CurrentFlowFrom", with an annotated Property-DataElement "AppliedRule", the Value-Only-payload is minimized to the following:

{
    "first": {
      "type": "ModelReference",
      "keys": [
        {
          "type": "Submodel",
          "value": "http://customer.com/demo/aas/1/1/1234859590"
        },
        {
          "type": "Property",
          "value": "PlusPole"
        }
      ]
    },
    "second": {
      "type": "ModelReference",
      "keys": [
        {
          "type": "Submodel",
          "value": "http://customer.com/demo/aas/1/0/1234859123490"
        },
        {
          "type": "Property",
          "value": "MinusPole"
        }
      ]
    },
    "annotations": [
      {
        "AppliedRule": "TechnicalCurrentFlowDirection"
      }
    ]
}

For an Entity named "MySubAssetEntity", the Value-Only-payload is minimized to the following:

{
    "statements": {
      "MaxRotationSpeed": 5000
    },
    "entityType": "SelfManagedEntity",
    "globalAssetId": {
      "type": "ExternalReference",
      "keys": [
        {
          "type": "GlobalReference",
          "value": "http://customer.com/demo/asset/1/1/MySubAsset"
        }
      ]
    }
}

For a BasicEventElement named "MyBasicEvent", the Value-Only-payload is minimized to the following:

{
    "observed": {
      "type": "ModelReference",
      "keys": [
        {
          "type": "Submodel",
          "value": "http://customer.com/demo/aas/1/1/1234859590"
        },
        {
          "type": "Property",
          "value": "MaxRotation"
        }
      ]
    }
}

JSON-Schema for the Value-Only Serialization

The following JSON-Schema represents the validation schema for the ValueOnly-Serialization of submodel elements. This holds true for all submodel elements mentioned in the previous clause except for SubmodelElementCollections. Since SubmodelElementCollections are treated as objects containing submodel elements of any kind, the integration into the same validation schema would result in a circular reference or ambiguous results ignoring the actual validation of submodel elements other than SubmodelElementCollections. Hence, the same validation schema must be applied for each SubmodelElementCollection within a submodel element hierarchy. In this case, it may be necessary to create a specific JSON-Schema for the individual use case. The SubmodelElementCollection is added to the following schema for completeness and clarity. It is, however, not referenced from the SubmodelElementValue-oneOf-Enumeration due to the reasons mentioned above.

See Annex ValueOnly-Serialization Example for an example that validates against this schema

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "title": "ValueOnly-Serialization-Schema",
  "$id": "https://admin-shell.io/schema/valueonly/json/V3.0",
  "definitions": {
    "AnnotatedRelationshipElementValue": {
      "type": "object",
      "properties": {
        "first": {
          "$ref": "#/definitions/ReferenceValue"
        },
        "second": {
          "$ref": "#/definitions/ReferenceValue"
        },
        "annotations": {
          "$ref": "#/definitions/ValueOnly"
        }
      },
      "required": [
        "first",
        "second"
      ],
      "additionalProperties": false
    },
    "BasicEventElementValue": {
      "type": "object",
      "properties": {
        "observed": {
          "$ref": "#/definitions/ReferenceValue"
        }
      },
      "required": [
        "observed"
      ],
      "additionalProperties": false
    },
    "BlobValue": {
      "type": "object",
      "properties": {
        "contentType": {
          "type": "string",
          "minLength": "1",
          "maxLength": "100"
        },
        "value": {
          "type": "string",
          "minLength": 1
        }
      },
      "required": [
        "contentType"
      ],
      "additionalProperties": false
    },
    "BooleanValue": {
      "type": "boolean",
      "additionalProperties": false
    },
    "EntityValue": {
      "type": "object",
      "properties": {
        "statements": {
          "$ref": "#/definitions/ValueOnly"
        },
        "entityType": {
          "enum": [
            "SelfManagedEntity",
            "CoManagedEntity"
          ]
        },
        "globalAssetId": {
          "type": "string"
        },
        "specificAssetIds": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/SpecificAssetIdValue"
          }
        }
      },
      "required": [
        "entityType"
      ],
      "additionalProperties": false
    },
    "FileValue": {
      "type": "object",
      "properties": {
        "contentType": {
          "type": "string",
          "minLength": "1",
          "maxLength": "100"
        },
        "value": {
          "type": "string",
          "minLength": "1",
          "maxLength": "2000"
        }
      },
      "required": [
        "contentType"
      ],
      "additionalProperties": false
    },
    "Identifier": {
      "type": "string"
    },
    "Key": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string"
        },
        "value": {
          "type": "string"
        }
      },
      "required": [
        "type",
        "value"
      ],
      "additionalProperties": false
    },
    "LangString": {
      "type": "object",
      "patternProperties": {
        "^[a-z]{2,4}(-[A-Z][a-z]{3})?(-([A-Z]{2}|[0-9]{3}))?$": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "MultiLanguagePropertyValue": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/LangString"
      },
      "additionalProperties": false
    },
    "NumberValue": {
      "type": "number",
      "additionalProperties": false
    },
    "OperationRequestValueOnly": {
      "inoutputArguments": {
        "$ref": "#/definitions/ValueOnly"
      },
      "inputArguments": {
        "$ref": "#/definitions/ValueOnly"
      },
      "timestamp": {
        "type": "string",
        "pattern": "^-?(([1-9][0-9][0-9][0-9]+)|(0[0-9][0-9][0-9]))-((0[1-9])|(1[0-2]))-((0[1-9])|([12][0-9])|(3[01]))T(((([01][0-9])|(2[0-3])):[0-5][0-9]:([0-5][0-9])(\\.[0-9]+)?)|24:00:00(\\.0+)?)(Z|\\+00:00|-00:00)$"
      },
      "additionalProperties": false
    },
    "OperationResultValueOnly": {
      "executionState": {
        "type": "string",
        "enum": ["Initiated", "Running", "Completed", "Canceled",
                 "Failed", "Timeout"]
      },
      "inoutputArguments": {
        "$ref": "#/definitions/ValueOnly"
      },
      "outputArguments": {
        "$ref": "#/definitions/ValueOnly"
      },
      "additionalProperties": false
    },
    "PropertyValue": {
      "oneOf": [
        {
          "$ref": "#/definitions/StringValue"
        },
        {
          "$ref": "#/definitions/NumberValue"
        },
        {
          "$ref": "#/definitions/BooleanValue"
        }
      ]
    },
    "RangeValue": {
      "type": "object",
      "properties": {
        "min": {
          "$ref": "#/definitions/RangeValueType"
        },
        "max": {
          "$ref": "#/definitions/RangeValueType"
        }
      },
      "additionalProperties": false
    },
    "RangeValueType": {
      "oneOf": [
        {
          "$ref": "#/definitions/StringValue"
        },
        {
          "$ref": "#/definitions/NumberValue"
        },
        {
          "$ref": "#/definitions/BooleanValue"
        }
      ]
    },
    "ReferenceElementValue": {
      "$ref": "#/definitions/ReferenceValue"
    },
    "ReferenceValue": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": ["ModelReference", "ExternalReference"]
        },
        "keys": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Key"
          }
        }
      },
      "additionalProperties": false
    },
    "RelationshipElementValue": {
      "type": "object",
      "properties": {
        "first": {
          "$ref": "#/definitions/ReferenceValue"
        },
        "second": {
          "$ref": "#/definitions/ReferenceValue"
        }
      },
      "required": [
        "first",
        "second"
      ],
      "additionalProperties": false
    },
    "SpecificAssetIdValue": {
      "type": "object",
      "patternProperties": {
        "(.*?)": {
          "type": "string"
        }
      }
    },
    "StringValue": {
      "type": "string",
      "additionalProperties": false
    },
    "SubmodelElementCollectionValue": {
      "$ref": "#/definitions/ValueOnly"
    },
    "SubmodelElementListValue": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/SubmodelElementValue"
      }
    },
    "SubmodelElementValue": {
      "oneOf": [
        {
          "$ref": "#/definitions/BasicEventElementValue"
        },
        {
          "$ref": "#/definitions/RangeValue"
        },
        {
          "$ref": "#/definitions/MultiLanguagePropertyValue"
        },
        {
          "$ref": "#/definitions/FileBlobValue"
        },
        {
          "$ref": "#/definitions/ReferenceElementValue"
        },
        {
          "$ref": "#/definitions/RelationshipElementValue"
        },
        {
          "$ref": "#/definitions/AnnotatedRelationshipElementValue"
        },
        {
          "$ref": "#/definitions/EntityValue"
        },
        {
          "$ref": "#/definitions/PropertyValue"
        },
        {
          "$ref": "#/definitions/SubmodelElementListValue"
        }
      ]
    },
    "ValueOnly": {
      "propertyNames": {
        "pattern": "^[A-Za-z_][A-Za-z0-9_-]*$"
      },
      "patternProperties": {
        "^[A-Za-z_][A-Za-z0-9_-]*$": {
          "$ref": "#/definitions/SubmodelElementValue"
        }
      },
      "additionalProperties": false
    }
  }
}

Format "Path" (idShortPath Serialization) in JSON

To get only the idShortPaths of a submodel element hierarchy, the serialization format is specified in terms of an idShortPath notation to be returned in an JSON array. The notation differs depending on whether a SubmodelElementCollection or a SubmodelElementList is present. In the first case, the submodel element’s idShort is separated by "." (dot) from top level down to child level. In the second case, square brackets with an index "[<Index>]" are appended after the idShort of the containing SubmodelElementList. In any case, the first item of any idShortPath is the idShort of the requested element.

Grammar:

<idShortPath> ::= <idShort> {["." <idShort> | "["<Index>"]" ]}*

<Index> ::= <Zero> | <PositiveNumber>

<PositiveNumber>  ::= <NonZeroDigit>{<Digit>}*
<Digit> ::= <Zero> | <NonZeroDigit>
<Zero>  ::= "0"
<NonZeroDigit>  ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

In the following example, where a request for idShortPaths targets a MySubmodelElementCollection with SerializationModifier level = deep, the list of idShortPaths is returned as follows:

EXAMPLE Submodel

Submodel: MySubmodel

  • Property: MyTopLevelProperty

  • SMC: MySubmodelElementCollection

    • Property: MySubProperty1

    • Property: MySubProperty2

    • SMC: MySubSubmodelElementCollection

      • Property: MySubSubProperty1

      • Property: MySubSubProperty2

    • SML: MySubSubmodelElementList1

      • Property: "MySubTestValue1"

      • Property: "MySubTestValue2"

    • SML: MySubSubmodelElementList2

      • SML: MySubSubmodelElementList3

        • Property: "MySubTestValue3"

idShortPaths for SMC MySubmodelElementCollection within the Submodel above:

[
  "MySubmodelElementCollection",
  "MySubmodelElementCollection.MySubProperty1",
  "MySubmodelElementCollection.MySubProperty2",
  "MySubmodelElementCollection.MySubmodelElementCollection",
  "MySubmodelElementCollection.MySubmodelElementCollection.MySubProperty1",
  "MySubmodelElementCollection.MySubmodelElementCollection.MySubProperty2",
  "MySubmodelElementCollection.MySubSubmodelElementList1",
  "MySubmodelElementCollection.MySubSubmodelElementList1[0]",
  "MySubmodelElementCollection.MySubSubmodelElementList1[1]",
  "MySubmodelElementCollection.MySubSubmodelElementList2",
  "MySubmodelElementCollection.MySubSubmodelElementList2[0]",
  "MySubmodelElementCollection.MySubSubmodelElementList2[0][0]"
]

Note: There is no idShortPath for Identifiables because idShort is optional for Identifiables.

Format "Reference"

In some use cases only the (model) reference to the object is needed in the first place.

References are possible for Referables, only. Potential child elements are ignored.

For references see Clause Referencing in Asset Administration Shells.

Format "Reference" - Example in JSON
      {
        "keys": [
          {
            "type": "AssetAdministrationShell",
            "value": "urn:an-example08:f3f73640"
          }
        ],
        "type": "ModelReference"
      }

Format "Normal" in XML

The metamodel of an Asset Administration Shell needs to be serialized for import and export scenarios. XML is a possible serialization format.

eXtensible Markup Language (XML[8]) is very well suited to derive information from an IT system, e.g. to process it manually and then feed it into another IT system. XML provides the possibilities of scheme definitions, which can be used to syntactically validate the represented information in each step.

While there are many possibilities to represent a model of an Asset Administration Shell in XML, we provide our "official" XML schema definition (XSD) to foment interoperability between different tools and systems.

Below we explain in more detail how our schema is constructed, point the user to the examples and finally give some background information on our particular schema design.

Note 1: the xml schema (.xsd files) is maintained in the repository "aas-specs" of the GitHub project admin-shell-io [51] in folder schemas\xml

Note 2: example files can be found in the repository "aas-specs" in the GitHub project admin-shell-io [51] in folder : schemas\xml\examples

Top-Level Structure

The root element of our XML is an XML element representing the instance of Environment. This environment contains three aggregations, corresponding to all Identifiable classes:

To simplify exploration of the XML data, identifiable instances are only available at the level of the environment, and nowhere else.

We now continue to see how to serialize the instances and their properties.

Mapping Rules

Building blocks of an XML document include only XML elements, XML attributes and text enclosed in an element. XML elements can nest children elements. Using these building blocks, we map an AAS model to XML.

UML Property to XML Element

Before we look into how to represent instances of classes, let us start bottom-up and see first how individual properties are represented.

We represent each property of a class with an XML element whose name corresponds to the property in the metamodel. The name is given in camel-case where all abbreviations are left as capitalized (dataSpecificationIec61360 instead of dataSpecificationIEC61360).

It is common in UML to use singular form for aggregations, which is the case for the metamodel. This is, however, in contrast to programming code, where plural form for sequences is common. Since the naming of XML elements has direct influence on the programming code, we name the properties in plural form diverging from the name in the metamodel. For example, submodelElements instead of submodelElement in case of Submodel/submodelElement property in the metamodel.

In cases where plural form made no sense for a property, we kept it as-is in singular form (e.g., isCaseOf). The full list of exceptions is available as code in aas-core-meta.

Why no XML attributes?

While some metamodel properties are indeed very apt to be succinctly represented as XML attributes, we decided not to use XML attributes at all for three reasons.

First, the XML attribute must be a string, and therefore does not allow for structured data to be represented with it. As the metamodel evolves, we need to be able to gracefully evolve the schema with as little breakages as possible. An XML attribute puts a limit in so far that an attribute can only be represented as string. Moreover, as the schema evolves, making diff’s is important to trace the changes. This is much harder when the attributes switch from an XML attribute to an XML element.

Second, many classes contain a mix of primitive properties and structured properties. If we allowed XML attributes, the former would be represented as XML attributes, while the latter would be represented as XML elements. This leads to confusion where the writer is forced to go back and forth in the specification, and always double-check whether a property should be represented as an XML attribute or an XML element.

Third, we automatically generate the schema from a machine-readable metamodel representation (see Section Background below). The mix of XML attributes and elements would have complicated the code and prolonged the development.

We finally decided that the drawbacks outlined above outweighed the advantage in form of succinct representation.

Optional Properties

If a property has cardinality 0..1 or 0..* and is not specified in the instance, the element is simply omitted.

Properties of Simple Data Types

The property values given in the metamodel as simple data types (see Section Primitive Data Types) are serialized as text enclosed in the XML element corresponding to the property. Please see Section Why no XML attributes? on why we do not serialize them as XML attributes.

The byte arrays (BlobType in metamodel) are serialized as Base64-encoded text.

Simple type rdf:langString is serialized as if it were a proper metamodel class with properties language and text. See the following Section Instances of Classes as Property Values about how to serialize instances of classes in general as that section directly applies to rdf:langString.

Instances of Classes as Property Values

To serialize instances of metamodel classes as values of properties, we need to nest them somehow within the XML element corresponding to the property. This is not as trivial as it seems.

If the property type is a concrete or abstract class with descendants, the deserializer needs to know the exact concrete class at the time of de-serialization. However, this information is obviously missing in the metamodel. For example, the property Submodel/submodelElement tells the deserializer that its items are instances of SubmodelElement, but the deserializer does not know which concrete deserialization method to apply to understand the nested XML data: is it Property , Range or some other descendant of SubmodelElement?

Therefore, the information about the concrete type of the serialized instance must be encoded somehow in XML when the type in the metamodel is too vague. This nugget of information is usually called a discriminator (e.g., see OpenAPI 3 specification on polymorphism).

On the other hand, when the metamodel mandates the type of property as a concrete class without descendants, the deserializer needs no additional information as the deserialization method is given by the metamodel. There is thus no need to include the discriminator in the serialization, and a redundant discriminator would only clutter the XML document.

We therefore distinguish two serializations of instances: one with discriminator, and one without, respectively.

Instances Serialized with Discriminator

We use the XML element named according to the concrete class at the serialization as the discriminator. The properties of the instance are nested below this discriminator XML element.

Let us make an example. The example will be agnostic of the particular metamodel version, so that it can age well across different versions. We fantasize a metamodel class SomeAbstractClass and assume it has two descendant classes, SomeConcreteClass and AnotherConcreteClass. Let us assume yet another class, YetAnotherClass, entails the property someProperty of type SomeAbstractClass.

Here is how the XML structure corresponding to YetAnotherClass/someProperty would look like in this fantasized case, where the value is an instance of SomeConcreteClass:

<someProperty>
    <SomeConcreteClass>
        <!--
            Serialized properties of SomeConcreteClass
        -->
    </SomeConcreteClass>
</someProperty>

If the value is an instance of AnotherConcreteClass, the serialization becomes:

<someProperty>
    <AnotherConcreteClass>
        <!--
            Serialized properties of AnotherConcreteClass
        -->
    </AnotherConcreteClass>
</someProperty>

The abstract class, SomeAbstractClass, does not show up in the serialization at all, as it is redundant information.

While this approach is succinct in terms of additional XML elements, but it comes with a caveat. Namely, if we introduce descendants to AnotherConcreteClass, the property someProperty becomes polymorph, and we need to introduce backwards-incompatible schema changes to allow for the [discriminator].

Instances Serialized without Discriminator

If the concrete type of the property at deserialization is unambiguous by the metamodel, we omit the discriminator to reduce the clutter. The instance is simply serialized as a sequence of XML elements corresponding to its properties.

Let us fantasize yet another example, similar to the one in Section Instances of Classes as Property Values. We will again draw an example such that it is agnostic of metamodel version for better evolution of this document. Assume a class SomeClass with a property SomeClass/someProperty. Now imagine the type of someProperty to be the class AnotherClass. The class AnotherClass has properties AnotherClass/anotherProperty and AnotherClass/yetAnotherProperty. The class AnotherClass has no descendants, so the concrete type of SomeClass/someProperty is unambiguous.

Here is how the XML structure would look like:

<someProperty>
    <anotherProperty>
        <!-- ... -->
    </anotherProperty>
    <yetAnotherProperty>
        <!-- ... -->
    </yetAnotherProperty>
</someProperty>

The type information about AnotherClass is omitted, as the type of the SomeClass/someProperty is fixed in the metamodel.

Properties as Aggregations

Many properties in the metamodel do not represent a single value (be it primitive or structured as a class), but aggregate instances of metamodel classes. For example, Submodel/submodelElement aggregates instances of SubmodelElement’s.

If we just concatenated all the properties of the instances, we would not know which property belongs to which instance (or such distinction would be complicated). We need a delimiter!

Following the approach described in Section Instances Serialized with Discriminator, we delimit the instances simply by nesting them beneath the discriminator elements. If the type of the list items is a concrete class, we nest beneath the discriminator element regardless.

For example, here is an XML snippet of an example submodel elements, where the first element is a Property, the second one is a Range and the third is a Property:

<submodel>
    <submodelElements>
        <!-- First element -->
        <property>
            <!-- ... some properties ... -->
        </property>

        <!-- Second element -->
        <range>
            <!-- ... another properties ... -->
        </range>

        <!-- Third element -->
        <property>
            <!-- ... yet another properties ... -->
        </property>
    </submodelElements>
</submodel>

We explicitly forbid empty lists in XML to avoid confusion about properties of cardinality 0..*. Namely, an empty list is semantically equal to an omitted property (according to the metamodel). Thus, the XML element representing an aggregation must be omitted if the aggregation is empty.

The following snippet is therefore invalid:

<submodel>
    <submodelElements/>
    <!-- other properties -->
</submodel>

… and should be written as:

<submodel>
    <!-- other properties -->
</submodel>

Order of the Properties

We fixed the order of the properties to match the metamodel for readability.

This is reflected in usage of xs:sequence throughout the XML schema.

Enumerations

Enumerations are serialized according to the exact values of enumeration literals in the metamodel as text.

For example, the enumeration literal EntityType/CoManagedEntity is serialized as CoManagedEntity, while the literal Direction/input as input.

Embedded Data Specifications

There is an abstract definition of data specifications as templates in the metamodel (see Section Data Specification Templates). This definition does not specify, though, how to access them from within an Environment, which is a requirement for many systems. To address this practical issue, the metamodel indicates that they should be embedded in serializations (see Section Embedded Data Specifications).

We therefore add additional XML element, named embeddedDataSpecifications, in the XML representations of HasDataSpecification class, and omit dataSpecification property by design. The embedded data specifications are serialized just as all the other classes of the metamodel, following the procedure outlined above.

Namespace

The XML elements representing the AAS model are explicitly required to live in our namespace. The namespace corresponds to the version of the metamodel.

For example, the serialization for the metamodel V3.0RC02 lives in the namespace https://admin-shell.io/aas/3/0/RC02.

Structure of the Schema

XML schemas tend to grow very complex, very quickly. Our schema is no exception. While we described so far how an XML document looks like for a concrete AAS model, let us briefly give you an overview of the schema beneath it.

At this point, we only outline its structure in broad brushes. Please refer to the actual file schema/xml/AAS.xsd for more details.

For each class, we define a xs:group which lays out the order (as a nested xs:sequence) and type of the XML elements corresponding to the properties of the class. The inheritance is dealt by nesting an additional xs:group element within the sequence with the ref attribute.

The individual properties are defined with xs:element in the xs:sequence.

For example:

<xs:group
        name="administrativeInformation">
    <xs:sequence>
        <xs:group
                ref="hasDataSpecification"/>
        <xs:element
                name="version"
                minOccurs="0"
                maxOccurs="1">
            <xs:simpleType>
                <xs:restriction
                        base="xs:string">
                    <xs:minLength
                            value="1"/>
                </xs:restriction>
            </xs:simpleType>
        </xs:element>
        <!-- ... More elements come here ... -->
    </xs:sequence>
</xs:group>

For each class, we define a xs:complexType, name it with an _t prefix and refer the complex type to the corresponding group. The complex types are necessary so that we can use them to specify aggregations.

For example, here is the definition of submodel_t:

<xs:complexType
        name="submodel_t">
    <xs:sequence>
        <xs:group
                ref="submodel"/>
    </xs:sequence>
</xs:complexType>

Here it is used in the definition of the aggregation:

<xs:group
        name="environment">
    <!-- ... -->
    <xs:element
            name="submodels"
            minOccurs="0"
            maxOccurs="1">
        <xs:complexType>
            <xs:sequence>
                <xs:element
                        name="submodel"
                        type="submodel_t"
                        minOccurs="1"
                        maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <!-- ... -->
</xs:group>

If a class has one or more descendants, we define an xs:group with the _choice suffix. This is necessary so that we can enforce a closed set of concrete classes at the de/serialization. In particular, we want to ensure that the discriminator is given correctly (see Section Instances Serialized with Discriminator).

Here is an example of a choice:

<xs:group
        name="submodelElement_choice">
    <xs:choice>
        <!-- ... -->
        <xs:element
                name="property"
                type="property_t"/>
        <xs:element
                name="range"
                type="range_t"/>
        <!-- ... -->
    </xs:choice>
</xs:group>

Here the choice is enforced in another group:

<xs:group
        name="submodel">
    <xs:sequence>
        <!-- ... -->
        <xs:element
                name="submodelElements"
                minOccurs="0"
                maxOccurs="1">
            <xs:complexType>
                <xs:sequence>
                    <xs:group
                            ref="submodelElement_choice"
                            minOccurs="1"
                            maxOccurs="unbounded"/>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    </xs:sequence>
</xs:group>

Examples

Examples of the XML serializations can be found in schemas/xml/examples/ folder.

Background

Handwritten Schema

When we started with the project, the schema had been manually written. One or two schema designers would sit down, follow the book and translate it into XML schema by best effort. This allowed for a lot of artistic freedom, but eventually caused problems due to mismatches with other serializations or internal inconsistencies. Especially as the metamodel evolved, maintaining the schema and keeping it up-to-date with the metamodel proved to be difficult.

Generated Schema

While the handwritten schema is arguably elegant, the maintenance is too demanding. Therefore, we developed a schema generator based on the machine-readable representation of the metamodel. The generator is provided in aas-core-codegen project, while the metamodel lives in aas-core-meta.

This allowed us to evolve the XML schema more quickly while keeping it in sync with other serialization schemas and SDKs. However, we had to give up on elegant parts of the schema, and had to straightjacket the schema into form that can be programmatically generated. For example, all properties are serialized as XML elements, and we could not use XML attributes.

Format "Normal" in JSON

JSON[9] (JavaScript Object Notation) is a further serialization format that serializes the metamodel of an Asset Administration Shell for import and export scenarios.

Additionally, JSON format is used to describe the payload in the http/REST API for active Asset Administration Shells [37].

Since JSON is a very versatile format, there are many ways how we could map an AAS model to it. Below we explore our particular design of the serialization schema based on JSON schema 2019-09 , and explain in detail the rules how we mapped the AAS metamodel to it.

Note 1: the JSON schema (.json files) is maintained in the repository "aas-specs" of the GitHub project admin-shell-io [51] in folder schemas\json

Note 2: example files can be found in the repository "aas-specs" in the GitHub project admin-shell-io [51] in folder schemas\json\examples

Top-Level Structure

The root of our serialization is a JSON object representing the instance of Environment. This environment contains three aggregations, corresponding to all identifiable classes:

The JSON properties of the environment correspond to these three aggregations.

To simplify exploration of the JSON data, identifiable instances are only available at the level of the environment, and nowhere else.

Mapping Rules

Classes to JSON definitions

For each class of the AAS metamodel, we provide a definition in the JSON schema. The instances of the classes, abstract and concrete alike, are modeled as JSON objects.

UML properties to JSON properties

The class properties of the metamodel (attributes and aggregations) correspond directly to JSON properties.

Optional attributes, i.e., the attributes with the cardinality 0..1, are modeled as non-required properties.

Aggregations, i.e., the properties with the cardinality 0.., 1.. etc., are modeled as JSON arrays.

We explicitly forbid empty JSON arrays to avoid confusion about properties which have cardinality 0..*. Namely, an empty array is semantically equal to an omitted attribute (according to the metamodel). Thus, the JSON property representing an aggregation attribute must be omitted if the aggregation is empty.

In UML, it is the convention to name associations and aggregations in singular form. The cardinality is to be taken into account to decide on whether there are none, a single or several elements in the corresponding association or aggregation. In JSON, it is best practice to use plural form for array in class properties. The singular name is used for its discriminator (see section on discriminators). Typically, the plural name is derived by just adding an "s" to the name. For example, submodelElements instead of submodelElement in case of Submodel class.

If plural form made no sense for a property, we kept it as-is (e.g., isCaseOf). The full list of exceptions is available as code in aas-core-meta.

Primitive attribute values

The UML specification uses XSD types. For the mapping of XSD to JSON types please refer to Section Format "Value" (Value-Only Serialization) in JSON.

There are the following exceptions:

Property/value and Range/min and Range/max are mapped to a JSON string. The type it needs to be converted to by the data consumer is declared in Property/valueType or Range/valueType, resp.

Primitive type BlobType (group of `byte`s) is mapped to a JSON string with base64 encoding.

Note: in valueOnly Format value has the JSON type as declared in Property/valueType taking the mapping of XSD to JSON types into account.

Hint: Round-Trip Conversions

Round-trip conversions XML to JSON to XML or RDF to JSON to RDF may not result in the original file.

The result of a model saved as XML is different to the model saved as JSON. For example, if the user typed in 1 for a boolean UML attribute (e.g. for SubmodelElementList /orderRelevant) in the editor, saved the model as JSON and opened it again, she would suddenly see true instead of 1 (since the JSON library would silently convert 1 to a JSON boolean true).

Inheritance

The inheritance relationships between the classes are modeled using allOf composition. While JSON schema knows no inheritance, we enforce through allOf that all the properties of the parent are defined in the descendants.

Discriminator

Many attributes in the metamodel refer to an abstract class. When we de-serialize such attributes, we need to know the concrete class at runtime, since otherwise the de-serialization algorithm would not know how to interpret the properties of the object.

For example, consider the attribute Submodel which contains instances of SubmodelElement. When the de-serializer encounters the property submodelElements as an array and starts de-serializing its items, how can it know which constructor to call to parse the item? This necessary nugget of information is commonly called ``discriminator'' (e.g., see OpenAPI 3 specification on polymorphism).

We define the discriminator for our serialization as an additional property, modelType , which do not correspond to any attribute in the metamodel. Every class which has one or more descendants will have the discriminator modelType in its definition.

When a deserializer needs to de-serialize an instance of an abstract class, it can do so by dispatching the de-serialization to the appropriate de-serialization method based on modelType.

Enumerations

The enumerations of the metamodel are directly mapped to enumerated values in JSON schema. Each enumeration is defined separately, and we do not in-line enumerations for readability.

Enumerations which are not directly used in the schema are omitted. For example, subsets of KeyTypes are omitted since only KeyTypes is used to define value of an attribute.

Embedded Data Specifications

The metamodel defines data specifications in abstract (see Section Data Specification Templates). However, the metamodel omits data specifications in an Environment, and data specifications are intentionally non-identifiable.

For practical applications, we need to access them somehow. Therefore, the metamodel mandates to embed them in serializations (see Section Embedded Data Specifications).

We consequently embed the data specifications by adding embeddedDataSpecifications property to the definition corresponding to HasDataSpecification, and deliberately omit the attribute HasDataSpecification/dataSpecification in the schema.

Examples

Examples of the JSON serializations can be found in the GitHub Repository in the /schemas/json/examples folder.

Background

From Manual Transcription …

The serialization to and from JSON changed over the course of different versions of the metamodel. Originally, the schema had been manually designed, where a group of authors combed "the book" and manually transcribed it to JSON schema. This was obviously error-prone as it often caused mismatches between other serializations (e.g., XML and RDF), contained inconsistencies etc.

… to Automatic Generation

We eventually moved over to generate the serialization schemas based on a single-point-of-truth. The current source is aas-core-meta, a domain-specific Python representation of the metamodel. The schemas are generated using aas-core-codegen, a translating tool which transpiles aas-core-meta into different schemas and other targets such as SDKs.

While this approach reduced the rate of errors significantly, it also imposed certain limits on our schema design. For example, the classes and enumerations are now programmatically mapped to JSON definitions, allowing for no exceptions. Where we could in-line some of them for better readability, we are now forced to stick with the programmatic definitions.

Format "Normal" in RDF

The Resource Description Framework (RDF) [32] is the recommended standard of the W3C to unambiguously model and present semantic data. RDF documents are structured in the form of triples, consisting of subjects, relations, and objects. The resulting model is often interpreted as a graph, with the subject and object elements as the nodes and the relations as the graph edges.

RDF is closely related to web standards, illustrated by the fact that all elements are encoded using (HTTP-)IRIs. As a common practice, the provision of additional information at the referenced location of an RDF entity directly allows the interlinking of entities[10] based on the web. This process – following links in order to discover related information – is called dereferencing a resource and is supported by any browser or web client. Connecting distributed data sources through the web in the described manner is referred to by the term "Linked Data". Connecting the available resources and capabilities of linked data with the expressiveness of the Asset Administration Shell is one motivation for the RDF serialization.

In addition, RDF is the basis of a wide range of logical inference and reasoning techniques. Vocabularies like RDF Schema (RDFS) and the Web Ontology Language (OWL) combine the graph-based syntax of RDF with formal definitions and axioms. This allows automated reasoners to understand the relation between entities to some extent and draw conclusions.

Combining both features, the RDF mapping of the Asset Administration Shell can provide the basis for complex queries and requests. SPARQL, the standard query language for the Semantic Web, can combine reasoning features with the integration of external data sources. In order to benefit of these abilities, the Asset Administration Shell requires a clear scheme of its RDF representation. In the following, the necessary transformation rules are presented, followed by an illustration of relevant parts of the scheme and an example.

The complete data model (rdf-ontology.ttl) together with the schema (shacl-schema.ttl) are listed in this GitHub Repository in the /schemas/rdf folder.

Note 1: the RDF scheme/OWL files (.ttl files) are maintained in the repository "aas-specs" of the GitHub project admin-shell-io [51] in folder /schemas/rdf

Note 2: example files can be found n the repository "aas-specs" of the GitHub project admin-shell-io [51] in folder /schemas/rdf/examples

RDF Mapping Rules

The concepts of the RDF and the derived RDF serialization of the AAS are explained by the mapping rules. These rules are implemented by the generators used to create the ontology and shacl files based on the independent project aas-core-works. The main design rules the following:

  • The default serialization format is Turtle - also for the ontology and the shapes. However, several equivalent serializations exist for RDF. Among them, the Turtle syntax is regarded as the most appropriate compromise between readability and tool-support. Other formats (RDF/XML, JSON-LD, N3, etc.) can be used without any loss of information.

  • Shape Graphs represent the validation schema. The data model itself is an RDF ontology. As RDF itself is following the open-world-assumption, SHACL constraints are necessary in order to enable schema validation. Similarly to XSD for XML, the SHACL format can be used to describe constraints (called shapes) of RDF graphs.

  • Every entity is encoded as either an IRI or a Literal. RDF uses IRIs for both entities and relations. If no IRI is predefined, a globally unique IRI is generated. Primitive values are encoded as Typed Literals.

  • Entities are enhanced with well-known RDF attributes. Interoperability of concepts and attributes is the main advantage of the RDF mapping. Therefore, applying common attributes (rdf:type (similar to modelType discriminator in JSON), rdfs:label, and rdfs:comment) enables the usage of standard tools and interfaces.

  • Repeating elements are described once and then linked using their IRI identifier. If a distinct element appears more than one time in the original model but in a different context, for instance in more than one submodel, the RDF entity represents the combination of all attributes.

  • Multilanguage Strings are split into distinct language strings (rdf:langString). Objects are expected to contain a singular information entity, and the currently available tools would not recognize the AAS LangString pattern.

  • Multiple object values are represented by repeating the property, one for each value object.

  • Abstract AAS classes are modeled in the ontology, nevertheless, using them leads to validation errors in the shapes. RDF does not contain a concept for abstract classes, therefore custom checks using SPARQL queries are supplied.

Example Overview

RDF is often regarded as a graph model, as it provides the flexibility to interlink entities at any stage. In the following, the ./examples/Complete_Example.ttl[complete example] is originally provided in Turtle but accompanied with visualizations of the represented graph (see Figure 2): Attributes referencing non-literal values are shown as directed links while Literal values are drawn together with the corresponding entity itself. In order to increase readability, the namespace declaring sections are omitted. The complete example with all namespaces can be found in the example folder. One can see the additionally inserted triples for rdf:type, rdfs:label, and rdfs:comment as determined by Rule 4. The first attribute states the instance’ class. The second provides its commonly used name, for instance based on the idShort attribute. rdfs:comment supplies a short description about the regarded entity, based on the description value. The generally available tools, for instance the open source tool Protégé, render these attributes and display the correct class hierarchy, render the elements with their labels or supply short explanations based on the comments.

Simplified graph of the core classes in the example
Figure 2. Simplified graph of the core classes in the example

A comprehensive set of generated examples is also provided in the GitHub Repository, always containing a complete and a minimal version of each class. The files have been created using the aas-core3.0-testgen project to simplify the maintenance process and to stick directly to the efforts made at aas-core-meta.


1. The word "data formats" is used as shortcut and includes the use of conceptual advantages such as information models, schemes, transmission protocols, etc.
2. see SerializationModifier in Part 2 of the Specification of the Asset Administration Shell
4. cf. https://eclipse-esmf.github.io/samm-specification/2.0.0/payloads.html (with adjustments for +/-INF, NaN, and language-typed literal support)
5. The Value-Only serialization of the product classification example can be seen above
6. for the API a special JSON query parameter, the SerializationModifier Extent, is set to WithoutBLOBValue for this case
7. in this case the JSON query parameter SerializationModifier Extent is set to WithBlobValue
10. Note: entity as a generic term and entity as a specific submodel element subtype need to be distinguished.