Qt XML文件的创建、读取介绍以及“重写XML不能覆盖原内容问题”解决

简介XML

XML(Extensible Markup Language,可扩展标记语言),是一种类似于HTML的标记语言,设计目的是用来传输数据,而不是显示数据。XML的标签没有被预定义,用户需要在使用时自行进行定义。XML是W3C(万维网联盟)的推荐标准。相对于数据库表格的二维表示,XML使用的树形结构更能表现出数据的包含关系,作为一种文本文件格式,XML简单明了的特性使得它在信息存储和描述领域非常流行。

Qt中提供了Qt XML模块来进行XML文档的处理,这里主要提供了两种解析方法: DOM方法,可以进行读写;SAX方法,可以进行读取。但是,从Qt 5开始Qt XML模块不再提供维护,而是推荐使用Qt Core模块中的QXmlStreamReader和QXmlStreamWriter进行XML读取和写入,这是一种基于流的方法。

如果要使用Qt XML模块,需要在项目文件(.pro文件)中添加QT += xml一行代码。

标准的XML文档示例:

<?xml version="1.0" encoding="UTF-8"?>
<library>
    <book id="01">
        <title>Qt</title>
        <author>shiming</author>
    </book>
    <book id="02">
        <title>Linux</title>
        <author>yafei</author>
    </book>
</library>

DOM

DOM(Document Object Model,文档对象模型),是W3C的推荐标准。它提供了一个接口来访问和改变一个XML文件的内容和结构,可以将XML文档表示为一个存储在内存中具有层次的树视图。文档本身由QDomDocument对象来表示,而文档树中所有的DOM节点都是QDomNode类的子类。

在Qt中使用QDomProcessingInstruction类来表示XML说明。元素对应QDomElement类。属性对应QDomAttr类。文本内容由QDomText类表示。所有的DOM节点,比如这里的说明、元素、属性和文本等,都使用QDomNode来表示。

下面用一个简单的实例来介绍XML文件的创建与读取。

XML创建

//生成配置文件
void Login::createConfigXML()
{
    //配置文件 参数
    QDomDocument doc;
    //根元素
    QDomElement root;
    //界面元素
    QDomElement interface;
    //界面子元素
    QDomElement child;
    //控件文本
    QDomText text;

    // 添加处理指令即XML说明
    QDomProcessingInstruction instruction;
    instruction = doc.createProcessingInstruction("xml",
                                                  "version=\"1.0\" encoding=\"UTF-8\"");
    doc.appendChild(instruction);

    // 添加根元素
    root = doc.createElement("色选机软件系统");
    doc.appendChild(root);


    //【一】管理员界面
    interface = doc.createElement("管理员界面");
    //...【1】
    child = doc.createElement("工作模式");
    text = doc.createTextNode("异色模式");
    child.appendChild(text);
    interface.appendChild(child);
    root.appendChild(interface);

    //【二】背景板界面
    interface = doc.createElement("背景板界面");
    //...【1】
    child = doc.createElement("镜头号");
    text = doc.createTextNode("1");
    child.appendChild(text);
    interface.appendChild(child);

    //...【2】
    child = doc.createElement("背景");
    text = doc.createTextNode("红色");
    child.appendChild(text);
    interface.appendChild(child);

    //添加界面数据
    root.appendChild(interface);

    //创建配置文件
    QFile file("ColorConfig.xml");

    if(!file.open(QIODevice::Truncate | QIODevice::WriteOnly))
    {
        QMessageBox::about(NULL, tr("错误"), tr("生成配置文件失败,请重试!"));
        return;
    }

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

生成的配置文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<色选机软件系统>
    <管理员界面>
        <工作模式>异色模式</工作模式>
    </管理员界面>
    <背景板界面>
        <镜头号>1</镜头号>
        <背景>红色</背景>
    </背景板界面>    
</色选机软件系统>

XML读取

//读取配置文件
void Login::readConfigXML()
{
    QFile file("ColorConfig.xml");
    if(!file.exists())
    {
        QMessageBox::about(NULL, tr("提示"), tr("未发现配置文件"));
        return;
    }
    if (!file.open(QIODevice::ReadOnly))
        return;

    QDomDocument Qdoc;
    if (!Qdoc.setContent(&file))
    {
        file.close();
        return ;
    }
    file.close();

    //【一】管理员界面
    QDomNodeList list = Qdoc.elementsByTagName("管理员界面");
    QDomNodeList child = list.at(0).childNodes();
    for(int i = 0; i < child.count(); ++i)
    {
        //输出子元素名
        qDebug()<< child.at(i).toElement().tagName() << endl;
        //输出字元素数据
        qDebug()<< child.at(i).toElement().text()) << endl;
    }

    //【二】背景板界面
    list = Qdoc.elementsByTagName("背景板界面");
    child = list.at(0).childNodes();
    for(int i = 0; i < child.count(); ++i)
    {
        //输出子元素名
        qDebug()<< child.at(i).toElement().tagName() << endl;
        //输出字元素数据
        qDebug()<< child.at(i).toElement().text()) << endl;
    }

}

还有另一种方式读取:

QFile file("ColorConfig.xml");
    if (!file.open(QIODevice::ReadOnly)) return ;
    QDomDocument doc;
    if (!doc.setContent(&file))  {    file.close();  return ; }
    file.close();
    QDomElement docElem = doc.documentElement();
    QDomNode n = docElem.firstChild();
    while(!n.isNull())  {
        if (n.isElement())  {
            QDomElement e = n.toElement();            
            QDomNodeList list = e.childNodes();
            for (int i=0; i<list.count(); i++)  {
                QDomNode node = list.at(i);
                if(node.isElement())
                {
                    //输出子元素名
                    qDebug()<< node.toElement().tagName() << endl;
                    //输出字元素数据
                    qDebug()<< node.toElement().text()) << endl;
                 }
        }  n = n.nextSibling();
    }

“重写XML不能覆盖原内容问题”解决

如果我们想覆盖XML中的原数据,重新写入数据,使用

file.open(QIODevice::Truncate | QIODevice::WriteOnly)

这种方式打开文件即可,Truncate 表示重写,将原文件数据清空。但是我在做项目中碰到如下问题,重新写入数据时,原数据没能覆盖,新数据也添加了进去,如下:

<?xml version="1.0" encoding="UTF-8"?>
<色选机软件系统>
    <管理员界面>
        <工作模式>异色模式</工作模式>
    </管理员界面>
    <背景板界面>
        <镜头号>1</镜头号>
        <背景>红色</背景>
    </背景板界面>    
</色选机软件系统>
<?xml version="1.0" encoding="UTF-8"?>
<色选机软件系统>
    <管理员界面>
        <工作模式>黄白模式</工作模式>
    </管理员界面>
    <背景板界面>
        <镜头号>3</镜头号>
        <背景>蓝色</背景>
    </背景板界面>    
</色选机软件系统>

最终发现原因:

我的项目中,软件打开时,默认加载配置文件的数据,然而我把读取、创建XML元素的对象们设置为全局的了,

    //配置文件 参数
    QDomDocument doc;
    //根元素
    QDomElement root;
    //界面元素
    QDomElement interface;
    //界面子元素
    QDomElement child;
    //控件文本
    QDomText text;

导致软件打开时,读取配置文件,这些变量都被占用,并没有释放。然后我再去重写XML内容时,就不可以将已占用的数据清空替换,导致新的配置文件数据在原数据下方产生。

解决方法:

将这些读取、创建XML元素的对象们设置为局部变量,一次用完自动释放,不妨碍其他操作。这样就正确了。

 

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值