Qt的XML封装类QXmlWrapper,实现XML文件的创建、删除以及元素节点的增加、删除、修改与查找等。

最近使用Qt开发软件,需要用到xml用于保存软件配置信息,发现Qt的XML使用起来不是很方便,所以基于QDomDocument类进一步封装了QXmlWrapper类。

注:博主用的Qt版本是4.8.5,开发环境是Qt Creator。


一、XML文件的创建、删除与重命名

1.XML文件的创建

bool QXmlWrapper::CreateXmlFile(const QString &_fileName,
                                const QString &_rootName,
                                const QString &_version,
                                const QString &_encoding,
                                const QString &_standalone)
{
    QFile file(_fileName);

    // 只写方式打开,并清空以前的信息
    if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
        return false;

    QDomDocument doc;
    QDomProcessingInstruction instruction;  //添加处理指令(声明)
    QString data;
    data = "version=\"" + _version + "\" encoding=\"" + _encoding + "\" standalone=\"" + _standalone + "\"";
    instruction = doc.createProcessingInstruction("xml", data);
    doc.appendChild(instruction);
    QDomElement root = doc.createElement(_rootName);
    doc.appendChild(root); //添加根元素

    QTextStream out(&file);
    doc.save(out,4); // 将文档保存到文件,4为子元素缩进字符数
    file.close();
    return true;
}


其中_fileName为文件名,_rootName为根节点名。


2.XML文件的删除

bool QXmlWrapper::DeleteXmlFile(const QString &_fileName)
{
    if (_fileName.isEmpty())
    {
        return false;
    }

    QFile file(_fileName);
    if(!file.setPermissions(QFile::WriteOwner)) // 修改文件属性
        return false;
    if(!QFile::remove(_fileName)) // 删除文件
        return false;

    return true;
}
若文件为只读属性,需要修改文件属性。


3.XML文件的重命名

bool QXmlWrapper::RenameXmlFile(const QString &_fileName,
                                const QString &_newName)
{
   return QFile::rename(_fileName, _newName);
}


二、元素节点的操作

无论查询节点、删除节点、修改节点和增加节点,其实都离不开一个函数,就是根据节点名获取相关节点。那么我们就先实现一个根据节点名获取节点的函数:

1.根据节点名获取节点

bool QXmlWrapper::GetNodeByName(QDomElement &_rootEle,
                                const QString &_nodeName,
                                QDomElement &_node)
{
    if(_nodeName == _rootEle.tagName()) // 若为根节点,则返回
    {
        _node = _rootEle;
        return true;
    }

    QDomElement ele = _rootEle;  //返回根元素

    for (ele = _rootEle.firstChildElement(); ele.isElement(); ele = ele.nextSiblingElement())
    {
        //递归处理子节点,获取节点
        if(GetNodeByName(ele, _nodeName, _node))
            return true;
    }
    return false;
}

其中,_rootEle为根节点,_nodeName为待查询的节点名,_node即为查找到的节点。

首先,根据节点名判断是否为根节点,若是则返回true,若不是则查询所有子节点是否符合条件;

然后,若还未查到则递归查询,直到满足为止。

若所有节点都不符合条件,则返回false。


2.新增元素节点

    这里分2种情况:有文本无属性的节点、既有文本又有属性的节点。

先说第一种,有文本无属性的节点:

首先根据XML文件名读取文件内容并存入QDomDocument对象Doc;

然后根据Doc获取根节点QDomElement rootEle = doc.documentElement();

再利用上面的提到的GetNodeByName获取该节点的父节点;

最后利用QDomElement的appChild方法插入该子节点。

