So verarbeiten Sie JSON-Daten in der Go-Sprache

Freigeben: 2020-01-11 17:14:07
nach vorne
11568 Leute haben es durchsucht

So verarbeiten Sie JSON-Daten in der Go-Sprache

Go JSON-Paket

Marshal(): Go-Datenobjekt -> >UnMarshal(): Json-Daten-> Go-Datenobjekt

JSON-Daten erstellen

Die Funktionen Marshal() und MarshalIndent() können Kapseln Sie die Daten in JSON-Daten.

1. Struktur, Slice, Array, Karte können alle in JSON konvertiert werden

2. Bei der Konvertierung von Struktur in JSON wird nur der erste Buchstabe des Feldes konvertiert

3. Beim Konvertieren der Karte muss der Schlüssel eine Zeichenfolge sein

4 Wenn es sich bei der Kapselung um einen Zeiger handelt, wird das Objekt, auf das der Zeiger zeigt, verfolgt und gekapselt

Zum Beispiel:

Es gibt eine Strukturstruktur:

func Marshal(v interface{}) ([]byte, error)
func Unmarshal(data []byte, v interface{}) error
Nach dem Login kopieren

Diese Struktur stellt die Art des Blogartikels dar, einschließlich Artikel-ID, Artikelinhalt und den einreichenden Autor des Artikels. Dazu gibt es nichts zu sagen, das Einzige, was angegeben werden muss, ist: Es handelt sich um eine Struktur, und die Struktur kann in JSON-Daten gekapselt (codiert) werden.

Um diese Strukturdaten in JSON zu konvertieren, verwenden Sie einfach Marshal(). Wie folgt:

type Post struct {
    Id      int
    Content string
    Author  string
}
Nach dem Login kopieren

Marshal() gibt einen []Byte-Typ zurück. Jetzt hat die Variable b einen Teil der JSON-Daten vom Typ []Byte gespeichert, der ausgegeben werden kann:

post := &Post{1, "Hello World", "userA"}
b, err := json.Marshal(post)
if err != nil {
    fmt.Println(nil)
}
Nach dem Login kopieren

Ergebnis:

fmt.Println(string(b))
Nach dem Login kopieren

kann „verschönert“ werden, wenn es in JSON gekapselt wird. Verwenden Sie MarshalIndent(), um automatisch ein Präfix (die Präfixzeichenfolge ist im Allgemeinen auf leer gesetzt) ​​und einen Einzug hinzuzufügen:

{"Id":1,"Content":"Hello World","Author":"userA"}
Nach dem Login kopieren

Ergebnis:

c,err := json.MarshalIndent(post,"","\t")
if err != nil {
    fmt.Println(nil)
}
fmt.Println(string(c))
Nach dem Login kopieren

Zusätzlich zu Struktur-, Array-, Slice- und Map-Strukturen können diese in JSON geparst werden. Wenn Map jedoch in JSON geparst wird, darf der Schlüssel nur eine Zeichenfolge sein, was für die JSON-Syntax erforderlich ist.

Zum Beispiel:

{
    "Id": 1,
    "Content": "Hello World",
    "Author": "userA"
}
Nach dem Login kopieren

Rückgabeergebnis:

// slice -> json
s := []string{"a", "b", "c"}
d, _ := json.MarshalIndent(s, "", "\t")
fmt.Println(string(d))

// map -> json
m := map[string]string{
    "a":"aa",
    "b":"bb",
    "c":"cc",
}
e,_ := json.MarshalIndent(m,"","\t")
fmt.Println(string(e))
Nach dem Login kopieren

Verwenden Sie das Struktur-Tag, um beim Erstellen von JSON zu helfen

struct Bei den Feldern, die konvertiert werden können, handelt es sich um alle Felder, deren Anfangsbuchstaben großgeschrieben werden. Wenn Sie jedoch in JSON Schlüssel verwenden möchten, die mit Kleinbuchstaben beginnen, können Sie das Tag von struct verwenden, um die Reflexion zu unterstützen.

