【问题标题】:golang json unstructured datagolang json 非结构化数据
【发布时间】:2021-06-19 09:25:48
【问题描述】:

我有一个 json(非结构化)并且想从 json 数据中检索每个键 然后循环遍历键和值。如果值是 json(嵌套)或数组类型,则继续。

我找到了结构化 json 解析的示例,但无法获取。 检查了此代码,但无法获得完整的代码

err := json.Unmarshal([]byte(input), &customers)

示例 json:

{
    "components": [
        {
            "key": "d1",
            "components": [
                {
                    "key": "custname",
                    "value": "Abraham",
                    "input": true,
                    "tableView": true
                },
                {
                    "key": "type",
                    "type": "radio",
                    "label": "Fisrt",
                    "values": [
                        {
                            "label": "Sole",
                            "value": "sole",
                            "shortcut": ""
                        },
                        {
                            "label": "Bata",
                            "value": "Bata",
                            "shortcut": ""
                        }
                    ],
                    "validate": {
                        "required": true
                    },
                    "tableView": false
                },
                {
                    "key": "registeredField",
                    "value": "reg 111",
                    "input": true,
                },
                {
                    "key": "dirc",
                    "value": "abraham",
                },
                {
                    "key": "gst",
                    "value": "textfield",                   
                    "useLocaleSettings": false
                },
                {
                    "key": "pan",
                    "value": "AAAAA0000",                    
                    "useLocaleSettings": false
                }
            ],
            "collapsible": false
        }
    ]
}

预期输出:

Key: custname Value: Abraham
Key: type Value: {
    "label": "Sole",
    "value": "sole",
    "shortcut": ""
}, {
    "label": "Bata",
    "value": "Bata",
    "shortcut": ""
}
Key: registeredField Value: reg 111

【问题讨论】:

  • 编辑问题以显示变量customers的类型、您尝试过的代码以及遇到的问题。
  • ...请同时包含“非结构化 json”的示例。
  • ... 以及来自“非结构化 json”的预期结果。
  • Go 中 JSON 解组的每个方面都已在 SO 上得到解答。
  • 预期输出不是 JSON 或 Go 值。目前尚不清楚您的要求是什么。

标签: arrays json go


【解决方案1】:

所以你有一个带有components 键的对象,它是一个组件切片。这些组件中的每一个都可以有许多键。首先要做的是评估一个组件可以拥有的所有可能的字段,并使用这些字段定义一个类型:

type Validation struct {
    Required bool `json:"required"`
}

type Value struct {
    Label    string `json:"label"`
    Value    string `json:"value"`
    Shortcut string `json:"shortcut"`
}

type Data struct {
    Components        []Data      `json:"components,omitempty"`
    Collapsable       bool        `json:"collapsable"`
    Input             bool        `json:"input"`
    Key               string      `json:"key"`
    TableView         bool        `json:"tableView"`
    Type              string      `json:"type"`
    Value             string      `json:"value"`
    UseLocaleSettings bool        `json:"useLocaleSettings"`
    Values            []Value     `json:"values,omitempty"`
    Validate          *Validation `json:"validate,omitempty"`
}

现在您只需将输入解组为 Data 类型:

data := Data{}
if err := json.Unmarshal([]byte(input), &data); err != nil {
    // handle error
    fmt.Printf("Oops, something went wrong: %+v", err)
    return
}

此时,我们已经将所有数据都放在了一个结构体中,因此我们可以开始将其全部打印出来。我们注意到的第一件事是Data 基本上包含Data 类型的切片。将其全部打印出来的递归函数是有意义的:

func PrintComponents(data []Data) {
    for _, c := range data {
        if len(c.Components) > 0 {
            PrintComponents(c.Components) // recursive
            continue                      // skip value of this component, remove this line if needed
        }
        val := c.Value // assign string value
        if len(c.Values) > 0 {
            // this component has a slice of values, not a single value
            vals, err := json.MarshalIndent(c.Values, "", "    ") // marshal with indent of 4 spaces, no prefix
            if err != nil {
                fmt.Printf("Oops, looks like we couldn't format something: %+v\n", err)
                return // handle this
            }
            val = string(vals) // marshalled values as string
        }
        fmt.Printf("Key: %s Value: %s\n", c.Key, val) // print output
    }
}

