【Linux C编程】第二十章XML-JSON

举报
Yuchuan 发表于 2021/04/20 10:57:18 2021/04/20
【摘要】 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);

示例:

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。