cJSON

  • ANSI C中的超轻量级JSON解析器。
  1. 通行证

执照

  • 版权所有(c)2009-2017 Dave Gamble和cJSON贡献者

  • 特此免费授予获得此软件和相关文档文件(“软件”)副本的任何人无限制地处理软件的权利,包括但不限于使用,复制,修改,合并的权利,发布,分发,再许可和/或出售本软件的副本,并允许具有本软件的个人遵循以下条件:
  • 以上版权声明和本许可声明应包含在本软件的所有副本或大部分内容中。
  • 本软件按“原样”提供,不提供任何形式的明示或暗示的担保,包括但不限于对适销性,特定目的的适用性和非侵权性的担保。无论是由于软件,使用或其他方式产生的,与之有关或与之有关的合同,侵权或其他形式的任何索赔,损害或其他责任,作者或版权所有者概不负责。软件。

用户页

  • 欢迎使用cJSON。
  • cJSON旨在成为您可以完成工作的最简洁的解析器。 它是C的单个C文件,以及单个H文件。
  • JSON的最佳描述如下:http://www.json.org/就像XML,但没有冗余的部分。 您可以使用它来传送数据,存储数据,或者只是在程序上处理数据。
  • 作为一个库文件,cJSON的存在是为了尽可能多地消除繁琐的工作,但不会妨碍您的正常工作。 出于实用的考虑(即忽略事实),我要说的是您可以在两种模式之一下使用它:自动和手动。 让我们快速浏览一下。
  • 我从此页面上提取了一些JSON:http://www.json.org/fatfree.html,该页面启发了我编写cJSON,这是一个试图与JSON本身共享相同哲学的解析器。 简单,操作简单,处理准确。

新建

  • 有几种方法可以将cJSON合并到您的项目中。

复制源文件

  • 因为整个库只有一个C文件和一个头文件,所以您只需将cJSON.h和cJSON.c复制到项目源并开始使用它。
  • cJSON用ANSI C(C89)编写,以便支持尽可能多的平台和编译器。

编译

  • 使用CMake,cJSON支持完整的构建系统。 这样,您可以获得最多的功能。 支持版本等于或高于2.8.5的CMake。 推荐使用CMake进行树外构建,这意味着将编译后的文件放在与源文件不同的目录中。 因此,为了在Unix平台上使用CMake构建cJSON,创建一个构建目录并在其中运行CMake。
mkdir build
cd build
cmake ..
  • 这将创建一个Makefile和一堆其他文件。 然后可以编译它:

make
  • 并使用make install进行安装。 默认情况下,它将头文件/ usr / local / include / cjson和库安装到/ usr / local / lib。 它还会为pkg-config安装文件,以使其更易于检测和使用CMake的现有安装。 并安装CMake配置文件,其他基于CMake的项目可以使用该文件来发现库。 
  • 您可以使用可传递给CMake的不同选项列表来更改构建过程。 使用“打开”打开它们,使用“关闭”关闭它们:

    -DENABLE_CJSON_TEST=On: Enable building the tests. (on by default)
    -DENABLE_CJSON_UTILS=On: Enable building cJSON_Utils. (off by default)
    -DENABLE_TARGET_EXPORT=On: Enable the export of CMake targets. Turn off if it makes problems. (on by default)
    -DENABLE_CUSTOM_COMPILER_FLAGS=On: Enable custom compiler flags (currently for Clang, GCC and MSVC). Turn off if it makes problems. (on by default)
    -DENABLE_VALGRIND=On: Run tests with valgrind. (off by default)
    -DENABLE_SANITIZERS=On: Compile cJSON with AddressSanitizer and UndefinedBehaviorSanitizer enabled (if possible). (off by default)
    -DENABLE_SAFE_STACK: Enable the SafeStack instrumentation pass. Currently only works with the Clang compiler. (off by default)
    -DBUILD_SHARED_LIBS=On: Build the shared libraries. (on by default)
    -DBUILD_SHARED_AND_STATIC_LIBS=On: Build both shared and static libraries. (off by default)
    -DCMAKE_INSTALL_PREFIX=/usr: Set a prefix for the installation.
    -DENABLE_LOCALES=On: Enable the usage of localeconv method. ( on by default )
    -DCJSON_OVERRIDE_BUILD_SHARED_LIBS=On: Enable overriding the value of BUILD_SHARED_LIBS with -DCJSON_BUILD_SHARED_LIBS.
  • 如果要为Linux发行版打包cJSON,则可能需要采取以下步骤:
