go基础库之从不完整的JSON数组中提取数据

本文将讲解一个实例,你的程序从不可靠的源中使用JSON,而JSON包含一个对象数组,这些对象具有开始标记[但数组中的项目数非常大,并且JSON的结尾可能被破坏。

从不完整的JSON数组中提取数据

Golang 版本

1.12.1

前沿

本文将讲解一个实例,你的程序从不可靠的源中使用JSON,而JSON包含一个对象数组,这些对象具有开始标记[但数组中的项目数非常大,并且JSON的结尾可能被破坏。

实现

package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

const js = `
          [
            {
              "name":"Axel",
              "lastname":"Fooley"
            },
            {
              "name":"Tim",
              "lastname":"Burton"
            },
            {
              "name":"Tim",
              "lastname":"Burton"
        `

type User struct {
	Name string `json:"name"`
	LastName string `json:"lastname"`
}

func main() {

	userSlice := make([]User, 0)
	r := strings.NewReader(js)
	dec := json.NewDecoder(r)
	for {
		tok, err := dec.Token()
		if err != nil {
			break
		}
		if tok == nil {
			break
		}
		switch tp := tok.(type) {
		case json.Delim:
			str := tp.String()
			if str == "[" || str == "{" {
				for dec.More() {
					u := User{}
					err := dec.Decode(&u)
					if err == nil {
						userSlice = append(userSlice, u)
					} else {
						break
					}
				}
			}
		}
	}

	fmt.Println(userSlice)
}
$go run main.go
[{Axel Fooley} {Tim Burton}]

原理

除了Unmarshall函数,json包还包含Decoder API。 使用NewDecoder,可以创建Decoder 。 通过在解码器上调用Token方法,读取底层Reader并返回Token接口。 这可能包含多个值。

其中一个是Delim类型,它是一个包含{[]}字符之一的rune。 基于此,检测到JSON数组的开头。 利用解码器上的More方法,可以检测到更多要解码的对象。