跳到主要内容

Browse

s.browse(node_id, filter) — 列出指定节点的直接子节点 (一层).

前置阅读 / 配套

签名

pub fn Session::browse(&self, node_id: &str, filter: NodeClass)
-> Result<Vec<Reference>, OpcUaError>;

pub fn Session::browse_many(&self, node_ids: &[&str], filter: NodeClass)
-> Result<Vec<Vec<Reference>>, OpcUaError>;

Reference 字段

pub struct Reference {
pub node_id: String,
pub browse_name: String, // 含 NamespaceIndex 前缀, 如 "2:Temperature"
pub display_name: String,
pub node_class: NodeClass,
}

例子

use darra_opcua::NodeClass;

// 列出 Boiler1 下所有子节点
let children = s.browse("ns=2;s=Boiler1", NodeClass::Unspecified)?;
for c in &children {
println!(" {:?} {} -> {}", c.node_class, c.browse_name, c.node_id);
}

// 只看 Variable 类型
let vars = s.browse("ns=2;s=Boiler1", NodeClass::Variable)?;

// 只看 Method
let methods = s.browse("ns=2;s=Calculator", NodeClass::Method)?;

批量浏览 (browse_many)

如果同时要浏览多个节点 (例如 GUI 初次展开树), 用 browse_many 一次 RPC:

let roots = ["i=85", "i=86"];   // Objects + Types
let results = s.browse_many(&roots, NodeClass::Unspecified)?;
for (root, children) in roots.iter().zip(results.iter()) {
println!("{}:", root);
for c in children {
println!(" {}", c.browse_name);
}
}

如果某个节点浏览失败 (NodeId 错), 对应槽位返回空 Vec, 不返回 Err.


NodeClass filter

pub enum NodeClass {
Unspecified = 0,
Object = 1,
Variable = 2,
Method = 4,
ObjectType = 8,
VariableType = 16,
ReferenceType = 32,
DataType = 64,
View = 128,
}
包含
Unspecified全部
Object仅 Object
Variable仅 Variable
Method仅 Method

当前 SDK 只支持单一 NodeClass filter (不支持按位或组合); 要多 class 请走 Unspecified 拿全部再客户端过滤.


错误

OpcUaError 携带:

  • BAD_NODE_ID_UNKNOWN — 节点不存在
  • BAD_COMMUNICATION_ERROR — 网络故障
  • DARRA_INVALID_ARGUMENT — node_id 含 NUL

transport 失败返回 Err, 单个子节点解析失败不返回 Err.

大节点的分页 (ContinuationPoint)

如果一个节点有 1000+ 个子节点, 单次 browse 服务端可能截断. 此时 browse 只返回第一页.

要看全部, 用 BrowseWithPaging + BrowseNext:

let mut page = s.browse_with_paging("ns=2;s=BigFolder", NodeClass::Unspecified)?;
let mut all_refs = page.references.clone();
while let Some(cp) = page.continuation_point.take() {
if cp.is_empty() { break; }
page = s.browse_next(&cp, false)?;
all_refs.extend(page.references.iter().cloned());
}

或一行式:

let all = s.browse_all("ns=2;s=BigFolder", NodeClass::Unspecified, 100)?;

Reference → Node 转换

for r in s.browse("ns=2;s=Boiler1", NodeClass::Variable)? {
let node = r.to_node(&s); // 转可操作 Node
let dv = node.value()?;
println!("{} = {:?}", r.display_name, dv.variant());
}

性能

  • 单次 Browse: ~5-15 ms (网络往返 + 服务端遍历)
  • browse_many 批量: 总耗时 ≈ 单次 (省 N-1 次往返)
  • 1000+ 子节点会分页, 用 browse_all / browse_next 处理

下一步