Zum Beispiel fügt die Post-Struktur ein Feld createAt mit einem kleingeschriebenen Anfangsbuchstaben hinzu.

[
    "a",
    "b",
    "c"
]
{
    "a": "aa",
    "b": "bb",
    "c": "cc"
}
Nach dem Login kopieren

Ergebnis:

type Post struct {
    Id      int      `json:"ID"`
    Content string   `json:"content"`
    Author  string   `json:"author"`
    Label   []string `json:"label"`
}


postp := &Post{
    2,
    "Hello World",
    "userB",
    []string{"linux", "shell"},
    }

p, _ := json.MarshalIndent(postp, "", "\t")
fmt.Println(string(p))
Nach dem Login kopieren

Bei der Verwendung des Struktur-Tags sind einige Punkte zu beachten:

1. Der im Tag identifizierte Name wird als Wert des Schlüssels bezeichnet die JSON-Daten

2. Das Tag kann auf „json:“-““ gesetzt werden, um anzugeben, dass dieses Feld nicht in JSON-Daten konvertiert wird, auch wenn der erste Buchstabe des Feldnamens großgeschrieben wird

Wenn Sie möchten, dass der Name des JSON-Schlüssels ein Zeichen „-“ ist, können Sie „json:“-,“ speziell behandeln, d. h. ein Komma hinzufügen

3. Wenn das Tag enthält Wenn der Wert dieses Felds 0 ist, also falsch, 0, „“, Null usw., wird dieses Feld nicht in JSON konvertiert

4. Wenn der Feldtyp ist bool, string, int class, float class, und das Tag enthält, string option, dann wird der Wert dieses Feldes in einen JSON-String konvertiert

Zum Beispiel:

{
    "ID": 2,
    "content": "Hello World",
    "author": "userB",
    "label": [
        "linux",
        "shell"
    ]
}
Nach dem Login kopieren

Parsen Sie die JSON-Daten in eine Struktur (die Struktur ist bekannt)

JSON-Daten können in eine Struktur oder eine leere Schnittstelle interface{} analysiert werden (es können auch Slice, Map usw. sein). .). Nachdem Sie die Tag-Regeln beim Erstellen von JSON oben verstanden haben, ist es sehr einfach, JSON zu verstehen und zu analysieren.

Das Folgende ist beispielsweise ein JSON-Datenelement:

type Post struct {
    Id      int      `json:"ID,string"`
    Content string   `json:"content"`
    Author  string   `json:"author"`
    Label   []string `json:"label,omitempty"`
}
Nach dem Login kopieren

Analysieren Sie dieses JSON-Datenelement:

1. Die geschweiften Klammern der obersten Ebene stellen ein anonymes Objekt dar. Angenommen, der Name dieser Struktur ist Post

2. Die Felder in den geschweiften Klammern sind alle Felder in der Post-Struktur , ihre Anfangsbuchstaben müssen alle groß geschrieben sein und Tags müssen gleichzeitig festgelegt werden. Der Name im Tag ist kleingeschrieben

3. Autor ist ein Unterobjekt, das einer anderen Struktur in Go zugeordnet ist . Der Name dieses Feldes in Post ist Autor. Unter der Annahme, dass der Name mit dem Strukturnamen übereinstimmt, ist es auch Autor

4. Label ist ein Array, das in Go einem Slice oder Array zugeordnet werden kann . Und da das JSON-Array leer ist, kann es sich bei dem Typ des Slice/Array um eine Variable handeln, oder es kann sich um ein Interface{} handeln string

5. nextPost ist ein Unterobjekt, das einer Struktur in Go zugeordnet ist. Da dieses Objekt in JSON jedoch null ist, bedeutet dies, dass dieses Objekt nicht existiert, daher ist der Typ der Struktur in Go zugeordnet kann nicht bestimmt werden. Aber für das Beispiel hier gibt es keinen nächsten Artikel, daher sollte sein Typ auch Beitragstyp

6 sein. Kommentar ist ein Unterobjekt und von einem Array umgeben. Es ist Go zugeordnet und ein Slice /array, der Typ des Slice/Arrays ist eine Struktur

