Chinaunix首页 | 论坛 | 博客
  • 博客访问: 338753
  • 博文数量: 100
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 521
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-31 11:37
个人简介

活到老,学到老

文章分类

全部博文(100)

文章存档

2018年(1)

2017年(2)

2016年(11)

2015年(82)

2014年(4)

我的朋友

分类: C/C++

2015-08-25 23:07:36

原文地址:http://www.cnblogs.com/Anker/p/3542058.html
1、前言

  xml广泛应用于网络数据交换,配置文件、Web服务等等。xml相对来说可视性更为直观,很容易看出数据之间的层次关系。关于xml的详细介绍可以参考。本文重点介绍解析xml的libxml2库的安装及使用,举例说明创建和解析xml的过程。

2、libxml2的安装

  关于libxml2的介绍请参考官方网址,下载最新的libxml2库

具体安装步骤:
1
、解压:$tar zxvf  libxml2-2.9.1.tar.gz
2、进入解压后的安装目录:$cd  libxml2-2.9.1
3、安装三部曲:

     1)$./configure
              2)$make
              3)$make install
安装完毕。

注意:libxml2默认安装到/usr/local/include/libxml2目录下

3、xml文档结构

  xml按照树形结构进行存储,节点分为元素和文本,必须有根节点。如下的xml文件:

<?xml version="1.0" encoding="UTF-8"?> <phone_books> <phone id="1"> <name>Anker</name> <tel>18923873456</tel> <address>Shenzheng</address> </phone> <phone id="2"> <name>Jermey</name> <tel>18623873456</tel> <address>Beijing</address> </phone> <phone id="3"> <name>Lili</name> <tel>13223873456</tel> <address>Shanghai</address> </phone> </phone_books>
复制代码

xml结构图如下所示:

4、测试例子

关于libxml2的提供的接口,可以参考http://blog.csdn.net/shanzhizi/article/details/7726679。libxml2常用的接口如下:

  内部字符类型:xmlChar,定义为:typedef unsigned char xmlChar,用无符号型的char方便表示utf-8编码。libxml2提供了一个宏进行转换,#define BAD_CAST (xmlChar *)。

     文档类型xmlDoc,指针类型xmlDocPtr。xmlDoc是个struct,保存了一个xml的相关信息,例如文件名、文件类型、子节点等等;xmlDocPtr等于xmlDoc*。

  xmlNewDoc函数创建一个新的文件指针。

  xmlParseFile函数以默认方式读入一个UTF-8格式的文件,并返回文件指针。

  xmlReadFile函数读入一个带有某种编码的xml文件,并返回文件指针;细节见libxml2参考手册。

  xmlFreeDoc释放文件指针。特别注意,当你调用xmlFreeDoc时,该文件所有包含的节点内存都被释放。 

  xmlFreeNodeList来释放动态分配的节点内存,除非你把该节点从文件中移除了。

     xmlSaveFile将文件以默认方式存入一个文件。

     xmlSaveFormatFileEnc可将文件以某种编码/格式存入一个文件中。

  节点类型xmlNode、指针xmlNodePtr

  节点应该是xml中最重要的元素了,xmlNode代表了xml文件中的一个节点,实现为一个struct,内容非常丰富:tree.h

  xmlDocSetRootElement函数能将一个节点设置为某个文件的根节点

     xmlNewNode函数创建一个节点指针root_node

(1)创建xml文件

