Go 基于Token解析JSON

Go的标准包encoding/json提供了解析JSON的方法,我已在另一篇博文Go操作JSON介绍了高级用法,这里介绍基于Token的低级解析方法。json.Decoder提供了Token方法,用来返回JSON串中的每一个Token。Token包括:json.Delim,基本类型(bool,float64,Number,string)和nil。其中json.Delim包括[ ] { }。每一次调用Token()方法都会返回以上Token中的一个。下例基于Token解析JSON并将解析结果格式化打印:

package main

import (
    "bytes"
    "container/list"
    "encoding/json"
    "fmt"
    "io"
    "os"
)

func main() {
    str := `{"took": 596,
    "timed_out": false,
    "_shards": {
        "total": 11,
        "successful": 11,
        "failed": 0
    }}`

    // 构建Decoder
    reader := bytes.NewReader([]byte(str))
    dec := json.NewDecoder(reader)

    const (
        obj = iota
        arr
    )
    curType := -1
    const (
        mapKey = iota
        mapValue
        arrEle
    )
    curEle := -1
    indent := ""
    const sep = "    "
    const newline = "\n"
    stack := list.New()
    setEleType := func() {
        switch curType {
        case obj:
            curEle = mapKey
        case arr:
            curEle = arrEle
        }
    }
    for {
        tok, err := dec.Token() // 返回待处理的下一个Token
        if err == io.EOF {
            break
        } else if err != nil {
            os.Exit(1)
        }

        switch tok := tok.(type) {  // 根据Token的类型,做相应处理
        case json.Delim:
            switch tok {
            case '{':
                stack.PushBack(obj)
                curType = obj
                setEleType()
                fmt.Printf("%s%s{%s", newline, indent, newline)
                indent += sep
            case '}':
                stack.Remove(stack.Back())
                if stack.Len() > 0 {
                    curType = stack.Back().Value.(int)
                    setEleType()
                }
                indent = indent[:len(indent)-len(sep)]
                fmt.Printf("%s%s}%s", newline, indent, newline)
            case '[':
                stack.PushBack(arr)
                curType = arr
                setEleType()
                fmt.Printf("%s%s[%s", newline, indent, newline)
                indent += sep
            case ']':
                stack.Remove(stack.Back())
                if stack.Len() > 0 {
                    curType = stack.Back().Value.(int)
                    setEleType()
                }
                indent = indent[:len(indent)-len(sep)]
                fmt.Printf("%s%s]%s", newline, indent, newline)
            }
        default:
            switch curType {
            case obj:
                switch curEle {
                case mapKey:
                    fmt.Printf("%s", indent)
                    fmt.Print(tok)
                    fmt.Printf(": ")
                    curEle = mapValue
                case mapValue:
                    fmt.Print(tok)
                    fmt.Printf(",%s", newline)
                    curEle = mapKey
                }
            case arr:
                switch curEle {
                case arrEle:
                    fmt.Printf("%s", indent)
                    fmt.Print(tok)
                    fmt.Printf(",%s", newline)
                }
            }
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值