Qt C++ 对XML的增删改查

Qt C++ 对XML的增删改查

新知笔记 📅 2020-08-14 ⏱ 约 18 分钟
✦
AI 摘要AI Abstract
  • Qt通过QDomDocument类实现XML文件的创建与结构化管理,支持设置根节点、子元素及属性。
  • 写入XML时需添加处理指令并逐级构建节点,使用save()方法输出带缩进的格式化内容。
  • 读取XML采用DOM解析方式,通过遍历节点树获取标签名、属性和文本内容。
  • Qt XML操作需在.pro文件中引入xml模块并在代码中包含<QtXml>头文件。

最近,学习了Qt C++对XML的一系列操作。今天,把相关代码和注释贴在这里, 以备后续使用。

什么是 XML

可扩展标记语言(英语:Extensible Markup Language,简称:XML)是一种标记语言。标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。

——from Wikipedia

Qt 如何操作 XML

.pro 文件

增加 QT += xml模块。

.cpp 文件

头部 #include <QtXml>

写入 XML

源代码

void Widget::write_xml()
{
    // 打开或创建文件
    QFile file("test.xml"); //相对路径、绝对路径、资源路径都可以
    if(!file.open(QFile::WriteOnly | QFile::Truncate))
        return;
    QDomDocument doc;
 
    // 写入XML头部
    QDomProcessingInstruction instruction;//添加处理命令
    instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
    doc.appendChild(instruction);
 
    // 添加根节点
    QDomElement root = doc.createElement("library");
    doc.appendChild(root);
 
    // 添加第一个子节点及其元素
    QDomElement book = doc.createElement("book");
    book.setAttribute("id", 1); // 方式一:创建属性  其中键值对的值可以是各种类型
    QDomAttr time = doc.createAttribute("time");
    time.setValue("2020/08/11"); // 方式二:创建属性  值必须是字符串
    book.setAttributeNode(time);
 
    QDomElement title = doc.createElement("title"); // 创建子元素
    QDomText text; // 设置括号标签中间的值
    text = doc.createTextNode("C++ primer");
    book.appendChild(title);
    title.appendChild(text);
 
    QDomElement author = doc.createElement("author"); // 创建子元素
    text = doc.createTextNode("Stanley Lippman");
    author.appendChild(text);
    book.appendChild(author);
    root.appendChild(book);
 
    QDomElement price = doc.createElement("price");
    text = doc.createTextNode("$29.9");
    price.appendChild(text);
    book.appendChild(price);
    root.appendChild(book);
 
 
    // 添加第二个子节点及其子元素,部分变量只需重新赋值
    book = doc.createElement("book");
    book.setAttribute("id", 2);
    time = doc.createAttribute("time");
    time.setValue("2020/08/10");
    book.setAttributeNode(time);
    title = doc.createElement("title");
    text = doc.createTextNode("Thinking in Java");
    book.appendChild(title);
    title.appendChild(text);
    author = doc.createElement("author");
    text = doc.createTextNode("Bruce Eckel");
    author.appendChild(text);
    book.appendChild(author);
    root.appendChild(book);
 
    // 输出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream, 4); // 缩进4格
    file.close();
}

调试结果 test.xml

<?xml version="1.0" encoding="UTF-8"?>
<library>
    <book time="2020/08/11" id="1">
        <title>C++ primer</title>
        <author>Stanley Lippman</author>
        <price>$29.9</price>
    </book>
    <book time="2020/08/10" id="2">
        <title>Thinking in Java</title>
        <author>Bruce Eckel</author>
    </book>
</library>
读取 XML

源代码

void Widget::read_xml()
{
    // 打开或创建文件
    QFile file("test.xml"); // 相对路径、绝对路径、资源路径
    if(!file.open(QFile::ReadOnly))
        {
            return;
        }
 
    QDomDocument doc;
    if(!doc.setContent(&file))
        {
            file.close();
            return;
        }
    file.close();
 
    QDomElement root = doc.documentElement(); // 返回根节点
    qDebug() << root.nodeName();
    QDomNode node = root.firstChild();
    while(!node.isNull()) // 如果节点不空
        {
            if(node.isElement())
                {
                	// 转换为元素,注意元素和节点是两个数据结构
                    QDomElement e = node.toElement(); 
                	// 打印键值对,tagName和nodeName是一个东西
                    qDebug() << e.tagName() << " " << e.attribute("id") << " " << e.attribute("time"); 
                    QDomNodeList list = e.childNodes();
                	// 遍历子元素,count和size都可以使用,可用于标签数计数
                    for (int i = 0; i < list.count(); i++) 
                        {
                            QDomNode n = list.at(i);
                            if(node.isElement())
                                {
                                    qDebug() << n.nodeName() << ":" << n.toElement().text();
                                }
                        }
                }
            node = node.nextSibling();
        }
}
增加 XML 内容