测试程序如下所示:

  1. /****************************************
  2.   2 *练习libxml库,创建通讯录xml文档,新增一个通讯录,
  3.   3 *如果xml文件存在,则添加一个新节点
  4.   4 *如果xml文件不存在,则新建一个xml文件
  5.   5 *
  6.   6 *@author: Anker @date: 2014/02/09
  7.   7 * ***************************************/
  8.   8
  9.   9 #include <stdio.h>
  10.  10 #include <string.h>
  11.  11 #include <unistd.h>
  12.  12 #include <assert.h>
  13.  13
  14.  14 #include <libxml/parser.h>
  15.  15 #include <libxml/tree.h>
  16.  16 #include <libxml/xmlmemory.h>
  17.  17
  18.  18 #define PHONE_BOOK_FILE "phone_book.xml"
  19.  19 #define ID_STR_LEN 16
  20.  20 #define NAME_STR_LEN 32
  21.  21 #define TEL_STR_LEN 16
  22.  22 #define ADDR_STR_LEN 128
  23.  23
  24.  24 //电话通讯录结构体
  25.  25 typedef struct phone_t {
  26.  26 int id; //编号
  27.  27 char name[NAME_STR_LEN]; //姓名
  28.  28 char tel[TEL_STR_LEN]; //电话
  29.  29 char address[ADDR_STR_LEN]; //地址
  30.  30 }phone;
  31.  31
  32.  32 //设置通讯录项
  33.  33 static void set_phone_item(phone *phone_item)
  34.  34 {
  35.  35 assert(phone_item);
  36.  36
  37.  37 phone_item->id = 10;
  38.  38 snprintf(phone_item->name, NAME_STR_LEN, "%s", "Anker");
  39.  39 snprintf(phone_item->tel, TEL_STR_LEN, "%s", "13223246599");
  40.  40 snprintf(phone_item->address, ADDR_STR_LEN, "%s", "Shenzheng");
  41.  41 }
  42.  42
  43.  43 //创建phone节点
  44.  44 static xmlNodePtr create_phone_node(const phone *phone_item)
  45.  45 {
  46.  46 assert(phone_item);
  47.  47
  48.  48 char id[ID_STR_LEN] = {0};
  49.  49 xmlNodePtr phone_node = NULL;
  50.  50
  51.  51 phone_node = xmlNewNode(NULL, BAD_CAST"phone");
  52.  52 if (phone_node == NULL) {
  53.  53 fprintf(stderr, "Failed to create new node.\n");
  54.  54 return NULL;
  55.  55 }
  56.  56 //设置属性
  57.  57 snprintf(id, ID_STR_LEN, "%d", phone_item->id);
  58.  58 xmlNewProp(phone_node, BAD_CAST"id", (xmlChar*)id);
  59.  59
  60.  60 xmlNewChild(phone_node, NULL, BAD_CAST"name", (xmlChar *)phone_item->name);
  61.  61 xmlNewChild(phone_node, NULL, BAD_CAST"tel", (xmlChar *)phone_item->tel);
  62.  62 xmlNewChild(phone_node, NULL, BAD_CAST"address", (xmlChar *)phone_item->address);
  63.  63
  64.  64 return phone_node;
  65.  65 }
  66.  66
  67.  67 //向根节点中添加一个phone节点
  68.  68 static int add_phone_node_to_root(xmlNodePtr root_node)
  69.  69 {
  70.  70 xmlNodePtr phone_node = NULL;
  71.  71 phone *phone_item = NULL;
  72.  72
  73.  73 //创建一个新的phone
  74.  74 phone_item = (phone *)malloc(sizeof(phone));
  75.  75 if (phone_item == NULL) {
  76.  76 fprintf(stderr, "Failed to malloc memory.\n");
  77.  77 return -1;
  78.  78 }
  79.  79 set_phone_item(phone_item);
  80.  80
  81.  81 //创建一个phone节点
  82.  82 phone_node = create_phone_node(phone_item);
  83.  83 if (phone_node == NULL) {
  84.  84 fprintf(stderr, "Failed to create phone node.\n");
  85.  85 goto FAILED;
  86.  86 }
  87.  87 //根节点添加一个子节点
  88.  88 xmlAddChild(root_node, phone_node);
  89.  89 free(phone_item);
  90.  90
  91.  91 return 0;
  92.  92 FAILED:
  93.  93 if (phone_item){
  94.  94 free(phone_item);
  95.  95 }
  96.  96 return -1;
  97.  97 }
  98.  98
  99.  99 //创建phone_books
  100. 100 static int create_phone_books(const char *phone_book_file)
  101. 101 {
  102. 102 assert(phone_book_file);
  103. 103
  104. 104 xmlDocPtr doc = NULL;
  105. 105 xmlNodePtr root_node = NULL;
  106. 106
  107. 107 //创建一个xml 文档
  108. 108 doc = xmlNewDoc(BAD_CAST"1.0");
  109. 109 if (doc == NULL) {
  110. 110 fprintf(stderr, "Failed to new doc.\n");
  111. 111 return -1;
  112. 112 }
  113. 113
  114. 114 //创建根节点
  115. 115 root_node = xmlNewNode(NULL, BAD_CAST"phone_books");
  116. 116 if (root_node == NULL) {
  117. 117 fprintf(stderr, "Failed to new root node.\n");
  118. 118 goto FAILED;
  119. 119 }
  120. 120 //将根节点添加到文档中
  121. 121 xmlDocSetRootElement(doc, root_node);
  122. 122
  123. 123 if (add_phone_node_to_root(root_node) != 0) {
  124. 124 fprintf(stderr, "Failed to add a new phone node.\n");
  125. 125 goto FAILED;
  126. 126 }
  127. 127 //将文档保存到文件中,按照utf-8编码格式保存
  128. 128 xmlSaveFormatFileEnc(phone_book_file, doc, "UTF-8", 1);
  129. 129 //xmlSaveFile("test.xml", doc);
  130. 130 xmlFreeDoc(doc);
  131. 131
  132. 132 return 0;
  133. 133 FAILED:
  134. 134 if (doc) {
  135. 135 xmlFreeDoc(doc);
  136. 136 }
  137. 137
  138. 138 return -1;
  139. 139 }
  140. 140
  141. 141 static int add_phone_node(const char *phone_book_file)
  142. 142 {
  143. 143 assert(phone_book_file);
  144. 144
  145. 145 xmlDocPtr doc = NULL;
  146. 146 xmlNodePtr root_node = NULL;
  147. 147 xmlNodePtr phone_node = NULL;
  148. 148 phone *phone_item = NULL;
  149. 149
  150. 150 doc = xmlParseFile(phone_book_file);
  151. 151 if (doc == NULL) {
  152. 152 fprintf(stderr, "Failed to parser xml file:%s\n", phone_book_file);
  153. 153 return -1;
  154. 154 }
  155. 155
  156. 156 root_node = xmlDocGetRootElement(doc);
  157. 157 if (root_node == NULL) {
  158. 158 fprintf(stderr, "Failed to get root node.\n");
  159. 159 goto FAILED;
  160. 160 }
  161. 161
  162. 162 if (add_phone_node_to_root(root_node) != 0) {
  163. 163 fprintf(stderr, "Failed to add a new phone node.\n");
  164. 164 goto FAILED;
  165. 165 }
  166. 166 //将文档保存到文件中,按照utf-8编码格式保存
  167. 167 xmlSaveFormatFileEnc(phone_book_file, doc, "UTF-8", 1);
  168. 168 xmlFreeDoc(doc);
  169. 169
  170. 170 return 0;
  171. 171 FAILED:
  172. 172 if (doc) {
  173. 173 xmlFreeDoc(doc);
  174. 174 }
  175. 175
  176. 176 return -1;
  177. 177 }
  178. 178
  179. 179 int main(int argc, char *argv[])
  180. 180 {
  181. 181 char *phone_book_file = PHONE_BOOK_FILE;
  182. 182
  183. 183 if (argc == 2) {
  184. 184 phone_book_file = argv[1];
  185. 185 }
  186. 186
  187. 187 if (access(phone_book_file, F_OK) == 0) {
  188. 188 //文件存在,添加一个新的phone节点
  189. 189 add_phone_node(phone_book_file);
  190. 190 }
  191. 191 else {
  192. 192 //文件不存在,创建一个信息的phone book
  193. 193 create_phone_books(phone_book_file);
  194. 194 }
  195. 195
  196. 196 return 0;
  197. 197 }

