Use URI path to get or set data
npm install jsonuriEnglish | 简体中文
一个轻量级、强大的 JSON 对象操作工具库,使用 linux 路径风格表达式来访问和修改嵌套的 JSON 数据,能快速访问数据的上级结构。





``bash`
npm i jsonuri或 pnpm add jsonuri / yarn add jsonuri
使用方式:
`ts
// 推荐按需导入(便于 tree-shaking)
import {
get,
set,
rm,
insert,
mv,
swap,
up,
down,
normalizeUri,
parseUri,
parent,
parents,
isCircular,
walk,
walkTopDownDFS,
walkTopDownBFS,
walkBottomUpDFS,
walkBottomUpBFS,
} from 'jsonuri'
// 或整体导入
import * as jsonuri from 'jsonuri'
`
---
- 分隔符:/(如 menu/popup/menuitem/0/value).
- 当前层:;父级:..\/
- 转义斜杠:在键名内使用 ,如 a\/b/c 解析为段 ["a/b", "c"]get
- 数组快捷段(仅 中解析,且要求当前值为数组):@first
- (首元素)@last
- 或 @length-1(末元素)@length-N
- (倒数第 N 个,N ≥ 0 且整数)
- 简单键 与 复杂路径 的判定:
传入的 path 若是不含 / 的字符串或非负整数索引,则按“简单键/索引”处理;否则按“复杂路径”解析。
> 若路径解析过程中父级超出根(例如过多的 ..),解析将判定为非法并返回空结果。
---
`json`
{
"menu": {
"id": 123,
"list": [0, 1, 2, 3, 4],
"popup": {
"menuitem": [
{ "value": "New", "onclick": "CreateNewDoc()" },
{ "value": "Open", "onclick": "OpenDoc()" },
{ "value": "Close", "onclick": "CloseDoc()" }
]
}
}
}
以下示例假设变量 data 为上面 JSON。
---
按路径读取值。
`ts`
get(data, 'menu/id') // 123
get(data, 'menu/popup/menuitem/0/value') // "New"
get(data, 'menu/popup/menuitem/0/value/..') // { value: "New", onclick: "CreateNewDoc()" }
get(data, 'menu/popup/menuitem/@last/value') // "Close"
get([10, 11, 12], '@length-2') // 11
get(data, '/') // 整个 data
> 若中途遇到 null/undefined,直接返回该值;非法路径返回 undefined。
---
按路径写入。中间缺失层会被创建为对象。
对数组会使用 splice 写入;写入键名为 length 时会裁剪/扩展数组长度。
`ts
set(data, 'menu/id', 789)
get(data, 'menu/id') // 789
set(data, 'menu/list/7', 999) // 自动扩容至索引 7
get(data, 'menu/list') // [0,1,2,3,4, undefined, undefined, 999]
// 直接改 length(简单键)
const arr = [0, 1, 2, 3]
set(arr, 'length', 2)
arr // [0,1]
`
> 保护键名:__proto__ / prototype / constructor 会被跳过(不会创建/写入)。
---
按路径删除值/项(对象用 delete,数组用 splice)。
`ts
rm(data, 'menu/id')
get(data, 'menu/id') // undefined
rm(data, 'menu/list/1')
get(data, 'menu/list') // [0,2,3,4]
`
---
仅对数组 生效:在 path 所指索引之前/之后插入一个元素。direction 仅支持 'before' | 'after'。
`ts
// 在第 0 项之前插入 9999
insert(data, 'menu/list/0', 9999, 'before') // [9999,0,1,2,3,4]
// 在第 2 项之后插入 -1
insert(data, 'menu/list/2', -1, 'after') // [9999,0,1,2,-1,3,4]
`
> 若索引 < 0 或 > length 会抛出 “Index Out of Bounds”。'inside'
> 源码中出现了 分支,但仅打印 TODO;不提供该能力。'append'
> 文本常量包含 字样,但实现未支持 'append'。
---
移动节点。常见用法为数组元素跨/同层级移动到目标索引前后。
`ts
set(data, 'menu/list', [0, 1, 2, 3, 4])
mv(data, 'menu/list/0', 'menu/list/3') // 默认 'before'
get(data, 'menu/list') // [1,2,3,0,4]
set(data, 'menu/list', [0, 1, 2, 3, 4])
mv(data, 'menu/list/0', 'menu/list/3', 'before')
get(data, 'menu/list') // [1,2,0,3,4]
`
当 toPath 指向的父容器为数组以外的对象/值时:
- 若 get(data, toPath) 不是对象/函数,将抛错(primitive values)。fromPath
- 否则会把 对应的值放到新路径 toPath + '/' + fromPath 下,然后删除 fromPath。fromPath
(这是源码的实际行为,注意新键名/嵌套可能包含 的多段。)
---
交换两个路径的值(不存在的源会记录错误并保持原值)。
`ts`
set(data, 'menu/list', [0, 1, 2, 3, 4])
swap(data, 'menu/list/0', 'menu/list/4')
get(data, 'menu/list') // [4,1,2,3,0]
---
将数组中某个元素上移/下移 step 步;越界将被钳制到边界。
`ts
set(data, 'menu/list', [0, 1, 2, 3, 4])
up(data, 'menu/list/3') // 上移 1
get(data, 'menu/list') // [0,1,3,2,4]
down(data, 'menu/list/1', 2) // 下移 2
get(data, 'menu/list') // [0,3,2,1,4]
`
---
组合并规范化路径片段(处理 .、.. 和数组/嵌套传参)。
`ts`
normalizeUri('a', 'b') // 'a/b'
normalizeUri(['a', 'b', '../'], 'c') // 'a/c'
相关辅助:
- parseUri(input) → 返回段数组(含转义与 .. 处理)parent(path)
- → 返回父路径或 nullparents(path)
- → 返回从近到远所有父路径(不含自身),如 a/b/c → ['a/b','a']
---
所有遍历回调签名一致:(value, key, parent, { uri, stop }) => any | Promise
- walk / walkTopDownDFS(同实现)
自顶向下 DFS-先序;不会在根节点调用回调,只对根的子节点及以下调用。
- walkTopDownBFS
自顶向下 BFS-先序;会在根节点调用回调。
- walkBottomUpDFS
自底向上 DFS-后序;会在根节点调用回调(最后)。
- walkBottomUpBFS
先按 BFS 收集,再自底向上回调;会在根节点调用回调(最后)。
示例(DFS-先序):
`ts`
await walk({ a: { a1: 'x' } }, (val, key, parent, { uri, stop }) => {
// 回调不会在根 {a:{a1:'x'}} 触发
// 第一次:val={a1:'x'}, key='a', uri='a'
// 第二次:val='x', key='a1', uri='a/a1'
if (uri === 'a/a1') stop() // 可中止后续遍历
})
> 若输入对象存在循环引用,四种遍历都会在开始前抛出错误。可先用 isCircular(obj) 预检。
---
检测循环引用。
`ts
isCircular({}) // false
const a: any = {}
set(a, '/b/c', a)
isCircular(a) // true
`
---
- 非法路径或容器类型不匹配(如对非数组执行 insert/up/down)会抛错或静默返回。insert
- 索引越界抛出 “the Index Out of Bounds”。set(arr, 'length', n)
- 要求 n 为非负整数,否则抛出 “value: n is not a natural number”。mv
- 到非对象目标且 toPath 指向原始类型时抛错(primitive values)。__proto__
- 写入时会跳过键名 / prototype / constructor`。
---
MIT