创建Go Json解析器:包括电池
这篇文章的灵感来自一个正在进行的项目。 我正在构建一个需要比较两个Json对象的服务。 问题是我需要能够替换键 , 过滤出路径并将比较功能应用于特定节点。
显然,标准库比较功能(例如reflect.DeepEqual()
将无法工作。 ????
解决方案是在Json对象的基础上构建AST ( 抽象语法树 )。 树中的每个Node
都表示一个string
, integer
, array
或object
。
通过这样做,我将具有灵活性,可以更轻松地将算法应用于数据。
为了构建它,我们将从Lexer开始以生成令牌 。 然后转到解析器 ,它将获取令牌并将其与Json语法匹配。 最后,我们将添加AST挂钩来生成树。
最终目录结构:
.
main.go
/lexer
lexer.go
lexer_test.go
/token
token.go
/parser
parser.go
/ast
ast.go
如果要查看并运行最终结果:
cd $GOPATH/src/github.com/Lebonesco
git clone https://github.com/Lebonesco/json_parser.git
go run main.go ./examples/test.json
Lexer
词法分析器的工作是获取json数据并将其转换为tokens
流。 这些令牌包括: INVALID
, EOF
, COMMA
, COLON
, LBRACE
, RBRACE
, LBRACKET
, RBRACKET
, STRING
和INTEGER
。
注意:词法分析器也称为扫描仪。
让我们从????开始
cd $GOPATH/src/github.com/Lebonesco/json_parser
mkdir token
cd token
touch token.go
您可以自由定义tokens
。 您添加到token
的数据越多,调试起来就越容易。
注意:我们将使用rune
数组[]rune
来存储token
文字,以允许使用Unicode字符。
接下来,让我们进入我们的lexer
????
mkdir lexer
cd lexer
touch lexer.go
touch lexer_test.go
lexer
将跟踪我们在输入中的位置,并向前看必要的字符。
在功能方面,它将需要能够创建一个新token
并在下一个token
之前达到峰值。
注意:此扫描仪不支持布尔值,但可以轻松添加它们。
Lexer测试
在这里,我们将接收一个子字符串,并确保它输出正确的令牌流。
要运行测试:
go test -v
=== RUN TestLexer
--- PASS: TestLexer (0.00s)
PASS
ok github.com/Lebonesco/json_parser/lexer 0.433s
您现在有一个工作的词法分析器
解析器
这是我们获取流并将其与json语法匹配以生成AST节点的部分。
如果我们要用正则表达式定义json ,它将由下面定义的语法表示
JSON : value
Value : Object | Array | String | Integer | Bool | Null
Array : '[' [Value] {',' Value}']'
Object : '{' [Property] {',' Property} '}'
Property : String ':' Value
在以上语法中, [expression]
表示表达式出现一次或多次,而{expression}
表示{expression}
出现零次或多次。
如果您提供正则表达式,则有类似gocc
工具将生成词法分析器和/或解析器。 如果您要处理更复杂的事情,这是推荐的方法。
但是由于Json非常简单,我们将手工完成! ????
让我们构造代表最终结果的AST nodes
。
mkdir ast
cd ast
touch ast.go
nodes
相当简单。 如果像我们的用例一样,我们更关心错误处理和跟踪node
哈希,则可以存储更多数据。
注意:因为Go使用composition
而不是inheritance
我们需要对每个node
类型应用TokenLiteral()
方法,以便将每个类型解释为Json
节点。
现在进入解析器!
让我们将它们放在一起并编写驱动程序main.go
注意: json.MarshalIndent()
可以很好地替代json.Marshal()
以获得更漂亮的json输出。
跑步:
go run main.go ./exampes/test.json
全部完成????
现在我们可以生成AST,可以轻松地向每个节点添加滚动哈希并执行所有其他自定义操作,例如:
- 替代节点值
- 滤除节点
- 将特殊比较功能应用于节点
我将那些扩展留给读者。 随意在评论中删除指向您工作的链接。 我很想看看你的想法。 ????
感谢您抽出宝贵的时间阅读本文。
如果您觉得它有用或有趣,请告诉我me。
From: https://hackernoon.com/create-a-go-json-parser-batteries-included-9d02d09fe508