你可以稍微改变这个函数,为每一级递归传递一个缩进参数,这样你就可以打印出缩进块中的组件:

func PrintComponents(data []Data, indent string) {
    for _, c := range data {
        if len(c.Components) > 0 {
            // print the key for this block of components
            fmt.Printf("Component block: %s\n", c.Key)
            PrintComponents(data, indent + "    ") // current indent + 4 spaces
            continue // we're done with this component
        }
        val := c.Value
        if len(c.Values) > 0 {
            vals, _ := json.MarshalIndent(c.Values, indent, "    ") // pass in indent level here, and DON'T ignore the error, that's just for brevity
            val = string(vals)
        }
        fmt.Printf("%sKey: %s Value: %s\n", indent, c.Key, val) // pass in indent
    }
}

综合起来,我们得到this

func main() {
    data := Data{}
    if err := json.Unmarshal(input, &data); err != nil {
        fmt.Println(err.Error())
        return
    }
    fmt.Println("Printing with simple recursive function")
    // print all components, these could be nested, so let's use a recursive function
    PrintComponents(data.Components)
    fmt.Println("\n\nPrinting with indented recursion:")
    PrintComponentsIndent(data.Components, "") // start with indent of 0
}

func PrintComponents(data []Data) {
    for _, c := range data {
        if len(c.Components) > 0 {
            PrintComponents(c.Components) // recursive
            continue                      // skip value of this component, remove this line if needed
        }
        val := c.Value // assign string value
        if len(c.Values) > 0 {
            // this component has a slice of values, not a single value
            vals, err := json.MarshalIndent(c.Values, "", "    ") // marshal with indent of 4 spaces, no prefix
            if err != nil {
                fmt.Printf("Oops, looks like we couldn't format something: %+v\n", err)
                return // handle this
            }
            val = string(vals) // marshalled values as string
        }
        fmt.Printf("Key: %s Value: %s\n", c.Key, val) // print output
    }

}

func PrintComponentsIndent(data []Data, indent string) {
    for _, c := range data {
        if len(c.Components) > 0 {
            fmt.Printf("%sComponent block: %s\n", indent, c.Key)
            PrintComponentsIndent(c.Components, indent + "    ")
            continue
        }
        val := c.Value
        if len(c.Values) > 0 {
            // this component has a slice of values, not a single value
            vals, _ := json.MarshalIndent(c.Values, indent, "    ")
            val = string(vals) // marshalled values as string
        }
        fmt.Printf("%sKey: %s Value: %s\n", indent, c.Key, val) // print output
    }

}

哪些输出:

Printing with simple recursive function
Key: custname Value: Abraham
Key: type Value: [
    {
        "label": "Sole",
        "value": "sole",
        "shortcut": ""
    },
    {
        "label": "Bata",
        "value": "Bata",
        "shortcut": ""
    }
]
Key: registeredField Value: reg 111
Key: dirc Value: abraham
Key: gst Value: textfield
Key: pan Value: AAAAA0000


Printing with indented recursion:
Component block: d1
    Key: custname Value: Abraham
    Key: type Value: [
        {
            "label": "Sole",
            "value": "sole",
            "shortcut": ""
        },
        {
            "label": "Bata",
            "value": "Bata",
            "shortcut": ""
        }
    ]
    Key: registeredField Value: reg 111
    Key: dirc Value: abraham
    Key: gst Value: textfield
    Key: pan Value: AAAAA0000

您想要的输出不包括值切片的方括号。嗯,这是一件很容易摆脱的事情。方括号始终是字符串的第一个和最后一个字符,json.Marshal 返回一个字节切片 ([]byte)。删除第一个和最后一个字符很简单:

val = string(vals[1:len(vals)-2])

获取json.Marshal返回的字节切片的一个子切片,从偏移量1开始(剪切偏移量0,即[),并保留所有内容直到倒数第二个字符(偏移量len(vals)-2) .对于缩进的示例,这将给您留下一个空白行,其中包含未知数量的空格(缩进)。您可以使用 strings 包修剪字符串的右侧:

// remove square brackets, trim trailing new-line and spaces
val = strings.TrimRight(string(vals[1:len(vals)-2]), "\n ")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-10
    • 2015-10-09
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多