簡體   English   中英

在Go中使用具有未知鍵值的JSON從JSON創建字符串映射

[英]create a map of string from a JSON with unknow key-values in Go

我嘗試使用未定義數量的未知鍵值從JSON創建字符串映射。

這是我的示例JSON文件:

{
         "localhost":
        {
                "tag": "dev_latest",
                "vhost": "localhost.com"
        },
        "development":
        {
                "tag": "dev_latest",
                "vhost": "dev.com"
        }
}

我想創建一個map[string]string ,其值如下:

config := map[string]string{
    "localhost-tag":      "dev_latest",
    "localhost-vhost": "localhost.com,
    "development-tag":   "dev_latest,
    ...
}

用已知值的"github.com/jmoiron/jsonq"解析JSON是很容易的,但是在這種情況下, localhost可以是任何東西,而tag可以是任何其他東西。

我在Go代碼中的入口點是這樣的:

func ParseJson(){
    configPath := GetConfigPath()
    b, err := ioutil.ReadFile(configPath) 

     //  Here, I need to create my map of strings..

    return configKeyStr

}

任何幫助將不勝感激。

謝謝!

容易做。 簡單地轉換。

package main

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

const s = `
{
         "localhost":
        {
                "tag": "dev_latest",
                "vhost": "localhost.com"
        },
        "development":
        {
                "tag": "dev_latest",
                "vhost": "dev.com"
        }
}
`

func main() {
    var m map[string]interface{}
    err := json.Unmarshal([]byte(s), &m)
    if err != nil {
        log.Fatal(err)
    }
    mm := make(map[string]string)
    for k, v := range m {
        mm[k] = fmt.Sprint(v)
    }
    fmt.Println(mm)
}

UPDATE

寫扁平化(也許可以作為魅力)

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "reflect"
)

const s = `
{
         "localhost":
        {
                "tag": "dev_latest",
                "vhost": "localhost.com"
        },
        "development":
        {
                "tag": "dev_latest",
                "vhost": "dev.com"
        }
}
`

func flatten(m map[string]interface{}) map[string]string {
    mm := make(map[string]string)
    for k, v := range m {
        switch reflect.TypeOf(v).Kind() {
        case reflect.Map:
            mv := flatten(v.(map[string]interface{}))
            for kk, vv := range mv {
                mm[k+"-"+kk] = vv
            }
        case reflect.Array, reflect.Slice:
            for kk, vv := range m {
                if reflect.TypeOf(vv).Kind() == reflect.Map {
                    mv := flatten(vv.(map[string]interface{}))
                    for kkk, vvv := range mv {
                        mm[k+"-"+kkk] = vvv
                    }
                } else {
                    mm[k+"-"+kk] = fmt.Sprint(vv)
                }
            }
        default:
            mm[k] = fmt.Sprint(v)
        }
    }
    return mm
}

func main() {
    var m map[string]interface{}
    err := json.Unmarshal([]byte(s), &m)
    if err != nil {
        log.Fatal(err)
    }
    b, _ := json.MarshalIndent(flatten(m), "", "  ")
    println(string(b))
}

您不能自動使用此功能,但是可以在“內部”映射上進行調整,並使用簡單的字符串連接( +運算符)將外部鍵與內部鍵組合在一起。 另外,建議直接解組為map[string]map[string]string的值,這樣就不必使用類型斷言。 同樣,也不需要為此使用任何外部庫,為此,標准的encoding/json包就足夠了。

例:

var mm map[string]map[string]string
if err := json.Unmarshal([]byte(src), &mm); err != nil {
    panic(err)
}
config := map[string]string{}
for mk, m := range mm {
    for k, v := range m {
        config[mk+"-"+k] = v
    }
}
fmt.Println(config)

輸出是預期的(在Go Playground上嘗試):

map[localhost-tag:dev_latest localhost-vhost:localhost.com
    development-tag:dev_latest development-vhost:dev.com]

由於在問題中您提到了不確定數量的未知鍵值 ,因此您可能需要處理嵌套數量未知且具有string以外的值的JSON文檔。 在這種情況下,您需要Unmarshal json到map[string]interface{} ,然后使用遞歸制作平面地圖。 將json文檔完整地map[string]interface{}map[string]interface{} ,請使用以下功能:

func flatMap(src map[string]interface{}, baseKey, sep string, dest map[string]string) {
    for key, val := range src {
        if len(baseKey) != 0 {
            key = baseKey + sep + key
        }
        switch val := val.(type) {
        case map[string]interface{}:
            flatMap(val, key, sep, dest)
        case string:
            dest[key] = val
        case fmt.Stringer:
            dest[key] = val.String()
        default:
            //TODO: You may need to handle ARRAY/SLICE

            //simply convert to string using `Sprintf`
            //NOTE: modify as needed.
            dest[key] = fmt.Sprintf("%v", val)
        }
    }
}

工作解決方案改編自https://play.golang.org/p/9SQsbAUFdY上的 mattn答案

正如mattn指出的那樣,當您想回寫配置值時可能會遇到問題。 在這種情況下,請使用現有的庫/框架。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM