2019.2.6 xml、minixml、json、cJSON

目录

1、xml

  • xml基础语法和规范
  • C程序中如何使用xml开源库
  • 借助开源库,在C程序中生成xml文件
  • 已知一个xml文件,如何借助开源库解析xml文件数据

2、Json

  • json的基础语法和规范
  • C程序中如何使用json开源库 - cjson
  • 使用cjson生成json文件
  • 已知一个json文件,使用cjson库解析文件数据

 

 

XML

 

安装minixml

 

安装包获取地址

http://www.msweet.org/projects.php/Mini-XML  (官网的访问是404)

https://pan.baidu.com/s/1qs9NIictlrXD_ojGE5vndA  (这是我的百度盘资源,也不知道官网以后会不会恢复)

 

安装

./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的使用

 

根标签对应的节点的父节点是——文件头节点

 

生成xml文件

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格式

  1. json数组
  2. json对象
  3. json数组+json对象

 

json数组

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

 

json对象

  • {}中是一些键值对
{

    "name":"zhang3",

    "name2":"li4"

}

 

  • key值: 必须是 字符串, 不重复
  • value值: json对象, json数组, 布尔, 整形, 字符串

 

json数组+json对象

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

 

 

 

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

 

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

安装过程:

unzip cJSON-master.zip

然后将cJSON.ccJSON.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;
}

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值