4.8 آموزش کار با json

4.8 آموزش کار با json

4.8.1 مقدمه #

JSON یک فرمت متنی است که برای مبادله و ذخیره داده‌ها استفاده می‌شود. نام JSON مخفف عبارت JavaScript Object Notation است و در ابتدا به عنوان یک زبان مبتنی بر جاوااسکریپت توسعه یافته است. با این حال، در حال حاضر JSON به راحتی با بیشتر زبان‌های برنامه‌نویسی سازگار است.

JSON یک مجموعه از جفت‌های «key: value» است که با کاما از یکدیگر جدا شده‌اند و بین آنها با «:» ارتباط دارند. JSON در بین برنامه‌نویسان به عنوان یک ساختار داده‌ای محبوب است و به راحتی داده‌ها را به صورت ساختاردهی شده در برنامه‌های کاربردی مختلف به کار می‌رود. این فرمت دیتا استاندارد و مستقل از زبان‌ها و پلتفرم‌های برنامه‌نویسی است و برای برنامه‌های تحت وب، موبایل، دسکتاپ و سرور قابل استفاده است.

ساختار یک فایل JSON شامل تعدادی از آبجکت‌ها و آرایه‌ها می‌باشد. به عبارتی داده‌های JSON می‌توانند در سه نوع اصلی “جسم آرکی”(object) ، “کالکشن آرای”(array) و “مقادیر اولیه”(values) تعریف شوند. آبجکت یک گروه از خصوصیات است که دارای یک کلید منحصر به فرد به عنوان “عنوان شی” می‌باشد. همچنین، آرایه نیز به مشابه یک لیست یا آرایه از خصوصیات است.

یک مثال ساده JSON:

 1{
 2    "name": "John Doe",
 3    "age": 30,
 4    "email": "johndoe@example.com",
 5    "address": {
 6        "street": "123 Main St",
 7        "city": "Anytown",
 8        "state": "CA",
 9        "zip": "12345"
10    },
11    "phone": [
12        {
13            "type": "home",
14            "number": "555-555-1234"
15        },
16        {
17            "type": "work",
18            "number": "555-555-5678"
19        }
20    ]
21}

در این مثال، یک شیء با عنوان “John Doe” تعریف شده است. این شیء دارای خصوصیاتی همچون نام، سن، ایمیل، آدرس و تلفن است. آدرس نیز یک شیء است که شامل خصوصیاتی همچون خیابان، شهر، ایالت و کد پستی است. همچنین، تلفن به عنوان یک آرایه از شیء‌ها تعریف شده است که شامل نوع تلفن و شماره تلفن است.

4.8.2 کار با marshal و unmarshal پکیج json #

در زبان برنامه‌نویسی Go، پکیج “encoding/json” برای کار با داده‌های JSON بسیار مفید است. این پکیج امکاناتی برای تبدیل داده‌های Go به فرمت JSON (marshal) و برعکس (unmarshal) در اختیار برنامه‌نویسان قرار می‌دهد.

4.8.2.1 کار با marshal #

با استفاده از تابع “Marshal”، برای مثال، می‌توان یک شیء با فرمت JSON تولید کرد. در کد زیر، یک شیء از نوع “person” تعریف شده است و با استفاده از تابع “Marshal” به فرمت JSON تبدیل شده است:

 1package main
 2
 3import (
 4    "encoding/json"
 5    "fmt"
 6)
 7
 8type person struct {
 9    Name  string `json:"name"`
10    Age   int    `json:"age"`
11    Email string `json:"email"`
12}
13
14func main() {
15    p := &person{Name: "John Doe", Age: 30, Email: "john.doe@example.com"}
16    
17    b, err := json.Marshal(p)
18    if err != nil {
19        fmt.Println("error:", err)
20    }
21    
22    fmt.Println(string(b))
23}
1$ go run main.go
2{"name":"John Doe","age":30,"email":"john.doe@example.com"}

