paint-brush
Fitur Baru di Go Memudahkan Iterasi dan Manipulasi Data JSONoleh@olvrng
Sejarah baru

Fitur Baru di Go Memudahkan Iterasi dan Manipulasi Data JSON

oleh Oliver Nguyen13m2024/12/17
Read on Terminal Reader

Terlalu panjang; Untuk membaca

Bagaimana jika Anda dapat melakukan pengulangan pada data JSON Anda, mengambil jalur setiap item, dan memutuskan apa yang harus dilakukan dengannya saat itu juga?
featured image - Fitur Baru di Go Memudahkan Iterasi dan Manipulasi Data JSON
Oliver Nguyen HackerNoon profile picture

Pernahkah Anda perlu mengubah data JSON yang tidak terstruktur di Go? Mungkin Anda harus menghapus password dan semua kolom yang masuk daftar hitam, mengganti nama kunci dari camelCase menjadi snake_case , atau mengubah semua id angka menjadi string karena JavaScript tidak menyukai int64 ? Jika solusi Anda adalah dengan melakukan unmarshal semuanya ke map[string]any menggunakan encoding/json lalu melakukan marshal kembali... yah, jujur saja, itu jauh dari kata efisien!


Bagaimana jika Anda dapat melakukan pengulangan melalui data JSON, mengambil jalur setiap item, dan memutuskan apa yang harus dilakukan dengannya saat itu juga?


Ya! Saya punya kabar baik! Dengan fitur iterator baru di Go 1.23, ada cara yang lebih baik untuk mengulang dan memanipulasi JSON. Perkenalkan ezpkg.io/iter.json — pendamping Anda yang hebat dan efisien untuk bekerja dengan JSON di Go.


1. Mengulangi JSON

Mengingat kita memiliki file alice.json :

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


Pertama, mari gunakan for range Parse() untuk mengulang file JSON, lalu cetak jalur, kunci, token, dan level setiap item. Lihat examples/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) } }


Kode akan menampilkan:

 | 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. Membangun JSON

Gunakan Builder untuk membuat data JSON. Builder menerima argumen opsional untuk indentasi. Lihat contoh/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", "[email protected]") 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)


Yang akan menampilkan JSON dengan indentasi:

 { "name": "Alice", "age": 22, "email": "[email protected]", "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. Memformat JSON

Anda dapat merekonstruksi atau memformat data JSON dengan mengirimkan kunci dan nilainya ke Builder . Lihat contoh/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) }


Contoh pertama memperkecil JSON sementara contoh kedua memformatnya dengan awalan "👉" pada setiap baris.

 --- 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. Menambahkan nomor baris

Dalam contoh ini, kami menambahkan nomor baris ke output JSON, dengan menambahkan b.WriteNewline() sebelum pemanggilan fmt.Fprintf() . Lihat contoh/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)


Ini akan menampilkan:

 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. Menambahkan komentar

Dengan meletakkan fmt.Fprintf(comment) di antara b.WriteComma() dan b.WriteNewline() , Anda dapat menambahkan komentar di akhir setiap baris. Lihat contoh/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)


Ini akan menampilkan:

 { // 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. Memfilter JSON dan mengekstraksi nilai

Ada item.GetPathString() dan item.GetRawPath() untuk mendapatkan jalur item saat ini. Anda dapat menggunakannya untuk memfilter data JSON. Lihat contoh/06.filter_print .


Contoh dengan item.GetPathString() dan regexp :

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


Contoh dengan item.GetRawPath() dan 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()) }


Kedua contoh akan menghasilkan:

 2 "Alice" . name 9 { . address 10 "The Sun" . address.city 11 10101 . address.zip 12 } . address

7. Memfilter JSON dan mengembalikan JSON baru

Dengan menggabungkan Builder dengan opsi SetSkipEmptyStructures(false) dan logika penyaringan, Anda dapat menyaring data JSON dan mengembalikan JSON baru. Lihat contoh/07.filter_json

 // 🦁Example: filter and output json b := iterjson.NewBuilder("", " ") b.SetSkipEmptyStructures(true) // 👉 skip empty [] or {} for item, err := range iterjson.Parse(data) { errorz.MustZ(err) if item.Token.IsOpen() || item.Token.IsClose() { b.Add(item.Key, item.Token) continue } path := item.GetPathString() switch { case path == "name", strings.Contains(path, "address"): // continue default: continue } b.Add(item.Key, item.Token) } out := errorz.Must(b.Bytes()) fmt.Printf("\n--- filter: output json ---\n%s\n----------\n", out)


Contoh ini akan mengembalikan JSON baru hanya dengan bidang yang difilter:

 { "name": "Alice", "address": { "city": "The Sun", "zip": 10101 } }

8. Mengedit nilai

Ini adalah contoh untuk mengedit nilai dalam data JSON. Asumsikan bahwa kita menggunakan id angka untuk API kita. Id tersebut terlalu besar dan JavaScript tidak dapat menanganinya. Kita perlu mengubahnya menjadi string. Lihat contoh/08.number_id dan order.json .


Ulangi data JSON, temukan semua bidang _id dan ubah id angka menjadi string:

 b := iterjson.NewBuilder("", " ") for item, err := range iterjson.Parse(data) { errorz.MustZ(err) key, _ := item.GetRawPath().Last().ObjectKey() if strings.HasSuffix(key, "_id") { id, err0 := item.Token.GetInt() if err0 == nil { b.Add(item.Key, strconv.Itoa(id)) continue } } b.Add(item.Key, item.Token) } out := errorz.Must(b.Bytes()) fmt.Printf("\n--- convert number id ---\n%s\n----------\n", out)


Ini akan menambahkan tanda kutip ke id nomor:

 { "order_id": "12345678901234", "number": 12, "customer_id": "12345678905678", "items": [ { "item_id": "12345678901042", "quantity": 1, "price": 123.45 }, { "item_id": "12345678901098", "quantity": 2, "price": 234.56 } ] }

Kesimpulan

Paket ezpkg.io/iter.json memberdayakan pengembang Go untuk menangani data JSON dengan presisi dan efisiensi. Baik Anda perlu mengulangi struktur JSON yang kompleks, membuat objek JSON baru secara dinamis, memformat atau mengecilkan data, memfilter bidang tertentu, atau bahkan mengubah nilai, iter.json menawarkan solusi yang fleksibel dan canggih.


Saya gembira dapat berbagi paket ini dengan komunitas sebagai alat untuk manipulasi JSON yang efektif tanpa perlu mengurai data secara menyeluruh. Meskipun masih dalam tahap pengembangan awal dan masih ada ruang untuk fitur-fitur lainnya, paket ini sudah berfungsi dengan baik untuk banyak kasus penggunaan umum.


Jika Anda memiliki persyaratan khusus atau ide untuk perbaikan, jangan ragu untuk menghubungi saya — saya ingin mendengar masukan Anda dan membantu mendukung kasus penggunaan Anda! 🥳



Pengarang

Saya Oliver Nguyen. Seorang insinyur perangkat lunak yang bekerja dengan Go dan JS. Saya senang belajar dan melihat versi diri saya yang lebih baik setiap hari. Sesekali membuat proyek sumber terbuka baru. Berbagi pengetahuan dan pemikiran selama perjalanan saya.


Postingan ini juga dipublikasikan di oliverguyen.io .