libxml2库读写数据

1. libxml2下载安装

下载地址:ftp://xmlsoft.org/libxml2/

编译(注意:如果configure文件没有可执行权限,增加可执行权限):

./configure
make
make install

此时libxml2相关的头文件应该在/usr/local/include/libxml2目录下,libxml2相关的库文件应该在/usr/local/lib目录下。

2. libxml2常用成员和函数

1.文档:

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

(2)创建文档: xmlNewDoc函数创建一个新的文档指针。
(3)读取文档
    3.1 xmlParseFile函数: 以默认方式读入一个UTF-8格式的文档,并返回文档指针。
    3.2 xmlReadFile函数读入一个带有某种编码的xml文档,并返回文档指针;细节见libxml2参考手册。
    建议使用xmlReadFile(libxml2的作者: "Use xmlReadFile, it's the modern API for parsing")

(4)释放文档指针
    xmlFreeDoc函数。特别注意,当你调用xmlFreeDoc时,该文档所有包含的节点内存都被释放,
    所以一般来说不需要手动调用xmlFreeNode或者xmlFreeNodeList来释放动态分配的节点内存,
    除非你把该节点从文档中移除了。一般来说,一个文档中所有节点都应该动态分配,然后加入文档,
    最后调用xmlFreeDoc一次释放所有节点申请的动态内存,这也是为什么我们很少看见xmlNodeFree的原因。
(5)保存文档
    xmlSaveFile将文档以默认方式存入一个文件。
    xmlSaveFormatFile
    xmlSaveFormatFileEnc可将文档以某种编码/格式存入一个文件中。

注意: 默认的Libxml2在写入XML文件时,都是将所有内容写成一行的,不便于文本查看。在读取时,会将空格作为一个文本节点,
     为了去掉空格,在使用xmlReadFile读取时第三个参数设为XML_PARSE_NOBLANKS即可不考虑空格。
     保存文件时使用xmlSaveFormatFile或xmlSaveFormatFileEnc或xmlSaveFormatFileTo,并设置最后一个参数format=1 

2.结点
xml举例

<?xml version="1.0"?>
<root>
  <node1 attribute="yes">content1</node2>
  <node2 attribute="no">content2</node2>
  <node3>
    <node4>5</node4>
  </node3>
</root>
(1)节点类型xmlNode和节点指针xmlNodePtr。xmlNodePtr等于xmlNode*。
(2)得到根节点: xmlDocGetRootElement
(3)常用的几种节点类型:XML_ELEMENT_NODE,XML_TEXT_NODE和XML_ATTRIBUTE_NODE
    3.1 root/node1/2/3/4是XML_ELEMENT_NODE
    3.2 content1和content2是XML_TEXT_NODE
    3.3 attribute="yes"是XML_ATTRIBUTE_NODE
(4)节点操作
    1)获得到结点的内容: xmlNodeGetContent(对应于xmlFree析构)
    2)获取子结点:      xmlNodePtr -> children
    3)获取结点名字:     xmlNodePtr -> name
    4)结点内遍历:       xmlNodePtr -> next
    5)获取属性值:        xmlNodePtr -> xmlGetProp
    6)修改节点的内容:    xmlNodePtr -> xmlNodeSetContent
    7)修改节点的属性值:   xmlNodePtr -> xmlSetProp

3. 从xml文件中读数据

以eg.xml为例

<?xml version="1.0"?>
<root>
  <node1>content1</node1>
  <node2>content2</node2>
  <node3>
    <node4>5</node4>
  </node3>
</root>
#include <iostream>
#include <vector>
#include <string.h>

#include <libxml/parser.h>
#include <libxml/xpath.h>
using namespace std;

void getChildNode(xmlNodePtr node, std::vector<std::string> &data)
{
    for (xmlNodePtr curNode = node; curNode; curNode = curNode->next) {
        // 判断当前节点的type
        if(curNode->type == XML_TEXT_NODE) {
            xmlChar *text = xmlNodeGetContent(curNode);
            if (nullptr != text) {
                data.push_back(reinterpret_cast<char*>(text));
                // 注意:用xmlNodeGetContent得到的xmlChar *一定要使用xmlFree释放
                xmlFree(text);
            }
        }
        // 递归遍历
        xmlNodePtr childNode = curNode->children;
        if (nullptr != childNode) {
            getChildNode(childNode, data);
        }
    }
}

