如果对开源库TinyXml有兴趣的可以去看看这篇文章。
C++使用TinyXml(开源库)读取*.XMl文件
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展置标语言的标准编程接口。它是一种与平台和语言无关的应用程序接口(API),它可以动态地访问程序和脚本,更新其内容、结构和www文档的风格(HTML和XML文档是通过说明部分定义的)。文档可以进一步被处理,处理的结果可以加入到当前的页面。
DOM是一种基于树的API文档,它要求在处理过程中整个文档都表示在存储器中。另外一种简单的API是基于事件的SAX,它可以用于处理很大的XML文档,由于大,所以不适合全部放在存储器中处理。
先来了解一下xml基本要素:
下面列出了Qt处理xml的一些类以及说明,加粗表示是常用。
类名 | 说明 |
---|---|
QDomAttr | The QDomAttr class represents one attribute of a QDomElement |
QDomNode | The QDomNode class is the base class for all the nodes in a DOM tree. |
QDomText | The QDomText class represents text data in the parsed XML document. |
QDomElement | The QDomElement class represents one element in the DOM tree. |
QDomCDATASection | The QDomCDATASection class represents an XML CDATA section |
QDomCharacterData | The QDomCharacterData class represents a generic string in the DOM |
QDomComment | The QDomComment class represents an XML comment |
QDomDocument | The QDomDocument class represents an XML document |
QDomDocumentFragment | The QDomDocumentFragment class is a tree of QDomNodes which is not usually a complete QDomDocument. |
QDomEntity | The QDomEntity class represents an XML entity. |
通过Qt Create创建一个工程。然后在*.pro配置文件中添加xml model。
在添加Qt解析xml相关的头文件
#include
#include
// xml文档
QDomDocument* m_Doc = new QDomDocument();
// 创建XML处理类,通常用于处理第一行描述信息
QDomProcessingInstruction instruction;
std::string note = "version=1.0 encoding=utf-8";
// 创建XML头部格式
instruction = m_Doc->createProcessingInstruction(QString::fromStdString(type), QString::fromStdString(note));
// 添加到XML文件中
m_Doc->appendChild(instruction);
// 打开文件
QFile m_File = new QFile("./1.xml");
if (false == m_File->open(mode))
{
QMessageBox::information(NULL, u8"提示", u8"文件打开失败!");
return;
}
// 将doc与file关联起来
// 这个函数从IO设备dev中读取XML文档,如果内容被成功解析,则返回true;否则返回false。
if (false == m_Doc->setContent(m_File))
{
QMessageBox::information(NULL, u8"提示", u8"操作的文件不是XML文件!");
m_File->close();
return ;
}
通过createElement
方法创建的第一个子节点就是根节点。然后通过appendChild
方法将创建的节点添加到doc中。
// 创建根节点
QDomElement rootNode = m_Doc->createElement(rootName);
// 添加到XML文件中
m_Doc->appendChild(rootNode);
添加一个没有属性的节点的方法和添加根节点的方法一致。
// 创建根节点
QDomElement rootNode = m_Doc->createElement(rootName);
// 添加到XML文件中
m_Doc->appendChild(rootNode);
std::list<std::pair<std::string, std::string>> Attribute{{"ID","2"},{"name","张三"}};
QDomElement node = m_Doc->createElement(nodeName);
// 给节点创建属性
for(const auto& elem : Attribute)
{
// 参数一是字符串,参数二可以是任何类型
node.setAttribute(QString::fromStdString(elem.first), QString::fromStdString(elem.second));
}
rootNode.appendChild(node);
// 创建子元素
QDomElement node = m_Doc->createElement(nodeName);
// 设置尖括号中的值
QDomText text = m_Doc->createTextNode(value);
// 添加关系
node.appendChild(text);
root.appendChild(node);
setAttribute
方法设置节点的属性名和属性值。
QDomElement elemNode = m_Doc->createElement(QString::fromStdString(name));
elemNode.setAttribute(QString::fromStdString(name), QString::fromStdString(value));
node.appendChild(elemNode);
removeChild
方法使用需要注意:
看下面官方文档说明
Removes oldChild from the list of children. oldChild must be a direct child of this node.
Returns a new reference to oldChild on success or a null node on failure.
类似于C++容器存在迭代器失效问题。所以我这里就从后向前删除了。
// 获取节点名字为Book的所有节点
QDomNodeList nodes = m_Doc->elementsByTagName(nodeName);
for (int i = nodes.size() - 1; i >= 0; i--)
{
// 获取节点
QDomElement element = nodes.at(i).toElement();
// 所以 要么从后向前删除 要么就需要重新指定新节点的位置
root.removeChild(element);
}
QDomNodeList nodes = m_Doc->elementsByTagName(nodeName);
for (int i = 0; i < nodes.count(); i++)
{
// 获取节点
QDomElement element = nodes.at(i).toElement();
bool isFind {true};
for(const auto& elem : attribute)
{
// 进行判断(返回属性的值进行判断)
if (element.attribute(QString::fromStdString(elem.first)) != QString::fromStdString(elem.second))
{
isFind = false;
}
}
if(true == isFind)
{
root.removeChild(nodes.at(i));
}
}
// 获取节点名字为Book的所有节点
QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));
// QDomElement root = GetRootNode();
for (int i = nodes.size() - 1; i >= 0; i--)
{
// 获取节点
QDomElement element = nodes.at(i).toElement();
// 获取父节点
QDomNode fNode = element.parentNode();
fNode.removeChild(element);
}
QFile* m_File= new QFile(fileName);
if (false == m_File->open(QFileDevice::WriteOnly | QFileDevice::Truncate))
{
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
QTextStream stream(m_File);
m_Doc->save(stream, retract);
if (node.toElement().tagName() == name)
{
return node;
}
if (node.toElement().tagName() == name)
{
return node.toElement().text().toStdString();
}
key为属性名
if (false == node.isNull() && true == node.toElement().hasAttribute(key))
{
value = node.toElement().attributeNode(key).value();
}
注:必须支持C++17
OperateXML.h
#ifndef OPERATEXML_H
#define OPERATEXML_H
// 读取xml必须要包含的
#include
#include
#include
#include
//#include
#include
#include
class OperateXML
{
public:
explicit OperateXML(/*std::string filename = std::string("")*/);
~OperateXML();
// 创建一个xml文件
bool CreateXmlFile(std::string filename = std::string(""), QIODevice::OpenMode mode = QFileDevice::WriteOnly | QFileDevice::Truncate);
// 添加一个信息头
void CreateXmlHeader(std::string type = std::string("xml"), std::string version = "1.0", std::string encoding = std::string("UTF-8"));
// 加载已有的xml文件
bool LoadXml(std::string filename, QIODevice::OpenMode mode = QFileDevice::ReadOnly);
// 获取根节点 Stu
QDomElement GetRootNode();
// 创建一个根节点 Stu
QDomElement CreateXmlRootNode(std::string rootName = std::string("root"));
// 添加一个没有属性的节点 Stu StuInfo
QDomElement AddNoAttributesNode(QDomElement fNode, std::string nodeName);
// 添加一个有属性的节点 Stu StuInfo ID 1 Name 张三
QDomElement AddAttributesNode(QDomElement fNode, std::string nodeName,
std::list<std::pair<std::string, std::string>> Attribute);
// 添加元素节点
QDomElement AddElementNode(QDomElement fNode, std::string nodeName, std::string value);
// 设置节点属性
QDomElement SetNodeAttribute(QDomElement node, std::string name, std::string value);
// 删除节点 删除当前节点下的所有名为nodename的节点
void DeleteNodes(QDomElement fNode, std::string nodename);
// 删除节点 删除当前节点下的所有名为nodename的节点 且属性值相同
void DeleteNode(QDomElement fNode, std::string nodename,
std::list<std::pair<std::string, std::string>> attribute);
// 删除节点 删除所有节点下名为nodename的节点
void DeleteNodes(std::string nodename);
// 删除节点 删除所有节点下名为nodename的节点 且属性值相同
void DeleteNode(std::string nodename, std::list<std::pair<std::string, std::string>> attribute);
// 保存Xml 进位空格数
void SaveXml(int retract = 4);
// 获取当前节点以及同级下的兄弟节点 且名为name的节点 如果为第一个孩子节点记得传入第三个参数为true
QDomElement GetElem(QDomElement& node, std::string name, bool first = false);
QDomElement GetElem(QDomElement& node, QString name, bool first = false);
// 获取当前节点以及同级下的兄弟节点 且名为name的节点的值
std::string GetElemValue(QDomElement& node, std::string name, bool first = false);
QString GetElemValue(QDomElement& node, QString name, bool first = false);
// 获取 该节点指定的 属性节点值
std::string GetElemAttributeValue(QDomElement node, std::string key);
QString GetElemAttributeValue(QDomElement node, QString key);
private:
QDomDocument* m_Doc;
QFile* m_File;
std::string m_FileName;
};
#endif // OPERATEXML_H
OperateXML.cpp
#include "OperateXML.h"
OperateXML::OperateXML(/*std::string filename*/)
: m_Doc(new QDomDocument())
, m_File{nullptr}
{
}
OperateXML::~OperateXML()
{
if(nullptr != m_Doc)
{
delete m_Doc;
m_Doc = nullptr;
}
if(nullptr != m_File)
{
m_File->close();
delete m_File;
m_File = nullptr;
}
}
bool OperateXML::CreateXmlFile(std::string filename, QIODevice::OpenMode mode)
{
if(true == filename.empty())
{
QMessageBox::information(NULL, u8"提示", u8"文件名为空!");
return false;
}
if(nullptr != m_File)
{
delete m_File;
m_File = nullptr;
}
m_File = new QFile(QString::fromStdString(filename));
if(false == m_File->open(mode))
{
QMessageBox::information(NULL, u8"提示", u8"文件打开或创建失败!");
return false;
}
if(false == m_File->isOpen())
{
QMessageBox::information(NULL, u8"提示", u8"文件打开或创建失败!");
return false;
}
return true;
}
void OperateXML::CreateXmlHeader(std::string type, std::string version, std::string encoding)
{
// 创建XML处理类,通常用于处理第一行描述信息
QDomProcessingInstruction instruction;
std::string note = std::string("version=\"") + version + std::string("\" ") +
std::string("encoding=\"") + encoding + std::string("\"");
// 创建XML头部格式
instruction = m_Doc->createProcessingInstruction(QString::fromStdString(type), QString::fromStdString(note));
// 添加到XML文件中
m_Doc->appendChild(instruction);
}
bool OperateXML::LoadXml(std::string filename, QIODevice::OpenMode mode)
{
// 打开文件
m_File = new QFile(QString::fromStdString(filename));
if (false == m_File->open(mode))
{
QMessageBox::information(NULL, u8"提示", u8"文件打开失败!");
return false;
}
// 将doc与file关联起来
// 这个函数从IO设备dev中读取XML文档,如果内容被成功解析,则返回true;否则返回false。
if (false == m_Doc->setContent(m_File))
{
QMessageBox::information(NULL, u8"提示", u8"操作的文件不是XML文件!");
m_File->close();
return false;
}
return true;
}
QDomElement OperateXML::GetRootNode()
{
QDomElement root = m_Doc->documentElement();
return root;
}
QDomElement OperateXML::CreateXmlRootNode(std::string rootName)
{
// 创建根节点
QDomElement rootNode = m_Doc->createElement(QString::fromStdString(rootName));
// 添加到XML文件中
m_Doc->appendChild(rootNode);
return rootNode;
}
QDomElement OperateXML::AddNoAttributesNode(QDomElement fNode, std::string nodeName)
{
if(true == fNode.isNull())
{
return QDomElement();
}
QDomElement node = m_Doc->createElement(QString::fromStdString(nodeName));
fNode.appendChild(node);
return node;
}
QDomElement OperateXML::AddAttributesNode(QDomElement fNode, std::string nodeName,
std::list<std::pair<std::string, std::string>> Attribute)
{
QDomElement node = m_Doc->createElement(QString::fromStdString(nodeName));
// 给节点创建属性
for(const auto& elem : Attribute)
{
// 参数一是字符串,参数二可以是任何类型
node.setAttribute(QString::fromStdString(elem.first), QString::fromStdString(elem.second));
}
fNode.appendChild(node);
return node;
}
QDomElement OperateXML::AddElementNode(QDomElement fNode, std::string nodeName, std::string value)
{
// 创建子元素
QDomElement node = m_Doc->createElement(QString::fromStdString(nodeName));
// 设置尖括号中的值
QDomText text = m_Doc->createTextNode(QString::fromStdString(value));
// 添加关系
node.appendChild(text);
fNode.appendChild(node);
return node;
}
QDomElement OperateXML::SetNodeAttribute(QDomElement node, std::string name, std::string value)
{
QDomElement elemNode = m_Doc->createElement(QString::fromStdString(name));
elemNode.setAttribute(QString::fromStdString(name), QString::fromStdString(value));
node.appendChild(elemNode);
return node;
}
void OperateXML::DeleteNodes(QDomElement fNode, std::string nodename)
{
// 获取节点名字为Book的所有节点
QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));
for (int i = nodes.size() - 1; i >= 0; i--)
{
// 获取节点
QDomElement element = nodes.at(i).toElement();
/*
* Removes oldChild from the list of children. oldChild must be a direct child of this node.
Returns a new reference to oldChild on success or a null node on failure.
所以 要么从后向前删除 要么就需要重新指定新节点的位置
*/
fNode.removeChild(element);
}
}
void OperateXML::DeleteNode(QDomElement fNode, std::string nodename, std::list<std::pair<std::string, std::string>> attribute)
{
QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));
for (int i = 0; i < nodes.count(); i++)
{
// 获取节点
QDomElement element = nodes.at(i).toElement();
bool isFind {true};
for(const auto& elem : attribute)
{
// 进行判断(返回属性的值进行判断)
if (element.attribute(QString::fromStdString(elem.first)) != QString::fromStdString(elem.second))
{
isFind = false;
}
}
if(true == isFind)
{
fNode.removeChild(nodes.at(i));
}
}
}
void OperateXML::DeleteNodes(std::string nodename)
{
// 获取节点名字为Book的所有节点
QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));
// QDomElement root = GetRootNode();
for (int i = nodes.size() - 1; i >= 0; i--)
{
// 获取节点
QDomElement element = nodes.at(i).toElement();
/*
* Removes oldChild from the list of children. oldChild must be a direct child of this node.
Returns a new reference to oldChild on success or a null node on failure.
所以 要么从后向前删除 要么就需要重新指定新节点的位置
*/
QDomNode fNode = element.parentNode();
fNode.removeChild(element);
}
}
void OperateXML::DeleteNode(std::string nodename, std::list<std::pair<std::string, std::string> > attribute)
{
QDomNodeList nodes = m_Doc->elementsByTagName(QString::fromStdString(nodename));
for (int i = 0; i < nodes.count(); i++)
{
// 获取节点
QDomElement element = nodes.at(i).toElement();
bool isFind {true};
for(const auto& elem : attribute)
{
// 进行判断(返回属性的值进行判断)
if (element.attribute(QString::fromStdString(elem.first)) != QString::fromStdString(elem.second))
{
isFind = false;
}
}
if(true == isFind)
{
QDomNode fNode = element.parentNode();
fNode.removeChild(nodes.at(i));
}
}
}
void OperateXML::SaveXml(int retract)
{
m_File->close();
if (false == m_File->open(QFileDevice::WriteOnly | QFileDevice::Truncate))
{
QMessageBox::information(NULL, "提示", "文件打开失败!");
return;
}
QTextStream stream(m_File);
m_Doc->save(stream, retract);
}
QDomElement OperateXML::GetElem(QDomElement& node, std::string name, bool first)
{
if(true == first)
{
node = node.firstChild().toElement();
}
while(false == node.isNull())
{
if (node.toElement().tagName() == QString::fromStdString(name))
{
return node;
}
node = node.nextSibling().toElement();
}
return QDomElement();
}
QDomElement OperateXML::GetElem(QDomElement &node, QString name, bool first)
{
if(true == first)
{
node = node.firstChild().toElement();
}
while(false == node.isNull())
{
// qDebug() << node.toElement().tagName();
if (node.toElement().tagName() == name)
{
return node;
}
node = node.nextSibling().toElement();
}
return QDomElement();
}
std::string OperateXML::GetElemValue(QDomElement& node, std::string name, bool first)
{
if(true == first)
{
node = node.firstChild().toElement();
}
while(false == node.isNull())
{
// qDebug() << node.toElement().tagName();
if (node.toElement().tagName() == QString::fromStdString(name))
{
return node.toElement().text().toStdString();
}
node = node.nextSibling().toElement();
}
return std::string();
}
QString OperateXML::GetElemValue(QDomElement &node, QString name, bool first)
{
if(true == first)
{
node = node.firstChild().toElement();
}
while(false == node.isNull())
{
// qDebug() << node.toElement().tagName();
if (node.toElement().tagName() == name)
{
return node.toElement().text();
}
node = node.nextSibling().toElement();
}
return QString();
}
std::string OperateXML::GetElemAttributeValue(QDomElement node, std::string key)
{
std::string value;
if (false == node.isNull() && true == node.toElement().hasAttribute(QString::fromStdString(key)))
{
value = node.toElement().attributeNode(QString::fromStdString(key)).value().toStdString();
}
return value;
}
QString OperateXML::GetElemAttributeValue(QDomElement node, QString key)
{
QString value;
if (false == node.isNull() && true == node.toElement().hasAttribute(key))
{
value = node.toElement().attributeNode(key).value();
}
return value;
}