我最近完成了一个项目,我使用了"对象钩子#34;在Python中检测JSON密钥是否与另一个密钥重复。普通的JSON解码器似乎只是给出了遇到的最后一个值,但我希望能够检测并返回错误。我的新项目(在新公司)是在golang中编写这个,所以想知道是否有类似于Python对象钩子的方法。我还使用了一个不同的对象钩子来获得一个"有序的dict"在Python中;本质上是JSON输入的列表形式,保留了原始JSON的顺序。 Haven还没有在golang中承担过这项任务,但我打赌它会来......不管怎样,输入这些JSON功能中的任何一个都与golang有关!
答案 0 :(得分:1)
你需要的是一个像bufio.Scanner
或SAX一样工作的json库。一个是在这里实现的:github.com/garyburd/json。它会在扫描时生成事件,您可以使用它来发现重复的密钥。
以下是如何使用它的示例:
package main
import (
"fmt"
"github.com/garyburd/json"
"io"
"strings"
)
type Nothing struct{}
type Context struct {
Kind json.Kind
Keys map[string]Nothing
}
func Validate(rdr io.Reader) error {
scanner := json.NewScanner(rdr)
stack := []Context{}
for scanner.Scan() {
if scanner.Kind() == json.Object || scanner.Kind() == json.Array {
stack = append(stack, Context{
Kind: scanner.Kind(),
Keys: map[string]Nothing{},
})
} else if scanner.Kind() == json.End {
if len(stack) == 0 {
return fmt.Errorf("expected start object or array")
}
stack = stack[:len(stack)-1]
} else if len(stack) > 0 {
current := stack[len(stack)-1]
if current.Kind == json.Object {
key := string(scanner.Name())
_, exists := current.Keys[key]
if exists {
return fmt.Errorf("found duplicate key: %v", key)
}
current.Keys[key] = Nothing{}
}
}
}
return nil
}
func main() {
rdr := strings.NewReader(`
{
"x": 10,
"y": {
"z": 1,
"z": 2
},
"z": [1,2,3,4,5]
}
`)
err := Validate(rdr)
if err == nil {
fmt.Println("valid json!")
} else {
fmt.Println("invalid json:", err)
}
}
当它遍历JSON对象时,它构建了一堆哈希表。 (对于嵌套对象/数组)其中一个哈希表中的任何重复键都会导致错误。如果您需要更多详细信息,可以轻松地向Name
添加Context
属性,然后向后移动堆栈以生成json路径。 (如a.b.c.d is a duplicate key
)