首頁 > 後端開發 > Golang > iter.json:在 Go 中迭代和操作 JSON 的強大而有效的方法

iter.json:在 Go 中迭代和操作 JSON 的強大而有效的方法

Barbara Streisand
發布: 2024-12-27 15:25:10
原創
797 人瀏覽過

iter.json: A Powerful and Efficient Way to Iterate and Manipulate JSON in Go

您是否曾經需要在 Go 中修改非結構化 JSON 資料?也許您必須刪除所有列入黑名單的字段,將鍵從camelCase重命名為snake_case,或者將所有數字ID轉換為字串,因為JavaScript不喜歡int64? 如果您的解決方案是使用編碼/json 將所有內容解組到 map[string]any 中,然後將其編組回去...好吧,讓我們面對現實吧,這遠非高效!

如果您可以循環遍歷 JSON 數據,獲取每個項目的路徑,並即時決定如何處理它,會怎麼樣?

是的!我有一個好消息!借助 Go 1.23 中的新迭代器功能,有更好的方法來迭代和操作 JSON。來認識 ezpkg.io/iter.json — 在 Go 中使用 JSON 的強大而高效的伴侶。


1. 迭代 JSON

假設我們有一個 alice.json 檔案:

{
  "name": "Alice",
  "age": 24,
  "scores": [9, 10, 8],
  "address": {
    "city": "The Sun",
    "zip": 10101
  }
}
登入後複製
登入後複製

首先,讓我們使用 for range Parse() 迭代 JSON 文件,然後列印每個項目的路徑、鍵、令牌和層級。請參閱範例/01.iter。

package main

import (
    "fmt"

    "ezpkg.io/errorz"
    iterjson "ezpkg.io/iter.json"
)

func main() {
    data := `{"name": "Alice", "age": 24, "scores": [9, 10, 8], "address": {"city": "The Sun", "zip": 10101}}`

    // ?Example: iterate over json
    fmt.Printf("| %12v | %10v | %10v |%v|\n", "PATH", "KEY", "TOKEN", "LVL")
    fmt.Println("| ------------ | ---------- | ---------- | - |")
    for item, err := range iterjson.Parse([]byte(data)) {
        errorz.MustZ(err)

        fmt.Printf("| %12v | %10v | %10v | %v |\n", item.GetPathString(), item.Key, item.Token, item.Level)
    }
}
登入後複製
登入後複製

程式碼將輸出:

|         PATH |        KEY |      TOKEN |LVL|
| ------------ | ---------- | ---------- | - |
|              |            |          { | 0 |
|         name |     "name" |    "Alice" | 1 |
|          age |      "age" |         24 | 1 |
|       scores |   "scores" |          [ | 1 |
|     scores.0 |            |          9 | 2 |
|     scores.1 |            |         10 | 2 |
|     scores.2 |            |          8 | 2 |
|       scores |            |          ] | 1 |
|      address |  "address" |          { | 1 |
| address.city |     "city" |  "The Sun" | 2 |
|  address.zip |      "zip" |      10101 | 2 |
|      address |            |          } | 1 |
|              |            |          } | 0 |
登入後複製
登入後複製

2. 建置 JSON

使用Builder建立JSON資料。它接受可選的縮排參數。請參閱範例/02.builder。

b := iterjson.NewBuilder("", "    ")
// open an object
b.Add("", iterjson.TokenObjectOpen)

// add a few fields
b.Add("name", "Alice")
b.Add("age", 22)
b.Add("email", "alice@example.com")
b.Add("phone", "(+84) 123-456-789")

// open an array
b.Add("languages", iterjson.TokenArrayOpen)
b.Add("", "English")
b.Add("", "Vietnamese")
b.Add("", iterjson.TokenArrayClose)
// close the array

// accept any type that can marshal to json
b.Add("address", Address{
    HouseNumber: 42,
    Street:      "Ly Thuong Kiet",
    City:        "Ha Noi",
    Country:     "Vietnam",
})

// accept []byte as raw json
b.Add("pets", []byte(`[{"type":"cat","name":"Kitty","age":2},{"type":"dog","name":"Yummy","age":3}]`))

// close the object
b.Add("", iterjson.TokenObjectClose)

out := errorz.Must(b.Bytes())
fmt.Printf("\n--- build json ---\n%s\n", out)
登入後複製
登入後複製

這將輸出帶縮排的 JSON:

{
    "name": "Alice",
    "age": 22,
    "email": "alice@example.com",
    "phone": "(+84) 123-456-789",
    "languages": [
        "English",
        "Vietnamese"
    ],
    "address": {"house_number":42,"street":"Ly Thuong Kiet","city":"Ha Noi","country":"Vietnam"},
    "pets": [
        {
            "type": "cat",
            "name": "Kitty",
            "age": 2
        },
        {
            "type": "dog",
            "name": "Yummy",
            "age": 3
        }
    ]
}
登入後複製
登入後複製

3.格式化JSON

您可以透過將 JSON 資料的鍵和值傳送到 Builder 來重建或格式化 JSON 資料。請參閱範例/03.reformat。