Nach der Analyse ist es einfach, die Struktur und das Tag der Struktur entsprechend zu erstellen. Das Folgende ist die Datenstruktur, die auf der Grundlage der obigen Analyse erstellt wurde:

{
    "id": 1,
    "content": "hello world",
    "author": {
        "id": 2,
        "name": "userA"
    },
    "published": true,
    "label": [],
    "nextPost": null,
    "comments": [{
            "id": 3,
            "content": "good post1",
            "author": "userB"
        },
        {
            "id": 4,
            "content": "good post2",
            "author": "userC"
        }
    ]
}
Nach dem Login kopieren

Beachten Sie, dass Zeiger, wie bereits bei der Einführung in die Konstruktion von JSON-Daten erläutert, verfolgt werden, sodass in der Struktur keine Zeigertypen verwendet werden müssen hier abgeleitet problematisch.

Parsen Sie also die oben genannten JSON-Daten in ein Objekt vom Typ „Post“, vorausgesetzt, dass diese JSON-Daten in einer.json-Datei gespeichert sind. Der Code lautet wie folgt:

type Post struct {
    ID        int64         `json:"id"`       
    Content   string        `json:"content"`  
    Author    Author        `json:"author"`   
    Published bool          `json:"published"`
    Label     []string      `json:"label"`    
    NextPost  *Post         `json:"nextPost"` 
    Comments  []*Comment    `json:"comments"` 
}

type Author struct {
    ID   int64  `json:"id"`  
    Name string `json:"name"`
}

type Comment struct {
    ID      int64  `json:"id"`     
    Content string `json:"content"`
    Author  string `json:"author"` 
}
Nach dem Login kopieren

Ausgabeergebnis:

{1 hello world {2 userA} true [] <nil> [0xc042072300 0xc0420723c0]}
Nach dem Login kopieren

也许你已经感受到了,从json数据反推算struct到底有多复杂,虽然逻辑不难,但如果数据复杂一点,这是件非常恶心的事情。所以,使用别人写好的工具来自动转换吧。本文后面有推荐json到数据结构的自动转换工具。

解析json到interface(结构未知)

上面是已知json数据结构的解析方式,如果json结构是未知的或者结构可能会发生改变的情况,则解析到struct是不合理的。这时可以解析到空接口interface{}或map[string]interface{}类型上,这两种类型的结果是完全一致的。

解析到interface{}上时,Go类型和JSON类型的对应关系如下

  JSON类型             Go类型                
---------------------------------------------
JSON objects    <-->  map[string]interface{} 
JSON arrays     <-->  []interface{}          
JSON booleans   <-->  bool                   
JSON numbers    <-->  float64                
JSON strings    <-->  string                 
JSON null       <-->  nil
Nach dem Login kopieren

例如:

func main() {
    // 读取json文件
    fh, err := os.Open("a.json")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer fh.Close()
    jsonData, err := ioutil.ReadAll(fh)
    if err != nil {
        fmt.Println(err)
        return
    }
    
    // 定义空接口接收解析后的json数据
    var unknown interface{}
    // 或:map[string]interface{} 结果是完全一样的
    err = json.Unmarshal(jsonData, &unknown)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(unknown)
}
Nach dem Login kopieren

输出结果:

map[nextPost:<nil> comments:[map[id:3 content:good post1
author:userB] map[id:4 content:good post2 author:userC]]
id:1 content:hello world author:map[id:2 name:userA] published:true label:[]]
Nach dem Login kopieren

上面将输出map结构。这是显然的,因为类型对应关系中已经说明了,json object解析到Go interface的时候,对应的是map结构。如果将上面输出的结构进行一下格式化,得到的将是类似下面的结构:

map[
    nextPost:<nil>
    comments:[
        map[
            id:3
            content:good post1
            author:userB
        ]
        map[
            id:4
            content:good post2
            author:userC
        ]
    ]
    id:1
    content:hello world
    author:map[
        id:2
        name:userA
    ]
    published:true
    label:[]
]
Nach dem Login kopieren