源代码

// 增加XML内容
void Widget::add_xml()
{
    // 打开文件
    QFile file("test.xml"); // 相对路径、绝对路径、资源路径都可以
    if(!file.open(QFile::ReadOnly))
        {
            return;
        }
 
    // 增加一个以及子节点以及元素
    QDomDocument doc;
    if(!doc.setContent(&file))
        {
            file.close();
            return;
        }
    file.close();
 
    QDomElement root = doc.documentElement();
    QDomElement book = doc.createElement("book");
    book.setAttribute("id", 3);
    book.setAttribute("time", "1999/09/09");
    QDomElement title = doc.createElement("title");
    QDomText text;
    text = doc.createTextNode("Pride and Prejudice");
    title.appendChild(text);
    book.appendChild(title);
    QDomElement author = doc.createElement("author");
    text = doc.createTextNode("Jane Austen");
    author.appendChild(text);
    book.appendChild(author);
    QDomElement price = doc.createElement("price");
    text = doc.createTextNode("$69.9");
    price.appendChild(text);
    book.appendChild(price);
    root.appendChild(book);
 
    if(!file.open(QFile::WriteOnly | QFile::Truncate))
        {
            // 先读进来,再重写 ,如果不用truncate就是在后面追加内容
            return;
        }
 
    // 输出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream, 4); // 缩进4格
    file.close();
}
删除 XML 内容

源代码

// 删除XML内容
void Widget::remove_xml()
{
    // 打开文件
    QFile file("test.xml"); // 相对路径、绝对路径、资源路径都可以
    if(!file.open(QFile::ReadOnly))
        {
            return;
        }
 
    // 删除一个一级子节点及其元素,外层节点删除内层节点与此相同
    QDomDocument doc;
    if(!doc.setContent(&file))
        {
            file.close();
            return;
        }
    file.close(); // 一定要记得关闭,不然无法完成操作
 
    QDomElement root = doc.documentElement();
    QDomNodeList list = doc.elementsByTagName("book"); // 由标签名定位
    for(int i = 0; i < list.count(); i++)
        {
            QDomElement e = list.at(i).toElement();
            if(e.attribute("time") == "2020/08/09") // 以属性名定位,类似于hash方式
                {
                    root.removeChild(list.at(i)); // 这里仅删除一个节点,可以加入break
                    break;
                }
        }
 
    if(!file.open(QFile::WriteOnly | QFile::Truncate))
        {
            return;
        }
 
    // 输出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream, 4);
    file.close();
}
更新 XML 内容

源代码

// 更新XML内容
void Widget::update_xml()
{
    // 打开文件
    QFile file("test.xml");
    if(!file.open(QFile::ReadOnly))
        {
            return;
        }
 
    //更新一个标签项,如果知道XML的结构,直接定位到那个标签定点更新
    //或者用遍历的方法去匹配tagname或者attribute,value来更新
    QDomDocument doc;
    if(!doc.setContent(&file))
        {
            file.close();
            return;
        }
    file.close();
 
    QDomElement root = doc.documentElement();
    QDomNodeList list = root.elementsByTagName("book");
    QDomNode node = list.at(list.size() - 1).firstChild(); // 定位到第三格以及子节点的子元素
    QDomNode oldnode = node.firstChild(); // 标签之间的内容作为节点的子节点出现,当前是 How to learn Python
    node.firstChild().setNodeValue("Update_success");
    QDomNode newnode = node.firstChild();
    node.replaceChild(newnode, oldnode);
 
    if(!file.open(QFile::WriteOnly | QFile::Truncate))
        {
            return;
        }
    // 输出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream, 4); // 缩进4格
    file.close();
}

今天的分享就到这里,后续我会继续更新我的Qt学习记录~

评论