2017-07-01 4 views
2

Je tente de créer une carte de chaînes à partir d'un JSON avec un nombre indéfini de valeurs-clés non identifiées.créer une carte de chaîne à partir d'un JSON avec des valeurs-clés inconnues dans Go

Voici mon exemple fichier JSON:

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

Je veux créer une map[string]string avec une valeur comme ceci:

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

Pour analyser un JSON avec "github.com/jmoiron/jsonq" avec des valeurs connues, est assez facile, mais dans ce cas, localhost peut être n'importe quoi et tag peut être n'importe quoi d'autre.

Mon point d'entrée dans mon code Go est comme ceci:

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

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

    return configKeyStr 

} 

Toute aide sera vraiment apprécier.

Merci!

Répondre

2

Facile à faire. Simplement convertir.

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) 
} 

MISE À JOUR

Wrote aplatissez (fonctionne peut-être que le charme)

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)) 
} 
+0

Merci beaucoup, ça marche mais pas exactement ce que je veux, Comment puis-je avoir une carte comme ceci: https://pastebin.com/6EJX01D6 –

+0

'mm' est votre prévu? – mattn

+1

Je pense qu'il veut * aplatir la carte *, c'est-à-dire que la clé JSON est combinée * récursivement * avec "-" comme séparateur. – putu

1

Vous ne pouvez pas avoir automatiquement, mais vous pouvez aller sur les cartes « internes », et combiner la partie extérieure touches avec les clés internes utilisant la concaténation de chaîne simple (opérateur +). En outre, il est recommandé de démélanger directement dans une valeur de map[string]map[string]string de sorte que vous n'avez pas besoin d'utiliser des assertions de type. Pas besoin d'utiliser de bibliothèques externes pour cela, le paquet standard encoding/json est parfaitement suffisant pour cela.

Exemple:

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) 

sortie est comme prévu (l'essayer sur le Go Playground):

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

Merci beaucoup, c'est parfait! –

0

Depuis la question que vous avez mentionné nombre indéfini de valeurs-clés inconnues, vous pouvez besoin de traiter un document JSON avec un nombre inconnu de niveaux d'imbrication et ayant une valeur autre que string. Dans ce cas, vous devez Unmarshal json à map[string]interface{}, puis utiliser la récursivité pour faire plat carte. Une fois que le document JSON unmrashaled à map[string]interface{}, utilisez la fonction suivante:

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) 
     } 
    } 
} 

La solution de travail adaptée de réponse mattn à https://play.golang.org/p/9SQsbAUFdY

Comme indiqué par mattn, vous pouvez avoir des problèmes quand vous voulez écriture différée de la valeur de configuration . Dans ce cas, utilisez la bibliothèque/infrastructure existante.