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