C++读写XML文件(Libxml2库)

Table of Contents

    C++程序有时候要读写XML文件, 这里介绍一个读写XML文件的库——Libxml2。

    主页:http://xmlsoft.org/index.html

    入门教程很详细的:http://jianlee.ylinux.org/Computer/C/libxml.html#sec11

    读取节点内容的话用XPath方式比较好,要问XPath与Libxml2库之间的关系,有个很形象的比喻:

    那就是SQL与数据库之间的关系。

    下面的代码是在Linux下实现的:

    
    #ifndef __XML_FILE_H__
    #define __XML_FILE_H__
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <libxml/parser.h>
    #include <libxml/tree.h>
    #include <map>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    const int XML_READ = 1;
    const int XML_WRITE = 0;
    
    typedef struct _XML_INFO XML_INFO;
    typedef struct _XML_INFO* HXML_INFO;
    
    struct _XML_INFO
    {
        char version[16];
        int update;
        int scan_speed;
        int type;
        int device_counts;
        int item_counts;
        
        map<string, string> map_item_info;
    };
    
    class CLibxml2
    {
    public:
        CLibxml2();
        ~CLibxml2();
    
        CLibxml2(const char *xml_file_path, bool is_read);
    
    	/*!
    	  \fn bool open(const char *xml_file_path, bool is_read)
    	  \brief 打开一个XML文件是以读的方式还是以写的方式
    	  \param in xml_file_path XML文件路径
    	  \param in is_read true为读,false为写
    	  \return true成功,false失败
    	*/
        bool open(const char *xml_file_path, bool is_read);
        
    	/*!
    	  \fn bool parse_xml_file(XML_INFO &xml_info)
    	  \brief 解析XML文件,将解析后的结果保存在XML_INFO结构体中
    	  \param out xml_info 保存解析后的结果
    	  \return true成功,false失败
    	*/
        bool parse_xml_file(const XML_INFO &xml_info);
    
    	/*!
    	  \fn bool save_xml_file(const XML_INFO &xml_info)
    	  \brief 写入XML文件
    	  \param in xml_info 需要写入的信息
    	  \return true成功,false失败
    	*/
        bool save_xml_file(XML_INFO &xml_info);
    
    private:
    	/*!
    	  \fn xmlNodePtr search_node_ptr(const char *sz_expr)
    	  \brief 查找指定节点
    	  \param in sz_expr 节点路径表达式(XPATH)
    	  \return success返回指定节点指针,fail返回NULL
    	*/
        xmlNodePtr search_node_ptr(const char *sz_expr);
    
    private:
        char m_sz_path[512];
        xmlDocPtr m_pdoc_read;
        xmlNodePtr m_proot;
    };
    
    
    #endif // __XML_FILE_H__
    
    
    
    
    #include "xml-file.h"
    #include <string.h>
    #include <libxml/xpath.h>
    #include <libxml/xpathInternals.h>
    #include <libxml/xmlmemory.h>
    #include <libxml/xpointer.h>
    
    CLibxml2::CLibxml2()
    {
        m_pdoc_read = NULL;
        m_proot = NULL;
        bzero(m_sz_path, sizeof(m_sz_path));
    }
    
    CLibxml2::~CLibxml2()
    {
        if (m_pdoc_read)
        {
            xmlFreeDoc(m_pdoc_read);
            m_pdoc_read = NULL;
    
            xmlCleanupParser();
            xmlMemoryDump();
        }
    }
    
    CLibxml2::CLibxml2(const char *xml_file_path, bool is_read)
    {
        if (xml_file_path)
        {
            open(xml_file_path, is_read);
        }
    }
    
    bool CLibxml2::open(const char *xml_file_path, bool is_read)
    {
        bool bret = false;
        
        m_pdoc_read = NULL;
        m_proot = NULL;
        bzero(m_sz_path, sizeof(m_sz_path));
        
        if (xml_file_path)
        {
            strcpy(m_sz_path, xml_file_path);
    
            if (is_read)
            {
                xmlKeepBlanksDefault(0);
                m_pdoc_read = xmlReadFile(xml_file_path, "UTF-8", XML_PARSE_RECOVER);
                m_proot = xmlDocGetRootElement(m_pdoc_read);
            }
            
            if (m_proot)
            {
                bret = true;
            }
        }
    
        return bret;
    }
    
    bool CLibxml2::parse_xml_file(XML_INFO &xml_info)
    {
        bool bret = false;
        if (m_proot)
        {
            xmlNodePtr node = search_node_ptr("//config_Information");
            xmlChar *str = xmlGetProp(node, node->properties->name);
            strcpy(xml_info.version, (const char*)BAD_CAST(str));
            //cout << xml_info.version << endl;
    
            node = search_node_ptr("//Config_Data_block");
            str = xmlGetProp(node, node->properties->name);
            xml_info.update = atoi((const char*)BAD_CAST(str));
            //cout << xml_info.update << endl;
    
            node = search_node_ptr("//ScanSpeed");
            str = xmlNodeGetContent(node);
            xml_info.scan_speed = atoi((const char*)BAD_CAST(str));
            //cout << xml_info.scan_speed << endl;
    
            node = search_node_ptr("//DeviceType");
            str = xmlGetProp(node, node->properties->name);
            xml_info.type = atoi((const char*)BAD_CAST(str));
            //cout << xml_info.type << endl;
    
            node = search_node_ptr("//Device_Counts");
            str = xmlNodeGetContent(node);
            xml_info.device_counts = atoi((const char*)BAD_CAST(str));
            //cout << xml_info.device_counts << endl;
    
            node = search_node_ptr("//Item_Counts");
            str = xmlNodeGetContent(node);
            xml_info.item_counts = atoi((const char*)BAD_CAST(str));
            //cout << xml_info.item_counts << endl;
    
            int i;
            char item_id[32];
            char key_word[32];
            char id_content[32];
            char key_content[32];
            xmlNodePtr node_id;
            xmlNodePtr node_key;
            
            for (i=1; i<=xml_info.item_counts; i++)
            {
                bzero(item_id, sizeof(item_id));
                bzero(key_word, sizeof(key_word));
                bzero(id_content, sizeof(id_content));
                bzero(key_content, sizeof(key_content));
                
                sprintf(item_id, "//ItemInfo[%d]/ItemID", i);
                sprintf(key_word, "//ItemInfo[%d]/KeyWord", i);
                node_id = search_node_ptr(item_id);
                node_key = search_node_ptr(key_word);
                xmlChar *temp_id = xmlNodeGetContent(node_id);
                xmlChar *temp_key = xmlNodeGetContent(node_key);
                strcpy(id_content, (const char*)BAD_CAST(temp_id));
                strcpy(key_content, (const char*)BAD_CAST(temp_key));
                xml_info.map_item_info.insert(pair<string, string>(id_content, key_content));
            }
            
            bret = true;
        }
    
        return bret;
    }
    
    bool CLibxml2::save_xml_file(const XML_INFO &xml_info)
    {
        if (NULL == m_sz_path)
        {
            return false;
        }
    
        char sz_temp[32];
        
        xmlDocPtr pdoc = xmlNewDoc(BAD_CAST(xml_info.version));
        xmlNodePtr config_info = xmlNewNode(NULL, BAD_CAST"config_Information");
        xmlNewProp(config_info, BAD_CAST"version", BAD_CAST(xml_info.version));
        xmlDocSetRootElement(pdoc, config_info);
        
        xmlNodePtr data_block = xmlNewNode(NULL, BAD_CAST"Config_Data_block");
        bzero(sz_temp, sizeof(sz_temp));
        sprintf(sz_temp, "%d", xml_info.update);
        xmlNewProp(data_block, BAD_CAST"update", BAD_CAST(sz_temp));
        xmlAddChild(config_info, data_block);
    
        bzero(sz_temp, sizeof(sz_temp));
        sprintf(sz_temp, "%d", xml_info.scan_speed);
        xmlNewTextChild(data_block, NULL, BAD_CAST"ScanSpeed", BAD_CAST(sz_temp));
    
        bzero(sz_temp, sizeof(sz_temp));
        sprintf(sz_temp, "%d", xml_info.type);
        xmlNodePtr device_type = xmlNewNode(NULL, BAD_CAST"DeviceType");
        xmlNewProp(device_type, BAD_CAST"type", BAD_CAST(sz_temp));
        xmlAddChild(data_block, device_type);
    
        bzero(sz_temp, sizeof(sz_temp));
        sprintf(sz_temp, "%d", xml_info.item_counts);
        xmlNewTextChild(device_type, NULL, BAD_CAST"Item_Counts", BAD_CAST(sz_temp));
        int index = 1;
        int ncounts = xml_info.item_counts;
        
        xmlNodePtr item_list = xmlNewNode(NULL, BAD_CAST"Item_list");
        xmlAddChild(device_type, item_list);
    
        map<string, string>::iterator iter;
        for (iter=xml_info.map_item_info.begin();
             iter!=xml_info.map_item_info.end();
             ++iter)
        {
            
            bzero(sz_temp, sizeof(sz_temp));
            sprintf(sz_temp, "%d", index++);
            xmlNodePtr item_info = xmlNewNode(NULL, BAD_CAST"ItemInfo");
            xmlNewProp(item_info, BAD_CAST"NO", BAD_CAST(sz_temp));
            xmlAddChild(item_list, item_info);
    
            xmlNewTextChild(item_info, NULL, BAD_CAST"ItemID",
                            BAD_CAST((*iter).first.c_str()));
            xmlNewTextChild(item_info, NULL, BAD_CAST"KeyWord",
                            BAD_CAST((*iter).second.c_str()));
        }
        
        xmlSaveFormatFileEnc(m_sz_path, pdoc, "UTF-8", 1);
        xmlFreeDoc(pdoc);
        return true;
    }
    
    xmlNodePtr CLibxml2::search_node_ptr(const char *sz_expr)
    {
        xmlNodePtr node_ret;
        
        if (sz_expr == NULL)
        {
            return NULL;
        }
        
        xmlChar *sz_path = BAD_CAST(sz_expr);
        xmlXPathContextPtr context = xmlXPathNewContext(m_pdoc_read);
        xmlXPathObjectPtr result = xmlXPathEvalExpression(sz_path, context);
        
        if (result == NULL)
        {
            return NULL;
        }
        if (xmlXPathNodeSetIsEmpty(result->nodesetval))
        {
            return NULL;
        }
    
        xmlXPathFreeContext(context);
        
        node_ret = xmlXPtrBuildNodeList(result);
    
        return node_ret;
    }
    
    /*/////////测试//////////////////////////
    int main(void)
    {
        //write/////////////////////////////////
        CLibxml2 lib("rmc1.xml", XML_WRITE);
    
        map<string, string> map_item;
        XML_INFO xml_info;
        xml_info.map_item_info.insert(pair<string, string>("CPU", ""));
        xml_info.map_item_info.insert(pair<string, string>("MEM", ""));
        xml_info.map_item_info.insert(pair<string, string>("DISK_C_FREE", "C"));
        xml_info.map_item_info.insert(pair<string, string>("RunTime", ""));
        xml_info.map_item_info.insert(pair<string, string>("MainProcess0", "test.exe"));
        xml_info.map_item_info.insert(pair<string, string>("NetPing", "127.0.0.1"));
        
        strcpy(xml_info.version, "1.0");
        xml_info.update = 0;
        xml_info.scan_speed = 100;
        xml_info.type = 2;
        xml_info.device_counts = 2;
        xml_info.item_counts = xml_info.map_item_info.size();
    
        lib.save_xml_file(xml_info);
        //////////////////////////////////////////
    
    
        //read/////////////////////////////////////
        XML_INFO xml_info;
        CLibxml2 lib("rmc.xml", XML_READ);
        lib.parse_xml_file(xml_info);
    
        map<string, string>::iterator iter;
        for (iter = xml_info.map_item_info.begin();
             iter != xml_info.map_item_info.end();
             ++iter)
        {
            cout << (*iter).first << endl;
            cout << (*iter).second << endl;
        }
        ////////////////////////////////////////////
    
       
        return 0;
    }
    //*////////////////////////////////
    
    
    
    
    <?xml version="1.0"?>
    <config_Information version="1.0">
    <Config_Data_block update="0">
    <ScanSpeed>100</ScanSpeed>
    <DeviceType type="2">
    <Device_Counts>1</Device_Counts>
    <Item_Counts>6</Item_Counts>
    <Item_list>
    <ItemInfo NO="1">
    	<ItemEvenFlag>1</ItemEvenFlag>
    	<ItemID>CPU</ItemID>
    	<KeyWord></KeyWord>
    </ItemInfo>
    <ItemInfo NO="2">
    	<ItemID>MEM</ItemID>
    	<KeyWord></KeyWord>
    </ItemInfo>
    <ItemInfo NO="3">
    	<ItemID>DISK_C_FREE</ItemID>
    	<KeyWord>C</KeyWord>
    </ItemInfo>
    <ItemInfo NO="4">
    	<ItemID>RunTime</ItemID>
    	<KeyWord></KeyWord>
    </ItemInfo>
    <ItemInfo NO="5">
    	<ItemID>MainProcess0</ItemID>
    	<KeyWord>test.exe</KeyWord>
    </ItemInfo>
    <ItemInfo NO="6">
    	<ItemID>NetPing</ItemID>
    	<KeyWord>127.0.0.1</KeyWord>
    </ItemInfo>
    </Item_list>
    </DeviceType>
    </Config_Data_block>
    </config_Information>