• xml、json解析与生成


    XML

    安装minixml

    安装包获取地址

    https://github.com/michaelrsweet/mxml/releases

    或者官网:迷你 XML 2.8 (msweet.org)

    安装

    ./configure
    make
    sudo make install

    prefix用于指定安装路径,如果安装时只执行 ./configure ,则会安装到默认目录中了,可能会找不到安装到哪里了,所以可以使用prefix来设置路径

    安装时也可以关闭线程库

    ./configure --enable-threads=no

    编译

    gcc -hello.c -0 hello -lmxml  -lpthread

    使用时要包含的头文件

    #include<mxml.h>

    语法规范

    1、新目录需要一个文件头 - 标准

    <?xml version="1.0" encoding="utf-8"?>
    • version不可以省略
    • encoding可以省略

    2、使用注意事项

    • 必须有一个根元素(节点) -- (只有一个)
    • xml标签对大小写敏感
    • 标签大多成对使用, 有开始, 有结束
    <date></date>
     
    <time></time>

    3、标签中可以添加属性

    <node date="17/11/2017">

    4、标签注释

    <!-- 这是注释 -->

    开源库minixml的使用

    1、创建一个新的xml文件(就是生成一个文件头)

    mxml_node_t *mxmlNewXML(const char *version);
    • 返回新创建的xml文件节点.
    • 默认的文件的编码为utf8

    2、删除节点的内存(每申请一个节点就会获取一块内存,删除节点内存的时候,只需要把根节点地址传入即可。释放是后序遍历的顺序删除节点)

    void mxmlDelete(mxml_node_t *node);

    3、添加一个新的节点

    mxml_node_t *mxmlNewElement(
            mxml_node_t *parent,         // 父节点
            const char *name             //  新节点标签名
    );

    4、设置节点的属性名和属性值

    void mxmlElementSetAttr(
            mxml_node_t *node,         // 被设置属性的节点
            const char *name,          // 节点的属性名
            const char *value          // 属性值
    );

    5、创建节点中的文本内容

    mxml_node_t *mxmlNewText ( 
            mxml_node_t *parent,         // 节点地址
            int whitespace,              //  是否有空白  0
            const char *string           // 文本内容
    );

    6、保存节点到xml文件

    int mxmlSaveFile(
            mxml_node_t *node,         // 根节点
            FILE *fp,                  // 文件指针
            mxml_save_cb_t cb          // 回调函数,默认MXML_NO_CALLBACK
     
    );

    使用示例

    #include<stdio.h>
    #include<mxml.h>
     
    int main(int argc, char *argv[]){
        //文件头
        mxml_node_t *root=mxmlNewXML("1.0");
     
        //根标签 china
        mxml_node_t *china=mxmlNewElement(root, "china");
     
        //子标签
        mxml_node_t *city=mxmlNewElement(china, "city");
        mxml_node_t *info=mxmlNewElement(city, "name");
     
        //给标签赋值
        mxmlNewText(info, 0, "北京");
        //给name标签添加属性    
        mxmlElementSetAttr(info, "isbig", "Yes");
        //面积,这样放不会发生数据的覆盖,因为数据已经被拷贝了
        info=mxmlNewElement(city, "area");
        mxmlNewText(info, 0, "16410 平方公里");
        //人口
        info=mxmlNewElement(city, "population");
        mxmlNewText(info, 0, "2000万人");
        
        //东京        
        //子标签
        city=mxmlNewElement(china, "city");
        info=mxmlNewElement(city, "name");
          
        //给标签赋值
        mxmlNewText(info, 0, "东京");
        //给name标签添加属性    
        mxmlElementSetAttr(info, "isbig", "Yes");
        //面积,这样放不会发生数据的覆盖,因为数据已经被拷贝了
        info=mxmlNewElement(city, "area");
        mxmlNewText(info, 0, "2222 平方公里");
        //人口
        info=mxmlNewElement(city, "population");
        mxmlNewText(info, 0, "3670万人");
     
        //数据保存在磁盘
        FILE* fp=fopen("china.xml", "w");
        //就先不判断是否打开成功了
        mxmlSaveFile(root, fp, MXML_NO_CALLBACK);
     
        fclose(fp);
        mxmlDelete(root);
        return 0;
    }

    编译

    gcc create.c -o create -lmxml -lpthread

    对于“动态库找不到”的错误的解决办法参考:https://blog.csdn.net/qq_29996285/article/details/86744372

    之后执行可执行文件会生成.xml文件

     推荐一个查看xml文件的工具

     获取链接——https://pan.baidu.com/s/1PSjpGcuvrvkvgnbyDpjJ3w

    解析xml文件

    1、从文件加载xml到内存

    mxml_node_t *mxmlLoadFile(
            mxml_node_t *top,                  // 一般为NULL
            FILE *fp,                          // 文件指针(注意加载读属性)
            mxml_type_t (*cb)(mxml_node_t *)   // 默认MXML_NO_CALLBACK
     
    );

    2、获取节点的属性

    const char *mxmlElementGetAttr(
            mxml_node_t *node,      //  带属性的节点的地址
            const char *name        //  属性名
    );

    3、获取指定节点的文本内容

    const char *mxmlGetText(
            mxml_node_t *node,           // 节点的地址
            int *whitespace              //  是否有空格
     
    );

    4、跳转到下一个节点

    mxml_node_t *mxmlWalkNext(
            mxml_node_t *node,     // 当前节点
            mxml_node_t *top,      // 根节点
            int descend
    );

    descend:搜索的规则

    • MXML_NO_DESCEND:查看同层级
    • MXML_DESCEND_FIRST:查看下一层级的第一个
    • MXML_DESCEND:一直向下搜索

    5、查找节点

    mxml_node_t *mxmlFindElement(
            mxml_node_t *node,               // 当前节点
            mxml_node_t *top,                //  根节点
            const char *name,                //  查找的标签名
            const char *attr,                //  查找的标签的属性,没有属性传NULL
            const char *value,               //  查找的标签的属性值
            int descend                      //  同上
    );

    使用示例

    #include <stdio.h>
    #include <mxml.h>
     
    int main(int argc, const char* argv[]){
        // 从磁盘加载xml文件
        FILE* fp = fopen("china.xml", "r");
        if(fp == NULL) {
            printf("fopen error\n");
            return 0;
        }
        // root 节点指向xml文件头,因为没有回调函数,所以用MXML_NO_CALLBACK
        mxml_node_t* root = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
     
        // 遍历 - 取出各个节点的值
        // 找到第一个城市节点
        mxml_node_t* city = mxmlFindElement(root, root, "City", NULL, NULL, MXML_DESCEND);
        if(city == NULL){
            printf("xml node not found\n");
            return 0;
        }
        while( city  ) {
            printf("==================\n");
            // 向下走一个节点
            mxml_node_t* node = mxmlWalkNext(city, root, MXML_DESCEND_FIRST);
            printf("city:   \n");
            printf("    name = %s\n", mxmlGetText(node, NULL));
            // 
            node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
            printf("    area = %s\n", mxmlGetText(node, NULL));
            //
            node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
            printf("    population = %s\n", mxmlGetText(node, NULL));
            // 搜索下一个城市节点
            city = mxmlFindElement(city, root, "City", NULL, NULL, MXML_DESCEND);
        }
     
        fclose(fp);
        mxmlDelete(root);
     
        return 0;
    }

     注意:mxmlWalkNext函数对于存在换行的xml文件和不存在换行的xml文件的解析结果是不同的,该函数解析换行的时候会出现错误。慎用mxmlWalkNext函数,用mxmlFindElement函数。

    json

    json格式

    json数组

      char array[23] = "slkjflajslfd"; ——c语言中的数组
      中括号[整形, 字符串, 布尔类型, json数组, json对象]——json数组
      [123, 123.2, true, false, [12, 34, 56, "hello, world"]]——数据类型可以是不一样的

    json对象

    • {}中是一些键值对
    • key值: 必须是 字符串, 不重复
    • value值: json对象, json数组, 布尔, 整形, 字符串
    {
     
        "name":"zhang3",
     
        "name2":"li4"
     
    }

    json数组+json对象

        {
            "name":"zhang3", 
            "name2":"li4",
            "张三":{
                "别名":"老王",
                "性别":"",
                "年龄":34,
                "孩子":["小红", "小绿", "小黑"]
                }
        }

    cjson——解析json格式文件的包

    安装包:https://pan.baidu.com/s/17_XxWpYJVhAApbAkF9d6vQ

    安装过程:unzip cJSON-master.zip

    然后将cJSON.c和cJSON.h拷贝到你要用的目录下即可。

    生成json文件

    1、创建一个json对象

    cJSON *cJSON_CreateObject(void);

    2、往json对象中添加数据成员

    void cJSON_AddItemToObject(
            cJSON *object,              //  json对象
            const char *string,         //  key值
            cJSON *item                 //  value值(int,string,array,obj)
    );

    3、创建一个整型值

    cJSON *cJSON_CreateNumber(double num);

    4、创建一个字符串

    cJSON *cJSON_CreateString(const char *string);

    5、创建一个json数组

    cJSON *cJSON_CreateArray(void); -- 空数组

    6、创建默认有count个整形值的json数组

    cJSON *cJSON_CreateIntArray(const int *numbers,int count);
    • int arry[] = {8,3,4,5,6};
    • cJSON_CreateIntArray(arry, 5);

    7、往json数组中添加数据成员

    void cJSON_AddItemToArray(cJSON *array, cJSON *item);

    8、释放jSON结构指针

    void cJSON_Delete(cJSON *c)

    9、将JSON结构转化为字符串

    char *cJSON_Print(cJSON *item);
    • 返回值需要使用free释放
    • FILE* fp = fopen();
    • fwrite();
    • fclose();

    使用示例

    #include<stdio.h>
    #include <string.h>
    #include "cJSON.h"
     
    int main(){
        // 创建json对象    
        cJSON* obj = cJSON_CreateObject(); 
        //创建子对象
        cJSON* subobj = cJSON_CreateObject();
        //子对象中添加键值对
        cJSON_AddItemToObject(subobj, "factory", cJSON_CreateString("一汽大众"));
        cJSON_AddItemToObject(subobj, "last", cJSON_CreateNumber(31));
        cJSON_AddItemToObject(subobj, "price", cJSON_CreateNumber(83));
     
        //创建数组
        cJSON* array=cJSON_CreateArray();
        //array添加元素
        cJSON_AddItemToArray(array, cJSON_CreateNumber(123));
        cJSON_AddItemToArray(array, cJSON_CreateBool(1));
        cJSON_AddItemToArray(array, cJSON_CreateString("hello word"));
     
        //创建数组中的对象
        cJSON* subsub = cJSON_CreateObject();
        cJSON_AddItemToObject(subsub, "梅赛德斯奔驰", cJSON_CreateString("心所向,持以恒"));
        cJSON_AddItemToArray(array, subsub);
     
        cJSON_AddItemToObject(subobj, "other", array);
        //obj中添加键值对
        cJSON_AddItemToObject(obj, "奔驰", subobj);
     
        //将数据格式化,格式化成字符串
        char* data=cJSON_Print(obj);
        FILE* fp=fopen("car.json", "w");
        fwrite(data, sizeof(char), strlen(data)+1, fp);
        fclose(fp);
     
        return 0;
    }

    编译(-lm是引入了一个数学库):

    gcc create.c cJSON.c -o create -lm  

    解析json数据

    1、将字符串解析为JSON结构

    cJSON *cJSON_Parse(const char *value);
    • 返回值需要使用cJSON_Delete释放

    2、根据键值查找json节点

    cJSON *cJSON_GetObjectItem(
            cJSON *object,           // 当前json对象
            const char *string       //  key值
    );

    3、获取json数组中元素的个数

    int cJSON_GetArraySize(cJSON *array);

    4、根据数组下标找到对应的数组元素

    cJSON *cJSON_GetArrayItem(cJSON *array, int index);

    5、判断是否有可以值对应的键值对

    int cJSON_HasObjectItem(cJSON *object, const char *string);

    cJSON结构体

    #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) 
     
    /* The cJSON structure: */
    typedef struct cJSON {
     
        struct cJSON *next;
        struct cJSON *prev;
        struct cJSON *child;
     
        int type;
        char *valuestring;
        int valueint;
        double valuedouble;
     
        char *string;
     
    } cJSON;

    cJSON解析json文件示例

    #include <stdio.h>
    #include <string.h>
    #include "cJSON.h"
     
    int main(int argc, const char* argv[]){
        if(argc < 2){
            printf("./a.out jsonfile\n");
            return 0;
        }
     
        // 加载json文件 
        FILE* fp = fopen(argv[1], "r");
        char buf[1024] = {0};
        fread(buf, 1, sizeof(buf), fp);
        //把字符串转成cJSON类型的结构块
        cJSON* root = cJSON_Parse(buf);
     
        cJSON* subobj = cJSON_GetObjectItem(root, "奔驰");
        // 判断对象是否存在
        if( subobj ){
            // 获取子对象
            cJSON* factory = cJSON_GetObjectItem(subobj, "factory");
            cJSON* last = cJSON_GetObjectItem(subobj, "last");
            cJSON* price = cJSON_GetObjectItem(subobj, "price");
            cJSON* sell = cJSON_GetObjectItem(subobj, "sell");
            cJSON* sum = cJSON_GetObjectItem(subobj, "sum");
            cJSON* other = cJSON_GetObjectItem(subobj, "other");
     
            // 打印value值
            printf("奔驰:\n");
            printf("    factory: %s\n", cJSON_Print(factory));
            printf("    last: %s\n", cJSON_Print(last));
            printf("    price: %s\n", cJSON_Print(price));
            printf("    sell: %s\n", cJSON_Print(sell));
            printf("    sum: %s\n", cJSON_Print(sum));
     
            // 打印数组内容
            printf("    other:\n");
            if(other->type == cJSON_Array) {
                //cJSON_GetArraySize获取数组大小
                for(int i=0; i<cJSON_GetArraySize(other); ++i){
                    cJSON* node = cJSON_GetArrayItem(other, i);
                    // 判断数据类型
                    if(node->type == cJSON_String){
                        printf("        %s  \n", node->valuestring);
                    }
                    if(node->type == cJSON_Number){
                        printf("        %d\n", node->valueint);
                    }
                    if(node->type == cJSON_True) {
                        printf("        %d\n", node->valueint);
                    }
                    if(node->type == cJSON_False){
                        printf("        %d\n", node->valueint);
                    }
                }
            }
        }
     
        cJSON_Delete(root);
        fclose(fp);
     
     
        return 0;
    }

    转自:(11条消息) 2019.2.6 xml、minixml、json、cJSON_一直走,不要回头-CSDN博客

  • 相关阅读:
    协议分析 - DHCP协议解码详解
    在SqlServer2000的视图中小心使用*符号
    sql 将 varchar 值转换为数据类型为 int 的列时发生语法错误 的解决办法
    LECCO SQL Expert工具之优化sql语句
    css+js简单应用
    对任何一天是星期几算法的实现
    asp.net ajax 1.0 出现"sys"未定义解决方法
    js日历脚本
    在ASP.NET中重写URL
    在ASP.NET中重写URL (续篇)
  • 原文地址:https://www.cnblogs.com/Malphite/p/15691310.html
Copyright © 2020-2023  润新知