现在,可以从这个map中去判断类型、取得对应的值。但是如何判断类型?可以使用类型断言:

func main() {
    // 读取json数据
    fh, err := os.Open("a.json")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer fh.Close()
    jsonData, err := ioutil.ReadAll(fh)
    if err != nil {
        fmt.Println(err)
        return
    }
    
    // 解析json数据到interface{}
    var unknown interface{}
    err = json.Unmarshal(jsonData, &unknown)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 进行断言,并switch匹配
    m := unknown.(map[string]interface{})
    for k, v := range m {
        switch vv := v.(type) {
        case string:
            fmt.Println(k, "type: string\nvalue: ", vv)
            fmt.Println("------------------")
        case float64:
            fmt.Println(k, "type: float64\nvalue: ", vv)
            fmt.Println("------------------")
        case bool:
            fmt.Println(k, "type: bool\nvalue: ", vv)
            fmt.Println("------------------")
        case map[string]interface{}:
            fmt.Println(k, "type: map[string]interface{}\nvalue: ", vv)
            for i, j := range vv {
                fmt.Println(i,": ",j)
            }
            fmt.Println("------------------")
        case []interface{}:
            fmt.Println(k, "type: []interface{}\nvalue: ", vv)
            for key, value := range vv {
                fmt.Println(key, ": ", value)
            }
            fmt.Println("------------------")
        default:
            fmt.Println(k, "type: nil\nvalue: ", vv)
            fmt.Println("------------------")
        }
    }
}
Nach dem Login kopieren

结果如下:

comments type: []interface{}
value:  [map[id:3 content:good post1 author:userB] map[author:userC id:4 content:good post2]]
0 :  map[id:3 content:good post1 author:userB]
1 :  map[id:4 content:good post2 author:userC]
------------------
id type: float64
value:  1
------------------
content type: string
value:  hello world
------------------
author type: map[string]interface{}
value:  map[id:2 name:userA]
name :  userA
id :  2
------------------
published type: bool
value:  true
------------------
label type: []interface{}
value:  []
------------------
nextPost type: nil
value:  <nil>
------------------
Nach dem Login kopieren

可见,从interface中解析非常复杂,而且可能因为嵌套结构而导致无法正确迭代遍历。这时候,可以使用第三方包simplejson,见后文。

解析、创建json流

除了可以直接解析、创建json数据,还可以处理流式数据。

1、type Decoder解码json到Go数据结构

2、ype Encoder编码Go数据结构到json

例如:

const jsonStream = `
    {"Name": "Ed", "Text": "Knock knock."}
    {"Name": "Sam", "Text": "Who&#39;s there?"}
    {"Name": "Ed", "Text": "Go fmt."}
    {"Name": "Sam", "Text": "Go fmt who?"}
    {"Name": "Ed", "Text": "Go fmt yourself!"}
`
type Message struct {
    Name, Text string
}
dec := json.NewDecoder(strings.NewReader(jsonStream))
for {
    var m Message
    if err := dec.Decode(&m); err == io.EOF {
        break
    } else if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s: %s\n", m.Name, m.Text)
}
Nach dem Login kopieren

输出:

Ed: Knock knock.
Sam: Who&#39;s there?
Ed: Go fmt.
Sam: Go fmt who?
Ed: Go fmt yourself!
Nach dem Login kopieren

再例如,从标准输入读json数据,解码后删除名为Name的元素,最后重新编码后输出到标准输出。

func main() {
    dec := json.NewDecoder(os.Stdin)
    enc := json.NewEncoder(os.Stdout)
    for {
        var v map[string]interface{}
        if err := dec.Decode(&v); err != nil {
            log.Println(err)
            return
        }
        for k := range v {
            if k != "Name" {
                delete(v, k)
            }
        }
        if err := enc.Encode(&v); err != nil {
            log.Println(err)
        }
    }
}
Nach dem Login kopieren

更多go语言知识请关注PHP中文网go语言教程栏目。

Das obige ist der detaillierte Inhalt vonSo verarbeiten Sie JSON-Daten in der Go-Sprache. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:cnblogs.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!