در کد بالا، ابتدا یک شیء از نوع “person” با مقادیر مشخص تعریف شده است. سپس از تابع “Marshal” برای تبدیل این شیء به فرمت JSON استفاده شده است. خروجی تابع “Marshal” یک بایت‌آرایه است که به عنوان یک رشته و با استفاده از تبدیل به “string” چاپ شده است.

4.8.2.2 کار با unmarshal #

با استفاده از تابع “Unmarshal” نیز می‌توان یک رشته JSON را به شیء Go تبدیل کرد. در کد زیر، یک رشته JSON با نام “data” تعریف شده است و با استفاده از تابع “Unmarshal” به یک شیء از نوع “person” تبدیل شده است:

 1package main
 2
 3import (
 4    "encoding/json"
 5    "fmt"
 6)
 7
 8type person struct {
 9    Name  string `json:"name"`
10    Age   int    `json:"age"`
11    Email string `json:"email"`
12}
13
14func main() {
15    data := `{"name":"John Doe","age":30,"email":"john.doe@example.com"}`
16    
17    var p person
18    err := json.Unmarshal([]byte(data), &p)
19    if err != nil {
20        fmt.Println("error:", err)
21    }
22    
23    fmt.Println(p.Name, p.Age, p.Email)
24}
1$ go run main.go
2John Doe 30 john.doe@example.com

در کد بالا، ابتدا یک رشته JSON با نام “data” تعریف شده است. سپس یک شیء از نوع “person” با استفاده از تابع “Unmarshal” و با این رشته JSON به شکل مقداردهی شده است. خروجی تابع “Unmarshal”، شیء “person” است که بعداً در کد چاپ شده است. توجه داشته باشید که در اینجا از “[]byte” برای تبدیل رشته به بایت‌آرایه استفاده شده است.

4.8.3 تبدیل آرایه و slice به json #

در Go، می‌توان آرایه‌ها و slice‌ها را به فرمت JSON تبدیل کرد. برای این کار، از تابع “Marshal” پکیج “encoding/json” استفاده می‌شود.

برای مثال، فرض کنید یک slice‌ از اعداد صحیح داشته باشیم. برای تبدیل این slice به فرمت JSON، کد زیر نمونه‌ای از چگونگی استفاده از تابع “Marshal” را نشان می‌دهد:

 1package main
 2
 3import (
 4    "encoding/json"
 5    "fmt"
 6)
 7
 8func main() {
 9    numbers := []int{1, 2, 3, 4, 5}
10
11    data, err := json.Marshal(numbers)
12    if err != nil {
13        fmt.Println("error:", err)
14    }
15
16    fmt.Println(string(data))
17}
1$ go run main.go
2[1,2,3,4,5]

در این کد، ابتدا یک slice‌ از اعداد صحیح تعریف شده است. سپس با استفاده از تابع “Marshal” این slice‌ به فرمت JSON تبدیل شده و در متغیر “data” ذخیره شده است. در نهایت، با استفاده از تبدیل به “string”، خروجی تابع “Marshal” به صورت یک رشته چاپ شده است.

همچنین، می‌توان آرایه‌های چند بعدی را نیز به فرمت JSON تبدیل کرد. در کد زیر، یک آرایه دوبعدی از اعداد صحیح تعریف شده است و به فرمت JSON تبدیل می‌شود:

 1package main
 2
 3import (
 4    "encoding/json"
 5    "fmt"
 6)
 7
 8func main() {
 9    var matrix [2][3]int = [2][3]int{{1, 2, 3}, {4, 5, 6}}
10
11    data, err := json.Marshal(matrix)
12    if err != nil {
13        fmt.Println("error:", err)
14    }
15
16    fmt.Println(string(data))
17}
1$ go run main.go
2[[1,2,3],[4,5,6]]

در این کد نیز، بعد از تعریف یک آرایه دوبعدی از اعداد صحیح، با استفاده از تابع “Marshal” آن را به فرمت JSON تبدیل شده و در متغیر “data” ذخیره شده است. خروجی تابع “Marshal” نیز به صورت یک رشته چاپ می‌شود.

