The ModelParser
class is used to determine whether one or more DTDL models are valid, to identify specific modeling errors, and to enable inspection of model contents.
This tutorial walks through an aspect of the third use: how to inspect complex schema elements in the object model.
This tutorial specifically inspects standard complex schemas referenced by contents.
Two related tutorials inspect complex schemas embedded in contents and complex schemas referenced by contents.
To parse a DTDL model, you need to instantiate a ModelParser
.
No arguments are required.
var modelParser = new ModelParser();
The DTDL language is syntactically JSON.
The ModelParser
expects a single string or an enumeration of strings.
The single string or each value in the enumeration is JSON text of a DTDL model.
string jsonText =
@"{
""@context"": ""dtmi:dtdl:context;3"",
""@id"": ""dtmi:example:anInterface;1"",
""@type"": ""Interface"",
""contents"": [
{
""@type"": ""Telemetry"",
""name"": ""currentLocation"",
""schema"": ""point""
}
]
}";
The main synchronous method on the ModelParser
is Parse()
.
One argument is required, which can be either a string or an enumeration of strings containing the JSON text to parse as DTDL.
If the submitted model is complete and valid, no exception will be thrown.
Proper code should catch and process exceptions as shown in other tutorials such as this one, but for simplicity the present tutorial omits exception handling.
IReadOnlyDictionary<Dtmi, DTEntityInfo> objectModel = modelParser.Parse(jsonText);
The Interface element can be looked up in the object model by its identifier:
var anInterfaceId = new Dtmi("dtmi:example:anInterface;1");
var anInterface = (DTInterfaceInfo)objectModel[anInterfaceId];
The content value can be accessed by name via the Contents
property on DTInterfaceInfo
:
string currentLocationName = "currentLocation";
var currentLocation = (DTTelemetryInfo)anInterface.Contents[currentLocationName];
The JSON text above shows that the Telemetry "currentLocation" has the schema value "point".
This appears in a different form in the object model, where it can be accessed via the Schema
property on the Telemetry object:
Console.WriteLine($"currentLocation schema is {currentLocation.Schema.Id}");
This snippet displays:
currentLocation schema is dtmi:standard:schema:geospatial:point;3
If we care to, we can map this identifier back to the term used in the JSON text of the DTDL model by using the ModelParser.GetTermOrUri()
static method:
Console.WriteLine($"currentLocation schema term is {ModelParser.GetTermOrUri(currentLocation.Schema.Id)}");
This snippet displays:
currentLocation schema term is point
An element with identifier "dtmi:standard:schema:geospatial:point;3" is defined in the DTDL v2 language model as a standard element. Because it is referenced by an element in the submitted model, the 'point' element and all of its transitively referenced elements are included in the object model.
The DTDL type of each element is expressed via the property EntityKind
on the DTEntityInfo
base class, which has type enum DTEntityKind
.
We can use this property to determine the complex schema type.
We can access the complex schema element as currentLocation.Schema
; however, will illustrate accessing it by identifier:
var pointId = new Dtmi("dtmi:standard:schema:geospatial:point;3");
var point = objectModel[pointId];
Console.WriteLine($"point type is {point.EntityKind}");
This snippet displays:
point type is Object
This is the same output we would see from the following line:
Console.WriteLine($"point type is {currentLocation.Schema.EntityKind}");
Which displays:
point type is Object
The object model can be inspected to determine the "fields" values of the point Object, but herein we will exploit our prior knowledge that there are two fields with names "type" and "coordinates".
By casting the schema element to a DTObjectInfo, we can extract the "fields" values using Linq
:
var pointObject = (DTObjectInfo)point;
DTFieldInfo typeField = pointObject.Fields.First(f => f.Name == "type");
DTFieldInfo coordinatesField = pointObject.Fields.First(f => f.Name == "coordinates");
The "type" field is an enum with a single enum value "Point", as the following snippet shows:
Console.WriteLine($"type field has schema type {typeField.Schema.EntityKind}");
Console.WriteLine($"type field schema has enum value {((DTEnumInfo)typeField.Schema).EnumValues[0].EnumValue}");
This snippet displays:
type field has schema type Enum
type field schema has enum value Point
The "coordinates" field is an array of double, as the following snippet shows:
Console.WriteLine($"coordinates field has schema type {coordinatesField.Schema.EntityKind}");
Console.WriteLine($"coordinates field schema has element schema {((DTArrayInfo)coordinatesField.Schema).ElementSchema.Id}");
This snippet displays:
coordinates field has schema type Array
coordinates field schema has element schema dtmi:dtdl:instance:Schema:double;2