2016-11-22 3 views
3
Services: 
- Orders: 
    - ID: $save ID1 
     SupplierOrderCode: $SupplierOrderCode 
    - ID: $save ID2 
     SupplierOrderCode: 111111 

Ich möchte diese yaml Zeichenfolge json konvertieren, führen die Quelldaten dynamisch ist, so kann ich es nicht auf eine Struktur Karte:Convert yaml zu json ohne Struktur (Golang)

var body interface{} 
err := yaml.Unmarshal([]byte(s), &body) 

dann möchte ich noch einmal, dass die Schnittstelle zu jSON-String konvertieren:

b, _ := json.Marshal(body) 

Aber ein Fehler auftreten:

panic: json: unsupported type: map[interface {}]interface {} 
+0

create body var wie folgt: 'body: = make (map [string] schnittstelle {})' –

Antwort

11

Vorwort: Ich optimierte und verbesserte die folgende Lösung und veröffentlichte sie als Bibliothek hier: github.com/icza/dyno. Die folgende Funktion ist als dyno.ConvertMapI2MapS() verfügbar.


Das Problem ist, dass wenn Sie den allgemeinste interface{} Typen verwenden, um in entpacken, der Standardtyp des github.com/go-yaml/yaml Paket verwendete Schlüssel-Wert-Paare entpacken wird map[interface{}]interface{} sein.

Erste Idee wäre map[string]interface{} zu verwenden:

var body map[string]interface{} 

Aber dieser Versuch fällt kurz, wenn die Tiefe der yaml Config mehr als eins ist, da dies body Karte zusätzliche Karten, deren Typ wieder enthalten map[interface{}]interface{} sein .

Das Problem ist, dass die Tiefe unbekannt ist, und es möglicherweise andere Werte als Karten gibt, so dass die Verwendung ist nicht gut.

Ein gangbarer Weg ist yaml Abstellungs in einen Wert vom Typ interface{} zu lassen und das Ergebnis durch rekursiv und konvertieren jedes map[interface{}]interface{} zu einem map[string]interface{} Wert angetroffen. Beide Karten und Slices müssen behandelt werden.

Hier ist ein Beispiel für diese Wandlerfunktion:

func convert(i interface{}) interface{} { 
    switch x := i.(type) { 
    case map[interface{}]interface{}: 
     m2 := map[string]interface{}{} 
     for k, v := range x { 
      m2[k.(string)] = convert(v) 
     } 
     return m2 
    case []interface{}: 
     for i, v := range x { 
      x[i] = convert(v) 
     } 
    } 
    return i 
} 

Und es mit:

func main() { 
    fmt.Printf("Input: %s\n", s) 
    var body interface{} 
    if err := yaml.Unmarshal([]byte(s), &body); err != nil { 
     panic(err) 
    } 

    body = convert(body) 

    if b, err := json.Marshal(body); err != nil { 
     panic(err) 
    } else { 
     fmt.Printf("Output: %s\n", b) 
    } 
} 

const s = `Services: 
- Orders: 
    - ID: $save ID1 
     SupplierOrderCode: $SupplierOrderCode 
    - ID: $save ID2 
     SupplierOrderCode: 111111 
` 

Ausgang:

Input: Services: 
- Orders: 
    - ID: $save ID1 
     SupplierOrderCode: $SupplierOrderCode 
    - ID: $save ID2 
     SupplierOrderCode: 111111 

Output: {"Services":[{"Orders":[ 
    {"ID":"$save ID1","SupplierOrderCode":"$SupplierOrderCode"}, 
    {"ID":"$save ID2","SupplierOrderCode":111111}]}]} 

Eine Sache zu beachten: von von yaml zu JSON Schalt Über Go-Maps verlieren Sie die Reihenfolge der Elemente, da Elemente (Schlüssel/Wert-Paare) in einer Go-Map nicht geordnet sind. Dies kann oder kann kein Problem sein.

+0

Vielen Dank Icza, du bist so nett: D – huynhminhtuan

0

https://github.com/ghodss/yaml ist "ein Wrapper um go-yaml entworfen, um eine bessere Art der Handhabung von YAML beim Marshalling zu und von Strukturen zu ermöglichen". Unter anderem bietet es yaml.YAMLToJSON Methode, die tun sollte, was Sie wollen.