C言語はcJsonを使ってjsonを解析します.

79906 ワード

C言語でjsonを解析します.
  • cjsonライブラリ
  • cjsonオブジェクトタイプと構造体
  • cjsonのいくつかの常用インターフェース
  • .cjsonライブラリをさらにパッケージ化する
  • .
  • 試験事例
  • を呼び出します.
  • 追加
  • cjsonライブラリ
    ギthubまたはgitee上でcjsonは、ライブラリ内のcJSON.ccJSON.hを使用すれば良い.以下はcjsonを使った事例です.参考にしてください.クリックして私のcJosnの使用例をダウンロードします.
    cjsonオブジェクトタイプと構造体
    /* cJSON Types: */
    #define cJSON_Invalid (0)
    #define cJSON_False  (1 << 0)
    #define cJSON_True   (1 << 1)
    #define cJSON_NULL   (1 << 2)
    #define cJSON_Number (1 << 3)
    #define cJSON_String (1 << 4)
    #define cJSON_Array  (1 << 5)
    #define cJSON_Object (1 << 6)
    #define cJSON_Raw    (1 << 7) /* raw json */
    
    /* The cJSON structure: */
    typedef struct cJSON
    {
       /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
       struct cJSON *next;
       struct cJSON *prev;
       /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
       struct cJSON *child; //     ,            ,     NULL
    
       /* The type of the item, as above. */
       int type;
    
       /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
       char *valuestring;
       /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
       int valueint;
       /* The item's number, if type==cJSON_Number */
       double valuedouble;
    
       /* The item's name string, if this item is the child of, 
       or is in the list of subitems of an object. */
       char *string; //     ,    ,    ,   
    } cJSON;
    
    
    cjsonのいくつかの常用インターフェース
    json文字列の解析は使い終わったら、解放空間を覚えてください.
    //   json   ,       cJSON  ,          ,
    // cJSON    ,    cJSON_Delete(cJSON *c)      .
    cJSON * cJSON_Parse(const char *value);
    
    cjsonオブジェクト空間のリリース
    //     cJSON_Parse,cJSON_CreateObject create       
    void cJSON_Delete(cJSON *c);
    
    cjsonオブジェクトのタイプを判断すると、次のような種類があります.
    /* These functions check the type of an item      cJSON    */
    CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
    CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
    CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
    CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
    CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
    CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
    CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
    CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
    CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
    CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
    
    cjsonオブジェクトを作成して、開放空間を覚えてください.
    /*   cjson  These calls create a cJSON item of the appropriate type. */
    CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
    CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
    CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
    CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
    CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
    CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
    /* raw json */
    CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
    CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
    CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
    
    作成または変更されたcjsonオブジェクトを文字列として出力し、自分でファイルに保存します.文字列を使い切ると、スペースが解放されます.
    /* Render a cJSON entity to text for transfer/storage. */
    CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
    
    アプリケーションとリリーススペース、cJSON_Print返した文字列空間は、cJSON_が使用できます.freeで釈放する
    CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
    CJSON_PUBLIC(void) cJSON_free(void *object);
    
    cjsonライブラリをさらにパッケージ化
    cjsonライブラリにはいくつかの関数が実装されています.
  • は、jsonファイルパスに従って、ファイルをjsonオブジェクトに変換し、失敗してNULL
    cJSON * json_parse(const char *path);
    
  • に戻る.
  • は、親オブジェクトにおいて、キーパッドペアの名前から対応するサブオブジェクトを取得し、失敗してNULL
    //pjson  cjson  , pitemname    ,     
    const cJSON * json_get_object(const cJSON *pjson, const char *pitemname);
    
  • に戻る.
  • は、親オブジェクトにおいて、キーパッドペアの名前に基づいて、対応する文字列
    //pjson  cjson  , pitemname    ,pdft    ,        ,        
    const char * json_get_string(const cJSON *pjson,  const char *pitemname, const char *pdft);
    
  • を取得する.
  • は、親オブジェクトにおいて、キーパッドペアの名前から対応する数値
    //pjson  cjson  , pitemname    ,pdft    ,        ,        
    int json_get_number(const cJSON *pjson,  const char *pitemname, int pdft);
    
  • を取得する.
  • は、親オブジェクトにおいて、行列型のサブオブジェクトを取得し、配列メンバー数
    int json_get_array_size(const cJSON *pjson, const char *pitemname)
    
  • comon.cのコードファイルを作成し、comon.hのヘッダファイルを作成します.comon.cの具体的なパッケージコードは以下の通りです.
    #include 
    #include 
    #include 
    #include "common.h"
    
    #define in_range(c, lo, up)  ((unsigned char)c >= lo && (unsigned char)c <= up)
    #define isdigit(c)           in_range(c, '0', '9')
    
    /**
     ******************************************************************************
     * @brief            
     * @param[in] : *pstr :    
     * @retval  >= 0 :   
     * @retval  <  0 :     
     ******************************************************************************
     */
    int
    str2i(const char *pstr)
    {
        int ret = 0;
        if (!(*pstr && isdigit(*pstr)))
            return -1;
        do
        {
            ret = ret * 10 + (*pstr - '0');
            pstr++;
        } while (*pstr && isdigit(*pstr));
        return ret;
    }
    
    /**
     ******************************************************************************
     * @brief    json     json   
     * @param[in]  *path :     
     * @retval  cJSON *  :  NULL      
     ******************************************************************************
     */
    cJSON *
    json_parse(const char *path)
    {
        int file_size = 0;
        FILE  *fp = NULL;
        char *pstr = NULL;
        cJSON *pjson = NULL;
        int ret = 0;
    
        /*
         * 1.       
         * 2.     ,     
         * 3.   cjson     
         * 4.     
         */
        do
        {
            if (!path)
            {
                break;
            }
            fp = fopen(path, "rb");
            if (NULL == fp)
            {
                break;
            }
    
    		fseek(fp, 0, SEEK_END);
            file_size = ftell(fp);
            fseek(fp, 0, SEEK_SET);
            pstr = malloc(file_size + 1);
            if (!pstr)
            {
                break;
            }
            pstr[file_size] = 0; //last = 1
            if (file_size != (int)fread(pstr, 1, file_size, fp))
            {
                break;
            }
    		cJSON_Print(pjson);
            pjson = cJSON_Parse(pstr);
            ret = pjson ? 1 : 0;
        } while (0);
    
        if (fp)
        {
            fclose(fp);
        }
        if (pstr)
        {
            free(pstr);
        }
        return ret ? pjson : NULL;
    }
    
    /**
     ******************************************************************************
     * @brief     json      
     * @param[in]  *pjson : json  
     * @param[in]  *pitemname :   
     * @retval     
     ******************************************************************************
     */
    const cJSON *
    json_get_object(const cJSON *pjson,
            const char *pitemname)
    {
        /*
         * 1.      (.)  
         * 2.     array,    [%d]
         */
        int pos;
        char item[64];
        char *ptmp;
        char *ptr = NULL;
        const char *pstr;
        const cJSON *parray;
        const cJSON *pobject = pjson;
    
        if (!pjson || !pitemname || !pitemname[0] || (strlen(pitemname) >= sizeof(item)))
        {
            return NULL;
        }
    
        strncpy(item, pitemname, sizeof(item));
        char* str = item;
    
        //  "."  
        while (pobject && (pstr = strtok_r(str, ".", &ptr)))
        {
            str = NULL;
            if ((ptmp = strstr(pstr, "["))) //Array
            {
                if (0 > (pos = str2i(ptmp + 1)))
                {
                    break;
                }
                ptmp[0] = 0;
                parray = cJSON_GetObjectItem(pobject, pstr);
                if (!cJSON_IsArray(parray) || (pos >= cJSON_GetArraySize(parray)))
                {
                    break;
                }
                pobject = cJSON_GetArrayItem(parray, pos);
            }
            else //object
            {
                pobject = cJSON_GetObjectItem(pobject, pstr);
            }
        }
        return pobject;
    }
    
    /**
     ******************************************************************************
     * @brief     json   
     * @param[in]  *pjson : json  
     * @param[in]  *pitemname :   
     * @param[in]  *pdft  :    
     * @retval      (    )
     ******************************************************************************
     */
    const char *
    json_get_string(const cJSON *pjson,
            const char *pitemname,
            const char *pdft)
    {
        const char *pstr;
        const cJSON *pobject;
        do
        {
            if (!pjson || !pitemname || !pitemname[0])
            {
                break;
            }
            if (!(pobject = json_get_object(pjson, pitemname)))
            {
                break;
            }
            pstr = cJSON_GetStringValue(pobject);
            return pstr ? pstr : "";
        } while (0);
        return pdft ? pdft : "";
    }
    
    /**
     ******************************************************************************
     * @brief     json  
     * @param[in]  *pjson : json  
     * @param[in]  *pitemname :   
     * @param[in]  dft    :    
     * @retval     
     ******************************************************************************
     */
    int
    json_get_number(const cJSON *pjson,
            const char *pitemname,
            int dft)
    {
        const cJSON *pobject;
        do
        {
            if (!pjson || !pitemname || !pitemname[0])
            {
                break;
            }
            if (!(pobject = json_get_object(pjson, pitemname)))
            {
                break;
            }
            if (!cJSON_IsNumber(pobject))
            {
                break;
            }
            return pobject->valueint;
        } while (0);
        return dft;
    }
    
    /**
     ******************************************************************************
     * @brief     json     
     * @param[in]  *pjson : json  
     * @param[in]  *pitemname :   
     * @retval     
     ******************************************************************************
     */
    int
    json_get_array_size(const cJSON *pjson,
            const char *pitemname)
    {
        const cJSON *pobject;
    
        do
        {
            if (!pjson || !pitemname || !pitemname[0])
            {
                break;
            }
            if (!(pobject = json_get_object(pjson, pitemname)))
            {
                break;
            }
            if (!cJSON_IsArray(pobject))
            {
                break;
            }
            return cJSON_GetArraySize(pobject);
        } while (0);
    
        return 0;
    }
    
    common.hファイル
    #ifndef _COMMON_H
    #define _COMMON_H
    
    #include "./json/cJSON.h"
    
    #if defined(__cplusplus)
    extern "C"
    {         
    #endif
    
    extern const cJSON *
    json_get_object(const cJSON *pjson,
            const char *pitemname);
    
    extern const char *
    json_get_string(const cJSON *pjson,
            const char *pitemname,
            const char *pdft);
    
    extern int
    json_get_number(const cJSON *pjson,
            const char *pitemname,
            int dft);
    
    extern int
    json_get_array_size(const cJSON *pjson,
            const char *pitemname);
    
    extern cJSON *
    json_parse(const char *path);
    #if defined(__cplusplus)
    }
    #endif
    #endif
    
    テストケースの呼び出しconfig.jsonファイルを作成しました.ファイルの内容は以下の通りです.
    {
        "multicastIp": "239.0.0.10",
        "multicastPort": 8805,
        "services": [
            "192.168.0.118",
            "172.19.75.111",
            "172.19.75.45",
            "172.19.75.234"
        ]
    }
    
    mian.cのテストファイルを作成します.
    #include 
    #include 
    #include 
    #include "common.h"
    #define CONFIG_FILE "./config.json"
    
    
    typedef struct{
        int muticast_port;    //     
        char * muticast_ip;   //  IP
        int service_count;    //      
        char**  service_ips;  //    ip  
    } config_info_t;
    
    config_info_t config;   //      ,    
    
    /**
     ******************************************************************************
     * @brief           
     * @retval      0:   , -1:   
     ******************************************************************************
     */
    int config_init()
    {
        char key[64];
        cJSON * obj = NULL;
    
        //          json  
        if (NULL == (obj = json_parse(CONFIG_FILE)))
        {
    		exit(1);
        }
        //   json    
        config.muticast_port = json_get_number(obj, "multicastPort", 8805);
        config.muticast_ip = strdup(json_get_string(obj, "multicastIp", "239.0.0.10"));
        config.service_count = json_get_array_size(obj, "services");//        
    
        //        ,     
        if (NULL == (config.service_ips = (char**) malloc(sizeof(char*) * config.service_count)))
        {
            cJSON_Delete(obj); //    
            return -1;
        }
     
        //           
        memset(key, 0, sizeof(key));
        for (int i = 0; i < config.service_count; ++i)
        {
            snprintf(key, sizeof(key), "services[%d]", i);
            config.service_ips[i] = strdup(json_get_string(obj, key, NULL));
        }
    
        cJSON_Delete(obj); //  json    
        return 0;
    }
    
    /**
     ******************************************************************************
     * @brief             ,     
     * @param[in]  * pconfig :       
     ******************************************************************************
     */
    void config_destroy()
    {
        if (config.muticast_ip)
        {
            free(config.muticast_ip);
            config.muticast_ip = NULL;
        }
    
        if (config.service_ips)
        {
            for (int i = 0; i < config.service_count; ++i)
            {
                if (config.service_ips[i])
                {
                    free(config.service_ips[i]);
                    config.service_ips[i] = NULL;
                }
            }
            free(config.service_ips);
            config.service_ips = NULL;
        }
    }
    
    int main(int argc, char * argv[])
    {
        config_init();
    
        printf("     :\t %d
    "
    , config.muticast_port); printf(" IP:\t %s
    "
    , config.muticast_ip); printf(" :\t %d
    "
    , config.service_count); for (int i = 0; i < config.service_count; i++) { printf(" %d:\t %s
    "
    , i, config.service_ips[i]); } config_destroy(); }
    テストの結果は以下の通りです
    lmz@lmz-X280:~/  /code/c/test/cJsonTest$ make all
    gcc -fPIC -c -o common.o common.c 
    gcc -fPIC -c -o cJSON.o ./json/cJSON.c
    gcc main.c -o main common.o cJSON.o
    lmz@lmz-X280:~/  /code/c/test/cJsonTest$ ./main 
         :      8805
       IP:         239.0.0.10
         :      4
       0:         192.168.0.118
       1:         172.19.75.111
       2:         172.19.75.45
       3:         172.19.75.234
    
    追加
    iperfの関数がcJSONをカプセル化しているのを見て、いいと思います.common.cに入れて、cJSONのより良い操作に便利です.必要な#include は、printfを用いてcJSONオブジェクトを作成する機能である.
    
    /* Helper routine for building cJSON objects in a printf-like manner.
    **
    ** Sample call:
    **   j = json_printf("foo: %b  bar: %d  bletch: %f  eep: %s", b, i, f, s);
    **
    ** The four formatting characters and the types they expect are:
    **   %b  boolean           int
    **   %d  integer           int64_t
    **   %f  floating point    double
    **   %s  string            char *
    ** If the values you're passing in are not these exact types, you must
    ** cast them, there is no automatic type coercion/widening here.
    **
    ** The colons mark the end of field names, and blanks are ignored.
    **
    ** This routine is not particularly robust, but it's not part of the API,
    ** it's just for internal iperf3 use.
    */
    cJSON*
    json_printf(const char *format, ...)
    {
        cJSON* o;
        va_list argp;
        const char *cp;
        char name[100];
        char* np;
        cJSON* j;
    
        o = cJSON_CreateObject();
        if (o == NULL)
            return NULL;
        va_start(argp, format);
        np = name;
        for (cp = format; *cp != '\0'; ++cp) {
    	switch (*cp) {
    	    case ' ':
    	    break;
    	    case ':':
    	    *np = '\0';
    	    break;
    	    case '%':
    	    ++cp;
    	    switch (*cp) {
    		case 'b':
    		j = cJSON_CreateBool(va_arg(argp, int));
    		break;
    		case 'd':
    		j = cJSON_CreateNumber(va_arg(argp, int64_t));
    		break;
    		case 'f':
    		j = cJSON_CreateNumber(va_arg(argp, double));
    		break;
    		case 's':
    		j = cJSON_CreateString(va_arg(argp, char *));
            break;
    		default:
    		va_end(argp);
    		return NULL;
    	    }
    	    if (j == NULL) {
    	    	va_end(argp);
    	    	return NULL;
    	    }
    	    cJSON_AddItemToObject(o, name, j);
    	    np = name;
    	    break;
    	    default:
    	    *np++ = *cp;
    	    break;
    	}
        }
        va_end(argp);
        return o;
    }
    
    cJSON* json_printf(const char *format, ...);使用例
    
    int main(int argc, char * argv[])
    {
        char ip[] = "127.0.0.1";
        int port = 8080;
    
        cJSON * cjobj = cJSON_CreateObject();
        /*printf       */
        cJSON * cjip = json_printf("ip: %s port: %d", ip, port);
        cJSON_AddItemToObject(cjobj, "service", cjip);
        
        char * p = cJSON_Print(cjobj);
    
        printf("%s 
    "
    , p); cJSON_free(p); cJSON_Delete(cjobj); }