2012-11-13 3 views
12

Solange ich Schlüssel-Wert-Paare haben unmarshalling ist ziemlich geradlinig, aber wie würde ich eine Reihe von verschiedenen Arten in unterschiedlicher Reihenfolge entordnen? Die einzelnen Elemente sind gut definiert und bekannt, aber die Reihenfolge ist nicht.Wie kann man ein Array von verschiedenen Typen korrekt entfernen?

Ich kann nicht mit einer schönen Lösung.

Würde ich versuchen, Fehler über alle Elemente? Gibt es eine Art Unionstyp, der das für mich tun könnte?

playground version

package main 

import (
    "encoding/json" 
    "fmt" 
) 

var my_json string = `{ 
    "an_array":[ 
     "with_a string", 
     { 
      "and":"some_more", 
      "different":["nested", "types"] 
     } 
    ] 
}` 

type MyInner struct { 
    And  string 
    Different []string 
} 

type MyJSON struct { 
    An_array []json.RawMessage 
} 

func main() { 
    var my_json_test MyJSON 

    e := json.Unmarshal([]byte(my_json), &my_json_test) 
    if e != nil { 
     fmt.Println(e) 
    } else { 
     for index, value := range my_json_test.An_array { 
      fmt.Println("index: ", index) 
      fmt.Println("value: ", string(value)) 
     } 
     var my_inner MyInner 
     err := json.Unmarshal(my_json_test.An_array[1], &my_inner) 
     if err != nil { 
      fmt.Println(err) 
     } else { 
      fmt.Println("inner structure: ", my_inner) 
     } 
    } 
} 

Antwort

21

Zum offiziellen Blog einen schönen Artikel über encoding/json hat: JSON and GO. Es ist möglich, "beliebige Daten zu dekodieren" in eine Schnittstelle {} und type assertion zu verwenden, um den Typ dynamisch zu bestimmen.

Ihr Code kann wahrscheinlich dazu geändert werden:

package main 

import (
    "encoding/json" 
    "fmt" 
) 

var my_json string = `{ 
    "an_array":[ 
    "with_a string", 
    { 
     "and":"some_more", 
     "different":["nested", "types"] 
    } 
    ] 
}` 

func WTHisThisJSON(f interface{}) { 
    switch vf := f.(type) { 
    case map[string]interface{}: 
     fmt.Println("is a map:") 
     for k, v := range vf { 
      switch vv := v.(type) { 
      case string: 
       fmt.Printf("%v: is string - %q\n", k, vv) 
      case int: 
       fmt.Printf("%v: is int - %q\n", k, vv) 
      default: 
       fmt.Printf("%v: ", k) 
       WTHisThisJSON(v) 
      } 

     } 
    case []interface{}: 
     fmt.Println("is an array:") 
     for k, v := range vf { 
      switch vv := v.(type) { 
      case string: 
       fmt.Printf("%v: is string - %q\n", k, vv) 
      case int: 
       fmt.Printf("%v: is int - %q\n", k, vv) 
      default: 
       fmt.Printf("%v: ", k) 
       WTHisThisJSON(v) 
      } 

     } 
    } 
} 

func main() { 

    fmt.Println("JSON:\n", my_json, "\n") 

    var f interface{} 
    err := json.Unmarshal([]byte(my_json), &f) 
    if err != nil { 
     fmt.Println(err) 
    } else { 
     fmt.Printf("JSON: ") 
     WTHisThisJSON(f) 
    } 
} 

Es gibt Ausgang wie folgt:

JSON: 
{ 
    "an_array":[ 
    "with_a string", 
    { 
     "and":"some_more", 
     "different":["nested", "types"] 
    } 
    ] 
} 

JSON: is a map: 
an_array: is an array: 
0: is string - "with_a string" 
1: is a map: 
and: is string - "some_more" 
different: is an array: 
0: is string - "nested" 
1: is string - "types" 

Es ist noch nicht vollständig, aber zeigt, wie es wird funktionieren.

+0

Genau das, was ich suchte. –

+1

Das fehlende Teil auf meiner Seite war [Typ Zusicherung] (http://golang.org/ref/spec#Type_assertions) –