mkdir build
cd build
cmake .. -DENABLE_CJSON_UTILS=On -DENABLE_CJSON_TEST=Off -DCMAKE_INSTALL_PREFIX=/usr
make
make DESTDIR=$pkgdir install
  •  在Windows上,CMake通常用于通过在Visual Studio的开发人员命令提示符中运行它来创建Visual Studio解决方案文件,有关确切步骤,请遵循CMake和Microsoft的官方文档并使用您选择的在线搜索引擎。 虽然并非所有选项都可在Windows上使用,但是上面选项的描述通常仍然适用。

生成文件

  • 注意:不建议使用此方法。 尽可能使用CMake。 Makefile支持仅限于修复Bug。如果您没有可用的CMake,但仍可以使用GNU make。 您可以使用makefile生成cJSON:
  • 在带有源代码的目录中运行此命令,它将自动编译静态和共享库以及一些测试程序(而不是完整的测试套件)。
make all
  • 如果需要,可以使用安装软件将编译的库安装到系统中。 默认情况下,它将在/ usr / local / include / cjson中安装标头,并在/ usr / local / lib中安装库。 但是您可以通过设置PREFIX和DESTDIR变量来更改此行为:make PREFIX = / usr DESTDIR = temp install。 

 

包含cJSON

  • 如果是通过CMake或Makefile安装的,则可以包含cJSON,如下所示:

 

#include <cjson/cJSON.h>

 

数据结构

  • cJSON使用cJSON结构数据类型表示JSON数据:
/* The cJSON structure: */
typedef struct cJSON
{
    struct cJSON *next;
    struct cJSON *prev;
    struct cJSON *child;
    int type;
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    / *不建议写入valueint,而是使用cJSON_SetNumberValue * /
    int valueint;
    double valuedouble;
    char *string;
} cJSON;
  • 此类型的项目表示JSON值。 类型以位标记的形式存储在类型中(这意味着您不能仅通过比较类型的值来找出类型)。

  • 要检查项目的类型,请使用相应的cJSON_Is ...函数。 它执行NULL检查,然后进行类型检查,如果该项属于此类型,则返回布尔值。

类型可以是以下之一:

cJSON_Invalid(检查cJSON_IsInvalid):表示不包含任何值的无效项目。如果将项目设置为全零字节,则将自动具有此类型。
    cJSON_False(使用cJSON_IsFalse进行检查):表示错误的布尔值。您通常还可以使用cJSON_IsBool检查布尔值。
    cJSON_True(检查cJSON_IsTrue):表示真实的布尔值。您通常还可以使用cJSON_IsBool检查布尔值。
    cJSON_NULL(检查cJSON_IsNull):表示空值。
    cJSON_Number(检查cJSON_IsNumber):表示数字值。该值存储为valuedouble和valueint中的double。如果数字超出整数范围,则将INT_MAX或INT_MIN用作valueint。
    cJSON_String(检查cJSON_IsString):表示一个字符串值。它以零终止字符串的形式存储在valuestring中。
    cJSON_Array(检查cJSON_IsArray):表示一个数组值。这是通过将child指向代表数组中值的cJSON项的链接列表来实现的。这些元素使用next和prev链接在一起,其中第一个元素具有prev == NULL,最后一个元素具有next == NULL。
    cJSON_Object(检查cJSON_IsObject):表示对象值。对象的存储方式与数组相同,唯一的区别是对象中的项将其键存储在字符串中。
    cJSON_Raw(与cJSON_IsRaw进行检查):表示以JSON形式存储的任何类型的JSON,这些字符串以零终止的值数组形式存在。例如,可以使用它来避免一遍又一遍地打印相同的静态JSON以节省性能。解析时,cJSON永远不会创建此类型。另请注意,cJSON不会检查其是否为有效JSON。

此外,还有以下两个标志:

cJSON_IsReference:指定子项指向的项目和/或valuestring不受该项目所有,它仅是引用。 因此,cJSON_Delete和其他函数将仅取消分配该项目,而不是其子代/值字符串。
cJSON_StringIsConst:这意味着字符串指向常量字符串。 这意味着cJSON_Delete和其他函数将不会尝试取消分配字符串。

处理数据结构

  • 对于每种值类型,都有一个cJSON_Create ...函数可用于创建该类型的项目。 所有这些都将分配一个cJSON结构,以后可以使用cJSON_Delete将其删除。 请注意,您必须在某些时候将其删除,否则会发生内存泄漏。 重要提示:如果已经将项目添加到数组或对象中,则不能使用cJSON_Delete删除它。 将其添加到数组或对象将转移其所有权,以便在删除该数组或对象时也将其删除。

