如何从 stdin 中解析无限 json 数组?
How to parse an infinite json array from stdin in go?
我正在尝试为 i3status 编写一个小的替代品,这是一个与符合 this 协议的 i3bar 通信的小程序。他们通过标准输入和标准输出交换消息。
双向流是 json 个对象的无限数组。从 i3bar 到 i3status(我想替换)的流的开头如下所示:
[
{"name": "some_name_1","instance": "some_inst_1","button": 1,"x": 213,"y": 35}
,{"name": "some_name_1","instance": "some_inst_2","button": 2,"x": 687,"y": 354}
,{"name": "some_name_2","instance": "some_inst","button": 1,"x": 786,"y": 637}
,{"name": "some_name_3","instance": "some_inst","button": 3,"x": 768,"y": 67}
...
这是一个 "array" 代表点击的对象。阵列永远不会关闭。
我现在的问题是:正确的解析方法是什么?
显然我不能使用 json
库,因为这不是一个有效的 json 对象。
您正在寻找的是 JSON 的流式传输 API。有许多可用的快速 Google 搜索显示 this 项目确实将流媒体列为其高级功能之一。
编写一个自定义 reader 函数(或解码器),它执行如下 "streaming array parse":
- 读取并丢弃前导空格。
- 如果下一个字符不是
[
则 return 错误(不能是数组)。
- 虽然是真的:
- 调用
json.Decoder.Decode
进入"next"项目。
- 生产或加工 "next" 项。
- 读取并丢弃空格。
- 如果下一个字符是:
- 一个逗号
,
然后继续#3中的for循环。
- 一个右括号
]
然后退出 #3 中的 for 循环。
- 否则return一个错误(无效的数组语法)。
我也在为 i3 中的点击事件编写自己的处理程序。这就是我偶然发现这个线程的方式。
Golang 标准库确实完全满足要求 (Golang 1.12)。不确定您是否问过这个问题?
// json parser read from stdin
decoder := json.NewDecoder(os.Stdin)
// Get he first token - it should be a '['
tk, err := decoder.Token()
if err != nil {
fmt.Fprintln(os.Stderr, "couldn't read from stdin")
return
}
// according to the docs a json.Delim is one [, ], { or }
// Make sure the token is a delim
delim, ok := tk.(json.Delim)
if !ok {
fmt.Fprintln(os.Stderr, "first token not a delim")
return
}
// Make sure the value of the delim is '['
if delim != json.Delim('[') {
fmt.Fprintln(os.Stderr, "first token not a [")
return
}
// The parser took the [ above
// therefore decoder.More() will return
// true until a closing ] is seen - i.e never
for decoder.More() {
// make a Click struct with the relevant json structure tags
click := &Click{}
// This will block until we have a complete JSON object
// on stdin
err = decoder.Decode(click)
if err != nil {
fmt.Fprintln(os.Stderr, "couldn't decode click")
return
}
// Do something with click event
}
我正在尝试为 i3status 编写一个小的替代品,这是一个与符合 this 协议的 i3bar 通信的小程序。他们通过标准输入和标准输出交换消息。
双向流是 json 个对象的无限数组。从 i3bar 到 i3status(我想替换)的流的开头如下所示:
[
{"name": "some_name_1","instance": "some_inst_1","button": 1,"x": 213,"y": 35}
,{"name": "some_name_1","instance": "some_inst_2","button": 2,"x": 687,"y": 354}
,{"name": "some_name_2","instance": "some_inst","button": 1,"x": 786,"y": 637}
,{"name": "some_name_3","instance": "some_inst","button": 3,"x": 768,"y": 67}
...
这是一个 "array" 代表点击的对象。阵列永远不会关闭。
我现在的问题是:正确的解析方法是什么?
显然我不能使用 json
库,因为这不是一个有效的 json 对象。
您正在寻找的是 JSON 的流式传输 API。有许多可用的快速 Google 搜索显示 this 项目确实将流媒体列为其高级功能之一。
编写一个自定义 reader 函数(或解码器),它执行如下 "streaming array parse":
- 读取并丢弃前导空格。
- 如果下一个字符不是
[
则 return 错误(不能是数组)。 - 虽然是真的:
- 调用
json.Decoder.Decode
进入"next"项目。 - 生产或加工 "next" 项。
- 读取并丢弃空格。
- 如果下一个字符是:
- 一个逗号
,
然后继续#3中的for循环。 - 一个右括号
]
然后退出 #3 中的 for 循环。 - 否则return一个错误(无效的数组语法)。
- 一个逗号
- 调用
我也在为 i3 中的点击事件编写自己的处理程序。这就是我偶然发现这个线程的方式。
Golang 标准库确实完全满足要求 (Golang 1.12)。不确定您是否问过这个问题?
// json parser read from stdin
decoder := json.NewDecoder(os.Stdin)
// Get he first token - it should be a '['
tk, err := decoder.Token()
if err != nil {
fmt.Fprintln(os.Stderr, "couldn't read from stdin")
return
}
// according to the docs a json.Delim is one [, ], { or }
// Make sure the token is a delim
delim, ok := tk.(json.Delim)
if !ok {
fmt.Fprintln(os.Stderr, "first token not a delim")
return
}
// Make sure the value of the delim is '['
if delim != json.Delim('[') {
fmt.Fprintln(os.Stderr, "first token not a [")
return
}
// The parser took the [ above
// therefore decoder.More() will return
// true until a closing ] is seen - i.e never
for decoder.More() {
// make a Click struct with the relevant json structure tags
click := &Click{}
// This will block until we have a complete JSON object
// on stdin
err = decoder.Decode(click)
if err != nil {
fmt.Fprintln(os.Stderr, "couldn't decode click")
return
}
// Do something with click event
}