Sterfive Specification

OPC UA YAML DSL

A human-friendly, declarative authoring format for OPC UA NodeSet2 information models
Document version: 0.0 (public draft) · Status: Working Draft · Date: 2026-05-01 · Editor: Etienne Rossignon, Sterfive SAS

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:

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

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 namespaceUri property at the document root. New nodes defined by the document are created in this namespace.
imported namespace
A namespace declared through namespaces or imports. 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:Name otherwise.
placeholder browse name
A browse name surrounded by <>, e.g. <ImageId>. It denotes a member created by an OptionalPlaceholder or MandatoryPlaceholder modelling rule.
browse path
A solidus-separated sequence of browse names. Browse paths starting with / are absolute and rooted at ua: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 typeDefinition rather 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:

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:

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:

  1. an array of bare strings — values are auto-assigned starting at 0; or
  2. an array of mappings each with at least name and value, optionally description and displayName.

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

NOTE

[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. MandatoryOptional) 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:

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:

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:

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:

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:

  1. the explicit browseName of the Add-In entry, if present;
  2. otherwise the defaultInstanceBrowseName of the Add-In's typeDefinition;
  3. otherwise the browseName of the typeDefinition with the trailing Type suffix 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):

  1. 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 inline references. The inline child must not declare a modellingRule.
  2. If no matching member exists, the inline child is treated as a new member added to this instance. The processor must require typeDefinition in 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:

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:

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:

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:

  1. Parse and schema-validate. Reject documents that fail YAML parsing or the JSON Schema validation.
  2. Resolve namespaces. Load every namespace declared in namespaces and imports; assign each a stable namespace index.
  3. 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 dataType is its enclosing type).
  4. 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, optionals and inline children (in that order). Before an instance is materialised, its optionals set is extended with the Optional members implied by the values the document assigns to it — from its own initializers and propertyValues, and from the top-level initializers entries 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.
  5. Apply additional references. Resolve and add every entry of the top-level and per-node references arrays.
  6. Apply initializers. Set Variant values on existing Variable nodes.
  7. Persist NodeIds. Update the symbol table so that all auto-assigned NodeIds remain stable across regenerations.
  8. 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:

  1. 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;
  2. identical Attribute values for each node, modulo whitespace in LocalizedText fields;
  3. identical hierarchical and non-hierarchical References, modulo ordering of References elements except where ordering is mandated by the ReferenceType (e.g. HasOrderedComponent);
  4. identical InstanceDeclaration hierarchies for every TypeDefinitionNode, preserving every HasModellingRule reference 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:

A processor should emit a non-fatal warning when:

21Security Considerations

The DSL is a static description of an OPC UA model and does not by itself transmit data over the network. However:

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