OPC UA YAML DSL
Abstract
This specification defines the Sterfive OPC UA YAML DSL, a declarative, human-readable authoring format that compiles to conformant OPC UA NodeSet2 XML information models. The DSL is intended as a generic, vendor-neutral specification and is open to multiple, independent implementations. It expresses the full OPC UA address-space vocabulary — ObjectTypes, VariableTypes, DataTypes (basic, enumeration, structure, union, option set), ReferenceTypes, InterfaceTypes, EventTypes, FiniteStateMachine types, instances, methods, add-ins and additional references — while shielding the author from the syntactic burden of NodeSet2 XML and from explicit numeric NodeId assignment.
The semantics of the produced address space are anchored in the OPC UA standard, and in particular in [OPC 10000-3] Address Space Model and [OPC 10000-5] Information Model. Where this specification constrains a feature more tightly than the OPC UA standard (for example by requiring a syntactic convention), the constraint is called out explicitly.
The companion JSON Schema artefact published as
schemas/nodeset2.schema.json is the machine-readable representation of the
syntactic rules in this specification and is normative for syntactic
validation. This document is normative for the semantics, the cross-property
invariants and the equivalence between a DSL document and the OPC UA address
space it produces.
Status of This Document
This is a Sterfive Working Draft published for public review. The specification may be updated, replaced or made obsolete by Sterfive at any time. Publication as a Sterfive Working Draft does not imply endorsement by, or affiliation with, the OPC Foundation.
References to OPC UA terminology and node classes are provided for interoperability. OPC, OPC UA and NodeSet2 are trademarks of the OPC Foundation; their use in this document is purely descriptive and refers to the format the DSL targets.
1Introduction
OPC UA address spaces are conventionally distributed as NodeSet2 XML documents. NodeSet2 XML is faithful to the OPC UA Address Space Model defined in [OPC 10000-3] but is verbose, tightly coupled to numeric NodeIds, and laborious to author or review. The Sterfive OPC UA YAML DSL provides a compact, declarative representation of the same model:
- nodes are addressed by browse name and browse path rather than by NodeId, in line with the symbolic-name convention of [OPC 10000-5] §4.1;
- numeric NodeIds are auto-assigned and persisted in a symbol-table CSV that survives regeneration;
- composite features such as DataType structures, EventTypes, Add-Ins and FiniteStateMachine types are written as concise YAML mappings;
- the document targets OPC UA 1.05 [OPC 10000-3] [OPC 10000-5], with an opt-in toggle to also emit the legacy 1.03 BinaryTypeDictionary entries for compatibility with older clients.
A DSL document is consumed by a Conformant Processor which produces a NodeSet2 XML document. Implementations may additionally produce TypeScript declaration files, Markdown or PDF documentation; those auxiliary artefacts are out of scope of this specification.
namespaceUri: http://acme.com/UA/TemperatureSensor
version: 1.0.0
publicationDate: 2026-01-01T00:00:00.000Z
namespaces:
- di
objectTypes:
- browseName: TemperatureSensorType
subtypeOf: di:DeviceType
components:
- browseName: di:ParameterSet
components:
- browseName: Temperature
typeDefinition: ua:AnalogItemType
dataType: ua:Double
engineeringUnits: "degree Celsius"
instances:
- browseName: Sensor01
typeDefinition: TemperatureSensorType
organizedBy: /ua:Objects/di:DeviceSet
2Conformance
This document uses normative keywords as defined by RFC 2119 / RFC 8174. The terms must, must not, required, shall, shall not, should, should not, recommended, may and optional, when typeset in this manner, denote the corresponding requirement levels.
This specification defines two conformance classes:
- Conformant Document
- A YAML 1.2 document whose root mapping satisfies every must requirement in sections 4 through 18.
- Conformant Processor
- An implementation that, given a Conformant Document, produces a NodeSet2 XML document NodeSet2-equivalent to the address space described by the document, and rejects with a diagnostic any document that violates a must requirement of this specification.
A Conformant Processor must implement sections 4–15 in full and
must reject documents that contain unknown root properties or unknown
sub-properties flagged by this specification as having
additionalProperties: false. Sections 16–18 (Events,
State Machines, Initializers) describe
optional features. A processor that does not implement an optional
feature must reject documents that use it rather than silently ignore
the feature.
3Terminology
- document
- A YAML 1.2 file whose root is a mapping conforming to this specification.
- own namespace
- The namespace whose URI is given by the
namespaceUriproperty at the document root. New nodes defined by the document are created in this namespace. - imported namespace
- A namespace declared through
namespacesorimports. Its nodes are visible to the document but not redefined by it. - browse name
- A qualified name. Written as a bare PascalCase identifier when in the own namespace, or as
alias:Nameotherwise. - placeholder browse name
- A browse name surrounded by
<>, e.g.<ImageId>. It denotes a member created by anOptionalPlaceholderorMandatoryPlaceholdermodelling rule. - browse path
- A solidus-separated sequence of browse names. Browse paths starting with
/are absolute and rooted atua:RootFolder; paths starting with$Identifier/are anchored at a node defined in the same document; otherwise the path is relative to the closest enclosing context. - connected object
- An instance linked to its parent through exactly one of the connection properties listed in §14.1.
- instance
- An OPC UA Object or Variable that lives in the address space at run time, as opposed to a Type which is a template.
- add-in
- A reusable Object aggregate, instantiated by reference to its
typeDefinitionrather than by writing out its members, with browse-name resolution rules described in §12. - symbol table
- A CSV file (conventionally named
<model>.symbols.csv) that stores the auto-assigned NodeId of every node in the document. Persistence of NodeIds across regeneration is achieved by consulting and updating this file.
4Lexical Conventions
4.1Browse names and placeholders
A bare browse name must match the regular expression
([A-Za-z0-9]+:)?(([A-Z][a-zA-Z0-9]*)|(<[A-Z][a-zA-Z0-9°#]*>)). The
optional alias: prefix selects an imported namespace; without it the
browse name belongs to the own namespace. PascalCase should be used for
the local part. English should be preferred over other languages when
authoring browse names.
A placeholder browse name is enclosed in <>, e.g. <ItemId>. It must
appear only on a member that declares modellingRule: OptionalPlaceholder
or modellingRule: MandatoryPlaceholder.
The alias ua is reserved for the OPC UA standard namespace
http://opcfoundation.org/UA/. A document must not redefine ua.
Aliases are case-sensitive.
4.2Browse paths and anchors
A browse path is a string of solidus-separated browse names matching
(/(alias:)?Name)+ with an optional anchor prefix.
| Form | Meaning |
|---|---|
/ua:Objects/... |
Absolute path rooted at ua:RootFolder. |
$Robot1/Axes |
Anchored path: $Robot1 resolves to the node defined in this document with browse name Robot1. |
Robot1/Axes |
Relative path; the resolver searches first the current parent, then sibling instances of the document by browse name. |
A Conformant Processor must reject a document if any browse path cannot be unambiguously resolved.
4.3Namespace aliases
The following aliases are reserved by this specification and resolve to
companion-spec namespaces published by the OPC Foundation. A document
must not use any of them as a custom imports[].alias.
adi, amb, autoId, cnc, commercialKitchenEquipment, di, gds,
glass, ia, ijtBase, iolink, iolinkIODD, irdi,
isa95JobControl, machinery, machineryJobs, machineryProcessValues,
machineryResult, machineTool, machineVision, metalForming,
packML, padim, robotics, standard, tightening, woodWorking.
4.4NodeId assignment
Numeric NodeIds should not be authored by hand. A Conformant Processor
must assign a fresh numeric NodeId to every node that lacks an explicit
nodeId, persisting the assignment in the symbol table so it remains
stable across regenerations.
When required (for example to interoperate with an external system that
hard-codes a NodeId), a node may declare an explicit nodeId string
matching one of:
s=<string>— string NodeId.g=<uuid>— GUID NodeId.b=<base64>— opaque NodeId.
The namespace prefix ns=<index>; must not appear: the namespace is
fixed by the own namespace. When a parent declares a string nodeId,
descendants whose NodeId is not explicitly stated should derive a
string NodeId from the parent (e.g. s=MyMachine-Child1).
4.5Localized text
A property typed as LocalizedText accepts either:
- a bare string (locale defaults to none), or
- a mapping
{ locale: <string|null>, text: <string> }.
5Namespace Imports
The namespaces property declares an ordered list of well-known
companion-spec aliases (see §5.3). Order matters: a
namespace must appear after every namespace it depends on. For example,
because adi depends on di, the order [di, adi] is required.
The imports property declares additional, non-well-known imports. Each
entry must be a mapping containing alias plus at least one of uri
or filename:
| Key | Type | Card. | Notes |
|---|---|---|---|
alias |
string | 1 | Short name used to qualify browse names; case-sensitive; must not collide with a reserved alias. |
uri |
URI string | 0..1 | Absolute namespace URI — the identity of the import. Resolution matches it against each candidate's <Model ModelUri>. |
filename |
string | 0..1 | Path to the NodeSet2 XML, resolved relative to the DSL document. A hint: if it is missing or stale and uri is given, uri is used. |
publicationDate |
date | 0..1 | Require a nodeset published on or after this date (OPC UA's PublicationDate >= required rule). Not a version range. |
sha256 |
string | 0..1 | Integrity pin: the sha256 of the exact file expected. |
An import that names only a uri is resolved by scanning, in order, the
document's own folder and a ./deps/ folder beside it, reading each candidate's
<Model ModelUri> header. Filenames inside ./deps/ are therefore irrelevant —
what identifies a nodeset is what it declares itself to be, which means the same
thing on every machine, whereas a path does not.
When both are given, filename is tried first and the loaded ModelUri is
verified against the declared uri; a mismatch is reported as a warning and
the file is still loaded, because uri was informative-only in earlier versions
and incorrect values exist in existing models.
A filename that is not a NodeSet2 XML is rejected with a diagnostic naming the
file. In particular, a YAML model cannot be imported directly — compile it to a
NodeSet2 first (opcua-modeler generate) and import the result.
{.props}
namespaces:
- di
- ia
- machinery
imports:
- alias: ts
uri: http://acme.com/UA/TemperatureSensor/
filename: ../temperature_sensor.NodeSet2.xml
6DataTypes
DataTypes describe the structure of Variant values, as defined in
[OPC 10000-3] §5.8. A DataType definition must declare browseName. It
may declare any of subtypeOf, isAbstract, description, nodeId,
plus the kind-specific properties below. The kind of a DataType is inferred
from the keys present, as defined in §7.1–§7.5.
6.1Basic DataType
A simple alias of an existing DataType. The mapping must declare
subtypeOf and must not declare fields, enum, isUnion or
isOptionSet.
6.2Enumeration
Enumerations are subtypes of ua:Enumeration as described in
[OPC 10000-3] §5.8.3. An enumeration may be declared with or without an
explicit subtypeOf: ua:Enumeration; the latter form is implied when an
enum property is present. The enum property accepts either:
- an array of bare strings — values are auto-assigned starting at 0; or
- an array of mappings each with at least
nameandvalue, optionallydescriptionanddisplayName.
Within a single enumeration the set of names must be unique and the
set of integer values must be unique.
dataTypes:
- browseName: SoftwareVersionFileType
subtypeOf: ua:Enumeration
enum:
- name: Current
value: 0
description:
text: The currently used version.
- name: Pending
value: 1
description:
text: The pending version that could be installed.
- name: Fallback
value: 2
6.3Structure
A DataType with a fields array is a Structure. Each field must declare
name and dataType; it may declare description, valueRank,
arrayDimensions and isOptional.
A Structure DataType may reference itself or a sibling defined later in the same document (forward references are permitted; see §19).
dataTypes:
- browseName: MyType
fields:
- name: Field1
dataType: ua:Double
valueRank: 1
6.4Union
A Structure with isUnion: true denotes a discriminated Union as defined in
[OPC 10000-3] §5.8.4: at most one field carries a value at run time.
isOptional must not appear on a Union field.
6.5Option set
A Structure with isOptionSet: true denotes an OptionSet DataType (a
structured bit-mask) as defined in [OPC 10000-3] §5.8.5. isUnion and
isOptionSet must not both be true on the same DataType.
6.6Companion VariableType
A Structure DataType may request the automatic creation of a companion
VariableType by setting hasVariableType: true. The companion VariableType
browse name is derived by replacing the trailing DataType suffix with
Type (e.g. MyStuffDataType → MyStuffType). When this convention does
not apply, the processor must still emit a deterministic browse name and
document the rule.
7ReferenceTypes
A ReferenceType definition must declare browseName and should
declare subtypeOf (default ua:NonHierarchicalReferences when omitted).
It may declare inverseName, symmetric, isAbstract and
description. The reserved hierarchical references of OPC UA Part 3
(HasChild, HasComponent, …) must not be redefined.
8ObjectTypes and VariableTypes
An entry of objectTypes describes one OPC UA ObjectType. The mapping
must declare browseName; if subtypeOf is omitted the type inherits
from ua:BaseObjectType. variableTypes entries follow the same shape
with the addition of dataType, valueRank, arrayDimensions, value and
accessLevel; an unspecified subtypeOf defaults to
ua:BaseDataVariableType and dataType is required for non-abstract
VariableTypes.
| Property | Type | Notes |
|---|---|---|
browseName |
browse name | Required. |
subtypeOf |
type reference | Default per node-class. |
isAbstract |
boolean | Default false. |
description |
localized text | Markdown permitted in the long form. |
documentation |
string | Markdown shown in the rendered docs only. |
nodeId |
string NodeId | See §5.4. |
defaultInstanceBrowseName |
browse name | See §9.3. |
properties |
array | HasProperty children. See §9.1. |
components |
array | HasComponent children. |
methods |
array | UAMethod members. See §13. |
organizes |
array | FolderType-like children (Organizes). |
orderedComponents |
array | HasOrderedComponent children. See §9.2. |
physicalComponents |
array | HasPhysicalComponent children. |
containedComponents |
array | HasContainedComponent children. |
attachedComponents |
array | HasAttachedComponent children. |
interfaces |
array | InterfaceTypes implemented by this type. See §11. |
addIns |
array | Add-Ins. See §12. |
references |
array | Per-node additional references. See §15. |
generatedEvents |
array of EventType reference | See §16. |
eventSources |
array of browse path | Materialised as HasEventSource references. |
eventSourceOf |
browse path | Inverse of eventSources. |
subtypes |
array of ObjectType / VariableType | Inline subtypes. See §9.4. |
8.1Aggregate members
Aggregate properties translate to standard hierarchical ReferenceTypes defined in [OPC 10000-3] §7.
| Property | OPC UA ReferenceType | Permitted children |
|---|---|---|
properties |
HasProperty |
Variables only (NodeClass Variable typed by PropertyType per [OPC 10000-3] §5.6.2). |
components |
HasComponent |
Variables, Objects or Methods. |
orderedComponents |
HasOrderedComponent |
Variables or Objects. |
methods |
HasComponent (NodeClass Method) |
UAMethod children. |
organizes |
Organizes |
Objects (typically FolderType-rooted). |
Each child must declare browseName. A child whose typeDefinition is
omitted inherits the default for its node-class (ua:BaseDataVariableType
for Variables, ua:BaseObjectType for Objects). A child whose nodeClass
is omitted has its node-class inferred from typeDefinition when possible,
then from the presence of dataType (Variable) or its absence (Object).
Authors may nevertheless write nodeClass: Object | Variable | Method
explicitly, and a processor must reject inconsistencies between the
explicit node-class and the inferred one.
objectTypes:
- browseName: MySensorType
components:
- browseName: MyMandatoryComponent
typeDefinition: ua:BaseObjectType
- browseName: MyOptionalComponent
typeDefinition: ua:BaseObjectType
modellingRule: Optional
- browseName: MyComponentWithNoModelingRule
typeDefinition: ua:BaseObjectType
modellingRule: false
- browseName: <MyOptionalPlaceholderComponent>
typeDefinition: ua:BaseObjectType
modellingRule: OptionalPlaceholder
- browseName: <MyMandatoryPlaceholderComponent>
typeDefinition: ua:BaseObjectType
modellingRule: MandatoryPlaceholder
8.2Advanced component containment
The orderedComponents, physicalComponents, containedComponents and
attachedComponents arrays declare child references using the OPC UA
reference types HasOrderedComponent, HasPhysicalComponent,
HasContainedComponent and HasAttachedComponent respectively. The order
of items in orderedComponents is significant and must be preserved by
a Conformant Processor when emitting NodeSet2 XML.
objectTypes:
- browseName: MyObjectType
orderedComponents:
- browseName: First
nodeClass: Object
typeDefinition: ua:BaseObjectType
- browseName: Second
nodeClass: Object
typeDefinition: ua:BaseObjectType
physicalComponents:
- browseName: Phys1
nodeClass: Object
containedComponents:
- browseName: Contained
nodeClass: Object
attachedComponents:
- browseName: Attached1
nodeClass: Object
8.3Default instance browse name
An ObjectType may declare a defaultInstanceBrowseName. When this type
is consumed as an Add-In with no explicit browseName, the
processor must use the default to name the instantiated child.
8.4Inline subtypes
An ObjectType or VariableType may declare an inline subtypes array.
Each entry is a full Type definition whose subtypeOf defaults to the
enclosing type. This convenience is equivalent to declaring the subtypes at
the document root with explicit subtypeOf.
9Modelling Rules and Optionals
Modelling rules describe the cardinality and constraints of a member of a
Type. This specification adopts the standard modelling rules defined in
[OPC 10000-3] §6.4.4.4 and adds one purely syntactic convenience (false).
The modellingRule property of a child member must take one of the
following values:
Mandatory— the child is always present in every instance of the enclosing type. This is the default when the property is omitted on a Type-side member.Optional— the child may be present; an instance opts in by listing the member browse name inoptionals, or a subtype tightens it throughpromotedToMandatory.MandatoryPlaceholder— at least one instance with an author-chosen browse name must be supplied.OptionalPlaceholder— zero or more instances with author-chosen browse names may be supplied.ExposesItsArray— defined by [OPC 10000-3] §6.4.4.4.5; permitted only on a Variable member of a VariableType whosevalueRankis ≥ 0.false(the YAML boolean) — a DSL convenience meaning "no modelling rule applies". The Conformant Processor must not emit aHasModellingRulereference for the member. It is equivalent to omitting the property altogether.
[OPC 10000-3] §6.4.4.4 defines modelling rules as an extensible concept: vendors may introduce additional modelling rules beyond those listed above. A Conformant Processor may accept additional values, but must reject a document if it cannot materialise them.
A modelling rule must not appear on a member of an instance, since instance members do not declare cardinality.
9.1Placeholder browse-name convention
[OPC 10000-3] §6.4.4.4.6 and §6.4.4.4.7 recommend that the browse name and
display name of OptionalPlaceholder and MandatoryPlaceholder instance
declarations be enclosed in angle brackets. This specification tightens the
recommendation into a requirement: the browse name of a member declaring a
placeholder modelling rule must be a placeholder browse name (matching
<Name>), and conversely a placeholder browse name must be paired with
a placeholder modelling rule.
9.2Subtype and instantiation overrides
A subtype may tighten the modelling rule of an inherited member following the rules of [OPC 10000-3] Table 21, reproduced here for convenience:
| Rule on supertype | Permitted rule on subtype |
|---|---|
Mandatory |
Mandatory |
Optional |
Mandatory or Optional |
MandatoryPlaceholder |
MandatoryPlaceholder |
OptionalPlaceholder |
MandatoryPlaceholder or OptionalPlaceholder |
A Conformant Processor must reject any override that violates this
table. Loosening (e.g. Mandatory → Optional) is not permitted.
9.3optionals
An optionals array enumerates browse names of inherited optional members
that this type or instance opts in to. Nested members may be expressed
using the dot-separated form "Property.ChildProperty", mirroring the
symbolic-name convention of [OPC 10000-5] §4.1. A Conformant Processor
must resolve names by walking the fully-inherited InstanceDeclaration
hierarchy.
On an instance, the array need not list an optional member the document already assigns a value to: assigning a value implies presence, per §18.1. Listing it anyway is redundant, not an error.
9.4promotedToMandatory
A subtype, an instance, or an interface application may promote
inherited Optional members to Mandatory, or OptionalPlaceholder
members to MandatoryPlaceholder, by listing their browse names in
promotedToMandatory. The transformations must respect Table 21 above.
Promotion is transitive across ancestors and across implemented interfaces.
objectTypes:
- browseName: PlateType
interfaces:
- browseName: di:IVendorNameplateType
promotedToMandatory:
- di:DeviceClass
- di:SerialNumber
- di:SoftwareRevision
defaultInstanceBrowseName: Identification
10InterfaceTypes
An interfaceTypes entry has the same shape as an ObjectType but its
subtypeOf defaults to ua:BaseInterfaceType. InterfaceTypes are subtypes
of BaseInterfaceType per [OPC 10000-5] and form their own hierarchy
through subtypeOf.
The interfaces property of an ObjectType, VariableType or instance lists
the InterfaceTypes that the node implements. Each entry must be a
mapping with:
browseName— required; the InterfaceType reference.promotedToMandatory— optional; promotes interface members per §10.4.optionals— optional; opts in to interface optional members per §10.3.
A Conformant Processor must add a HasInterface reference (defined in
[OPC 10000-5]) from the implementing Type to the InterfaceType.
10.1Lean materialisation
This specification adopts a lean interpretation of interface application that follows OPC UA Part 3 v1.05 §6.3.3.1 to the letter:
"Subtypes inherit the fully-inherited parent type's InstanceDeclarations. As long as those InstanceDeclarations are not overridden they are not referenced by the subtype."
Combined with §4.10.2, which describes interface members as living in the "fully-inherited InstanceDeclarationHierarchy of the ObjectType" (a conceptual collection that already includes inherited and interface-derived members), the rule a Conformant Processor must apply when an ObjectType / VariableType implements an interface is:
- Mandatory interface members are materialised directly on the
implementing Type, with their original
Mandatorymodelling rule. - Optional interface members listed in the YAML
optionals:on the interface application are materialised directly on the Type, preserving theirOptionalmodelling rule. - Optional interface members listed in
promotedToMandatory:are materialised directly on the Type with their modelling rule promoted toMandatory. - Every other Optional interface member is not referenced from the
implementing Type. It remains reachable through the
HasInterfacereference and the interface's own InstanceDeclarationHierarchy.
This deliberately diverges from the eager-copy behaviour of some upstream node-opcua releases. The lean approach keeps the interface as the single source of truth for its members, prevents redundant nodes on every implementer, and makes overrides — the only legitimate reason for a Type to reference an interface member directly — visually unambiguous in the generated NodeSet2 XML.
10.2Instance-time interface walk
Because the implementing Type is lean, instance materialisation must
walk the Type's HasInterface references (transitively up the HasSubtype
chain) and apply each interface to the instance under the lean rules of
§11.1. Specifically, for every interface implemented (directly or by
inheritance) by the instance's typeDefinition:
- Mandatory members of the interface must be materialised on the instance (a Server creating an instance must reproduce the fully-inherited InstanceDeclarationHierarchy — Part 3 §6.4).
- Optional members listed in the instance's
optionals:must be materialised on the instance. - Other Optional members must not be materialised.
The HasInterface reference itself stays on the TypeDefinitionNode; an
instance must not add a duplicate HasInterface reference (Part 3
§4.10.2: "Instances should not have a HasInterface Reference to an
Interface if it was already applied to the TypeDefinitionNode").
10.3Instance with its own interfaces: block
An instance may declare its own interfaces: block to apply an
interface that the TypeDefinitionNode does not already implement. In that
case the instance:
- must add a
HasInterfacereference to the interface; and - must materialise members per the lean rules of §11.1, treating the
per-entry
optionals:andpromotedToMandatory:lists as overrides on the instance.
interfaceTypes:
- browseName: ILevelType
properties:
- browseName: L1Prop
dataType: ua:String
- browseName: ILevel2Type
subtypeOf: ILevelType
properties:
- browseName: L2Prop1
dataType: ua:String
- browseName: L2Prop2
dataType: ua:String
modellingRule: Optional
objectTypes:
- browseName: XYZDeviceType
interfaces:
- browseName: ILevel2Type
instances:
- browseName: XYZInstance1
typeDefinition: XYZDeviceType
organizedBy: /ua:Objects
optionals: [L2Prop2]
11Add-Ins
An Add-In is an Object aggregate referenced by its typeDefinition rather
than enumerated member-by-member. The addIns property of a Type or
instance may list Add-Ins; each entry is a mapping with at least
typeDefinition and optionally browseName, modellingRule, and
optionals.
The browse name of the materialised Add-In instance is determined as follows, in order:
- the explicit
browseNameof the Add-In entry, if present; - otherwise the
defaultInstanceBrowseNameof the Add-In'stypeDefinition; - otherwise the
browseNameof thetypeDefinitionwith the trailingTypesuffix removed.
A Conformant Processor must reject a document if rule 3 is reached but the resulting browse name is empty or collides with an existing sibling.
objectTypes:
- browseName: ThermometerComponentType
components:
- browseName: Temperature
dataType: ua:Float
defaultInstanceBrowseName: Thermometer
instances:
- browseName: Equipment
typeDefinition: ua:BaseObjectType
organizedBy: /ua:Objects
addIns:
- typeDefinition: ThermometerComponentType
browseName: MyThermometer1
- typeDefinition: ThermometerComponentType
browseName: MyThermometer2
12Methods
A method declaration must declare browseName. inputArguments and
outputArguments are ordered arrays of mappings; each entry must
declare name and dataType and may declare description,
valueRank (default -1) and arrayDimensions.
On a Type-side member, a method may declare modellingRule; on an
instance-side member it must not. A method may declare an
executable boolean (default true).
13Instances
An entry of the top-level instances array describes an Object or Variable
instance. The mapping must declare browseName and typeDefinition,
and must declare its parent through exactly one of the
connection properties. An instance may
additionally declare any of:
| Property | Notes |
|---|---|
nodeId |
Explicit string NodeId; see §5.4. |
description, displayName |
Localized text overrides. |
optionals |
Inherited optional members to instantiate. |
interfaces |
InterfaceTypes implemented by this instance. |
addIns |
Add-Ins to instantiate; see §12. |
properties, components, organizes, methods |
Inline children that override or augment the instantiated members; see §14.2. |
propertyValues |
Values for the instance's members, addressed by nesting; see §14.4. |
initializers |
Values for the instance's members, addressed by browse path; see §18. |
value, accessLevel |
Permitted only when the instance is a Variable (i.e. typeDefinition resolves to a VariableType). |
13.1Connected-object rule
Every Object or Variable in an OPC UA address space is reached from the
Server's Objects, Types or Views folder through hierarchical References
([OPC 10000-3] §7.5). Accordingly an instance in this DSL must declare
its parent through exactly one of the following properties; the JSON
Schema ConnectedObject definition enforces this with a oneOf:
| Property | OPC UA reference |
|---|---|
organizedBy |
Organizes |
componentOf |
HasComponent |
propertyOf |
HasProperty |
orderedComponentOf |
HasOrderedComponent |
physicalComponentOf |
HasPhysicalComponent |
containedComponentOf |
HasContainedComponent |
The value of each connection property is a browse path (absolute, anchored or relative). Two top-level instances may use different connection properties.
13.2Inline children and overrides
An instance may include properties, components, organizes or
methods arrays. The processor must match each inline child by
browseName against the members materialised from typeDefinition (and
from implemented interfaces / add-ins):
- If a matching member exists, the inline child overrides it and may
set
value,description,displayName,dataType(when narrowing is permitted by OPC UA),valueRank,arrayDimensions,accessLevel, sub-aggregates and inlinereferences. The inline child must not declare amodellingRule. - If no matching member exists, the inline child is treated as a new
member added to this instance. The processor must require
typeDefinitionin this case for non-Method children.
objectTypes:
- browseName: MySubObjectType
components:
- browseName: ComponentA
nodeClass: Object
- browseName: ComponentVarB
nodeClass: Variable
dataType: ua:Double
valueRank: -2 # any
- browseName: MyObjectType
components:
- browseName: SubObject1
typeDefinition: MySubObjectType
components:
- browseName: ComponentVarB
dataType: ua:Double
valueRank: 1 # narrowed to array
13.3Browse-name uniqueness
Two distinct nodes may share the same browse name as long as they do not share the same hierarchical parent. A processor must reject documents in which two sibling nodes share the same browse name. This rule applies uniformly to top-level instances, inline children and members materialised through Add-Ins or interfaces.
instances:
- browseName: MyInstance
typeDefinition: MyObjectType
organizedBy: /ua:Objects
- browseName: SomeLittleThing
typeDefinition: LittleThingType
componentOf: MyInstance/Folder1
- browseName: SomeLittleThing
typeDefinition: LittleThingType
componentOf: MyInstance/Folder2
13.4PropertyValues
propertyValues assigns values to an instance's members by nesting rather
than by path. It is a mapping whose shape mirrors the instance's aggregate
structure: each key is a member browse name, alias-qualified per
§5.3, and each value is either the value to assign or a
nested mapping addressing that member's own children.
instances:
- browseName: Pump1
typeDefinition: di:DeviceType
organizedBy: /ua:Objects
propertyValues:
di:Manufacturer: Sterfive
di:ParameterSet:
Pressure: 4.2
A Conformant Processor must resolve each key against the children of the node the enclosing mapping addresses, and must reject a key that names no such member rather than creating one — a misspelled member is an authoring error, not a new node. A leaf must address a Variable; assigning to an Object is an error.
$value
A member that carries both a value and children of its own is addressed with
the reserved key $value, which assigns to the enclosing Variable itself:
propertyValues:
Level:
$value: 42.0
ua:EngineeringUnits: "%"
$value must be rejected when the enclosing node is not a Variable.
Value literals
A mapping is normally a sub-tree, which makes the two OPC UA structures that a model most often writes inline ambiguous. A Conformant Processor must therefore treat a mapping as a VALUE, not a sub-tree, when — and only when — it matches one of these shapes against the target Variable's DataType:
{ text, locale? }where the basic DataType isLocalizedText;{ low, high }where the DataType isRange.
The test must be applied before recursing, and must not be relaxed to
a subset or superset of those keys: { txt: "Acme" } is not a LocalizedText
with a typo, it is a reference to a child named txt, and must produce
the same "no such member" error any other unknown key would. Every other
mapping recurses.
Relationship to initializers
propertyValues and initializers express the same thing —
values for existing Variables — and differ only in how the target is
addressed: by nesting, or by a browse path. A document may use either or
both. Both are subject to §18.1: a
value written at any depth of a propertyValues tree opts every Optional
node on its path in.
14Additional References
The top-level references array, and the per-node references sub-arrays
on Types, instances and add-ins, declare references that are not
expressible through aggregates or connection properties (typically
non-hierarchical or cross-namespace references).
Each entry must be a mapping with:
referenceType— required; browse name of a ReferenceType.target— required; browse path of the target node.source— required only on the top-level form (omitted in per-node form, where source is implicit).isForward— optional boolean; defaulttrue.
15Events
Event types are declared in the top-level eventTypes array; each entry
has the shape of an ObjectType with default subtypeOf: ua:BaseEventType.
The generatedEvents property of any Type lists the event types it raises;
the processor must emit a GeneratesEvent reference for each entry.
The eventSources / eventSourceOf properties materialise
HasEventSource references.
objectTypes:
- browseName: MyObjectType
generatedEvents:
- MyEventType
eventTypes:
- browseName: MyEventType
16State Machines
A stateMachines entry produces a FiniteStateMachine type as defined in
[OPC 10000-5] §B (FiniteStateMachineType, StateType, TransitionType). The
default subtypeOf is ua:FiniteStateMachineType. The mapping must
declare:
browseName— the type browse name;states— either an array of state browse names (numeric values auto-assigned starting at 0) or an array of mappings{ name, value, description?, isInitialState? };transitions— an array of mappings, each with at minimumfromandto; an optionalbrowseName,valueanddescriptionmay be provided. Default transition browse names follow the pattern<FromState>To<ToState>.
A state machine may additionally declare subtypeOf, isAbstract,
transitionHaveEffect (the EventType raised on each transition),
components and promotedToMandatory.
stateMachines:
- browseName: MyFiniteStateMachine
states: [LowLow, Low, High, HighHigh]
transitions:
- from: LowLow
to: Low
- from: Low
to: High
- from: High
to: HighHigh
- from: HighHigh
to: High
- from: High
to: Low
- from: Low
to: LowLow
17Initializers
The initializers array declares default values for existing variables,
identified by variable (a browse path). Each entry must declare
variable and value; engineeringUnits, range and description are
optional and apply only to AnalogItem-like variables.
An initializers block may appear on an instance, where variable is a
path relative to that instance, or at the top level of the document, where
the first segment of variable must name a symbol — an instance
declared by the document, written with or without the $ sigil. The two
forms are equivalent: $Robot1/FlangeLoad written at the top level and
FlangeLoad written inside Robot1 denote the same Variable and must
have the same effect.
Initializers are applied after all node materialisation has completed and before NodeSet2 XML serialisation. They must not create or remove nodes.
17.1Presence implied by initialization
Assigning a value implies the presence of the node that receives it. Where
variable resolves, through the fully-inherited InstanceDeclaration
hierarchy, to a member whose modelling rule is Optional — or reaches such
a member through an Optional ancestor — a Conformant Processor must
treat every Optional node on that path as though it had been listed in
the target instance's optionals array.
This is a materialisation-phase rule, not an exception to the paragraph
above: the nodes are created in phase 4 like any other
opted-in optional member, and phase 6 still only writes values to nodes that
already exist. A processor that defers the decision to phase 6 cannot
implement it, because instantiate() has already run.
The same rule governs propertyValues, where a value
written at any depth of the tree opts its path in.
An entry that names a member the type does not declare must not be
opted in — it is an authoring error, and the diagnostic a processor already
emits for an unresolvable variable path is the correct response.
18Processing Model
A Conformant Processor must process a document in the following phases:
- Parse and schema-validate. Reject documents that fail YAML parsing or the JSON Schema validation.
- Resolve namespaces. Load every namespace declared in
namespacesandimports; assign each a stable namespace index. - Topological sort. Build a dependency graph over types defined in the
document; resolve forward references; reject cycles unless the cycle is
a self-reference permitted by OPC UA (e.g. a Structure field whose
dataTypeis its enclosing type). - Materialise nodes. Create ReferenceTypes, DataTypes, ObjectTypes,
VariableTypes, EventTypes, InterfaceTypes, FiniteStateMachine types,
then top-level instances. For each Type, copy inherited members, apply
interfaces,addIns,promotedToMandatory,optionalsand inline children (in that order). Before an instance is materialised, itsoptionalsset is extended with theOptionalmembers implied by the values the document assigns to it — from its owninitializersandpropertyValues, and from the top-levelinitializersentries anchored at it (see §18.1). The top-level block is only readable this early because its paths are rooted at symbols, not at nodes. - Apply additional references. Resolve and add every entry of the
top-level and per-node
referencesarrays. - Apply initializers. Set Variant values on existing Variable nodes.
- Persist NodeIds. Update the symbol table so that all auto-assigned NodeIds remain stable across regenerations.
- Serialise. Emit a NodeSet2 XML document that is NodeSet2-equivalent to the address space described by the document.
19Equivalence with NodeSet2 XML
A NodeSet2 XML document is described by [OPC 10000-6]. Two address spaces are NodeSet2-equivalent if and only if, after canonicalisation, they declare:
- the same set of nodes (matched by NodeId after namespace-index remapping); each node has the same NodeClass and the same set of Attributes as defined in [OPC 10000-3] §5;
- identical Attribute values for each node, modulo whitespace in LocalizedText fields;
- identical hierarchical and non-hierarchical References, modulo ordering
of
Referenceselements except where ordering is mandated by the ReferenceType (e.g.HasOrderedComponent); - identical InstanceDeclaration hierarchies for every TypeDefinitionNode,
preserving every
HasModellingRulereference required by the modelling rules of §10.
A Conformant Processor must produce, for any Conformant Document, a NodeSet2 XML document that is NodeSet2-equivalent to the address space described by the document.
20Diagnostics
A Conformant Processor must reject a document and emit a diagnostic when:
- the JSON Schema validation fails;
- a referenced browse name, browse path or namespace alias cannot be resolved;
- two sibling nodes share the same browse name;
- an instance does not satisfy the connected-object rule;
- a
modellingRuleis used on an instance-side member; - a placeholder browse name is not paired with a placeholder modelling rule;
- an enumeration field has a duplicate
nameorvalue; - a Structure declares both
isUnion: trueandisOptionSet: true; - an Add-In's resolved browse name is empty or collides with an existing sibling;
- a state-machine transition references an unknown state;
- a property is encountered that is not defined by this specification on a
section that has
additionalProperties: false.
A processor should emit a non-fatal warning when:
- an unused
importsentry, an unused symbol-table NodeId or an empty optional array is encountered; - a node uses an explicit string NodeId that conflicts with an existing entry in the symbol table.
21Security Considerations
The DSL is a static description of an OPC UA model and does not by itself transmit data over the network. However:
- Documents may reference local files via
imports[].filename. Implementations should reject paths that escape the project root unless the user has explicitly opted in. - The Markdown
documentationblock is rendered into external artefacts. Implementations must sanitise any embedded HTML according to the rules of the target output format before rendering it to a browser. - Initializers (§18) accept only literal scalar or array values, so they do not in themselves execute code; implementations that extend the format with programmable initializers must sandbox the evaluation context.
22References
- [OPC 10000-3]
- OPC Foundation, OPC Unified Architecture — Part 3: Address Space Model, version 1.05. https://reference.opcfoundation.org/Core/Part3/v105/docs/
- [OPC 10000-5]
- OPC Foundation, OPC Unified Architecture — Part 5: Information Model, version 1.05. https://reference.opcfoundation.org/core/Part5/v105/docs/
- [OPC 10000-6]
- OPC Foundation, OPC Unified Architecture — Part 6: Mappings (defines the NodeSet2 / UANodeSet XML schema). https://reference.opcfoundation.org/Core/Part6/
- [YAML 1.2.2]
- YAML Language Development Team, YAML Ain't Markup Language (YAML™) version 1.2 (revision 1.2.2). https://yaml.org/spec/1.2.2/
- [JSON Schema 2020-12]
- JSON Schema Organisation, JSON Schema Specification, Draft 2020-12. https://json-schema.org/draft/2020-12/json-schema-core.html
- [RFC 2119]
- Bradner, S., Key words for use in RFCs to Indicate Requirement Levels, IETF, 1997. https://www.rfc-editor.org/rfc/rfc2119
- [RFC 8174]
- Leiba, B., Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words, IETF, 2017. https://www.rfc-editor.org/rfc/rfc8174
- [RFC 3339]
- Klyne, G., Newman, C., Date and Time on the Internet: Timestamps, IETF, 2002. https://www.rfc-editor.org/rfc/rfc3339