{
    // ?Example: minify json
    b := iterjson.NewBuilder("", "")
    for item, err := range iterjson.Parse(data) {
        errorz.MustZ(err)
        b.AddRaw(item.Key, item.Token)
    }
    out := errorz.Must(b.Bytes())
    fmt.Printf("\n--- minify ---\n%s\n----------\n", out)
}
{
    // ?Example: format json
    b := iterjson.NewBuilder("?   ", "\t")
    for item, err := range iterjson.Parse(data) {
        errorz.MustZ(err)
        b.AddRaw(item.Key, item.Token)
    }
    out := errorz.Must(b.Bytes())
    fmt.Printf("\n--- reformat ---\n%s\n----------\n", out)
}
登入後複製

第一個範例縮小了 JSON,而第二個範例則使用前綴「?」對其進行格式化。每行。

--- minify ---
{"name":"Alice","age":24,"scores":[9,10,8],"address":{"city":"The Sun","zip":10101}}
----------

--- reformat ---
?   {
?       "name": "Alice",
?       "age": 24,
?       "scores": [
?           9,
?           10,
?           8
?       ],
?       "address": {
?           "city": "The Sun",
?           "zip": 10101
?       }
?   }
----------
登入後複製

4. 新增行號

在此範例中,我們透過在 fmt.Fprintf() 呼叫之前新增 b.WriteNewline() 來將行號新增至 JSON 輸出。請參閱範例/04.line_number。

// ?Example: print with line number
i := 0
b := iterjson.NewBuilder("", "    ")
for item, err := range iterjson.Parse(data) {
    i++
    errorz.MustZ(err)
    b.WriteNewline(item.Token.Type())

    // ? add line number
    fmt.Fprintf(b, "%3d    ", i)
    b.Add(item.Key, item.Token)
}
out := errorz.Must(b.Bytes())
fmt.Printf("\n--- line number ---\n%s\n----------\n", out)
登入後複製

這將輸出:

  1    {
  2        "name": "Alice",
  3        "age": 24,
  4        "scores": [
  5            9,
  6            10,
  7            8
  8        ],
  9        "address": {
 10            "city": "The Sun",
 11            "zip": 10101
 12        }
 13    }
登入後複製

5.新增評論

透過在 b.WriteComma() 和 b.WriteNewline() 之間放置 fmt.Fprintf(comment),您可以在每行末尾新增註解。請參閱範例/05.comment。

i, newlineIdx, maxIdx := 0, 0, 30
b := iterjson.NewBuilder("", "    ")
for item, err := range iterjson.Parse(data) {
    errorz.MustZ(err)
    b.WriteComma(item.Token.Type())

    // ? add comment
    if i > 0 {
        length := b.Len() - newlineIdx
        fmt.Fprint(b, strings.Repeat(" ", maxIdx-length))
        fmt.Fprintf(b, "// %2d", i)
    }
    i++

    b.WriteNewline(item.Token.Type())
    newlineIdx = b.Len() // save the newline index

    b.Add(item.Key, item.Token)
}
length := b.Len() - newlineIdx
fmt.Fprint(b, strings.Repeat(" ", maxIdx-length))
fmt.Fprintf(b, "// %2d", i)

out := errorz.Must(b.Bytes())
fmt.Printf("\n--- comment ---\n%s\n----------\n", out)
登入後複製

這將輸出:

{                             //  1
    "name": "Alice",          //  2
    "age": 24,                //  3
    "scores": [               //  4
        9,                    //  5
        10,                   //  6
        8                     //  7
    ],                        //  8
    "address": {              //  9
        "city": "The Sun",    // 10
        "zip": 10101          // 11
    }                         // 12
}                             // 13
登入後複製

6. 過濾 JSON 並提取值

有item.GetPathString()和item.GetRawPath()來取得目前item的路徑。您可以使用它們來過濾 JSON 資料。請參閱範例/06.filter_print。

使用 item.GetPathString() 和正規表示式的範例:

fmt.Printf("\n--- filter: GetPathString() ---\n")
i := 0
for item, err := range iterjson.Parse(data) {
    i++
    errorz.MustZ(err)

    path := item.GetPathString()
    switch {
    case path == "name",
        strings.Contains(path, "address"):
        // continue
    default:
        continue
    }

    // ? print with line number
    fmt.Printf("%2d %20s . %s\n", i, item.Token, item.GetPath())
}
登入後複製

item.GetRawPath() 和 path.Match() 範例:

fmt.Printf("\n--- filter: GetRawPath() ---\n")
i := 0
for item, err := range iterjson.Parse(data) {
    i++
    errorz.MustZ(err)

    path := item.GetRawPath()
    switch {
    case path.Match("name"),
        path.Contains("address"):
        // continue
    default:
        continue
    }

    // ? print with line number
    fmt.Printf("%2d %20s . %s\n", i, item.Token, item.GetPath())
}
登入後複製

兩個範例都會輸出:

{
  "name": "Alice",
  "age": 24,
  "scores": [9, 10, 8],
  "address": {
    "city": "The Sun",
    "zip": 10101
  }
}
登入後複製
登入後複製

7. 過濾 JSON 並傳回新的 JSON

透過將 Builder 與選項 SetSkipEmptyStructures(false) 和過濾邏輯結合,您可以過濾 JSON 資料並傳回新的 JSON。請參閱範例/07.filter_json

package main

import (
    "fmt"

    "ezpkg.io/errorz"
    iterjson "ezpkg.io/iter.json"
)

func main() {
    data := `{"name": "Alice", "age": 24, "scores": [9, 10, 8], "address": {"city": "The Sun", "zip": 10101}}`

    // ?Example: iterate over json
    fmt.Printf("| %12v | %10v | %10v |%v|\n", "PATH", "KEY", "TOKEN", "LVL")
    fmt.Println("| ------------ | ---------- | ---------- | - |")
    for item, err := range iterjson.Parse([]byte(data)) {
        errorz.MustZ(err)

        fmt.Printf("| %12v | %10v | %10v | %v |\n", item.GetPathString(), item.Key, item.Token, item.Level)
    }
}
登入後複製
登入後複製

此範例將傳回一個僅包含過濾欄位的新 JSON:

|         PATH |        KEY |      TOKEN |LVL|
| ------------ | ---------- | ---------- | - |
|              |            |          { | 0 |
|         name |     "name" |    "Alice" | 1 |
|          age |      "age" |         24 | 1 |
|       scores |   "scores" |          [ | 1 |
|     scores.0 |            |          9 | 2 |
|     scores.1 |            |         10 | 2 |
|     scores.2 |            |          8 | 2 |
|       scores |            |          ] | 1 |
|      address |  "address" |          { | 1 |
| address.city |     "city" |  "The Sun" | 2 |
|  address.zip |      "zip" |      10101 | 2 |
|      address |            |          } | 1 |
|              |            |          } | 0 |
登入後複製
登入後複製

8. 編輯值

這是編輯 JSON 資料中的值的範例。假設我們的 API 使用數字 ID。 id 太大,JavaScript 無法處理它們。我們需要將它們轉換為字串。請參閱範例/08.number_id 和 order.json。

迭代 JSON 數據,找到所有 _id 欄位並將數字 id 轉換為字串:

b := iterjson.NewBuilder("", "    ")
// open an object
b.Add("", iterjson.TokenObjectOpen)

// add a few fields
b.Add("name", "Alice")
b.Add("age", 22)
b.Add("email", "alice@example.com")
b.Add("phone", "(+84) 123-456-789")

// open an array
b.Add("languages", iterjson.TokenArrayOpen)
b.Add("", "English")
b.Add("", "Vietnamese")
b.Add("", iterjson.TokenArrayClose)
// close the array

// accept any type that can marshal to json
b.Add("address", Address{
    HouseNumber: 42,
    Street:      "Ly Thuong Kiet",
    City:        "Ha Noi",
    Country:     "Vietnam",
})

// accept []byte as raw json
b.Add("pets", []byte(`[{"type":"cat","name":"Kitty","age":2},{"type":"dog","name":"Yummy","age":3}]`))

// close the object
b.Add("", iterjson.TokenObjectClose)

out := errorz.Must(b.Bytes())
fmt.Printf("\n--- build json ---\n%s\n", out)
登入後複製
登入後複製

這將為數字 id 加上引號:

{
    "name": "Alice",
    "age": 22,
    "email": "alice@example.com",
    "phone": "(+84) 123-456-789",
    "languages": [
        "English",
        "Vietnamese"
    ],
    "address": {"house_number":42,"street":"Ly Thuong Kiet","city":"Ha Noi","country":"Vietnam"},
    "pets": [
        {
            "type": "cat",
            "name": "Kitty",
            "age": 2
        },
        {
            "type": "dog",
            "name": "Yummy",
            "age": 3
        }
    ]
}
登入後複製
登入後複製

結論

ezpkg.io/iter.json 套件使 Go 開發人員能夠精確且有效率地處理 JSON 資料。無論您需要迭代複雜的 JSON 結構、動態建立新的 JSON 物件、格式化或縮小資料、過濾特定字段,甚至轉換值,iter.json 都提供了靈活而強大的解決方案。

我很高興與社群分享這個套件作為有效 JSON 操作的工具,而無需完全解析資料。雖然它仍處於早期開發階段,並且還有更多功能的空間,但它已經適用於許多常見用例。

如果您有具體的要求或改進想法,請隨時與我們聯繫 - 我很樂意聽到您的反饋並幫助支持您的用例! ?


作者

我是奧利佛‧阮 。  一名使用 Go 和 JS 的軟體工程師。我喜歡每天學習並看到更好的自己。偶爾會衍生出新的開源專案。在我的旅程中分享知識和想法。

該貼文也發佈在 olivernguyen.io。

以上是iter.json:在 Go 中迭代和操作 JSON 的強大而有效的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板