一、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
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>
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 }
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 ", mxmlElementGetAttr(book, "category")); 13 14 mxml_node_t* node = mxmlWalkNext(book, root, MXML_DESCEND_FIRST); 15 printf(" title: %s ", mxmlGetText(node, 0)); 16 17 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 18 printf(" author: %s ", mxmlGetText(node, 0)); 19 20 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 21 printf(" year: %s ", mxmlGetText(node, 0)); 22 23 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 24 printf(" price: %s ", mxmlGetText(node, 0)); 25 26 fclose(fp); 27 28 mxmlDelete(root); 29 30 return 0; 31 }
(2)生成下面的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>
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 }
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 "); 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 "); 22 return 0; 23 } 24 while( city ) 25 { 26 printf("================== "); 27 // 向下走一个节点 28 mxml_node_t* node = mxmlWalkNext(city, root, MXML_DESCEND_FIRST); 29 printf("city: "); 30 printf(" name = %s ", mxmlGetText(node, NULL)); 31 // 32 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 33 printf(" area = %s ", mxmlGetText(node, NULL)); 34 // 35 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 36 printf(" population = %s ", 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进行调整,注意运行查看解析结果。
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>
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>
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 "); 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 ", 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 ", mxmlGetText(node, 0)); 30 // color 31 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 32 printf(" color: %s ", mxmlGetText(node, 0)); 33 // price 34 node = mxmlWalkNext(node, root, MXML_NO_DESCEND); 35 printf(" price: %s ", mxmlGetText(node, 0)); 36 printf(" ========================================= "); 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);
(3)示例
生成下面的JSON
1 { 2 "奔驰": { 3 "factory": "一汽大众", 4 "last": 31, 5 "price": 83, 6 "sell": 49, 7 "sum": 80, 8 "other": [124, "hello, world", false] 9 } 10 }
1 #include <stdio.h> 2 #include <string.h> 3 #include "cJSON.h" 4 5 int main(int argc, const char* argv[]) 6 { 7 // 创建json对象 8 cJSON* obj = cJSON_CreateObject(); 9 10 // 创建子对象 - 品牌 11 cJSON* brand = cJSON_CreateObject(); 12 // 添加键值对 13 cJSON_AddItemToObject(brand, "factory", cJSON_CreateString("一汽大众")); 14 cJSON_AddItemToObject(brand, "last", cJSON_CreateNumber(31)); 15 cJSON_AddItemToObject(brand, "price", cJSON_CreateNumber(83)); 16 cJSON_AddItemToObject(brand, "sell", cJSON_CreateNumber(49)); 17 cJSON_AddItemToObject(brand, "sum", cJSON_CreateNumber(80)); 18 19 // 创建json数组 20 cJSON* array = cJSON_CreateArray(); 21 cJSON_AddItemToArray(array, cJSON_CreateNumber(124)); 22 cJSON_AddItemToArray(array, cJSON_CreateString("hello, world")); 23 cJSON_AddItemToArray(array, cJSON_CreateBool(0)); 24 cJSON_AddItemToObject(brand, "other", array); 25 26 cJSON_AddItemToObject(obj, "奔驰", brand); 27 28 // 格式化json对象 29 char* text = cJSON_Print(obj); 30 FILE* fp = fopen("car.json", "w"); 31 fwrite(text, 1, strlen(text), fp); 32 fclose(fp); 33 34 return 0; 35 }
1 /* 2 Copyright (c) 2009 Dave Gamble 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 THE SOFTWARE. 21 */ 22 23 /* cJSON */ 24 /* JSON parser in C. */ 25 26 #include <string.h> 27 #include <stdio.h> 28 #include <math.h> 29 #include <stdlib.h> 30 #include <float.h> 31 #include <limits.h> 32 #include <ctype.h> 33 #include "cJSON.h" 34 35 /* define our own boolean type */ 36 typedef int cjbool; 37 #define true ((cjbool)1) 38 #define false ((cjbool)0) 39 40 static const unsigned char *global_ep = NULL; 41 42 const char *cJSON_GetErrorPtr(void) 43 { 44 return (const char*) global_ep; 45 } 46 47 /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ 48 #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 3) || (CJSON_VERSION_PATCH != 0) 49 #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. 50 #endif 51 52 extern const char* cJSON_Version(void) 53 { 54 static char version[15]; 55 sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); 56 57 return version; 58 } 59 60 /* case insensitive strcmp */ 61 static int cJSON_strcasecmp(const unsigned char *s1, const unsigned char *s2) 62 { 63 if (!s1) 64 { 65 return (s1 == s2) ? 0 : 1; /* both NULL? */ 66 } 67 if (!s2) 68 { 69 return 1; 70 } 71 for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) 72 { 73 if (*s1 == '