Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Golang-检测JSON输入中的重复键_Python_Json_Go - Fatal编程技术网

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

Python Golang-检测JSON输入中的重复键,python,json,go,Python,Json,Go,我最近完成了一个项目,在该项目中,我使用Python中的“对象挂钩”来检测JSON键是否是另一个键的副本。普通的JSON解码器似乎只给出遇到的最后一个值,但我希望能够检测并返回一个错误。我的新项目(在新公司)是用golang编写的,所以我想知道是否有类似于Python的对象钩子的方法。我还使用了另一个对象钩子来获得Python中的“有序dict”;本质上是JSON输入的列表形式,保留了原始JSON的顺序。在golang还没有被派去做这件事,但我打赌它会来的。。。。无论如何,对于与golang相关

我最近完成了一个项目,在该项目中,我使用Python中的“对象挂钩”来检测JSON键是否是另一个键的副本。普通的JSON解码器似乎只给出遇到的最后一个值,但我希望能够检测并返回一个错误。我的新项目(在新公司)是用golang编写的,所以我想知道是否有类似于Python的对象钩子的方法。我还使用了另一个对象钩子来获得Python中的“有序dict”;本质上是JSON输入的列表形式,保留了原始JSON的顺序。在golang还没有被派去做这件事,但我打赌它会来的。。。。无论如何,对于与golang相关的这些JSON功能的输入,我们表示赞赏

您需要的是一个json库,它的工作原理类似于
bufio.Scanner
或SAX。一个是在这里实现的:。它将在扫描时生成事件,您可以使用这些事件来发现重复的密钥

下面是一个如何使用它的示例:

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对象时,它会构建一个哈希表堆栈。(对于嵌套对象/数组)其中一个哈希表中的任何重复键都会导致错误。如果需要更多详细信息,可以轻松地将
名称
属性添加到
上下文
中,并向后遍历堆栈以生成json路径。(如
a.b.c.d是一个重复的键

json中的重复键不是有效的json。是吗?Go中的JSON解码器允许通过
解组器接口进行自定义反序列化。您可以使用这个接口来支持Python的
json
库中的对象钩子机制@fabrizioM是正确的,但由于手动生成或手动编辑,有时会显示无效的JSON。我使用的Python JSON包默默地忽略了重复的键;如果您解码这个伪json:a:1、b:2、a:3,它将为您提供b:2、a:3作为输出-最后一个键值胜过先前的值。我更希望它在这个问题上出错,而不是默默地失败。看起来JSON扫描程序的github repo已经不存在了。