Chinaunix首页 | 论坛 | 博客
  • 博客访问: 315133
  • 博文数量: 82
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 490
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-13 10:58
文章分类

全部博文(82)

文章存档

2018年(2)

2017年(9)

2016年(71)

我的朋友

分类: C/C++

2017-01-09 21:36:17

 cJSON使用简介

1.1 下载

下载地址:

解压后,将cJSON.hcJSON.c单独拿出来使用。
 

1.2 实现简述

  typedef struct cJSON

  {

    struct cJSON *next;

    struct cJSON *prev;

    struct cJSON *child;

    int type;

    char *valuestring;

    int valueint;

    double valuedouble;

    char *string;

  } cJSON;

 

cJSON对象的实现采用了树形结构,每个对象是树的一个节点,每个节点由cJSON这个结构体组成,对象中的元素也由cJSON这个结构体组成。同一层的对象和元素是双向链表结构,由nextprev指针链接。不同层的对象或元素由child指针链接起来。type表示对象或元素类型,string表示对象或节点的名称。元素的值存储在valuestring,  valueintvaluedouble中。cJSON.h中有详细的注释,可参考。

其它详细可参考:

  

1.3 编译注意

编译时有可能报下边这个错误

  1. [root@192 cJSON]# make
  2. cc -std=c99 -lm -c -o cJSON.o cJSON.c
  3. cJSON.c: In function ‘cJSON_AddItemToObjectCS’:
  4. cJSON.c:1760: error: #pragma GCC diagnostic not allowed inside functions
  5. cJSON.c:1761: error: #pragma GCC diagnostic not allowed inside functions
  6. cJSON.c:1763: error: #pragma GCC diagnostic not allowed inside functions
  7. make: *** [cJSON.o] Error 1

貌似是编译器版本太低了,所以我直接将cJSON_AddItemToObjectCS函数中的#pragma GCC注释掉了,没有任何影响。


  1. void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
  2. {
  3.     if (!item)
  4.     {
  5.         return;
  6.     }
  7.     if (!(item->type & cJSON_StringIsConst) && item->string)
  8.     {
  9.         cJSON_free(item->string);
  10.     }
  11. //#pragma GCC diagnostic push
  12. //#pragma GCC diagnostic ignored "-Wcast-qual"
  13.     item->string = (char*)string;
  14. //#pragma GCC diagnostic pop
  15.     item->type |= cJSON_StringIsConst;
  16.     cJSON_AddItemToArray(object, item);
  17. }

  

1.4 接口使用注意

1. 打印到字符串最好使用下边的函数,直接打印到缓冲上,不需要自己释放内存。
 int cJSON_PrintPreallocated(cJSON *item,char *buf, const int len, const cjbool fmt) 
2.解析字符串最好使用下边的函数,cJSON *cJSON_Parse(const char *value)有bug,看了下边的例子就知道了。
 cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjbool require_null_terminated)

  

1.5
测试