bool QXmlWrapper::AddNode_Text(const QString &_fileName,
                               const QString &_parentNodeName,
                               const QString &_nodeName,
                               const QString &_nodeText)
{
    if (_fileName.isEmpty()) // 文件名为空
    {
        return false;
    }

    // 新建QDomDocument类对象,它代表一个XML文档
    QDomDocument doc;
    // 建立指向“_fileName”文件的QFile对象
    QFile file(_fileName);
    // 以只读方式打开
    if (!file.open(QIODevice::ReadOnly))
        return false;
    // 将文件内容读到doc中
    if (!doc.setContent(&file))
    {
        file.close();
        return false;
    }
    // 关闭文件
    file.close();

    QDomElement rootEle = doc.documentElement();  //返回根元素
    QDomElement parentNode;
    GetNodeByName(rootEle, _parentNodeName, parentNode);

    // 添加元素及其文本
    QDomElement childEle = doc.createElement(_nodeName);
    QDomText text;
    text = doc.createTextNode(_nodeText);
    childEle.appendChild(text);
    parentNode.appendChild(childEle);

    if(!file.open(QFile::WriteOnly|QFile::Truncate)) //先读进来,再重写,如果不用truncate就是在后面追加内容,就无效了
            return false;
    //输出到文件
    QTextStream out(&file);
    doc.save(out,4); // 将文档保存到文件,4为子元素缩进字符数
    file.close();

    return true;
}

 

3.删除元素节点

与新增元素节点类似,只是查找的不是父节点而是该节点本身,最后利用QDomElement的removeChild()方法删除该节点。

    // 假如是根节点
    if (rootEle == nodeEle)
       //doc.removeChild(rootEle);
        return false;

    // 假如是其它节点
    if (nodeEle.isElement())
    {
        QDomNode parentEle = nodeEle.parentNode();

        if (parentEle.isElement())
            parentEle.removeChild(nodeEle);
        else
            return false;
    }


4.修改元素节点

这里也分2种情况:修改节点文本与修改节点属性。
与之前删除节点类似,找到节点后,不能直接修改该节点文本,需要利用新的文本替换该节点文本,具体操作如下:

    if(nodeEle.isElement())
    {
       QDomNode oldnode = nodeEle.firstChild();     //标签之间的内容作为节点的子节点出现,得到原来的子节点
       nodeEle.firstChild().setNodeValue(_nodeText);   //用提供的value值来设置子节点的内容
       QDomNode newnode = nodeEle.firstChild();     //值修改过后
       nodeEle.replaceChild(newnode,oldnode);      //调用节点的replaceChild方法实现修改功能
    }

5.查询元素节点

这里也分2种情况:查询节点文本与查询节点属性。
与之前删除节点类似,找到节点后,分别利用QDomElement的text()与attribute()方法获取节点的文本与属性具体操作如下:

    if(nodeEle.isElement())    {
       QDomNode oldnode = nodeEle.firstChild();     //标签之间的内容作为节点的子节点出现,得到原来的子节点
       nodeEle.firstChild().setNodeValue(_nodeText);   //用提供的value值来设置子节点的内容
       QDomNode newnode = nodeEle.firstChild();     //值修改过后
       nodeEle.replaceChild(newnode,oldnode);      //调用节点的replaceChild方法实现修改功能
    }

