본문 바로가기
카테고리 없음

JSON 다루기

by 경자꿈사 2025. 3. 6.

지난번 글에서는 배열에 담긴 데이터를 CSV 포맷으로 파일에 저장하고, 다시 CSV 파일로부터 배열을 생성하는 방법을 알아보았다.
이번 글에서는 해시 등 객체에 담긴 데이터를 JSON 포맷의 문자열로 변환하고 다시 JSON 포맷의 문자열을 파싱하여 해시 등 객체를 생성하는 방법을 알아보자.

JSON(JavaScript Object Notation)은 텍스트 기반의 데이터 저장 및 전송을 위한 포맷이다.
이름과는 달리 특정 프로그래밍 언어에 종속되지 않고 현재 주로 사용하는 대부분의 언어들은 모두 JSON을 쉽게 처리할 수 있도록 라이브러리를 제공한다.
JSON은 키-값 쌍의 집합을 중괄호({ })로 묶어 객체를 표현하고, 쉼표로 구분된 값들을 대괄호([ ])로 묶어 배열을 표현한다.
그리고 JSON에서 사용할 수 있는 값의 종류에는 문자열, 숫자, 불리언(true와 false), null, 객체, 배열 등이 있다.

아래 그림을 보면 JSON 모듈의 generate 모듈 메서드를 사용하여 해시를 JSON 포맷의 문자열로 변환하고 다시 parse 모듈 메서드를 사용하여 JSON 문자열을 해시로 변환하였다.

>> require 'json'
=> true
>>
>> data = { name: "홍길동", age: 30, languages: ["Ruby", "Java"] }
=> {:name=>"홍길동", :age=>30, :languages=>["Ruby", "Java"]}
>> json_str = JSON.generate(data)
=> "{\"name\":\"홍길동\",\"age\":30,\"languages\":[\"Ruby\",\"Java\"]}"
>> puts json_str
{"name":"홍길동","age":30,"languages":["Ruby","Java"]}
=> nil
>>
>> JSON.parse(json_str)
=> {"name"=>"홍길동", "age"=>30, "languages"=>["Ruby", "Java"]}

해시와 JSON 문자열의 내용을 비교해 보면 원래 심볼이던 해시의 키가 JSON에서는 문자열로 바뀌었을 뿐 나머지는 동일한 것을 볼 수 있다.
그리고 parse 메서드를 사용하여 JSON 문자열로부터 해시 객체를 생성하면 해시의 키가 문자열인데, 아래 그림처럼 symbolize_names 옵션 값을 true로 주면 해시의 키로 심볼을 사용하도록 할 수 있다.

>> JSON.parse(json_str, symbolize_names: true)
=> {:name=>"홍길동", :age=>30, :languages=>["Ruby", "Java"]}

generate 메서드에는 JSON 포맷으로 변환할 때 적용할 수 있는 여러 옵션들이 있는데, 아래는 indent(들여 쓰기) 옵션을 기본값("")으로 했을 때와 "  "(공백 2 개)으로 지정했을 때의 차이를 보여준다.
indent를 "  "으로 지정하면 가장 바깥쪽 객체의 각 키-값 쌍들 앞에는 공백 2개가 추가되고 languages 배열의 요소들은 하나 더 들여 쓰기가 되어 공백 4개가 앞에 붙는 것을 볼 수 있다.

>> require 'json'
=> true
>>
>> data = { name: "홍길동", age: 30, languages: ["Ruby", "Java"] }
=> {:name=>"홍길동", :age=>30, :languages=>["Ruby", "Java"]}
>> puts JSON.generate(data)
{"name":"홍길동","age":30,"languages":["Ruby","Java"]}
=> nil
>> puts JSON.generate(data, indent: "  ")
{  "name":"홍길동",  "age":30,  "languages":[    "Ruby",    "Java"]}
=> nil

이번에는 indent 옵션과 함께 추가로 space 옵션의 값을 " "(공백 1 개)으로 지정하여 generate 메서드의 결과를 확인해 보자.
아래 그림의 결과를 보면 space 옵션에 지정한 공백(" ")을 각각의 키-값 쌍에서 값 앞에 추가하는 것을 볼 수 있다.

>> puts JSON.generate(data, indent: "  ", space: " ")
{  "name": "홍길동",  "age": 30,  "languages": [    "Ruby",    "Java"]}
=> nil

다음은 object_nl 옵션을 개행 문자("\n")로 지정하면 변환 결과가 어떻게 달라지는지 확인해 보자.
결과를 보면 객체의 각 키-값 쌍이 새로운 줄에 표현되는 걸 볼 수 있다.

>> puts JSON.generate(data, indent: "  ", space: " ", object_nl: "\n")
{
  "name": "홍길동",
  "age": 30,
  "languages": [    "Ruby",    "Java"]
}
=> nil

끝으로 array_nl 옵션을 개행 문자("\n")로 지정하면 변환된 JSON 문자열에서 배열의 요소들이 새로운 줄에 표현되는 걸 볼 수 있다.
object_nl과 array_nl 옵션에서 'nl'은 'new line'을 의미한다.

>> puts JSON.generate(data, indent: "  ", space: " ", object_nl: "\n", array_nl: "\n")
{
  "name": "홍길동",
  "age": 30,
  "languages": [
    "Ruby",
    "Java"
  ]
}
=> nil

그런데 JSON 모듈의 pretty_generate 메서드를 사용하면 앞에서 적용한 옵션들이 기본으로 적용되어 읽기 쉬운 JSON 포맷의 문자열을 쉽게 생성할 수 있다. 
또한, 옵션을 통해 pretty_generate 메서드에서 기본으로 사용하는 옵션 값을 변경할 수도 있다.

>> puts JSON.pretty_generate(data)
{
  "name": "홍길동",
  "age": 30,
  "languages": [
    "Ruby",
    "Java"
  ]
}
=> nil
>> puts JSON.pretty_generate(data, indent: "    ")
{
    "name": "홍길동",
    "age": 30,
    "languages": [
        "Ruby",
        "Java"
    ]
}
=> nil

 

다음 글에서는 객체를 JSON 포맷으로 변환하는 기능을 직접 만들어보도록 하자.

 

See you again~