马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?站点注册
×
本帖最后由 pbai 于 2026-8-14 09:22 编辑
PBIDEA:用 uo_json 的 set/get 与路径语法操作 JSON
做接口对接、配置文件、前端数据交换时,绕不开 JSON。PBIDEA 的 uo_json 把「建树、取值、改值」压成两个动作:set 和 get,再用一套 /items/0/text 的路径语法直接定位到数组里的任意一层。本文只讲清楚一件事:怎么用 set/get 配合路径语法,读写一棵带数组的 JSON,且中途自动建树、不会踩空。
一、核心结论先放这儿
- set(key, value):键不存在就自动创建,支持嵌套路径,先 set 父再 set 子也行,顺序随意。
- get(key, ref value):返回 boolean 表示是否取到,第二参是输出。取不到不会报错崩溃。
- 路径语法:"a/b/c" 走对象,"a/0/b" 走数组第 0 个元素(0 基)。数组下标用数字即可。
- 数字默认当 double 存,get 到 long/int 会自动转;要当字符串保留位数用 GetString。
二、最小可运行示例
下面这段代码不依赖任何业务,粘进按钮的 clicked 事件就能跑。它构造了一个带 items 数组的对象,再原样读回来:
- uo_json js
- js = create uo_json
- // 1) 顶层字段:set 自动建树,先写谁都行
- js.set("name", "小明")
- js.set("age", 32) // 数字按 double 存
- js.set("vip", true) // 布尔
- // 2) 数组 + 路径语法:/items/0/text 表示 items 数组第 0 项的 text 字段
- js.set("/items/0/text", "搜索")
- js.set("/items/0/icon", "search.svg")
- js.set("/items/1/text", "设置")
- js.set("/items/1/icon", "gear.svg")
- // 3) 取回——get 返回 boolean,取不到时变量保持原值,可给默认值
- string ls_name, ls_first, ls_icon
- if js.get("name", ls_name) then
- // 成功
- end if
- js.get("/items/0/text", ls_first) // -> "搜索"
- js.get("/items/1/icon", ls_icon) // -> "gear.svg"
- // 4) 数字:get 到 long 自动转;想拿字符串用 GetString
- long ll_age
- js.get("age", ll_age) // -> 32
- string ls_age
- ls_age = js.GetString("age") // -> "32"
- // 5) 数组长度 & 遍历
- long ll_cnt, i
- ll_cnt = js.ArrCount("items") // -> 2
- string ls_t
- for i = 0 to ll_cnt - 1
- js.get("/items/" + string(i) + "/text", ls_t)
- // 依次得到 "搜索"、"设置"
- next
- // 6) 导出
- string ls_out
- ls_out = js.ToString(true, false, false) // 美化输出,不转 unicode
- destroy js
复制代码
三、set 的几个易混点
set 的第二个参数类型
set 是重载的,第二参可以是 string / number(int,long,double,decimal...) / boolean / blob / uo_json / 数组。传 blob 时默认走 BASE64 编码(常量 SetBlob=1);想存原始字节序用 SetBytes=2 形式(带第三个参数 SetType)。日常配置基本只用 string/number/boolean。
路径里数组下标从 0 开始
这是最容易写错的地方。/items/1/text 是第 2 个元素。下标写错不会报错,只是 get 返回 false、取不到值——所以取数组前先用 ArrCount 确认长度,别硬取。
想直接塞一整个数组
可以用数组形式一次 set:
- string ls_tags[] = {"pb", "ide", "json"}
- js.set("tags", ls_tags) // tags 变成 ["pb","ide","json"]
- long n
- n = js.ArrCount("tags") // -> 3
复制代码
四、从字符串 / 文件反向解析
接口返回的报文、本地配置文件,都是「先有字符串,再解析成对象」:
- uo_json j2
- j2 = create uo_json
- // 解析内存字符串
- if j2.Parse('{"code":0,"msg":"ok","data":["a","b"]}') then
- long ll_code
- j2.get("code", ll_code) // -> 0
- end if
- // 解析文件(中文路径注意编码)
- if j2.ParseFile("menu_cn.json") then
- // 后续同样用 get / 路径语法
- end if
- // 转成 UTF-8 BLOB,直接交给 uo_httpclient 发出去
- blob b_body = j2.ToUTF8()
- destroy j2
复制代码
Parse 还有 Parse(str, removeEscape)、Parse(str, removeEscape, NumAsString) 等重载:网络报文常带转义,removeEscape=true 可顺手清掉;NumAsString=true 让所有数字以字符串形式保留(避免 1.0 变 1、丢精度)。
五、改值、删值、清空
- js.Replace("name", "小红") // 替换已存在的节点
- js.Remove("/items/0") // 删除数组第 0 项(后面的下标会自动前移)
- js.Remove("vip") // 删除顶层字段
- js.Clear() // 清空整棵对象
复制代码
注意 Remove("/items/0") 删的是数组项,删掉后原第 1 项变成新的第 0 项——遍历时别用「先算长度再固定下标」的写法去删,会越界或漏删。
六、什么时候用便利方法
字段多、类型杂时,用 GetString / GetLong / GetDouble / GetLongLong 比 get(..., ref) 少写一行类型声明:
- string s
- long l
- double d
- s = js.GetString("name", "") // 带默认值,取不到返回 ""
- l = js.GetLong("age")
- d = js.GetDouble("score")
复制代码
GetKeys(ref keys[]) 能拿出全部顶层 key(含类型),做「通用遍历 / 不确定结构」时很实用。
七、小结
记住一条主线就够用:create uo_json → set(路径, 值) 建树 → get(路径, ref 变量) 取值(先判返回值)→ ToString/ToUTF8 导出。路径语法 /a/0/b 让「数组里套对象、对象里再套数组」的深层结构,也能一行定位。下一篇我们接着看怎么用它组装 HTTP 请求体发出去。
|