cJSON.h, cJSON.cmain.c一起编译,main.c是我用来测试的代码,这个代码几乎测试了cjson的所有接口函数以备后用。也可以参考源目录中的test.cmain.c代码如下:


  1. #include <math.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include "cJSON.h"


  6. static void print_cjson_obj_value(const cJSON * obj)
  7. {
  8.     if (!obj) {
  9.         printf("NULL object!\n");
  10.     }

  11.     switch (obj->type) {
  12.         case cJSON_False:
  13.             printf("%s: false\n", obj->string);
  14.             break;
  15.         case cJSON_True:
  16.             printf("%s: true\n", obj->string);
  17.             break;
  18.         case cJSON_NULL:
  19.             printf("%s: cJSON_NULL\n", obj->string);
  20.             break;
  21.         case cJSON_Number:
  22.             printf("%s: %d, %f\n",
  23.                     obj->string, obj->valueint, obj->valuedouble);
  24.             break;
  25.         case cJSON_String:
  26.             printf("%s: %s\n",
  27.                     obj->string, obj->valuestring);
  28.             break;
  29.         case cJSON_Array:
  30.             printf("%s: cJSON_Array\n", obj->string);
  31.             break;
  32.         case cJSON_Object:
  33.             printf("%s: cJSON_Object\n", obj->string);
  34.             break;
  35.         default:
  36.             printf("unknown type\n");
  37.     }
  38. }

  39. /* *
  40.  * 字符串转换成json对象
  41.  */
  42. int test_parse_json_string_to_object()
  43. {
  44. #define MY_JSON_STRING    \
  45.     "{\"name\": \"Jack (\\\"Bee\\\") Nimble\", \
  46.         \"format\": {                     \
  47.             \"type\":      \"rect\", \
  48.             \"width\":     1920,     \
  49.             \"interlace\": true, \
  50.             \"height\": 123.1 \
  51.         },                                 \
  52.         \"brother\": [ \
  53.             \"Lea\",                     \
  54.             \"Boo\"                         \
  55.         ]                                 \
  56.     }"

  57.     /* 1. 解析,打印
  58.      (1) cJSON_Parse解析字符串为json对象
  59.      (2) cJSON_Print将json对象打包成字符串,使用之后需要释放字符串空间
  60.     */
  61.     printf("(1) parse, print\n");
  62.     cJSON * cj_root = cJSON_Parse(MY_JSON_STRING);
  63.     const char * cj_str = cJSON_Print(cj_root);
  64.     printf("%s\n\n", cj_str);
  65.     free(cj_str);

  66.     /* 2. 获取对象
  67.           (1) 如果获取的对象不存在,cJSON_GetObjectItem返回为空
  68.           (2) cJSON_GetObjectItem只能获得当前对象的元素,不能获取前对象的元素中的对象
  69.               例如
  70.                    cJSON_GetObjectItem(cj_root,"format");不为空
  71.                    cJSON_GetObjectItem(cj_root,"type");为空
  72.           (3) 判断对象是否存在不使用cJSON_HasObjectItem(),直接判断cJSON_GetObjectItem()返回的指针是否为空
  73.     */
  74.     printf("(2) get object\n");
  75.     cJSON * format = cJSON_GetObjectItem(cj_root, "format");
  76.     cJSON * brother = cJSON_GetObjectItem(cj_root, "brother");
  77.     cJSON * type = cJSON_GetObjectItem(cj_root, "type");
  78.     printf("format [%p]\n", format);
  79.     printf("brother [%p]\n", brother);
  80.     printf("type [%p]\n", type);
  81.     
  82.     /* 3. 获取对象的值
  83.           (1) 每个对象是由cJSON结构体组成
  84.      (2) cJSON_Number包括整形和浮点型
  85.      (3) 打印数组对象的值先判断数组长度,再打印。或者使用cJSON_ArrayForEach宏,后一个遍历速度更快
  86.      (4) json使用完之后需要释放其空间
  87.     */

  88.     printf("\n(3) get object value\n");
  89.     print_cjson_obj_value(cJSON_GetObjectItem(cj_root, "name"));
  90.     print_cjson_obj_value(cJSON_GetObjectItem(format, "type"));
  91.     print_cjson_obj_value(cJSON_GetObjectItem(format, "width"));
  92.     print_cjson_obj_value(cJSON_GetObjectItem(format, "interlace"));
  93.     print_cjson_obj_value(cJSON_GetObjectItem(format, "height"));

  94. #if 0
  95.     int size = cJSON_GetArraySize(brother);
  96.     for (int i = 0; i < size; i++) {
  97.         print_cjson_obj_value(cJSON_GetArrayItem(brother, i));
  98.     }
  99. #else
  100.     cJSON * pos = NULL;
  101.     cJSON_ArrayForEach(pos, brother) {
  102.         print_cjson_obj_value(pos);
  103.     }
  104. #endif

  105.     /* *
  106.      * cjson使用完成之后需要释放空间
  107.      */
  108.     cJSON_Delete(cj_root);
  109.     
  110. #undef MY_JSON_STRING
  111. }

  112. /* *
  113.  * json对象转化成字符串
  114.  */
  115. int test_pack_json_object_to_string()
  116. {

  117.     /*
  118.      (1) 创建json对像,要先使用cJSON_CreateObject()创建一个根对象
  119.      (2) 在使用cJSON_AddItemToObject()添加各种对象到根对象中。也可以直接使用头文件提供的宏来添加对象和值,如下
  120.          cJSON_AddNullToObject(object,name)
  121.         cJSON_AddTrueToObject(object,name)
  122.         cJSON_AddFalseToObject(object,name)
  123.         cJSON_AddBoolToObject(object,name,b)
  124.         cJSON_AddNumberToObject(object,name,n)
  125.         cJSON_AddStringToObject(object,name,s)
  126.     */

  127.     cJSON * root = NULL;
  128.     cJSON * format = NULL;
  129.     cJSON * brother = NULL;
  130.     root = cJSON_CreateObject();
  131.     cJSON_AddStringToObject(root, "name", "Jack (\"Bee\") Nimble");
  132.     cJSON_AddItemToObject(root, "format", format=cJSON_CreateObject());
  133.     cJSON_AddItemToObject(root, "brother", brother=cJSON_CreateArray());

  134.     /* 普通对象中插入对象和值 */
  135.     {
  136.         cJSON_AddStringToObject(format, "type", "rect");
  137.         cJSON_AddFalseToObject(format, "interlace");
  138.         cJSON_AddNumberToObject(format, "width", 1920);    
  139.         cJSON_AddNumberToObject(format, "height", 1920.11);
  140.         cJSON_AddBoolToObject(format, "flag", 1);
  141.     }

  142.     /* 数组中插入对象和值 */
  143.     {    
  144.         cJSON_AddItemToArray(brother,cJSON_CreateString("Lea"));
  145.         cJSON_AddItemToArray(brother,cJSON_CreateString("Boo"));
  146.     }

  147.     const char * cj_str = cJSON_Print(root);
  148.     printf("%s\n\n", cj_str);
  149.     free(cj_str);

  150.     /* *
  151.      * cjson使用完成之后需要释放空间
  152.      */
  153.     cJSON_Delete(root);
  154. }

  155. void print_cjson_string(const char * describe, const char *cj_str)
  156. {
  157.     printf("%s\n%s\n\n", describe, cj_str);
  158.     free(cj_str);
  159. }

  160. /* *
  161.  * 使用cjson提供的其它接口操作,都在cJSON.h中
  162.  */
  163. int test_cjson_operation()
  164. {
  165. #define MY_JSON_STRING    \
  166.         "{\"name\": \"Lee\"}"

  167.     /* *
  168.      (1) cJSON_PrintUnformatted打印出的json字符串是紧凑的不用换行,适合传输json字符串时使用
  169.      (2) cJSON_PrintBuffered可以事先指定分配一个缓冲区,如果足够大,则可以节省不断重新分配空间的时间;
  170.          如果指定缓冲区过小,则与cJSON_Print和cJSON_PrintUnformatted性能能相同。
  171.      (3) cJSON_PrintPreallocated可以将json字符串填入给定的缓冲区,并指定缓冲区大小。
  172.          成功返回1,失败返回0。除了这个打印json字符串的函数,以上的函数在生成json字符串时若空间不足,
  173.          都会重新分配一次空间。     
  174.      */
  175.     cJSON * root = cJSON_Parse(MY_JSON_STRING);
  176.     print_cjson_string("(1) cJSON_PrintUnformatted",
  177.                  cJSON_PrintUnformatted(root));
  178.     print_cjson_string("(2) cJSON_PrintBuffered",
  179.                  cJSON_PrintBuffered(root, 1, 1));
  180.     print_cjson_string("(3) cJSON_PrintBuffered",
  181.                  cJSON_PrintBuffered(root, 1, 0));
  182. #define BUF_LEN 1024
  183.     char buf[BUF_LEN] = {0};
  184.     if (0 == cJSON_PrintPreallocated(root, buf, BUF_LEN, 0)) {
  185.         printf("(4) cJSON_PrintPreallocated\nfail\n\n");
  186.     } else {
  187.         printf("(4) cJSON_PrintPreallocated\n%s\n\n", buf);
  188.     }
  189. #undef BUF_LEN

  190.     /* *
  191.      (4) cJSON_GetErrorPtr可以获取字符串解析函数cJSON_Parse出错时的字符位置。
  192.      如果解析没有错误,则返回NULL。
  193.      */

  194.     printf("(5) cJSON_GetErrorPtr\n");
  195.     const cJSON * cj_tmp = cJSON_Parse("{\"haha\":12,, \"xixi\":34}");
  196.     printf("[%s]\n\n", cJSON_GetErrorPtr());

  197.     /* *
  198.      (5) cJSON_CreateIntArray, cJSON_CreateFloatArray, cJSON_CreateDoubleArray和cJSON_CreateStringArray
  199.      这4个函数可以直接将数组转换成json数组对象
  200.      */
  201.     int intarray[4] = {0, 1, 2, 3};
  202.     cJSON_AddItemToObject(root, "intarray",cJSON_CreateIntArray(intarray, 4));
  203.     print_cjson_string("(6) cJSON_CreateIntArray",cJSON_Print(root));

  204.     /* *
  205.      (6) cJSON_AddItemToObjectCS中的string参数是一个字符串常量,不需要为string分配空间。
  206.          感觉没什么用。
  207.      */
  208.     const char * con_str = "haha";
  209.     cJSON_AddItemToObjectCS(root, con_str, cJSON_CreateString("go"));
  210.     print_cjson_string("(7) cJSON_AddItemToObjectCS",cJSON_Print(root));

  211.     /* *
  212.      (7) cJSON_AddItemReferenceToObject和cJSON_AddItemReferenceToArray
  213.          将一个json对象引用到另一个json对象上,只拷贝了被引用对象的根节点,并不是复制所有节点到另一个json对象。
  214.      */
  215.     
  216.     cJSON * n_root = cJSON_CreateObject();
  217.     cJSON_AddItemReferenceToObject(n_root, "n_intarray",
  218.                                  cJSON_GetObjectItem(root,"intarray"));
  219.     print_cjson_string("(8) cJSON_AddItemReferenceToObject",cJSON_Print(n_root));

  220.     /* *
  221.      (8) cJSON_DetachItemFromArray, cJSON_DeleteItemFromArray, cJSON_DetachItemFromObject, cJSON_DeleteItemFromObject
  222.          cJSON_DetachItemFromArray是从json数组对象中分离出来第n个节点,cJSON_DeleteItemFromArray是删除json数组对象的第n个节点
  223.          cJSON_DetachItemFromObject是分离任意节点,cJSON_DeleteItemFromObject是删除任意节点
  224.      */
  225.     cJSON_DeleteItemFromArray(cJSON_GetObjectItem(root,"intarray"), 2);
  226.     print_cjson_string("(9) cJSON_DeleteItemFromArray",cJSON_Print(root));    

  227.     /* *
  228.      (9) cJSON_InsertItemInArray 插入节点到数组中
  229.          cJSON_ReplaceItemInArray 替换数组中的第n个节点
  230.          cJSON_ReplaceItemInObject 替换任意节点
  231.      */
  232.     cJSON_InsertItemInArray(cJSON_GetObjectItem(root,"intarray"),
  233.                              2, cJSON_CreateNumber(2));
  234.       cJSON_ReplaceItemInObject(root, "name", cJSON_CreateString("Bluce"));
  235.        print_cjson_string("(10) cJSON_DeleteItemFromArray",cJSON_Print(root));

  236.        /* *
  237.      (10) cJSON_InsertItemInArray 插入节点到数组中
  238.          cJSON_ReplaceItemInArray 替换数组中的第n个节点
  239.          cJSON_ReplaceItemInObject 替换任意节点
  240.      */
  241.     cJSON_InsertItemInArray(cJSON_GetObjectItem(root,"intarray"),
  242.                              2, cJSON_CreateNumber(2));
  243.       cJSON_ReplaceItemInObject(root, "name", cJSON_CreateString("Bluce"));
  244.        print_cjson_string("(11) cJSON_DeleteItemFromArray",cJSON_Print(root));    

  245.        /* *
  246.      (11) cJSON_Duplicate recurse为1表示递归复制一个json对象。
  247.      */
  248.        cJSON * cj_duplicate = cJSON_Duplicate(root, 1);
  249.     print_cjson_string("(12) cJSON_Duplicate",cJSON_Print(cj_duplicate));     

  250.        /* *
  251.      (12) cJSON_ParseWithOpts
  252.          该函数是cJSON_Parse的实现,但是它比cJSON_Parse更灵活。
  253.          1.如果cJSON_Parse解析错误,必须调用cJSON_GetErrorPtr找到解析错误位置
  254.          2.cJSON_Parse解析不严谨,如"{\"name\": \"Lee\"} }"这个字符串,后边多了一个大括号,但还是解析成功了。
  255.          3.cJSON_ParseWithOpts的return_parse_end参数可以获取解析失败的位置,
  256.           require_null_terminated参数为1会检查剩余未解析字符串是否是空字符串,
  257.           若不为空字符串,则会释放内存,返回空。
  258.           @所以因该使用cJSON_ParseWithOpts解析json对象
  259.      */
  260.     {
  261.         printf("(13) cJSON_ParseWithOpts\n");
  262.         char * end = NULL;
  263.      cJSON * cj_ParseWithOpts = cJSON_ParseWithOpts("{\"name\": \"Lee\"} }", &end, 1);
  264.      if (cj_ParseWithOpts) {
  265.             printf("%s\n\n", cJSON_Print(cj_ParseWithOpts));
  266.      } else {
  267.             printf("[%s]\n\n", end);
  268.      }
  269.     }
  270.     
  271.     {
  272.         printf("(14) cJSON_Parse\n");
  273.         char * end = NULL;
  274.      cJSON * cj_ParseWithOpts = cJSON_Parse("{\"name\": \"Lee\"} }");
  275.      if (cj_ParseWithOpts) {
  276.             printf("%s\n\n", cJSON_Print(cj_ParseWithOpts));
  277.      } else {
  278.             printf("[%s]\n\n", end);
  279.      }
  280.     }

  281.     /* *
  282.      (12) cJSON_SetIntValue和cJSON_SetNumberValue相同,
  283.           既可以设置整形值,也可以设置double类型值。
  284.      */
  285.     printf("(15) cJSON_SetIntValue\n");
  286.     cJSON * int_cj = cJSON_CreateNumber(1);
  287.     printf("%s\n", cJSON_Print(int_cj));
  288.     cJSON_SetIntValue(int_cj, 1.1);
  289.     printf("%s\n\n", cJSON_Print(int_cj));

  290.     cJSON_Delete(root);
  291. }


  292. int main()
  293. {
  294.     //将json字符串解析成json对象
  295.     printf("<< test_parse_json_string_to_object >>\n");
  296.     test_parse_json_string_to_object();

  297.     //将生成json对象,并将json对象组成字符串
  298.     printf("\n<< test_pack_json_object_to_string >>\n");
  299.     test_pack_json_object_to_string();

  300.     //其它一些json接口测试
  301.     printf("<< test_cjson_operation >>\n");
  302.     test_cjson_operation();
  303.     return 0;
  304. }

