目录
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格式
- json数组
- json对象
- 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.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;
}