另还有QXmlWrapper实现了查询所有子节点的文本等功能。想要获取完成的代码可以查看这里点击打开链接









  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供一个简单的基于 Qt封装 XML 操作类的示例代码,实现节点的增删改查和初始化等功能。 首先,我们需要在头文件中引入 Qt 的相关库和命名空间: ```cpp #include <QtCore/QFile> #include <QtCore/QXmlStreamReader> #include <QtCore/QXmlStreamWriter> #include <QtCore/QDebug> #include <QtCore/QList> #include <QtCore/QString> #include <QtCore/QXmlStreamAttributes> #include <QtCore/QXmlStreamNamespaceDeclarations> ``` 然后,我们定义一个类来封装 XML 操作,包括节点的增删改查和初始化等功能。以下是一个简单的示例类: ```cpp class XmlManager { public: XmlManager(const QString &fileName); virtual ~XmlManager(); void initXmlDocument(); void readXmlDocument(); void writeXmlDocument(); void addNode(const QString &parentNodeName, const QString &nodeName, const QString &nodeValue); void removeNode(const QString &nodeName); void updateNode(const QString &nodeName, const QString &newValue); QString getNodeValue(const QString &nodeName); private: QFile m_file; QXmlStreamReader m_reader; QXmlStreamWriter m_writer; QString m_fileName; }; ``` 在类的构造函数中,我们需要打开 XML 文件,并初始化 `QXmlStreamReader` 和 `QXmlStreamWriter` 以进行读写操作: ```cpp XmlManager::XmlManager(const QString &fileName) : m_fileName(fileName) { m_file.setFileName(m_fileName); if (!m_file.open(QIODevice::ReadWrite | QIODevice::Text)) { qDebug() << "Failed to open file " << m_fileName; } m_reader.setDevice(&m_file); m_writer.setDevice(&m_file); } ``` 在类的析构函数中,我们需要关闭文件: ```cpp XmlManager::~XmlManager() { m_file.close(); } ``` 接下来,我们实现类中的各个方法。首先是 `initXmlDocument()` 方法,该方法用于初始化一个空的 XML 文档: ```cpp void XmlManager::initXmlDocument() { m_writer.setAutoFormatting(true); m_writer.writeStartDocument(); m_writer.writeEndDocument(); } ``` 然后是 `readXmlDocument()` 方法,用于读取 XML 文档的所有节点: ```cpp void XmlManager::readXmlDocument() { while (!m_reader.atEnd() && !m_reader.hasError()) { QXmlStreamReader::TokenType token = m_reader.readNext(); if (token == QXmlStreamReader::StartDocument) { continue; } if (token == QXmlStreamReader::StartElement) { QString name = m_reader.name().toString(); QString value = m_reader.readElementText(); qDebug() << name << ":" << value; } } } ``` `writeXmlDocument()` 方法用于将更改后的 XML 文档写回文件: ```cpp void XmlManager::writeXmlDocument() { m_file.resize(0); m_writer.writeEndDocument(); } ``` `addNode()` 方法用于在指定的父节点下添加一个新的子节点: ```cpp void XmlManager::addNode(const QString &parentNodeName, const QString &nodeName, const QString &nodeValue) { m_reader.setDevice(&m_file); m_writer.setDevice(&m_file); while (!m_reader.atEnd() && !m_reader.hasError()) { QXmlStreamReader::TokenType token = m_reader.readNext(); if (token == QXmlStreamReader::StartElement) { QString name = m_reader.name().toString(); if (name == parentNodeName) { m_writer.writeStartElement(nodeName); m_writer.writeCharacters(nodeValue); m_writer.writeEndElement(); } } } } ``` `removeNode()` 方法用于删除指定的节点: ```cpp void XmlManager::removeNode(const QString &nodeName) { m_reader.setDevice(&m_file); m_writer.setDevice(&m_file); while (!m_reader.atEnd() && !m_reader.hasError()) { QXmlStreamReader::TokenType token = m_reader.readNext(); if (token == QXmlStreamReader::StartElement) { QString name = m_reader.name().toString(); if (name == nodeName) { m_writer.writeEndElement(); } } } } ``` `updateNode()` 方法用于更新指定节点的值: ```cpp void XmlManager::updateNode(const QString &nodeName, const QString &newValue) { m_reader.setDevice(&m_file); m_writer.setDevice(&m_file); while (!m_reader.atEnd() && !m_reader.hasError()) { QXmlStreamReader::TokenType token = m_reader.readNext(); if (token == QXmlStreamReader::StartElement) { QString name = m_reader.name().toString(); if (name == nodeName) { m_writer.writeStartElement(nodeName); m_writer.writeCharacters(newValue); m_writer.writeEndElement(); } else { m_writer.writeStartElement(name); m_writer.writeCharacters(m_reader.readElementText()); m_writer.writeEndElement(); } } } } ``` 最后是 `getNodeValue()` 方法,用于获取指定节点的值: ```cpp QString XmlManager::getNodeValue(const QString &nodeName) { m_reader.setDevice(&m_file); while (!m_reader.atEnd() && !m_reader.hasError()) { QXmlStreamReader::TokenType token = m_reader.readNext(); if (token == QXmlStreamReader::StartElement) { QString name = m_reader.name().toString(); if (name == nodeName) { return m_reader.readElementText(); } } } return ""; } ``` 以上是一个简单的基于 Qt封装 XML 操作类的示例代码。您可以按照您的需求进行修改和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值