bool readXMLFile(std::string strXMLFilePathAndName, std::vector<std::string> &data)
{
    xmlDocPtr doc = nullptr;
    xmlNodePtr rootElement = nullptr;
    /*****************打开xml文档********************/
    // XML_PARSE_NOBLANKS: 防止程序把元素前后的空白文本符号当作一个node
    doc = xmlReadFile(strXMLFilePathAndName.c_str(), nullptr, XML_PARSE_NOBLANKS);
    if (nullptr == doc) {
        cout << "document is not parsed successfully!" << endl;
        return false;
    }
    /*****************获取xml文档对象的根节对象********************/
    rootElement = xmlDocGetRootElement(doc);
    if (nullptr == rootElement) {
        xmlFreeDoc(doc);
        cout << "the document is empty!" << endl;
        return false;
    }
    
    // 获取节点内容
    getChildNode(rootElement, data);

    /*free the document*/
    xmlFreeDoc(doc);

    return true;
}
int main()
{
    std::vector<std::string> data;
    std::string path = "./eg.xml";
    bool ret = readXMLFile(path, data);
    for (int i = 0; i < data.size(); i++) {
        cout << "node: " << data[i] << endl;
    }
}
//编译:假设该文件名为main.cpp
$ g++ -g main.cpp -o main -I /usr/local/include/libxml2 -L /usr/local/lib -lxml2 -std=c++11
// 执行
$ ./main
// 结果
$ node: content1
$ node: content2
$ node: 5

4. 向xml文件中写数据

#include <iostream>
#include <vector>
#include <string.h>

#include <libxml/parser.h>
#include <libxml/xpath.h>
using namespace std;

// 获取搜索的节点列表
xmlXPathObjectPtr getNodeSet(xmlDocPtr doc, const xmlChar *xpath)
{
    xmlXPathContextPtr context = nullptr;
    xmlXPathObjectPtr result = nullptr;
    context = xmlXPathNewContext(doc);
    if (nullptr == context) {
        cout << "failed to alloc ctxt!" << endl;
        return nullptr;
    }
    result = xmlXPathEvalExpression(xpath, context);
    xmlXPathFreeContext(context);
    if (nullptr == result) {
        cout << "xmlXPathEvalExpression return nullptr!" << endl;
        return nullptr;
    }
 
    if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
        xmlXPathFreeObject(result);
        cout << "nodeset is empty!" << endl;
        return nullptr;
    }

    return result;
}

int main()
{
    std::vector<std::string> data;
    std::string path = "./eg.xml";
    bool ret = readXMLFile(path, data);
    for (int i = 0; i < data.size(); i++) {
        cout << "node: " << data[i] << endl;
    }

    xmlDocPtr doc = nullptr;
    doc = xmlReadFile(path.c_str(), nullptr, XML_PARSE_NOBLANKS);
    if (nullptr == doc) {
        cout << "document is not parsed successfully!" << endl;
    }
    // 搜索node4节点,得到它的搜索结果
    xmlXPathObjectPtr result = getNodeSet(doc, BAD_CAST("/root/node3/node4"));
    if (nullptr != result) {
        for (int i = 0; i < result->nodesetval->nodeNr; i++) {
            xmlNodePtr node = result->nodesetval->nodeTab[i]->children;
            if (nullptr != node && node->type == XML_TEXT_NODE) {
                char value[256];
                sprintf(value, "%lf", 6.666);
                // 写node4节点的child里写内容
                xmlNodeSetContent(node, (const xmlChar*)value);
            }
        }
        xmlXPathFreeObject(result);
    }
    xmlSaveFormatFile(path.c_str(), doc, 1);
    xmlFreeDoc(doc);
    return 0;
}

经过写如数据后,eg.xml变为

<?xml version="1.0"?>
<root>
  <node1>content1</node1>
  <node2>content2</node2>
  <node3>
    <node4>6.666000</node4>
  </node3>
</root>

参考:
https://www.cnblogs.com/catgatp/p/6505451.html
http://slucx.blog.chinaunix.net/uid-26707720-id-3181119.html
http://blog.chinaunix.net/uid-25695950-id-3921541.html
https://blog.csdn.net/chinazgr/article/details/8727997

posted on 2021-05-27 17:25  JJ_S  阅读(894)  评论(0编辑  收藏  举报