4.8.4 تبدیل map به json #

در Go، می‌توان map را به فرمت JSON تبدیل کرد با استفاده از تابع “Marshal” در پکیج “encoding/json” میتوان این کار را انجام داد.

برای مثال، فرض کنید یک map از داده‌های شخصی داشته باشیم که شامل نام، سن و ایمیل است. برای تبدیل این map به فرمت JSON، کد زیر نمونه‌ای از چگونگی استفاده از تابع “Marshal” را نشان می‌دهد:

 1package main
 2
 3import (
 4    "encoding/json"
 5    "fmt"
 6)
 7
 8func main() {
 9    data := map[string]interface{}{
10        "name": "John Doe",
11        "age": 30,
12        "email": "john.doe@example.com",
13    }
14
15    output, err := json.Marshal(data)
16    if err != nil {
17        fmt.Println("error:", err)
18    }
19
20    fmt.Println(string(output))
21}
1$ go run main.go
2{"age":30,"email":"john.doe@example.com","name":"John Doe"}

در کد بالا، یک map از داده‌های شخصی با نام “data” تعریف شده است و سپس با استفاده از تابع “Marshal” به فرمت JSON تبدیل شده است. خروجی تابع “Marshal” نیز به صورت یک رشته چاپ شده است.

توجه داشته باشید که در این نمونه، نوع داده‌ی مقدارهای مپ از نوع خاصی استفاده نشده است و به جای آن، از نوع “interface{}” برای مقادیر استفاده شده است. این به این دلیل است که ممکن است مقادیر مختلفی در map وجود داشته باشد ولی نوعشان کاملاً شناخته شده نباشد. با استفاده از “interface{}"، مقادیر به صورت پویا تعریف شده و برنامه قادر است به درستی تبدیل را انجام دهد.

4.8.5 کتابخانه GJSON #

استفاده از فرمت json در زبان برنامه نویسی گو به راحتی استفاده از این فرمت در سایر زبان های برنامه نویسی دیگر مثل پایتون نیست و برای اینکه این مورد ساده‌تر شود توصیه میشود از کتابخانه GJSON استفاده شود.

کتابخانه GJSON یک بسته Go است که راهی سریع و ساده برای دریافت مقادیر از یک سند json ارائه می دهد. دارای ویژگی هاییone line retrievaldot notation pathsiteration,، و parsing json lines است.

این توضیحات یک نمای کلی از نحوه استفاده از GJSON است، برای اطلاعات بیشتر،GJSON Syntax را بررسی کنید.

4.8.5.1 راه اندازی و نصب GJSON #

برای نصب می توانیم از کد زیر استفاده کنیم.

1go get -u github.com/tidwall/gjson

با این کار کتابخانه نصب می شود.

4.8.5.2 خواندن مقادیر با GJSON #

برای جستجوی مقدار مورد نظر json را برای آدرس یا فایل مشخص شده دریافت کنید. کافیست کلید های تو در تو را تنها توسط یک نقطه، مانند ’name.last’ یا ‘age’ فراخوانی کرده و مقدار درون آن را بدست آورید. به عنوان مثال در کد زیر:

 1package main
 2
 3import "github.com/tidwall/gjson"
 4
 5const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
 6
 7func main() {
 8	value := gjson.Get(json, "name.last")
 9	println(value.String())
10}

خروجی به صورت زیر خواهد بود:

1Prichard

همچنین تابع GetMany برای دریافت چندین مقدار در یک زمان و GetBytes برای کار با slices بایت JSON وجود دارد.

4.8.5.3 Path Syntax #

در زیر یک نمای کلی از path syntax ارائه شده است، برای اطلاعات کامل تر لطفاً GJSON Syntax را بررسی کنید.