基本类型:

 使用cJSON_CreateNull创建null
     布尔值是使用cJSON_CreateTrue,cJSON_CreateFalse或cJSON_CreateBool创建的
     使用cJSON_CreateNumber创建数字。 这将同时设置valuedouble和valueint。 如果数字超出整数范围,则将INT_MAX或INT_MIN用作valueint
     字符串是使用cJSON_CreateString(复制字符串)或cJSON_CreateStringReference(直接指向字符串)创建的。这意味着valueString不会被cJSON_Delete删除,并且您要对字符串的生命期负责,这对常量很有用。

矩阵

  • 您可以使用cJSON_CreateArray创建一个空数组。 cJSON_CreateArrayReference可用于创建不“拥有”其内容的数组,因此cJSON_Delete不会删除其内容。
  • 要将项目添加到数组,请使用cJSON_AddItemToArray将项目追加到末尾。使用cJSON_AddItemReferenceToArray可以将元素添加为对另一个项目,数组或字符串的引用。这意味着cJSON_Delete将不会删除该项目的子项或valuestring属性,因此,如果已经在其他地方使用了双重释放,则不会发生任何双重释放。要在中间插入项目,请使用cJSON_InsertItemInArray。它将在基于0的给定索引处插入一个项目,并将所有现有项目向右移动。
  • 如果要从给定索引的数组中取出项目并继续使用它,请使用cJSON_DetachItemFromArray,它将返回分离的项目,因此请确保将其分配给指针,否则会发生内存泄漏。
  • 删除项目是使用cJSON_DeleteItemFromArray完成的。它的工作方式类似于cJSON_DetachItemFromArray,但通过cJSON_Delete删除了分离的项目。
  • 您还可以替换数组中的项目。使用带有索引的cJSON_ReplaceItemInArray或使用cJSON_ReplaceItemViaPointer给定了指向元素的指针。如果cJSON_ReplaceItemViaPointer失败,则将返回0。这在内部所做的是分离旧项目,将其删除,然后将新项目插入其位置。
  • 要获取数组的大小,请使用cJSON_GetArraySize。使用cJSON_GetArrayItem获取给定索引处的元素。
  • 由于数组存储为链接列表,因此通过索引对其进行迭代效率不高(O(n²)),因此您可以使用cJSON_ArrayForEach宏以O(n)时间复杂度对数组进行迭代。

对象

  • 如果要从对象中取出项目,请使用cJSON_DetachItemFromObjectCaseSensitive,它将返回分离的项目,因此请确保将其分配给指针,否则会发生内存泄漏。
  • 删除项目是使用cJSON_DeleteItemFromObjectCaseSensitive完成的。它的工作方式类似于cJSON_DetachItemFromObjectCaseSensitive,然后是cJSON_Delete。
  • 您也可以在适当位置替换对象中的项目。使用带有密钥的cJSON_ReplaceItemInObjectCaseSensitive或带有给定元素指针的cJSON_ReplaceItemViaPointer。如果cJSON_ReplaceItemViaPointer失败,则将返回0。这在内部所做的是分离旧项目,将其删除,然后将新项目插入其位置。
  • 要获取对象的大小,可以使用cJSON_GetArraySize,这是可行的,因为在内部将对象存储为数组。
  • 如果要访问对象中的项目,请使用cJSON_GetObjectItemCaseSensitive。
  • 要遍历对象,可以使用与数组相同的方式使用cJSON_ArrayForEach宏。
  • cJSON还提供了便捷的帮助器功能,用于快速创建新项目并将其添加到对象,例如cJSON_AddNullToObject。它们返回指向新项目的指针,如果失败,则返回NULL。

解析JSON

  • 给定一些以零结尾的字符串的JSON,您可以使用cJSON_Parse对其进行解析。
cJSON *json = cJSON_Parse(string);
  • 它将解析JSON并分配代表它的cJSON项树。一旦返回,您将完全负责将其与cJSON_Delete一起使用后进行分配。
  • cJSON_Parse使用的分配器默认为malloc且可用,但可以使用cJSON_InitHooks进行更改(全局更改)。
  • 如果发生错误,则可以使用cJSON_GetErrorPtr访问指向输入字符串中错误位置的指针。请注意,尽管这会在多线程方案中产生竞争条件,但在这种情况下,最好将cJSON_ParseWithOpts与return_parse_end结合使用。默认情况下,输入字符串中已解析的JSON后面的字符将不被视为错误。
  • 如果需要更多选项,请使用cJSON_ParseWithOpts(const char * value,const char ** return_parse_end,cJSON_bool require_null_terminated)。 return_parse_end返回一个指针,指向输入字符串中JSON的末尾或发生错误的位置(从而以线程安全的方式替换cJSON_GetErrorPtr)。如果输入字符串包含JSON之后的数据,则require_null_terminated(如果设置为1)将导致错误。

