zoukankan      html  css  js  c++  java
  • libxml2的安装及使用[总结]

    1、前言

      xml广泛应用于网络数据交换,配置文件、Web服务等等。近段时间项目中做一些配置文件,原来是用ini,现在改用xml。xml相对来说可视性更为直观,很容易看出数据之间的层次关系。关于xml的详细介绍可以参考http://baike.baidu.com/view/159832.htm?fromId=63。本文重点介绍解析xml的libxml2库的安装及使用,举例说明创建和解析xml的过程。

    2、libxml2的安装

      关于libxml2的介绍请参考官方网址http://xmlsoft.org/,下载最新的libxml2库http://xmlsoft.org/downloads.html

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

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

    执行结果如下图所示:

    (2)解析xml文档

    测试程序如下所示:

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

    测试结果如下所示:

  • 相关阅读:
    cityscapes和Mapillary Vistas两种不同分割数据集的label映射
    探究Z-Order
    Java ——对Swing、AWT和SWT的认识 原创
    UOJ-581 NOIP2020 字符串匹配
    UOJ-618 JOISC2021 聚会 2
    Codeforces Round #740 (Div. 1, based on VK Cup 2021
    PipeCAD
    第三次全国国土调查相关信息记录
    统计研究区内Landsat影像数量
    GEE数据导出注意事项
  • 原文地址:https://www.cnblogs.com/Anker/p/3542058.html
Copyright © 2011-2022 走看看