84.2 JSON 파일 읽기
이제 본격적으로 parson을 사용하여 JSON 문서를 읽어보겠습니다. 다음 내용을 main.c 파일이 있는 폴더에 example.json으로 저장합니다(파일은 GitHub 저장소의 Unit 84/84.2/parson/parson 폴더에 들어있습니다).
example.json
{ "Title": "Inception", "Year": 2010, "Runtime": 148, "Genre": "Sci-Fi", "Director": "Christopher Nolan", "Actors": [ "Leonardo DiCaprio", "Joseph Gordon-Levitt", "Ellen Page", "Tom Hardy", "Ken Watanabe" ], "imdbRating": 8.8, "KoreaRelease": true }
-
JSON_Value * json_parse_file(const char *filename)
- JSON 파일을 읽어서 파싱한 뒤 JSON_Value 포인터를 반환합니다.
-
JSON_Object * json_value_get_object(const JSON_Value *value)
- JSON_Value에서 JSON_Object 포인터를 얻습니다.
-
const char * json_object_get_string(const JSON_Object *object, const char *name)
- JSON 객체(JSON_Object)에서 키에 해당하는 문자열을 가져옵니다.
-
double json_object_get_number(const JSON_Object *object, const char *name)
- JSON 객체에서 키에 해당하는 숫자를 가져옵니다.
-
JSON_Array * json_object_get_array(const JSON_Object *object, const char *name)
- JSON 객체에서 키에 해당하는 배열의 포인터를 얻습니다.
-
size_t json_array_get_count(const JSON_Array *array)
- JSON 배열의 요소 개수를 구합니다.
-
const char * json_array_get_string(const JSON_Array *array, size_t index)
- JSON 객체에서 키에 해당하는 배열 중 인덱스를 지정하여 문자열을 가져옵니다.
-
int json_object_get_boolean(const JSON_Object *object, const char *name)
- JSON 객체에서 키에 해당하는 불 값을 가져옵니다.
-
void json_value_free(JSON_Value *value)
- JSON_Value에 할당된 동적 메모리를 해제합니다.
다음과 같이 parson 함수를 사용하여 초기화, 사용, 해제의 순서로 JSON 파일을 쓰게 됩니다.
먼저 parson의 함수를 사용하려면 #include로 parson.h 헤더 파일을 포함합니다.
#include <stdio.h> #include "parson.h" // parson.h 헤더 파일 포함
이제 json_parse_file 함수에 example.json 파일을 지정하여 파일의 내용을 파싱합니다. parson은 JSON을 JSON_Value와 JSON_Object 두 가지로 분리해서 처리하는데 json_parse_file 함수는 JSON_Value 포인터를 반환합니다. 따라서 JSON_Value에서 값을 꺼내려면 json_value_get_object 함수를 사용하여 JSON_Object 포인터를 얻습니다.
int main () { JSON_Value *rootValue; JSON_Object *rootObject; /* 초기화 */ rootValue = json_parse_file("example.json"); // JSON 파일을 읽어서 파싱 rootObject = json_value_get_object(rootValue); // JSON_Value에서 JSON_Object를 얻음
보통 JSON 문서에서 처음 시작하는 {를 root object라고 부릅니다.
json_object_get_string 함수로 객체에서 키에 해당하는 문자열을 가져오고, json_object_get_number 함수로 객체에서 키에 해당하는 숫자를 가져오면 됩니다. 여기서 json_object_get_number 함수는 double형으로 값을 반환하므로 실수로 사용하고 싶으면 그대로 출력하면 되고, 정수로 사용하고 싶으면 앞에 (int)를 붙여서 자료형 변환을 해주면 됩니다.
/* 사용 */ // 객체에서 키에 해당하는 문자열을 가져옴 printf("Title: %s\n", json_object_get_string(rootObject, "Title")); // 객체에서 키에 해당하는 숫자를 가져옴 printf("Year: %d\n", (int)json_object_get_number(rootObject, "Year")); printf("Runtime %d\n", (int)json_object_get_number(rootObject, "Runtime")); // 객체에서 키에 해당하는 문자열을 가져옴 printf("Genre: %s\n", json_object_get_string(rootObject, "Genre")); printf("Director: %s\n", json_object_get_string(rootObject, "Director"));
배열을 사용할 때는 먼저 json_object_get_array 함수로 객체에서 키에 해당하는 배열의 포인터(JSON_Array *)를 가져옵니다. 그리고 나서 반복문으로 반복할 때는 json_array_get_count 함수를 사용하면 배열의 요소 개수만큼 반복할 수 있습니다. 반복문 안에서는 json_array_get_string 함수로 배열의 문자열을 가져오면 됩니다.
printf("Actors:\n"); // 객체에서 키에 해당하는 배열을 가져옴 JSON_Array *array = json_object_get_array(rootObject, "Actors"); for (int i = 0; i < json_array_get_count(array); i++) // 배열의 요소 개수만큼 반복 { // 배열에 인덱스를 지정하여 문자열을 가져옴 printf(" %s\n", json_array_get_string(array, i)); }
객체에서 불 값을 가져올 때는 json_object_get_boolean 함수를 사용하면 됩니다.
// 객체에서 키에 해당하는 숫자를 가져옴 printf("imdbRating: %f\n", json_object_get_number(rootObject, "imdbRating")); // 객체에서 키에 해당하는 불 값을 가져옴 printf("KoreaRelease: %d\n", json_object_get_boolean(rootObject, "KoreaRelease"));
모든 출력이 끝났으면 json_value_free 함수를 사용하여 동적 메모리를 해제합니다(rootValue를 해제하면 안에 들어있는 rootObject까지 함께 해제됩니다).
/* 해제 */ json_value_free(rootValue); // JSON_Value에 할당된 동적 메모리 해제 return 0; }
다음은 전체 소스 코드입니다(파일은 GitHub 저장소의 Unit 84/84.2/parson/parson 폴더에 들어있습니다).
main.c
#include <stdio.h> #include "parson.h" // parson.h 헤더 파일 포함 int main() { JSON_Value *rootValue; JSON_Object *rootObject; /* 초기화 */ rootValue = json_parse_file("example.json"); // JSON 파일을 읽어서 파싱 rootObject = json_value_get_object(rootValue); // JSON_Value에서 JSON_Object를 얻음 /* 사용 */ // 객체에서 키에 해당하는 문자열을 가져옴 printf("Title: %s\n", json_object_get_string(rootObject, "Title")); // 객체에서 키에 해당하는 숫자를 가져옴 printf("Year: %d\n", (int)json_object_get_number(rootObject, "Year")); printf("Runtime %d\n", (int)json_object_get_number(rootObject, "Runtime")); // 객체에서 키에 해당하는 문자열을 가져옴 printf("Genre: %s\n", json_object_get_string(rootObject, "Genre")); printf("Director: %s\n", json_object_get_string(rootObject, "Director")); printf("Actors:\n"); // 객체에서 키에 해당하는 배열을 가져옴 JSON_Array *array = json_object_get_array(rootObject, "Actors"); for (int i = 0; i < json_array_get_count(array); i++) // 배열의 요소 개수만큼 반복 { // 배열에 인덱스를 지정하여 문자열을 가져옴 printf(" %s\n", json_array_get_string(array, i)); } // 객체에서 키에 해당하는 숫자를 가져옴 printf("imdbRating: %f\n", json_object_get_number(rootObject, "imdbRating")); // 객체에서 키에 해당하는 불 값을 가져옴 printf("KoreaRelease: %d\n", json_object_get_boolean(rootObject, "KoreaRelease")); /* 해제 */ json_value_free(rootValue); // JSON_Value에 할당된 동적 메모리 해제 return 0; }
Visual Studio에서 Ctrl+F5 키를 눌러서 프로그램을 실행하면 다음과 같이 JSON 문서를 파싱한 내용이 출력됩니다.
실행 결과
Title: Inception Year: 2010 Runtime 148 Genre: Sci-Fi Director: Christopher Nolan Actors: Leonardo DiCaprio Joseph Gordon-Levitt Ellen Page Tom Hardy Ken Watanabe imdbRating: 8.800000 KoreaRelease: 1
이처럼 기존에 구현되어 있는 JSON 파서를 이용하면 좀 더 체계적이고 효율적으로 JSON 문서를 처리할 수 있습니다.