یک path مجموعه ای از کلیدها است که با یک نقطه از هم جدا شده اند. یک کلید ممکن است حاوی کاراکترهای ویژه ‘*’ و ‘؟’ باشد. برای دسترسی به مقدار آرایه از شاخص به عنوان کلید استفاده کنید. برای به دست آوردن تعداد عناصر در یک آرایه یا دسترسی به یک path فرزند، از کاراکتر ‘#’ استفاده کنید. کاراکترهای dot و wildcard را می توان با ’’ escape کرد.

‍‍

 1{
 2  "name": {"first": "Tom", "last": "Anderson"},
 3  "age":37,
 4  "children": ["Sara","Alex","Jack"],
 5  "fav.movie": "Deer Hunter",
 6  "friends": [
 7    {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
 8    {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
 9    {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
10  ]
11}
 1"name.last"          >> "Anderson"
 2"age"                >> 37
 3"children"           >> ["Sara","Alex","Jack"]
 4"children.#"         >> 3
 5"children.1"         >> "Alex"
 6"child*.2"           >> "Jack"
 7"c?ildren.0"         >> "Sara"
 8"fav\.movie"         >> "Deer Hunter"
 9"friends.#.first"    >> ["Dale","Roger","Jane"]
10"friends.1.last"     >> "Craig"

همچنین می‌توانید با استفاده از #(...), آرایه‌ای را برای پیدا کردن اولین match یا تطابق مورد نظر بررسی کنید، یا همه موارد مورد نظر را با #(...)# را پیدا کنید. کوئری ها از عملگرهای مقایسه ==!=<<=>>= و الگوی ساده تطبیق عملگرهای  % (like) و  !% (not like) پشتیبانی می کنند.

‍‍‍‍‍

1friends.#(last=="Murphy").first    >> "Dale"
2friends.#(last=="Murphy")#.first   >> ["Dale","Jane"]
3friends.#(age>45)#.last            >> ["Craig","Murphy"]
4friends.#(first%"D*").last         >> "Murphy"
5friends.#(first!%"D*").last        >> "Craig"
6friends.#(nets.#(=="fb"))#.first   >> ["Dale","Roger"]

لطفاً توجه داشته باشید که قبل از نسخه 1.3.0، کوئری ها از براکت های #[…] استفاده می کردند. این در نسخه 1.3.0 تغییر کرد تا از سردرگمی با سینتکس چند مسیری جدید جلوگیری شود. برای backwards compatibility ، #[…] تا نسخه اصلی بعدی به کار خود ادامه خواهد داد.

4.8.5.4 Result Type #

کتابخانه GJSON از انواع json string، number، bool و null پشتیبانی می کند. آرایه ها و اشیاء به عنوان نوع خام json خود برگردانده می شوند.

نوع Result یکی از این موارد را دارد:

‍‍‍

1bool, for JSON booleans
2float64, for JSON numbers
3string, for JSON string literals
4nil, for JSON null

برای دسترسی مستقیم به مقدار مورد نظر:

1result.Type           // can be String, Number, True, False, Null, or JSON
2result.Str            // holds the string
3result.Num            // holds the float64 number
4result.Raw            // holds the raw json
5result.Index          // index of raw value in original json, zero means index unknown
6result.Indexes        // indexes of all the elements that match on a path containing the '#' query character.

انواع مختلفی از توابع مفید وجود دارد که بر روی یک نتیجه کار می کنند:

 1result.Exists() bool
 2result.Value() interface{}
 3result.Int() int64
 4result.Uint() uint64
 5result.Float() float64
 6result.String() string
 7result.Bool() bool
 8result.Time() time.Time
 9result.Array() []gjson.Result
10result.Map() map[string]gjson.Result
11result.Get(path string) Result
12result.ForEach(iterator func(key, value Result) bool)
13result.Less(token Result, caseSensitive bool) bool

تابع  result.Value() یک interface{} را برمی‌گرداند که به   type assertion نیاز دارد و که یکی از type های Go به صورت زیر است:

1boolean >> bool
2number  >> float64
3string  >> string
4null    >> nil
5array   >> []interface{}
6object  >> map[string]interface{}

تابع result.Array() آرایه ای از مقادیر را برمی گرداند. اگر نتیجه یک مقدار غیر موجود را نشان دهد، یک آرایه خالی برگردانده می شود. اگر نتیجه یک آرایه JSON نباشد، مقدار بازگشتی یک آرایه حاوی یک نتیجه خواهد بود.

64-bit integers #

فراخوانی های result.Int() و  result.Uint() قادر به خواندن تمام 64 بیت هستند و امکان کار با اعداد صحیح JSON را فراهم می کنند.

1result.Int() int64    // -9223372036854775808 to 9223372036854775807
2result.Uint() uint64   // 0 to 18446744073709551615

4.8.5.5 Modifiers and path chaining #

اصلاح کننده یک جزء مسیر است که پردازش custom شده‌ای را روی json انجام می دهد.

چندین مسیر را می توان با استفاده از pipe character به هم «chained» کرد. این برای دریافت نتایج از یک query اصلاح شده مفید است.

به عنوان مثال، با استفاده از اصلاح‌کننده  @reverse داخلی در سند json بالا، آرایه فرزندان را دریافت می‌کنیم و ترتیب را برعکس می‌کنیم:

1"children|@reverse"           >> ["Jack","Alex","Sara"]
2"children|@reverse|0"         >> "Jack"

در حال حاضر اصلاح کننده های داخلی زیر وجود دارد:

  • @reverse: یک آرایه یا اعضای یک شی را معکوس کنید.
  • @ugly: تمام فضای خالی را از یک سند json حذف کنید.
  • @pretty: سند json را برای انسان قابل خواندن تر کنید.
  • @this: عنصر فعلی را برمی‌گرداند. می توان از آن برای بازیابی عنصر ریشه استفاده کرد.
  • @valid: مطمئن شوید که سند json معتبر است.
  • @flatten: یک آرایه را صاف می کند.
  • @join: چندین شی را به یک شیء متصل می کند.
  • @keys: آرایه ای از کلیدها را برای یک شی برمی گرداند.
  • @values: آرایه ای از مقادیر را برای یک شی برمی گرداند.
  • @tostr: json را به یک رشته تبدیل می کند. یک رشته json را می پیچد.
  • @fromstr: یک رشته را از json تبدیل می کند. یک رشته json را باز می کند.
  • @group: آرایه های اشیاء را گروه بندی می کند.  e4fc67c. را ببینید.

Modifier arguments

یک اصلاح کننده ممکن است یک آرگومان اختیاری را بپذیرد. آرگومان می تواند یک سند JSON معتبر یا فقط کاراکتر باشد.

به عنوان مثال، اصلاح کننده  @pretty یک شی json را به عنوان آرگومان خود می گیرد.

@pretty:{"sortKeys":true} 

که json را زیبا می کند و تمام کلیدهای آن را سفارش می دهد.

 1{
 2  "age":37,
 3  "children": ["Sara","Alex","Jack"],
 4  "fav.movie": "Deer Hunter",
 5  "friends": [
 6    {"age": 44, "first": "Dale", "last": "Murphy"},
 7    {"age": 68, "first": "Roger", "last": "Craig"},
 8    {"age": 47, "first": "Jane", "last": "Murphy"}
 9  ],
10  "name": {"first": "Tom", "last": "Anderson"}
11}

لیست کامل گزینه های  @pretty عبارتند از  sortKeysindentprefix, و width. لطفاً برای اطلاعات بیشتر به _Pretty Options_مراجعه کنید.

Custom modifiers #

همچنین می توانید اصلاح کننده های سفارشی اضافه کنید. به عنوان مثال، در اینجا ما یک اصلاح کننده ایجاد می کنیم که کل سند json را upper case یا lower case می کند.

1gjson.AddModifier("case", func(json, arg string) string {
2  if arg == "upper" {
3    return strings.ToUpper(json)
4  }
5  if arg == "lower" {
6    return strings.ToLower(json)
7  }
8  return json
9})
"children|@case:upper"           >> ["SARA","ALEX","JACK"]
"children|@case:lower|@reverse"  >> ["jack","alex","sara"]

4.8.5.6 JSON Lines #

پشتیبانی از JSON Lines با استفاده از پیشوند .. وجود دارد که یک سند چند خطی را به عنوان یک آرایه در نظر می گیرد.

به عنوان مثال:

{"name": "Gilbert", "age": 61}
{"name": "Alexa", "age": 34}
{"name": "May", "age": 57}
{"name": "Deloise", "age": 44}

تابع  ForEachLines از طریق خطوط JSON تکرار می شود.

1gjson.ForEachLine(json, func(line gjson.Result) bool{
2    println(line.String())
3    return true
4})

4.8.5.7 خواندن مقدارهای تو در تو یا nested #

فرض کنید همه نام‌های خانوادگی را از json زیر می‌خواهید:

‍‍

 1{
 2  "programmers": [
 3    {
 4      "firstName": "Janet", 
 5      "lastName": "McLaughlin", 
 6    }, {
 7      "firstName": "Elliotte", 
 8      "lastName": "Hunter", 
 9    }, {
10      "firstName": "Jason", 
11      "lastName": "Harold", 
12    }
13  ]
14}

شما می توانید از مسیر ‘programmers.#.lastName’ مانند این استفاده کنید:

‍‍

1result := gjson.Get(json, "programmers.#.lastName")
2for _, name := range result.Array() {
3	println(name.String())
4}

همچنین می توانید یک شی در داخل یک آرایه را پرس و جو کنید:

1name := gjson.Get(json, `programmers.#(lastName="Hunter").firstName`)
2println(name.String())  // prints "Elliotte"

4.8.5.8 پیمایش یک شی یا آرایه #

تابع  ForEach امکان تکرار سریع از طریق یک شی یا آرایه را فراهم می کند. کلید و مقدار برای اشیا به تابع تکرار کننده ارسال می شود. فقط مقدار برای آرایه ها ارسال می شود. برگرداندن false از یک تکرار کننده، تکرار را متوقف می کند.

1result := gjson.Get(json, "programmers")
2result.ForEach(func(key, value gjson.Result) bool {
3	println(value.String()) 
4	return true // keep iterating
5})

4.8.5.9 Simple Parse and Get #

یک تابع  Parse(json) وجود دارد که یک تجزیه ساده را انجام می دهد و  result.Get(path) که یک نتیجه را جستجو می کند. به عنوان مثال، همه اینها نتیجه یکسانی را نشان می دهند:

1gjson.Parse(json).Get("name").Get("last")
2gjson.Get(json, "name").Get("last")
3gjson.Get(json, "name.last")

4.8.5.10 بررسی جهت وجود یک value خاص #

گاهی اوقات فقط می خواهیم بدانیم که آیا یک مقدار وجود دارد یا خیر.

 1value := gjson.Get(json, "name.last")
 2if !value.Exists() {
 3	println("no last name")
 4} else {
 5	println(value.String())
 6}
 7
 8// Or as one step
 9if gjson.Get(json, "name.last").Exists() {
10	println("has a last name")
11}

4.8.5.11 اعتبار سنجی JSON #

توابع  Get* و Parse* انتظار دارند که فایل حاوی json به سالم و استاندارد باشد. خطا در فایل json باعث حالت panic نمی‌شود، اما ممکن است نتایج غیرمنتظره را بازگرداند.

اگر JSON را از یک منبع غیرقابل نامشخص استفاده کنید، ممکن است بخواهید قبل از استفاده از GJSON اعتبار سنجی کنید.

1if !gjson.Valid(json) {
2	return errors.New("invalid json")
3}
4value := gjson.Get(json, "name.last")

4.8.5.12 Unmarshal به یک map #

برای unmarshal به مپ به صورت  map[string]interface{}:

‍‍

1m, ok := gjson.Parse(json).Value().(map[string]interface{})
2if !ok {
3	// not a map
4}

4.8.5.13 کار با byte ها #

اگر درJSON فایل مورد نظر شما  []byte slice وجود دارد، تابع  GetBytes برای این حالت وجود دارد. این تابع در استفاده از  Get(string(data), path) ترجیح داده می شود.

‍‍

1var json []byte = ...
2result := gjson.GetBytes(json, path)

اگر از تابع  gjson.GetBytes(json, path) استفاده می کنید و می خواهید از تبدیل result.Raw به []byte اجتناب کنید، می توانید از این الگو استفاده کنید:

1var json []byte = ...
2result := gjson.GetBytes(json, path)
3var raw []byte
4if result.Index > 0 {
5    raw = json[result.Index:result.Index+len(result.Raw)]
6} else {
7    raw = []byte(result.Raw)
8}

این روش از فیلد result.Index استفاده می‌کند که موقعیت داده‌های خام در json فایل است. ممکن است که مقدار result.Index برابر با صفر باشد، در این صورت result.Raw به یک []byte تبدیل می‌شود.

4.8.5.14 خواندن چندین value #

تابع  GetMany می تواند برای دریافت چندین مقدار به طور همزمان استفاده شود.

‍‍

1results := gjson.GetMany(json, "name.first", "name.last", "age")

مقدار بازگشتی یک  []Result است، که همیشه دارای دقیقاً همان تعداد آیتم‌هایی است که مسیرهای ورودی دارند.

4.8.6 کتابخانه SJSON #

در واقع SJSON یک کتابخانه‌ای است که یک راه بسیار سریع و ساده برای تنظیم یک value در یک سند json ارائه می دهد. در بخش قبلی فقط می‌توانستیم مقادیر موجود در یک سند json بازخوانی کنیم ولی به کمک sjson می توانیم مقادیر مورد نظر را در یک سند json وارد کرده یا به روزرسانی و حذف دهیم.

4.8.6.1 راه اندازی و نصب SJSON #

برای شروع استفاده از SJSON باید آن را نصب کنید و go get را اجرا کنید:

1$ go get -u github.com/tidwall/sjson

با این کار کتابخانه نصب می شود.

4.8.6.2 Set a value #


دستور Set مقدار یا value ای را برای path مشخص شده اجرا می کند. یک path در یک dot syntax مشخص می‌شود، مانند ’name.last’ یا ‘age’. در این عملکرد انتظار می‌رود که ساختار کلی json صحیح و valid باشد. در صورت اشکال در ساختار json فایل و Invalid بودن آن، حالت panic رخ نمی‌دهد، اما ممکن است نتایج غیرمنتظره‌ای را برگرداند. البته pathهای نامعتبر ممکن است ایجاد خطا کند. به عنوان مثال کد زیر:

 1package main
 2
 3import "github.com/tidwall/sjson"
 4
 5const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
 6
 7func main() {
 8	value, _ := sjson.Set(json, "name.last", "Anderson")
 9	println(value)
10}

خروجی به شکل زیر خواهد بود:

1{"name":{"first":"Janet","last":"Anderson"},"age":47}

4.8.6.3 Path syntax #


در واقع path یا مسیر مجموعه ای از کلیدها است که با یک نقطه از هم جدا شده اند. کاراکترهای dot و colon را می توان با کاراکتر \ به راحتی escape کرد.

 1{
 2  "name": {"first": "Tom", "last": "Anderson"},
 3  "age":37,
 4  "children": ["Sara","Alex","Jack"],
 5  "fav.movie": "Deer Hunter",
 6  "friends": [
 7	{"first": "James", "last": "Murphy"},
 8	{"first": "Roger", "last": "Craig"}
 9  ]
10}
"name.last"          >> "Anderson"
"age"                >> 37
"children.1"         >> "Alex"
"friends.1.last"     >> "Craig"

از کلید -1 می توان برای افزودن یک مقدار به آرایه موجود استفاده کرد:

"children.-1"  >> appends a new value to the end of the children array

معمولاً از کلیدهای عددی برای اصلاح آرایه ها استفاده می شود، اما می توان با استفاده از کاراکتر دو نقطه، یک کلید شی عددی را اجرا کرد:

1{
2  "users":{
3    "2313":{"name":"Sara"},
4    "7839":{"name":"Andy"}
5  }
6}

همینطور colon path به صورت زیر است:

"users.:2313.name"    >> "Sara"

4.8.6.4 Supported types #


در کتابخانه SJSON تقریباً هر نوع متغیر یا type ای پشتیبانی می شود:

1sjson.Set(`{"key":true}`, "key", nil)
2sjson.Set(`{"key":true}`, "key", false)
3sjson.Set(`{"key":true}`, "key", 1)
4sjson.Set(`{"key":true}`, "key", 10.5)
5sjson.Set(`{"key":true}`, "key", "hello")
6sjson.Set(`{"key":true}`, "key", []string{"hello", "world"})
7sjson.Set(`{"key":true}`, "key", map[string]interface{}{"hello":"world"})

هنگامی که یک type شناسایی نمی شود، SJSON به رمزگذاری encoding/json باز می گردد.

4.8.6.5 مثال SJSON #


در این بخش به بررسی چند مثال از SJSON می پردازیم:

وارد کردن یک مقدار در یک json document خالی.

1value, _ := sjson.Set("", "name", "Tom")
2println(value)
3
4// Output:
5// {"name":"Tom"}

وارد کردن یک مقادیر تو در تو یا nested در یک json document خالی.

1value, _ := sjson.Set("", "name.last", "Anderson")
2println(value)
3
4// Output:
5// {"name":{"last":"Anderson"}}

وارد کردن مقدار جدید در سند:

1value, _ := sjson.Set(`{"name":{"last":"Anderson"}}`, "name.first", "Sara")
2println(value)
3
4// Output:
5// {"name":{"first":"Sara","last":"Anderson"}}

بروزرسانی و آپدیت یک سند:

1value, _ := sjson.Set(`{"name":{"last":"Anderson"}}`, "name.last", "Smith")
2println(value)
3
4// Output:
5// {"name":{"last":"Smith"}}

وارد کردن مقدار آرایه جدید:

1value, _ := sjson.Set(`{"friends":["Andy","Carol"]}`, "friends.2", "Sara")
2println(value)
3
4// Output:
5// {"friends":["Andy","Carol","Sara"]

اضافه کردن مقدار جدید به انتهای آرایه با استفاده از گزینه 1- :

1value, _ := sjson.Set(`{"friends":["Andy","Carol"]}`, "friends.-1", "Sara")
2println(value)
3
4// Output:
5// {"friends":["Andy","Carol","Sara"]

اضافه کردن مقدار جدید به انتهای آرایه و null کردن سایر سلول‌های آرایه که بین انتهای آرایه و آخرین سلولی که دارای مقدار مشخص بوده است :

1value, _ := sjson.Set(`{"friends":["Andy","Carol"]}`, "friends.4", "Sara")
2println(value)
3
4// Output:
5// {"friends":["Andy","Carol",null,null,"Sara"]

حذف کردن یک مقدار:

1value, _ := sjson.Delete(`{"name":{"first":"Sara","last":"Anderson"}}`, "name.first")
2println(value)
3
4// Output:
5// {"name":{"last":"Anderson"}}

حذف کردن مقادیر آرایه ای:

1value, _ := sjson.Delete(`{"friends":["Andy","Carol"]}`, "friends.1")
2println(value)
3
4// Output:
5// {"friends":["Andy"]}

حذف کردن انتهای آرایه:

1value, _ := sjson.Delete(`{"friends":["Andy","Carol"]}`, "friends.-1")
2println(value)
3
4// Output:
5// {"friends":["Andy"]}