[나름해석]JSMN-kyu.version1.2
https://github.com/J-Kyu/jsmn
Original creator of jsmn: zserge
(※설명과 해석은 어디까지나 글쓴이의 주관적 사고로 부터 나왔습니다※)
<JSMN>
목적
jsmn은 C에서 JSON의 minmalistic 버전이다. 주어진 block token들을 {,[,",\,:등을 기준으로 data들을 분리하고 전달하는데 그 목적이 있다.
jsmn.h
-jsmntype_t
typedef enum {
JSMN_UNDEFINED = 0,
JSMN_OBJECT = 1,
JSMN_ARRAY = 2,
JSMN_STRING = 3,
JSMN_PRIMITIVE = 4
} jsmntype_t
jsmntype_t는 token의 type을 지정해주는 enum 변수이다
-jsmerr
enum jsmnerr {
/* Not enough tokens were provided */
JSMN_ERROR_NOMEM = -1,
/* Invalid character inside JSON string */
JSMN_ERROR_INVAL = -2,
/* The string is not a full JSON packet, more bytes expected */
JSMN_ERROR_PART = -3
};
jsmerr는 block token을 parsing 할 때, 각 token에 대한 오류를 나타내고 있다
-jsmntok_t
typedef struct {
jsmntype_t type;
int start;
int end;
int size;
#ifdef JSMN_PARENT_LINKS
int parent;
#endif
} jsmntok_t;
jsmntok_t는 각 token에 대하여 token의 data의 위치와 정보를 지니고 있는 구조체이다
-jsmn_parser
*/
typedef struct {
unsigned int pos; /* offset in the JSON string */
unsigned int toknext; /* next token to allocate */
int toksuper; /* superior token node, e.g parent object or array */
} jsmn_parser;
jsmn_parser는 jsmn_pase()함수가 token block을 pasing할 때, 사용 가능한 token들에 대한 정보과 현재 token의 위치를 알려주는 구조체이다
jsmn.c
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,jsmntok_t *tokens, size_t num_tokens)
-새로운 token에 들어 갈 때, 초기 값을 주어주면서 token의 기본 정보(jsmntok_t)에 대해서 할당해주는 함수
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, int end) {
-token에 대하여 type을 정해주고, 시작과 그리고 size의 값을 선언해준다
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) {
-jsmn_parse()함수에서 *js에 대하여 token이 primitive type인지 아닌지 검사하는 함수이다
-return: token에 대해서 모든 것이 primitive인 경우 return 0를 하며, error 인 경우 해당 error code(음수)를 return 한다
static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens)
-jsmn_parse()함수에서 *js에 대하여 token의 element가 string type인지 검사하는 함수
" \" "와 "\"를 기준으로 string을 확인한다
-return: token에 대하여 string인지를 검사할 때, token들의 정보가 정확하다면, return 0,이며, error인 경우 해당 error code(음수)가 return된다
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens)
-*js에 해당하는 token들을 parse하는데 주 목적이 있다. Parsing 할때, token의 개수를 return한다. 그라고 *js의 element의 요소에 따라 token을 만들어 주며, 각 token에 대한 정보를 각 변수의 주소 값을 참조하여 값들을 부여한다
return: array of token의 개수를 return하는데, 그 기준이 바로 jsmn_string과 jsmn_primitive를 따지면서 return하게 될 count의 value를 증가 시킨다
static int jsmn_init(jsmn_parser *parser)
-jsmn_parser의 type의 변수를 새롭게 선언해주는 것 함수아다
simple.c(주석 처리를 통해서 코드 설명)
/*
* A small example of jsmn parsing when JSON structure is known and number of
* tokens is predictable.
*/
static const char *JSON_STRING =
"{\"user\": \"johndoe\", \"admin\": false, \"uid\": 1000,\n "
"\"groups\": [\"users\", \"wheel\", \"audio\", \"video\"]}";
/*
JSON_STRING은 여러개의 string을 갖고 있는 포인터 변수이다.
그리고 사용자는 jsmn을 통해서 JSON_STRING을 분석하고 정렬하는데
그 목적이 있다
*/
static int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start &&
strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
return 0;
}
return -1;
}
/*
*해당 token의 정보를 지닌 tok가 json(JSON_STRING)에 접근하여서
*얻은 string과 *s(String 변수)가 동일한지 검사하는 함수
*/
int main() {
int i;
int r;
jsmn_parser p; //parsing할 때, token을 참조하는 기준의 정보르 갖는 구조체
jsmntok_t t[128]; //가장 많이 지닐 수 있는 token의 max를 지정해 주었다
jsmn_init(&p); //paring 할 때 필요한 p의 초기 값을 선언해준다
r = jsmn_parse(&p, JSON_STRING, strlen(JSON_STRING), t, sizeof(t)/sizeof(t[0]));
/*JSON_STRING을 parising하기 위해서 JSON_STRINGd에 포함 된 array of token의 수를 r 변수에 저장한다
*이때, t는 token 정보를 지니는 행열의 변수이며, sizeof(t)/sizeof(t[0])는 max 값인 128을 뜻한다
*/
if (r < 0) {
printf("Failed to parse JSON: %d\n", r);
return 1;
/* r값이 음수로 나오는 경우 JSON_STRING을 parsing 할때,
*token의 data값 중 error 여겨지는 값이 존할 때, 이 문구가 print되고
*프로그램이 종료된다
*/
}
/* Assume the top-level element is an object */
if (r < 1 || t[0].type != JSMN_OBJECT) {
printf("Object expected\n");
return 1;
/*t[0]는 JSON_STRING의 전체 정보를 갖고있는데
*그 정보의 type이 object가 아니거나
*r이 1보다 작은 경우는 error는 아니지만 어떠한 token도 발견되지 않을 때,
*만들어지는 이 문구가 print되고 프로그램이 종료 된다
*/
}
printf("\n\n%d",r); //r은 JSON_STRING의 token이 counting된 int값을 print하는 확인 구문이다
/* Loop over all keys of the root object */
printf("\n\nt[0]의 element: %.*s\n\n\n", t[0].end-t[0].start,
JSON_STRING + t[0].start); //t[0]의 전체 token을 출력한다
for (i = 1; i < r; i++) {
if (jsoneq(JSON_STRING, &t[i], "user") == 0) {
/* We may use strndup() to fetch string value */
printf("- User: %.*s-->", t[i+1].end-t[i+1].start,
JSON_STRING + t[i+1].start);
printf("%d+1번째\n",i); //해당 token의 몇번째 정보를 출력되었는 지 알기 위해서 만든 구문
i++;
} else if (jsoneq(JSON_STRING, &t[i], "admin") == 0) {
/* We may additionally check if the value is either "true" or "false" */
printf("- Admin: %.*s-->", t[i+1].end-t[i+1].start,
JSON_STRING + t[i+1].start);
printf("%d+1번째\n",i); //해당 token의 몇번째 정보를 출력되었는 지 알기 위해서 만든 구문
i++;
} else if (jsoneq(JSON_STRING, &t[i], "uid") == 0) {
/* We may want to do strtol() here to get numeric value */
printf("- UID: %.*s-->", t[i+1].end-t[i+1].start,
JSON_STRING + t[i+1].start);
printf("%d+1번째\n",i); //해당 token의 몇번째 정보를 출력되었는 지 알기 위해서 만든 구문
i++;
} else if (jsoneq(JSON_STRING, &t[i], "groups") == 0) {
int j;
printf("- Groups:\n");
if (t[i+1].type != JSMN_ARRAY) { /*JSON_STRING의 해당 token값이 group 이기 때문에 token의 type이 array아닌 경우
continue를 통해서 아래 string을 무시하고 내려간다*/
continue; /* We expect groups to be an array of strings */
}
for (j = 0; j < t[i+1].size; j++) {
jsmntok_t *g = &t[i+j+2];
printf(" * %.*s\n", g->end - g->start, JSON_STRING + g->start);
}
printf("-->%d+1번째\tsize_of_t[8]_:%d\n",i,t[8].size); //해당 token의 몇번째 정보를 출력되었는 지 알기 위해서 만든 구문
i += t[i+1].size + 1;
printf("증가 후,_%d\n",i); //i += t[i+1].size + 1;의 증가 값을 확인하기위해서 출려하는 구문
} else {
printf("Unexpected key: %.*s\n", t[i].end-t[i].start,
JSON_STRING + t[i].start);
}
}
EXIT_SUCCESS;
}
~
결과값)
-------------------------------------------------------------------------------------
변경후)
-----------------------------------------------------------------------------------------
2. 추가 설명
-simple.c는 이미 정해저 있는, JSON_STRING을 jsmn_parsing을 통해서 token by token으로 parsing하여 분류한다. (물론 중간에 error도 검사한다). 각 type별로 parsing한뒤, 출력을 해당 type에 의해서 출력한다
-JSON_STRING을 parsing을 통해서 각각 paring한 값을 출력한다. 마치 python에서 dictionary를 사용하여서 출력하는 값들과 유사하다.
token은 구분은 JSMN_STRING에서 \" \"를 기준으로 하나의 token으로 count하며, :으로 parent와 child 관계를 알려준다. 물론 object도 ([ ])하나의 token이 되며, object안에도 token이기 때문에, token속에 token이 된다.
(JSON_STRING도 하나의 Object이기 때문에 하나의 token이 된다)
Original coded by zserge
Modified and explained by Kyu