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:
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:
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:
| Shape | When |
|---|---|
{text, locale?} | the variable's DataType is LocalizedText |
{low, high} | the variable's DataType is 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:
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::
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.
propertyValues | initializers | |
|---|---|---|
| Addressing | nested, mirrors the type | a browse path per entry |
| Placement | on the instance | on the instance, or at the document root |
| Reads well when | setting many values under one parent | setting 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 }