Golang - 检测JSON输入中的重复键

时间:2015-01-13 16:37:43

标签: python json go

我最近完成了一个项目,我使用了"对象钩子#34;在Python中检测JSON密钥是否与另一个密钥重复。普通的JSON解码器似乎只是给出了遇到的最后一个值,但我希望能够检测并返回错误。我的新项目(在新公司)是在golang中编写这个,所以想知道是否有类似于Python对象钩子的方法。我还使用了一个不同的对象钩子来获得一个"有序的dict"在Python中;本质上是JSON输入的列表形式,保留了原始JSON的顺序。 Haven还没有在golang中承担过这项任务,但我打赌它会来......不管怎样,输入这些JSON功能中的任何一个都与golang有关!

1 个答案:

答案 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

相关问题