Qt通过Doc模式读取XML并设计一个增删改查方便的一个操作类
Posted 林夕07
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt通过Doc模式读取XML并设计一个增删改查方便的一个操作类相关的知识,希望对你有一定的参考价值。
前言
如果对开源库TinyXml有兴趣的可以去看看这篇文章。
C++使用TinyXml(开源库)读取*.XMl文件
目录
DOC 文档对象模型
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展置标语言的标准编程接口。它是一种与平台和语言无关的应用程序接口(API),它可以动态地访问程序和脚本,更新其内容、结构和www文档的风格(html和XML文档是通过说明部分定义的)。文档可以进一步被处理,处理的结果可以加入到当前的页面。
DOM是一种基于树的API文档,它要求在处理过程中整个文档都表示在存储器中。另外一种简单的API是基于事件的SAX,它可以用于处理很大的XML文档,由于大,所以不适合全部放在存储器中处理。
先来了解一下xml基本要素:
QtXML基本结构
下面列出了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. |
操作XML
部署环境
通过Qt Create创建一个工程。然后在*.pro配置文件中添加xml model。
在添加Qt解析xml相关的头文件
#include <QtXml>
#include <QDomDocument>
添加信息头
// 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);
读取XML文件
// 打开文件
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);
保存XML
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 <QtXml>
#include <QDomDocument>
#include <QIODevice>
#include <QMessageBox>
//#include <QtCore5Compat/QTextCodec>
#include <string>
#include <map>
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"));
// 添加一个没有属性的节点 <StuInfo/> Stu StuInfo
QDomElement AddNoAttributesNode(QDomElement fNode, std::string nodeName);
// 添加一个有属性的节点 <StuInfo ID = "1"> 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_Filenullptr
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(Q以上是关于Qt通过Doc模式读取XML并设计一个增删改查方便的一个操作类的主要内容,如果未能解决你的问题,请参考以下文章