json
#Reading
#Tooling
#Libraries
#Recipes
#ordered json
See next example of inlining
, with help of sorted slics we can have sorted keys in json.
// - unordered.go -
// Working with unordered maps json data
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"sort"
)
type pkgjs struct {
Order []string
Map map[string]interface{}
}
func main() {
jsonStr := `
{
"name": "foo",
"dependencies": {
"@serverless/cli": "^1.5.2",
"yaml-ast-parser": "0.0.43"
},
"foobar": "barbar"
}`
var s pkgjs
if err := json.Unmarshal([]byte(jsonStr), &s); err != nil {
log.Fatal(err)
}
// adding new values
key, value := "sss", struct {
Data struct {
Url string `json:"url,omitempty"`
Version string `json:"version,omitempty"`
GitHash string `json:"git_commit,omitempty"`
} `json:"data"`
}{}
value.Data.Url = "http://example.com"
s.Replace(key, value)
b1, _ := s.MarshalJSON()
fmt.Printf("Result:\n %s\n", b1)
b2, _ := json.Marshal(s)
fmt.Printf("Result:\n %s\n", b2)
}
func (pj *pkgjs) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(b, &pj.Map); err != nil {
return err
}
//nolint: wsl
index := make(map[string]int)
for key := range pj.Map {
pj.Order = append(pj.Order, key)
esc, _ := json.Marshal(key)
index[key] = bytes.Index(b, esc)
}
sort.Slice(pj.Order, func(i, j int) bool {
return index[pj.Order[i]] < index[pj.Order[j]]
})
return nil
}
func (pj pkgjs) Replace(key string, value interface{}) {
pj.Map[key] = value
}
func (pj pkgjs) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
fmt.Fprintf(&buf, "{\n")
seen := map[string]struct{}{}
// extra keys
for i := range pj.Order {
seen[pj.Order[i]] = struct{}{}
}
for k := range pj.Map {
if _, ok := seen[k]; ok {
continue
}
pj.Order = append(pj.Order, k)
}
// building json
for i, key := range pj.Order {
seen[key] = struct{}{}
// keys
km, err := json.Marshal(key)
if err != nil {
return nil, err
}
fmt.Fprintf(&buf, "%s%s:", " ", km)
// values
vm, err := json.MarshalIndent(pj.Map[key], " ", " ")
if err != nil {
return nil, err
}
buf.Write(vm)
if i != len(pj.Map)-1 {
fmt.Fprintf(&buf, ",")
}
fmt.Fprintf(&buf, "\n")
}
// extra added
fmt.Fprintf(&buf, "}\n")
return buf.Bytes(), nil
}
#,inline
// - skip_json_fileds.go -
// -------------------------------------
// Skip fields in json (tags)
// -------------------------------------
package main
import (
"encoding/json"
"fmt"
)
func main() {
raw := []byte(`{"uno":"one", "ein":"one"}`)
var data struct {
Uno string `json:"uno"`
Ein string `json:"-"` // <- this is minus, and it used for skipping.....
}
_ = json.Unmarshal(raw, &data)
fmt.Printf("Unmarshaled - %#v\n", data)
data.Ein = "odyn"
fmt.Printf("Ein is fixed - %#v\n", data)
jsonStr, _ := json.Marshal(data)
fmt.Println("Marshaled", string(jsonStr))
}
#,omitempty
// - omitempty.go -
package main
import (
"encoding/json"
"fmt"
)
func main() {
Struct := struct {
A string
B string `json:"b"`
C string `json:"e"`
D string `json:",omitempty"`
F *string `json:",omitempty"`
i string `json:"r"`
}{
i: "i",
}
b, _ := json.Marshal(&Struct)
fmt.Println(string(b))
}
>> {"A":"","b":"","e":""}
#-
json:"-"
Helps to skip Records population
// - skip_json_fileds.go -
// -------------------------------------
// Skip fields in json (tags)
// -------------------------------------
package main
import (
"encoding/json"
"fmt"
)
func main() {
raw := []byte(`{"uno":"one", "ein":"one"}`)
var data struct {
Uno string `json:"uno"`
Ein string `json:"-"` // <- this is minus, and it used for skipping.....
}
_ = json.Unmarshal(raw, &data)
fmt.Printf("Unmarshaled - %#v\n", data)
data.Ein = "odyn"
fmt.Printf("Ein is fixed - %#v\n", data)
jsonStr, _ := json.Marshal(data)
fmt.Println("Marshaled", string(jsonStr))
}
#htmlquoting
// - htmlquoting.go -
// Dealing with html quoting
package main
import (
"encoding/json"
"fmt"
"log"
"strings"
)
func main() {
jsonStr := `
{
"name": "foo",
"dependencies": {
"@serverless/cli": "^1.5.2",
"yaml-ast-parser": "0.0.43"
},
"foobar": "barbar"
}`
tmp := map[string]any{}
if err := json.Unmarshal([]byte(jsonStr), &tmp); err != nil {
log.Fatal(err)
}
body, _ := json.MarshalIndent(tmp, " ", " ")
// character to rune transition
// https://golang.org/src/encoding/json/encode.go?s=6551:6569#L188
bodyStr := string(body)
bodyStr = strings.ReplaceAll(bodyStr, `\u003e`, ">")
bodyStr = strings.ReplaceAll(bodyStr, `\u003c`, "<")
bodyStr = strings.ReplaceAll(bodyStr, `\u0026`, "&")
fmt.Printf("%s", bodyStr)
}
#json.Raw
// - raw.go -
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
jsonStr := `
{
"name": "foo",
"dependencies": {
"@serverless/cli": "^1.5.2",
"yaml-ast-parser": "0.0.43"
},
"foobar": "barbar"
}
`
tmp := map[string]interface{}{}
if err := json.Unmarshal([]byte(jsonStr), &tmp); err != nil {
log.Fatal(err)
}
// hiding all fields in other field!
var out struct {
Name string `json:"name"`
Raw json.RawMessage `json:"data,omitempty"`
}
out.Name = tmp["name"].(string)
out.Raw = json.RawMessage(jsonStr)
body, _ := json.MarshalIndent(out, " ", " ")
fmt.Printf("%s", string(body))
}