打印JSON

  • 给定一棵cJSON项目树,您可以使用cJSON_Print将它们打印为字符串。
char * string = cJSON_Print(json);
  • 它将分配一个字符串并在其中打印树的JSON表示形式。一旦返回,您将完全负责与分配器一起使用后对其进行分配。 (通常是free,取决于cJSON_InitHooks设置的内容)。
  • cJSON_Print将使用空格打印以进行带格式打印。如果要打印不带格式的,请使用cJSON_PrintUnformatted。
  • 如果您对结果字符串的大小有一个大概的了解,可以使用cJSON_PrintBuffered(const cJSON * item,int prebuffer,cJSON_bool fmt)。 fmt是一个布尔值,用于打开和关闭空白格式。 prebuffer指定要用于打印的第一个缓冲区大小。
  • cJSON_Print打印当前使用的第一个缓冲区大小为256个字节。一旦打印空间不足,将分配一个新的缓冲区,并在继续打印之前复制旧缓冲区。
  • 通过使用cJSON_PrintPreallocated(cJSON * item,char * buffer,const int length,const cJSON_bool格式),可以完全避免这些动态缓冲区分配。它需要一个指向指针的缓冲区才能打印到它的长度。如果达到该长度,则打印将失败并返回0。如果成功,则返回1。请注意,您应该提供比实际需要更多的5个字节,因为cJSON在估计提供的内存是否足够时不是100%准确的。

例程

  • 在此示例中,我们要构建并解析以下JSON:
{
    "name": "Awesome 4K",
    "resolutions": [
        {
            "width": 1280,
            "height": 720
        },
        {
            "width": 1920,
            "height": 1080
        },
        {
            "width": 3840,
            "height": 2160
        }
    ]
}
  • 让我们构建上面的JSON并将其打印为字符串:
//create a monitor with a list of supported resolutions
//NOTE: Returns a heap allocated string, you are required to free it after use.
char* create_monitor(void)
{
    const unsigned int resolution_numbers[3][2] = {
        {1280, 720},
        {1920, 1080},
        {3840, 2160}
    };
    char *string = NULL;
    cJSON *name = NULL;
    cJSON *resolutions = NULL;
    cJSON *resolution = NULL;
    cJSON *width = NULL;
    cJSON *height = NULL;
    size_t index = 0;

    cJSON *monitor = cJSON_CreateObject();
    if (monitor == NULL)
    {
        goto end;
    }

    name = cJSON_CreateString("Awesome 4K");
    if (name == NULL)
    {
        goto end;
    }
    /* after creation was successful, immediately add it to the monitor,
     * thereby transferring ownership of the pointer to it */
    cJSON_AddItemToObject(monitor, "name", name);

    resolutions = cJSON_CreateArray();
    if (resolutions == NULL)
    {
        goto end;
    }
    cJSON_AddItemToObject(monitor, "resolutions", resolutions);

    for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
    {
        resolution = cJSON_CreateObject();
        if (resolution == NULL)
        {
            goto end;
        }
        cJSON_AddItemToArray(resolutions, resolution);

        width = cJSON_CreateNumber(resolution_numbers[index][0]);
        if (width == NULL)
        {
            goto end;
        }
        cJSON_AddItemToObject(resolution, "width", width);

        height = cJSON_CreateNumber(resolution_numbers[index][1]);
        if (height == NULL)
        {
            goto end;
        }
        cJSON_AddItemToObject(resolution, "height", height);
    }

    string = cJSON_Print(monitor);
    if (string == NULL)
    {
        fprintf(stderr, "Failed to print monitor.\n");
    }

end:
    cJSON_Delete(monitor);
    return string;
}
  • 另外,我们可以使用cJSON_Add ... ToObject帮助器函数使我们编写程序更轻松一些:
//NOTE: Returns a heap allocated string, you are required to free it after use.
char *create_monitor_with_helpers(void)
{
    const unsigned int resolution_numbers[3][2] = {
        {1280, 720},
        {1920, 1080},
        {3840, 2160}
    };
    char *string = NULL;
    cJSON *resolutions = NULL;
    size_t index = 0;

    cJSON *monitor = cJSON_CreateObject();

    if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL)
    {
        goto end;
    }

    resolutions = cJSON_AddArrayToObject(monitor, "resolutions");
    if (resolutions == NULL)
    {
        goto end;
    }

    for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
    {
        cJSON *resolution = cJSON_CreateObject();

        if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL)
        {
            goto end;
        }

        if(cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL)
        {
            goto end;
        }

        cJSON_AddItemToArray(resolutions, resolution);
    }

    string = cJSON_Print(monitor);
    if (string == NULL) {
        fprintf(stderr, "Failed to print monitor.\n");
    }

