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的一些类以及说明,加粗表示是常用。

类名说明
QDomAttrThe QDomAttr class represents one attribute of a QDomElement
QDomNodeThe QDomNode class is the base class for all the nodes in a DOM tree.
QDomTextThe QDomText class represents text data in the parsed XML document.
QDomElementThe QDomElement class represents one element in the DOM tree.
QDomCDATASectionThe QDomCDATASection class represents an XML CDATA section
QDomCharacterDataThe QDomCharacterData class represents a generic string in the DOM
QDomCommentThe QDomComment class represents an XML comment
QDomDocumentThe QDomDocument class represents an XML document
QDomDocumentFragmentThe QDomDocumentFragment class is a tree of QDomNodes which is not usually a complete QDomDocument.
QDomEntityThe 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并设计一个增删改查方便的一个操作类的主要内容,如果未能解决你的问题,请参考以下文章

xml的增删改查

XML——对XML文档的创建与增删改查

Qt 史上最详细 - “操作XML文件” - 笔记

android中如何对xml中存储的数据进行增删改查?求完整的例子。谢谢

XML基本概念及增删改查操作

jqgrid怎么实现增删改查