【Linux C编程】第二十章XML-JSON
一、XML
1. minixml官网地址
http://www.msweet.org/projects.php/Mini-XML
其他解析xml开源库:tinyxml pugixml
1)包含头文件: mxml.h
2)编译的时候需要添加动态库: libmxml.so
- -lmxml
- /usr/local/lib
2. minixml安装:
- ./configure --enable-threads=no && make
- sudo make install
3. 新目录需要一个文件头 - 标准
<?xml version="1.0" encoding="utf-8"?>
- version不可以省略
- encoding可以省略
4. 使用注意事项
- 必须有一个根元素(节点) -- (只有一个)
- xml标签对大小写敏感
- 标签大多成对使用, 有开始, 有结束
<date></date>
<time></time>
5. 标签中可以添加属性
<node date="17/11/2017">
属性值必须加引号
6. 标签注释
<!-- 这是注释 -->
7. 开源库minixml的使用
(1)跟标签的对应的节点,父亲节点是:文件头节点
(2)生成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
);
(3)解析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, // 查找的标签的属性值,没有属性传NULL
int descend // 同上
);
8. 示例
(1)生成下面的xml
create_xml.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <bookstore>
3 <book category="儿童">
4 <title>哈利波特</title>
5 <autoro>JK.Rowling</autoro>
6 <year>2005</year>
7 <price>29.99</price>
8 </book>
9 </bookstore>
create.c
1 #include <stdio.h>
2 #include "mxml.h"
3
4 int main(int argc, const char* argv[])
5 {
6 // 添加文件头
7 mxml_node_t* rootNode = mxmlNewXML("1.0");
8
9 // 添加一个新节点
10 mxml_node_t *bookStore = mxmlNewElement(rootNode, "bookstore");
11 // 添加子节点 - book
12 mxml_node_t* book = mxmlNewElement(bookStore, "book");
13 // 添加book 的属性
14 mxmlElementSetAttr(book, "category", "儿童");
15 // 添加标题
16 mxml_node_t* title = mxmlNewElement(book, "title");
17 mxmlNewText(title, 0, "哈利波特");
18 // 添加作者
19 mxml_node_t* author = mxmlNewElement(book, "autoro");
20 mxmlNewText(author, 0, "JK.Rowling");
21 // 添加时间
22 mxml_node_t* year = mxmlNewElement(book, "year");
23 mxmlNewText(year, 0, "2005");
24 // 添加价格
25 mxml_node_t* price = mxmlNewElement(book, "price");
26 mxmlNewText(price, 0, "29.99");
27
28 // 保存数据到文件
29 FILE* fp = fopen("book.xml", "w");
30 mxmlSaveFile(rootNode, fp, MXML_NO_CALLBACK);
31 fclose(fp);
32
33 return 0;
34 }
parsexml.c
1 #include <stdio.h>
2 #include "mxml.h"
3
4 int main(int argc, const char* argv[])
5 {
6 // 加载xml文件
7 FILE* fp = fopen("book.xml", "r");
8 mxml_node_t* root = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
9
10 // 查找book节点
11 mxml_node_t* book = mxmlFindElement(root, root, "book", "category", NULL, MXML_DESCEND);
12 printf("book attr: %s\n", mxmlElementGetAttr(book, "category"));
13
14 mxml_node_t* node = mxmlWalkNext(book, root, MXML_DESCEND_FIRST);
15 printf(" title: %s\n", mxmlGetText(node, 0));
16
17 node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
18 printf(" author: %s\n", mxmlGetText(node, 0));
19
20 node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
21 printf(" year: %s\n", mxmlGetText(node, 0));
22
23 node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
24 printf(" price: %s\n", mxmlGetText(node, 0));
25
26 fclose(fp);
27
28 mxmlDelete(root);
29
30 return 0;
31 }
(2)生成下面的xml
create_xml.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <China>
3 <City>
4 <Name isbig="true">北京</Name>
5 <Area>1.641万平方千米</Area>
6 <Population>2200万</Population>
7 </City>
8 <City>
9 <Name isbig="false">石家庄</Name>
10 <Area>15848平方千米</Area>
11 <Population>107万</Population>
12 </City>
13 </China>
create.c
1 #include <stdio.h>
2 #include <mxml.h>
3
4 int main(int argc, const char* argv[])
5 {
6 // 创建xml文件头节点
7 mxml_node_t *xml = mxmlNewXML("1.0");
8
9 // 创建xml根节点 - china
10 mxml_node_t* china = mxmlNewElement(xml, "China");
11
12
13 // 创建城市节点
14 mxml_node_t* city = mxmlNewElement(china, "City");
15 // 添加子节点
16 // name
17 mxml_node_t* name = mxmlNewElement(city, "Name");
18 // 设置标签值
19 mxmlNewText(name, 0, "北京");
20 mxmlElementSetAttr(name, "isbig", "true");
21 // 面积
22 mxml_node_t* area = mxmlNewElement(city, "Area");
23 mxmlNewText(area, 0, "1.641万平方千米");
24 // 人口
25 mxml_node_t* popu = mxmlNewElement(city, "Population");
26 mxmlNewText(popu, 0, "2200万");
27
28 // 第二个城市节点
29 city = mxmlNewElement(china, "City");
30 // name
31 name = mxmlNewElement(city, "Name");
32 mxmlNewText(name, 0, "石家庄");
33 mxmlElementSetAttr(name, "isbig", "false");
34 area = mxmlNewElement(city, "Area");
35 mxmlNewText(area, 0, "15848平方千米");
36 popu = mxmlNewElement(city, "Population");
37 mxmlNewText(popu, 0, "107万");
38
39 // 将xml内容保存到磁盘
40 FILE* fp = fopen("china.xml", "w");
41 mxmlSaveFile(xml, fp, MXML_NO_CALLBACK);
42 fclose(fp);
43 mxmlDelete(xml);
44
45 return 0;
46 }
parse_xml.c
1 #include <stdio.h>
2 #include <mxml.h>
3
4 int main(int argc, const char* argv[])
5 {
6 // 从磁盘加载xml文件
7 FILE* fp = fopen("china.xml", "r");
8 if(fp == NULL)
9 {
10 printf("fopen error\n");
11 return 0;
12 }
13 // root 节点指向xml文件头
14 mxml_node_t* root = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
15
16 // 遍历 - 取出各个节点的值
17 // 找到第一个城市节点
18 mxml_node_t* city = mxmlFindElement(root, root, "City", NULL, NULL, MXML_DESCEND);
19 if(city == NULL)
20 {
21 printf("xml node not found\n");
22 return 0;
23 }
24 while( city )
25 {
26 printf("==================\n");
27 // 向下走一个节点
28 mxml_node_t* node = mxmlWalkNext(city, root, MXML_DESCEND_FIRST);
29 printf("city: \n");
30 printf(" name = %s\n", mxmlGetText(node, NULL));
31 //
32 node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
33 printf(" area = %s\n", mxmlGetText(node, NULL));
34 //
35 node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
36 printf(" population = %s\n", mxmlGetText(node, NULL));
37 // 搜索下一个城市节点
38 city = mxmlFindElement(city, root, "City", NULL, NULL, MXML_DESCEND);
39 }
40
41 fclose(fp);
42 mxmlDelete(root);
43
44 return 0;
45 }
(3)xml 解析注意问题
注意:使用 minixml 开源库生成的 xml 会在一行,如果手动将调整 xml,则解析会有问题。下面的示例相同的xml,只是将在一行的xml进行调整,注意运行查看解析结果。
car1.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <car>
3 <factory>
4 <name>一汽大众</name>
5 <brand>
6 <name>高尔夫</name>
7 <color>红色</color>
8 <price>15万</price>
9 </brand>
10 <brand>
11 <name>速腾</name>
12 <color>银白</color>
13 <price>18万</price>
14 </brand>
15 <brand>
16 <name>迈腾</name>
17 <color>黑灰</color>
18 <price>28万</price>
19 </brand>
20 </factory>
21 <factory>
22 <brand>
23 <name>帕萨特</name>
24 <color>黑色</color>
25 <price>25万</price>
26 </brand>
27 <brand>
28 <name>POLO</name>
29 <color>灰色</color>
30 <price>8万</price>
31 </brand>
32 </factory>
33 </car>
car2.xml
1 <?xml version="1.0" encoding="utf-8"?><car><factory name="一汽大众"><brand><name>高尔夫</name><color>红色</color><price>15万</price></brand><brand><name>速腾</name><color>银白</color><price>18万</price></brand><brand><name>迈腾</name><color>黑灰</color><price>28万</price></brand></factory><factory name="上海大众"><brand><name>帕萨特</name><color>黑色</color><price>25万</price></brand><brand><name>POLO</name><color>灰色</color><price>8万</price></brand></factory></car>
parsecar.c
1 #include <stdio.h>
2 #include "mxml.h"
3
4 int main(int argc, const char* argv[])
5 {
6 if(argc < 2)
7 {
8 printf("./a.out filename\n");
9 return 0;
10 }
11 // 加载xml文件
12 FILE* fp = fopen(argv[1], "r");
13 mxml_node_t* root = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
14
15 // 找到第一个factory节点
16 mxml_node_t* factory = mxmlFindElement(root, root, "factory", "name", NULL, MXML_DESCEND);
17 // 循环查找
18 while( factory )
19 {
20 // 打印几点的属性值
21 printf("factory attr: %s\n", mxmlElementGetAttr(factory, "name"));
22
23 // 向下移动一个节点
24 mxml_node_t* brand = mxmlWalkNext(factory, root, MXML_DESCEND);
25 while( brand )
26 {
27 // name
28 mxml_node_t* node = mxmlWalkNext(brand, root, MXML_DESCEND_FIRST);
29 printf(" name: %s\n", mxmlGetText(node, 0));
30 // color
31 node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
32 printf(" color: %s\n", mxmlGetText(node, 0));
33 // price
34 node = mxmlWalkNext(node, root, MXML_NO_DESCEND);
35 printf(" price: %s\n", mxmlGetText(node, 0));
36 printf(" =========================================\n");
37
38 // 找到下一个品牌节点
39 brand = mxmlFindElement(brand, root, "brand", NULL, NULL, MXML_NO_DESCEND);
40 }
41 // 打印该厂家对应的车辆品牌和属性信息
42 // 查找下一个节点
43 factory = mxmlFindElement(factory, root, "factory", "name", NULL, MXML_NO_DESCEND);
44 }
45 mxmlDelete(root);
46 fclose(fp);
47
48 return 0;
49 }
上面代码编译:gcc c文件 -lmxml -lpthread
二、JSON
1. cjson的使用
压缩包解压缩,直接使用里边的cJSON.c和cJSON.h即可
链接时还需要加上-lm 表示链接math库
2. json数组
- char array[23] = "slkjflajslfd";
- 中括号[整形, 字符串, 布尔类型, json数组, json对象],比如[123, 123.2, true, false, [12, 34, 56, "hello, world"]]
3. json对象
{}中是一些键值对
{
"name":"zhang3",
"name2":"li4"
}
key值: 必须是 字符串, 不重复
value值: json对象, json数组, 布尔, 整形, 字符串
4. json数组+json对象
{
"name":"zhang3",
"name2":"li4",
"张三":{
"别名":"老王",
"性别":"男",
"年龄":34,
"孩子":["小红", "小绿", "小黑"]
}
}
5. C语言json开源解析库 - cjson
(1)生成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();
(2)解析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);
- 点赞
- 收藏
- 关注作者
评论(0)