end:
    cJSON_Delete(monitor);
    return string;
}

解析JSON

遍历解析几个数组

/* return 1 if the monitor supports full hd, 0 otherwise */
int supports_full_hd(const char * const monitor)
{
    const cJSON *resolution = NULL;
    const cJSON *resolutions = NULL;
    const cJSON *name = NULL;
    int status = 0;
    cJSON *monitor_json = cJSON_Parse(monitor);
    if (monitor_json == NULL)
    {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL)
        {
            fprintf(stderr, "Error before: %s\n", error_ptr);
        }
        status = 0;
        goto end;
    }

    name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
    if (cJSON_IsString(name) && (name->valuestring != NULL))
    {
        printf("Checking monitor \"%s\"\n", name->valuestring);
    }

    resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
    cJSON_ArrayForEach(resolution, resolutions)
    {
        cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
        cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");

        if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
        {
            status = 0;
            goto end;
        }

        if ((width->valuedouble == 1920) && (height->valuedouble == 1080))
        {
            status = 1;
            goto end;
        }
    }

end:
    cJSON_Delete(monitor_json);
    return status;
}
  • 请注意,除了cJSON_Parse的结果外,没有NULL检查,因为cJSON_GetObjectItemCaseSensitive已经检查NULL输入,因此仅传递NULL值,如果输入为NULL,则cJSON_IsNumber和cJSON_IsString返回0。

注意事项

  • cJSON不支持包含零字符“ \ 0”或\ u0000的字符串。对于当前的API,这是不可能的,因为字符串以零结尾。
  • 字符编码
    cJSON仅支持UTF-8编码的输入。但是在大多数情况下,它不会拒绝无效的UTF-8作为输入,而只是将其原样传播。只要输入不包含无效的UTF-8,输出将始终是有效的UTF-8。
  • C标准
    cJSON用ANSI C(或C89,C90)编写。如果您的编译器或C库未遵循此标准,则不能保证正确的行为。
    注意:ANSI C不是C ++,因此不应使用C ++编译器进行编译。您可以使用C编译器对其进行编译,然后将其与C ++代码链接。尽管可以使用C ++编译器进行编译,但不能保证正确的行为。
  • 浮点数字
    除IEEE754双精度浮点数外,cJSON不正式支持任何双实现。它可能仍然可以与其他实现一起使用,但是这些实现的错误将被视为无效。
    目前,cJSON支持的浮点文字的最大长度为63个字符。
  • 数组和对象的深层嵌套
    cJSON不支持嵌套太深的数组和对象,因为这会导致堆栈溢出。为了防止这种情况,cJSON将深度限制为CJSON_NESTING_LIMIT,默认情况下为1000,但可以在编译时更改。
  • 线程安全
    通常,cJSON不是线程安全的。
    但是,在以下情况下它是线程安全的:
    永远不会使用cJSON_GetErrorPtr(可以使用cJSON_ParseWithOpts的return_parse_end参数)
    在任何线程中使用cJSON之前调用cJSON_InitHooks。

    在返回对cJSON函数的所有调用之前,永远不会调用setlocale。
  • 区分大小写
    最初创建cJSON时,它不遵循JSON标准,并且没有区分大写字母和小写字母。如果您想要正确的,符合标准的行为,则需要使用CaseSensitive函数(如果有)。复制对象成员
  • JSON支持解析和打印JSON,该JSON包含具有多个具有相同名称的成员的对象。但是,cJSON_GetObjectItemCaseSensitive将始终仅返回第一个。

欢迎使用cJSON!
     Dave Gamble(原作者)
     Max Bruckner(现任维护人员)
     和其他cJSON贡献者

本作者翻译水平有限,目的是为了认真看一遍,顺便就翻译一下,不足之处,欢迎指正哦

GitHub 加速计划 / cj / cJSON
10.45 K
3.16 K
下载
Ultralightweight JSON parser in ANSI C
最近提交(Master分支:2 个月前 )
424ce4ce This reverts commit 5b502cdbfb21fbe5f6cf9ffbd2b96e4281a741e6. Related to #860 4 个月前
32497300 - 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