Skip to main content

Property Values

propertyValues sets values on an instance's members by nesting, mirroring the shape of the type. It is the alternative to initializers, which addresses the same variables by path — use whichever reads better for the model at hand, or both.


Nesting mirrors the type​

Each key is a member browse name, alias-qualified like everywhere else in the DSL. A value is either the value to assign, or a nested mapping addressing that member's own children:

Values by nesting
instances:
- browseName: Pump1
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
di:Manufacturer: Sterfive
ParameterSet:
Pressure: 4.2
Flow: 120.0

A key that names no member of the enclosing node is an error, not a new node — so a misspelling is reported rather than silently creating something the type never declared.


$value — a variable that also has children​

A variable with sub-properties of its own needs a way to say "this one, not a child of it". The reserved key $value does that:

A value alongside its own sub-properties
instances:
- browseName: Pump2
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
Level:
# the variable's OWN value, alongside its sub-properties
$value: 42.0
ua:EngineeringUnits: "%"
ua:EURange:
low: 0.0
high: 100.0

$value is rejected on an Object — only a Variable has a value to set.


Value literals​

Because a mapping normally means "recurse into children", the two structures models most often write inline would be ambiguous. Two shapes are therefore read as values:

ShapeWhen
{text, locale?}the variable's DataType is LocalizedText
{low, high}the variable's DataType is Range
Inline LocalizedText and Range
instances:
- browseName: Pump3
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
# {text, locale?} on a LocalizedText is a VALUE, not a child named "text"
di:Manufacturer:
text: Sterfive
locale: en
# {low, high} on a Range is likewise a value
Level:
ua:EURange:
low: 0.0
high: 250.0

The match is exact and deliberate: {txt: "Sterfive"} is not a LocalizedText with a typo, it is a reference to a child named txt, and you get the usual "cannot find child" error. That is what keeps a typo from being silently swallowed as a value.


Structures​

A variable whose DataType is a structure takes a mapping of the structure's fields as its value, and an array of structures takes one list item per element. Nested structures nest the same way, in block or flow style:

A structure, and an array of structures
instances:
- browseName: Pump5
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
# a structure: a mapping of its fields
CurrentSeal:
Material: FKM
MaxPressure: 16.0
# an array of structures: one list item per element, nested structures included
ServiceHistory:
- Hours: 1000
Seal:
Material: NBR
MaxPressure: 10.0
- Hours: 5000
Seal: { Material: FKM, MaxPressure: 16.0 }

A key that names no field is an error that lists the fields — ServiceRecordDataType has no field "Hour"; its fields are Hours, Seal — never a field left at its default. So is an empty list item (a bare -). A field you leave out takes its default value; an optional field (isOptional: true) you leave out is absent from the encoded value.

A union (subtypeOf: ua:Union) holds one of its fields: write exactly one key. Two keys, or none, is an error that lists the choices.

If the variable also has child nodes, its keys name those children, so its own value goes under $value. ua:Range keeps the stricter rule from the table above: both low and high.

In the editor, completion on the key writes the whole value: every required field with a default to tab through, nested structures expanded, an array as its first - item, and of a union its first choice. On a new - item it offers the fields one by one — optional ones marked as such — or all the required ones at once.


Optional members​

Assigning a value implies presence here too, at any depth of the tree — the instance does not need to repeat the member under optionals::

An Optional member needs no optionals: entry
instances:
- browseName: Pump4
typeDefinition: PumpType
organizedBy: /ua:Objects
# no `optionals:` — assigning a value opts MaintenanceNote in
propertyValues:
MaintenanceNote: "replace seal at 5000 h"

See Initializing an optional member for the same rule as it applies to initializers:.


Choosing between propertyValues and initializers​

Both write values to existing variables; they differ only in how the target is named.

propertyValuesinitializers
Addressingnested, mirrors the typea browse path per entry
Placementon the instanceon the instance, or at the document root
Reads well whensetting many values under one parentsetting a few scattered values, or grouping every value in one section
📄 Full working example — property-values.model.yaml
#
# Living documentation example for: s67_property-values.md
# Validate: opcua-modeler generate --input property-values.model.yaml
#
namespaceUri: http://example.com/doc-examples/property-values/
namespaces:
- di
version: 1.0.0

dataTypes:
- browseName: SealDataType
fields:
- name: Material
dataType: ua:String
- name: MaxPressure
dataType: ua:Double
- browseName: ServiceRecordDataType
fields:
- name: Hours
dataType: ua:UInt32
- name: Seal
dataType: SealDataType

objectTypes:
- browseName: PumpType
subtypeOf: di:DeviceType
components:
- browseName: ParameterSet
typeDefinition: ua:FolderType
components:
- browseName: Pressure
dataType: ua:Double
- browseName: Flow
dataType: ua:Double
- browseName: Level
dataType: ua:Double
typeDefinition: ua:AnalogUnitRangeType
- browseName: MaintenanceNote
dataType: ua:String
modellingRule: Optional
- browseName: CurrentSeal
dataType: SealDataType
valueRank: -1
- browseName: ServiceHistory
dataType: ServiceRecordDataType
valueRank: 1

instances:
- browseName: Pump1
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
di:Manufacturer: Sterfive
ParameterSet:
Pressure: 4.2
Flow: 120.0

- browseName: Pump2
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
Level:
# the variable's OWN value, alongside its sub-properties
$value: 42.0
ua:EngineeringUnits: "%"
ua:EURange:
low: 0.0
high: 100.0

- browseName: Pump3
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
# {text, locale?} on a LocalizedText is a VALUE, not a child named "text"
di:Manufacturer:
text: Sterfive
locale: en
# {low, high} on a Range is likewise a value
Level:
ua:EURange:
low: 0.0
high: 250.0

- browseName: Pump4
typeDefinition: PumpType
organizedBy: /ua:Objects
# no `optionals:` — assigning a value opts MaintenanceNote in
propertyValues:
MaintenanceNote: "replace seal at 5000 h"

- browseName: Pump5
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
# a structure: a mapping of its fields
CurrentSeal:
Material: FKM
MaxPressure: 16.0
# an array of structures: one list item per element, nested structures included
ServiceHistory:
- Hours: 1000
Seal:
Material: NBR
MaxPressure: 10.0
- Hours: 5000
Seal: { Material: FKM, MaxPressure: 16.0 }