结果:

  1. [root@192 cJSON]# ./main
  2. << test_parse_json_string_to_object >>
  3. (1) parse, print
  4. {
  5.         "name": "Jack (\"Bee\") Nimble",
  6.         "format": {
  7.                 "type": "rect",
  8.                 "width": 1920,
  9.                 "interlace": true,
  10.                 "height": 123.100000
  11.         },
  12.         "brother": ["Lea", "Boo"]
  13. }

  14. (2) get object
  15. format [0x9a87080]
  16. brother [0x9a871a8]
  17. type [(nil)]

  18. (3) get object value
  19. name: Jack ("Bee") Nimble
  20. type: rect
  21. width: 1920, 1920.000000
  22. interlace: true
  23. height: 123, 123.100000
  24. (null): Lea
  25. (null): Boo

  26. << test_pack_json_object_to_string >>
  27. {
  28.         "name": "Jack (\"Bee\") Nimble",
  29.         "format": {
  30.                 "type": "rect",
  31.                 "interlace": false,
  32.                 "width": 1920,
  33.                 "height": 1920.110000,
  34.                 "flag": true
  35.         },
  36.         "brother": ["Lea", "Boo"]
  37. }

  38. << test_cjson_operation >>
  39. (1) cJSON_PrintUnformatted
  40. {"name":"Lee"}

  41. (2) cJSON_PrintBuffered
  42. {
  43.         "name": "Lee"
  44. }

  45. (3) cJSON_PrintBuffered
  46. {"name":"Lee"}

  47. (4) cJSON_PrintPreallocated
  48. {"name":"Lee"}

  49. (5) cJSON_GetErrorPtr
  50. [, "xixi":34}]

  51. (6) cJSON_CreateIntArray
  52. {
  53.         "name": "Lee",
  54.         "intarray": [0, 1, 2, 3]
  55. }

  56. (7) cJSON_AddItemToObjectCS
  57. {
  58.         "name": "Lee",
  59.         "intarray": [0, 1, 2, 3],
  60.         "haha": "go"
  61. }

  62. (8) cJSON_AddItemReferenceToObject
  63. {
  64.         "n_intarray": [0, 1, 2, 3]
  65. }

  66. (9) cJSON_DeleteItemFromArray
  67. {
  68.         "name": "Lee",
  69.         "intarray": [0, 1, 3],
  70.         "haha": "go"
  71. }

  72. (10) cJSON_DeleteItemFromArray
  73. {
  74.         "name": "Bluce",
  75.         "intarray": [0, 1, 2, 3],
  76.         "haha": "go"
  77. }

  78. (11) cJSON_DeleteItemFromArray
  79. {
  80.         "name": "Bluce",
  81.         "intarray": [0, 1, 2, 2, 3],
  82.         "haha": "go"
  83. }

  84. (12) cJSON_Duplicate
  85. {
  86.         "name": "Bluce",
  87.         "intarray": [0, 1, 2, 2, 3],
  88.         "haha": "go"
  89. }

  90. (13) cJSON_ParseWithOpts
  91. [}]

  92. (14) cJSON_Parse
  93. {
  94.         "name": "Lee"
  95. }

  96. (15) cJSON_SetIntValue
  97. 1
  98. 1.100000


阅读(24837) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~