yoongrammer

[Go] JSON 패키지 알아보기 본문

언어/Go 언어

[Go] JSON 패키지 알아보기

yoongrammer 2021. 1. 2. 10:45
728x90

목차

    [Go] JSON 패키지 알아보기


    JSON (JavaScript Object Notation)은 간단한 데이터 교환 형식입니다.

     

    json 패키지를 사용하면 go프로그램에서 JSON 데이터를 읽고 쓸 수 있습니다.

    Encoding


    JSON 데이터를 인코딩하기 위해서는 Marshal 함수를 사용합니다.

    func Marshal(v interface{}) ([]byte, error)

    Marshal 함수는 v를 인코딩한 JSON 값을 반환합니다.

     

    Marshal 함수는 아래와 같은 규칙으로 데이터를 JSON으로 인코딩합니다.

    - Boolean 값은 JSON boolean 값으로 인코딩 됩니다.

    bolB, _ := json.Marshal(true)  // true

     

    - Number(int, float)값은 JSON number로 인코딩 됩니다.

    intB, _ := json.Marshal(1)    // 1
    fltB, _ := json.Marshal(3.14) // 3.14

     

    - string은 JSON string으로 인코딩 됩니다.

    v, _ := json.Marshal("apple") // "apple"

     

    - Array 와 slice 값은 JSON array로 인코딩 됩니다.

    slcB, _ := json.Marshal([]string{"apple", "peach", "pear")
    // ["apple","peach","pear"]

     

    - struct 값은 JSON object로 인코딩 됩니다.

    - 구조체 필드명이 소문자로 시작하는 경우 인코딩에서 제외됩니다.

    v, _ := json.Marshal(struct{Page int; Fruits []string}{10,[]string{"apple","peach"})
    // {"Page":10,"Fruits":["apple","peach"]}

     

    - map 값은 JSON object로 인코딩 됩니다. 

    - map 유형을 인코딩하려면 반드시 map[string]T 형식이어야 합니다.

    - 여기서 T는 json package에서 재공되는 go type입니다.

    mapB, _ := json.Marshal(map[string]int{"apple": 5, "lettuce": 7})
    // {"apple":5,"lettuce":7}

     

    - 포인터는 가리키는 값으로 인코딩 됩니다.

    var num int = 15
    var numPtr *int = &num
    pB, _ := json.Marshal(numPtr) // 15

     

    - 인터페이스 값은 인터페이스에 포함된 값으로 인코딩 됩니다. 

    v, _ := json.Marshal(interface{}(10))
    // 10

     

    - nill 값은 null값으로 인코딩 됩니다.

    v, _ := json.Marshal(nil)
    // null

     

    - Channel, complex 및 함숫값은 JSON으로 인코딩할 수 없습니다.

    - 순환 데이터 구조는 지원하지 않습니다.

     

    필드 태그


    구조체 필드를 인코딩할 때 필드 태그를 사용하면 필드를 제외하거나 필드명을 변경하는 등 커스터마이징 할 수 있습니다.

     

    필드 태그는 역 따옴표(`)로 감싸진 문자열이고 json key로 시작합니다.

    필드 태그가 없다면 구조체 필드명으로 인코딩 됩니다.

     

    예시:

    type User struct {
      Name    string `json:"myName"` 
      Age     int   
    }
    
    v, _ := json.Marshal(User{"Tom", 20}) 
    // {"myName":"Tom", "Age":20} <- Name이 아닌 태그에 있는 myName으로 인코딩 됨.

    태그에 컴마(,)를 사용하여 필드에 옵션을 추가할 수 있습니다.

     

    옵션 설명:

    omitempty

    - 필드가 빈 값(false, 0, nil pointer, nil interface, empty array, slice, map or string)인 경우 인코딩에서 생략됩니다.

    type User struct{
      Name string `json:"myName"`
      Age int `json:"age,omitempty"`
    }
    
    v, _= json.Marshal(User{"Tom", 0})
    // {"myName":"Tom"} <- Age 필드 값이 빈 값(0)이기 때문에 인코딩에서 제외됨

    string

    - 필드 값을 string으로 인코딩합니다.

    - 문자열, 부동 소수점, 정수 또는 부울 유형의 필드에만 적용됩니다.

    type User struct{
      Name string `json:"myName"`
      Age int `json:"age,string"`
    }
    
    v, _= json.Marshal(User{"Tom", 20})
    // {"myName":"Tom","age":"20"} <- int 값이 string으로 인코딩 됨

     

    태그 값이 -인 경우, 해당 필드는 인코딩에서 항상 제외됩니다.

    type User struct{
      Name string `json:"myName"`
      Age int `json:"-"`
    }
    
    v, _= json.Marshal(User{"Tom", 20})
    // {"myName":"Tom"} <- Age 필드 값이 인코딩에서 제외됨

     

    - 값을 필드명으로 사용하고 싶은 경우 -, 태그를 사용하면 됩니다.

    type User struct{
      Name string `json:"myName"`
      Age int `json:"-,"`
    }
    
    v, _= json.Marshal(User{"Tom", 20})
    // {"myName":"Tom","-":20}

    Decoding


    JSON 데이터를 디코딩하기 위해서는 Unmarshal 함수를 사용합니다.

    func Unmarshal(data []byte, v interface{}) error

    Unmarshal은 JSON으로 인코딩 된 데이터를 구문 분석하고 결과를 v가 가리키는 값에 저장합니다.

     

    Unmarshal은 디코딩된 데이터를 저장하기 위한 필드를 식별하기 위해 다음과 같은 규칙을 따릅니다.

    • 주어진 JSON 객체키와 디코딩하기 위한 구조체 필드이름 또는 태그와 같아야 합니다.
    • 대소 문자를 구분하지 않습니다. (하지만 대문자로 시작해야 됨)
    • 구조체 필드에 없는 JSON 키는 무시됩니다.
    type User struct{
      Name string `json:"myName"`
      Age int 
    }
    
    JSONBlob := []byte(`{"myName":"Bob", "Age":10, "Number":3}`)
    var u User
    err := json.Unmarshal(JSONBlob, &u)
    fmt.Printf("%+v", u) // {Name:Bob Age:10}

     

    JSON 데이터 구조를 모른다면 빈 인터페이스(interface {})를 사용합니다.

    JSONBlob := []byte(`{"myName":"Bob", "Age":10}`)
    var u interface{}
    err := json.Unmarshal(JSONBlob, &u)
    fmt.Printf("%+v", u) // map[Age:10 Name:Bob]

    JSON을 인터페이스 값으로 역 정렬화 하기 위해 다음 중 하나를 인터페이스 값에 저장합니다.

    • JSON 객체 → map[string]interface{}
    • JSON 배열 → []interface{}
    • 나머지 → interface{}
      • JSON booleans→ bool
      • JSON numbers → float64
      • JSON strings→ string
      • JSON null → nil

    type assertion을 사용하여 데이터에 접근할 수 있습니다.

    user := u.(map[string]interface{})
    fmt.Println(user["Age"])

    깔끔한 출력


    JSON은 일반적으로 추가 공백 없이 하나의 긴 바이트로 저장됩니다.

    MarshalIndent


    MarshalIndent 함수를 사용하면 들여 쓰기를 설정하여 출력 형식을 정할 수 있습니다.

    func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

    prefix 인자는 모든 라인에 쓸 문자를 지정하고 indent는 들여 쓰기에 사용은 문자를 지정합니다.

     

    사용 예:

    data := map[string]int{
    		"a": 1,
    		"b": 2,
    	}
    
      json, _ := json.Marshal(data)
    // output: 
    // {"a":1,"b":2}
    
    
    	json, _ := json.MarshalIndent(data, "<prefix>", "<indent>")
    // output:
    // {
    //  <prefix><indent>"a": 1,
    //  <prefix><indent>"b": 2
    //  <prefix>}
    
      json, _ := json.MarshalIndent(data,"","  ")
    // output:
    // {
    //   "a": 1,
    //   "b": 2
    // }

    보통 prefix는 사용하지 않고 indent는 2-space 또는 을 많이 사용합니다.

    Compact


    들여 쓰기 함수의 반대는 Compact 함수입니다.

    func Compact(dst *bytes.Buffer, src []byte) error

    JSON 인코딩 된 src에 공백 문자를 제거하여 dst에 추가합니다.

     

    사용 예:

    data := map[string]int{
    		"a": 1,
    		"b": 2,
    	}
    
    	b, _ := json.MarshalIndent(data, "", "  ")
    	fmt.Println(string(b))
    // output:
    // {
    //   "a": 1,
    //   "b": 2
    // }
    
    	var out bytes.Buffer
    	json.Compact(&out, b)
    
    	out.WriteTo(os.Stdout)
    // output:
    // {"a":1,"b":2}

     

    참고:

    golang.org/pkg/encoding/json/

    blog.golang.org/json

    medium.com/go-walkthrough/go-walkthrough-encoding-json-package-9681d1d37a8f#.eszbi1cjw

    728x90

    '언어 > Go 언어' 카테고리의 다른 글

    [Go] go get 알아보기  (0) 2021.01.11
    [Go] context 사용하기  (0) 2020.12.14
    [Go] context 알아보기  (0) 2020.12.13
    [Go] Modules 사용하기  (0) 2020.12.07
    [Go] Modules 알아보기  (0) 2020.12.06
    Comments