跳到主要内容

结构体解码

概述

OPC UA 1.04+ 把每个自定义结构体的字段定义放到 DataType 节点的 DataTypeDefinition 属性 (AttributeId=27, Part 5 §6.4.2)。StructDecoder 实现完整协议层: 全部基本类型 + 嵌套结构 + 数组 + 枚举 + Union + Optional 字段。

API

成员类别读写说明
new StructDecoder(ua)构造绑定到会话
decoder.decode(variant)方法解码, 返回 DynamicExtensionObject
decoder.decodeBody(bytes, dataTypeId)方法直接给字节 + DataType 解码
decoder.getDefinition(dataTypeId)方法获取 / 缓存 StructDefinition
decoder.prefetchDefinitions(ids)方法预热缓存
obj.get(fieldName)方法取字段
obj.fields()方法字段名→值 Map
obj.definition()方法StructDefinition

相关结构:

public enum StructureKind {
STRUCTURE, // 普通
STRUCTURE_WITH_SUBTYPED_VALUES, // 含子类型
STRUCTURE_WITH_OPTIONAL_FIELDS, // 含可选 (前置 EncodingMask)
UNION, // Union (前置 selector)
UNION_WITH_SUBTYPED_VALUES // Union + 子类型
}

代码示例

import com.darra.opcua.*;

try (DarraOpcUa ua = new DarraOpcUa("opc.tcp://localhost:4840")) {
ua.connect();

StructDecoder dec = new StructDecoder(ua);

// 1) 读自定义结构
try (DataValue dv = ua.read("ns=2;s=Robot.CurrentPose")) {
DynamicExtensionObject pose = dec.decode(dv.value);
System.out.println("x = " + pose.get("X"));
System.out.println("y = " + pose.get("Y"));

// 2) 全字段遍历
for (var e : pose.fields().entrySet())
System.out.println(e.getKey() + " = " + e.getValue());

// 3) 嵌套
DynamicExtensionObject quat = (DynamicExtensionObject) pose.get("Quaternion");
System.out.println("qw = " + quat.get("W"));

// 4) 数组字段
Object[] arr = (Object[]) pose.get("JointAngles");
for (Object a : arr) System.out.println(a);
}

// 5) 预热
dec.prefetchDefinitions(List.of("ns=2;i=3001", "ns=2;i=3002"));
}

实现限制

  • Native 层未导出 ExtensionObject 字节提取接口, decode(Variant) 在拿不到字节时返回带 _status 字段的部分结果
  • 协议层全部已实现, native 接通后 decodeBody(bytes, typeId) 立刻可用
  • DiagnosticInfo 跳过

最佳实践

  • 共享一个 decoder, 字段表缓存复用
  • prefetchDefinitions 启动时调
  • 嵌套结构 cast 后访问
  • Union 看 selector

跨语言对照

C#PythonJavaC++RustC
StructDecoderStructDecoderStructDecoderStructDecoderStructDecoderDarraUa_StructDecoder
DecodedecodedecodeDecodedecodeDarraUa_StructDecoder_Decode

下一步