编译命令如下:gcc -g create_phone_book.c -o create_phone_book -I /usr/local/include/libxml2/ -lxml2 

执行结果如下图所示:

(2)解析xml文档

测试程序如下所示:

  1. 1 /************************************
  2.   2 * 调用libxml2库解析xml,提取出电话薄信息
  3.   3 *
  4.   4 * @author:Anker @date:2014/02/09
  5.   5 * *********************************/
  6.   6
  7.   7 #include <stdio.h>
  8.   8 #include <assert.h>
  9.   9
  10.  10 #include <libxml/xmlmemory.h>
  11.  11 #include <libxml/parser.h>
  12.  12
  13.  13 #define DEFAULT_XML_FILE "phone_book.xml"
  14.  14
  15.  15 //解析每一个phone,提取出name、tel、address
  16.  16 static int parse_phone(xmlDocPtr doc, xmlNodePtr cur)
  17.  17 {
  18.  18 assert(doc || cur);
  19.  19 xmlChar *key;
  20.  20
  21.  21 cur = cur->xmlChildrenNode;
  22.  22 while (cur != NULL) {
  23.  23 //获取name
  24.  24 if ((!xmlStrcmp(cur->name, (const xmlChar *)"name"))) {
  25.  25 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
  26.  26 printf("name: %s\t", key);
  27.  27 xmlFree(key);
  28.  28 }
  29.  29 //获取tel
  30.  30 if ((!xmlStrcmp(cur->name, (const xmlChar *)"tel"))) {
  31.  31 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
  32.  32 printf("tel: %s\t", key);
  33.  33 xmlFree(key);
  34.  34 }
  35.  35 //获取address
  36.  36 if ((!xmlStrcmp(cur->name, (const xmlChar *)"address"))) {
  37.  37 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
  38.  38 printf("address: %s\n", key);
  39.  39 xmlFree(key);
  40.  40 }
  41.  41 cur = cur->next;
  42.  42 }
  43.  43 return 0;
  44.  44 }
  45.  45
  46.  46 static int parse_phone_book(const char *file_name)
  47.  47 {
  48.  48 assert(file_name);
  49.  49
  50.  50 xmlDocPtr doc; //xml整个文档的树形结构
  51.  51 xmlNodePtr cur; //xml节点
  52.  52 xmlChar *id; //phone id
  53.  53
  54.  54 //获取树形结构
  55.  55 doc = xmlParseFile(file_name);
  56.  56 if (doc == NULL) {
  57.  57 fprintf(stderr, "Failed to parse xml file:%s\n", file_name);
  58.  58 goto FAILED;
  59.  59 }
  60.  60
  61.  61 //获取根节点
  62.  62 cur = xmlDocGetRootElement(doc);
  63.  63 if (cur == NULL) {
  64.  64 fprintf(stderr, "Root is empty.\n");
  65.  65 goto FAILED;
  66.  66 }
  67.  67
  68.  68 if ((xmlStrcmp(cur->name, (const xmlChar *)"phone_books"))) {
  69.  69 fprintf(stderr, "The root is not phone_books.\n");
  70.  70 goto FAILED;
  71.  71 }
  72.  72
  73.  73 //遍历处理根节点的每一个子节点
  74.  74 cur = cur->xmlChildrenNode;
  75.  75 while (cur != NULL) {
  76.  76 if ((!xmlStrcmp(cur->name, (const xmlChar *)"phone"))) {
  77.  77 id = xmlGetProp(cur, "id");
  78.  78 printf("id:%s\t",id);
  79.  79 parse_phone(doc, cur);
  80.  80 }
  81.  81 cur = cur->next;
  82.  82 }
  83.  83 xmlFreeDoc(doc);
  84.  84 return 0;
  85.  85 FAILED:
  86.  86 if (doc) {
  87.  87 xmlFreeDoc(doc);
  88.  88 }
  89.  89 return -1;
  90.  90 }
  91.  91
  92.  93 int main(int argc, char*argv[])
  93.  94 {
  94.  95 char *xml_file = DEFAULT_XML_FILE;
  95.  96
  96.  97 if (argc == 2) {
  97.  98 xml_file = argv[1];
  98.  99 }
  99. 100
  100. 101 if (parse_phone_book(xml_file) != 0) {
  101. 102 fprintf(stderr, "Failed to parse phone book.\n");
  102. 103 return -1;
  103. 104 }
  104. 105
  105. 106 return 0;
  106. 107 }

测试结果如下所示:

 

阅读(914) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~