TranslateBrowsePaths (C)
TranslateBrowsePathsToNodeIds 服务: 输入 起始节点 + 相对路径数组 (如 "/2:Boilers/1:Drum/Level"), 输出每个路径解析后的 NodeId 字符串. 比客户端循环 Browse 快得多 (单 RPC).
前置阅读
- 想链式探索建议用 Browse 单层浏览.
- 100+ 路径批量初始化必用本 API.
API
DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_TranslateBrowsePaths(
DarraUa_SessionHandle h,
const char* const* starting_node_ids,
const char* const* browse_paths,
uint32_t count,
char*** out_node_ids, /* 出参 */
DarraUa_Status* out_status_per_path); /* 出参, 调用方分配 count 个 */
| 参数 | 说明 |
|---|---|
starting_node_ids | 每个路径的起点 NodeId 字符串数组 (长度 = count) |
browse_paths | 路径数组, 段间用 / 分 (长度 = count) |
count | 路径数量 |
out_node_ids | 出参: char** 数组, 每项是解析到的 NodeId 字符串 (NULL = 失败) |
out_status_per_path | 出参: 每项 StatusCode |
释放
out_node_ids 数组与每个非 NULL 字符串都由 Stack malloc:
if (node_ids) {
for (uint32_t i = 0; i < count; ++i) {
if (node_ids[i]) DarraUa_Free(node_ids[i]);
}
DarraUa_Free(node_ids);
}
路径段语法
| 段格式 | 含义 |
|---|---|
BrowseName | namespace 0 |
2:BrowseName | namespace 2 |
/A/B/C | 起点不含, 直接以 / 起 |
例子:
| BrowsePath | 含义 |
|---|---|
/Server | ns=0 下子节点 Server |
/2:Boiler1 | ns=2 下子节点 Boiler1 |
/Server/2:Boilers/2:Boiler1/2:Temperature | 多层组合 |
/2:Boilers/1:Drum/Level 表示从起点出发, 先到 ns=2;Boilers, 再到 ns=1;Drum, 再到 Level (ns=0).
完整示例
#include <darra_opcua/darra_opcua.h>
#include <stdio.h>
int main(int argc, char** argv)
{
const char* endpoint = (argc >= 2) ? argv[1] : "opc.tcp://localhost:4840";
DarraUa_Initialize();
DarraUa_SessionConfig cfg;
DarraUa_SessionConfig_Init(&cfg);
cfg.endpoint_url = endpoint;
cfg.security_policy_uri = "http://opcfoundation.org/UA/SecurityPolicy#None";
DarraUa_SessionHandle h = DARRA_UA_INVALID_SESSION_HANDLE;
DarraUa_Session_Create(&cfg, &h);
DarraUa_Session_Connect(h);
/* 4 个路径 */
const char* starts[] = {
"i=85", "i=85", "ns=2;s=Boiler1", "ns=2;s=Boiler1",
};
const char* paths[] = {
"/Server/ServerStatus/CurrentTime",
"/Server/ServerStatus/State",
"/Temperature",
"/Pressure",
};
uint32_t count = 4;
char** node_ids = NULL;
DarraUa_Status results[4] = { 0 };
DarraUa_Status st = DarraUa_Session_TranslateBrowsePaths(
h, starts, paths, count, &node_ids, results);
if (!DARRA_UA_STATUS_IS_GOOD(st)) {
fprintf(stderr, "TranslateBrowsePaths failed: 0x%08X (%s)\n",
(unsigned)st, DarraUa_StatusName(st));
} else {
for (uint32_t i = 0; i < count; ++i) {
printf("[%u] %-50s -> ", i, paths[i]);
if (DARRA_UA_STATUS_IS_GOOD(results[i]) && node_ids && node_ids[i])
printf("%s\n", node_ids[i]);
else
printf("FAILED (%s)\n", DarraUa_StatusName(results[i]));
}
}
/* 释放 */
if (node_ids) {
for (uint32_t i = 0; i < count; ++i) {
if (node_ids[i]) DarraUa_Free(node_ids[i]);
}
DarraUa_Free(node_ids);
}
DarraUa_Session_Disconnect(h);
DarraUa_Session_Close(h);
DarraUa_Shutdown();
return 0;
}
与 ResolveBrowsePath 的对比
| 函数 | 实现方式 | 性能 | 用途 |
|---|---|---|---|
DarraUa_Session_TranslateBrowsePaths | 服务端原生 (OPC UA 服务) | 快, 单 RPC, 批量 | 生产 |
DarraUa_Session_ResolveBrowsePath | 客户端循环 Browse 爬 | 慢, N 次 RPC, 单条 | Server 不支持 TranslateBrowsePaths 时, 或仅一条 |
ResolveBrowsePath:
DARRA_OPCUA_API int32_t DARRA_OPCUA_CALL DarraUa_Session_ResolveBrowsePath(
DarraUa_SessionHandle h,
const char* start_node_id,
const char* path,
char* out_node_id,
int32_t out_buf_size);
| 参数 | 说明 |
|---|---|
out_node_id | 调用方提供的 buffer |
out_buf_size | buffer 字节数 |
返回值: 解析到的 NodeId 字符串长度 (含 NUL); ≤ 0 表示失败.
char buf[128];
int32_t n = DarraUa_Session_ResolveBrowsePath(
h, "i=85",
"/Server/ServerStatus/CurrentTime",
buf, (int32_t)sizeof(buf));
if (n > 0) printf("Resolved -> %s\n", buf);
错误码 (per path)
| StatusCode | 含义 |
|---|---|
Good | 解析成功 |
BadNoMatch | 路径段在树上找不到 |
BadBrowseNameInvalid | 段语法错 |
BadNodeIdUnknown | 起点不存在 |
最佳实践
- 业务启动时一次性把所有需要的"配置路径" 翻成 NodeId 缓存起来, 后续直接用 NodeId 读写
- 不要每次读 / 写都重新 Translate, 浪费 RPC
- 超大路径列表分批 (建议每批 ≤ 100), 防止服务端拒绝
BadTooManyOperations(0x80100000=DARRA_UA_STATUS_BAD_TOO_MANY_OPERATIONS)