IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> C7—Qt中使用XML格式文档 -> 正文阅读

[系统运维]C7—Qt中使用XML格式文档

Qt读写XML文档

什么是XML?

XML(eXtensible Markup Language)是一种通用的文本格式,与数据库一样被广泛运用于数据交换和数据存储,但在使用场景上二者有着巨大的差别,这是由于自身属性决定的。与数据库相比,XML缺少数据库具备的特性:高效的存储、索引和数据修改机制;严格的数据安全访问控制;完整的事务和数据一致性控制;多用户访问机制;触发器、完善的并发控制等。因此,用户量大、数据集成度高以及性能要求高的数据环境中还是需要数据库来完成任务,可以进行大量数据的存储和分析。

而xml是一种存储数据的标准格式,是为了便于网络数据传输和交互,解决的是数据在网上传输标准的问题,把原来各种各样的数据孤岛可以通过xml这座桥梁连接起来,而存在的期性能和存储的数据量,严重受着文件的大小而影响,存储xml的文件越大传递和读取起来越耗时。

所以打个比方,数据库就好比是盛数据的桶,而xml则是数据传输转换的桥梁,所以数据库是数据库,xml是xml,二者是截然不同的,当然二者也存在非常紧密的联系,毕竟都是处理数据的工具。
以上部分主要参考King-Blog的博客

Qt对于XML的支持

Qt 提供提供了Qt XML模块来进行XML文档的处理,主要提供了DOM方法和SAX方法。

DOM(Document Object Model)即文档对象模型,提供了一个接口来访问和改变一个XML文件的内容、结构,可以将XML文档表示为一个存储在内存中具有层次的树形视图,使用DOM可以很方便地进行XML的随机访问与增删改查,这是他最大的优点。与此同时带来的问题是需要一次性将整个XML文档读入内存,会占用很大的内存。

SAX(Simple API for XML)为XML解析器提供了一个基于事件的标准接口。如果不需要对文档进行操作,只需要读取整个XML文档,那么使用SAX方法最高效。不过他只能读取XML文档。
此外,从Qt4.3开始引入了两个新的类来读取和写入XML文档:QXmlStreamReader和QXmlStreamWriter,一种快速的基于流的方式访问良格式 XML 文档。它是作为SAX解析器的替代品身份出现的,它比SAX解析器更快更方便。本文介绍DOM方法与XML流方法。

DOM方法读写XML

Dom方法读XML

<?xml version="1.0" encoding="UTF-8"?>
<Begin>
	<Type1 myLover="yxx">	
		<sex>girl</sex>
		<school>XiAn</school>
		<age>1996</age>
		<special>beautiful</special>
		<relationship>classmate</relationship>
		<duration>2years</duration>
	</Type1>
	<Type2 myLover="83">	
		<aa>woceng</aa>
		<bb>aiguo</bb>
		<cc>yeshiqu</cc>
		<dd>guo</dd>
		<ee>changguo</ee>
		<ff>aide</ff>
	</Type2>
	<Type3>	
		<yy>tianyuse</yy>
		<xx>521</xx>
		<xx>0803</xx>
		<ll>!!!</ll>
		<oo>give</oo>
		<vv>me</vv>
		<ee>hug</ee>
	</Type3>
	
</Begin>

一个XML文件如下所示,首先应该搞清楚几个常用的术语。以下代码中,
第一行说明该文件的版本号和编码;"begin"是根节点,可以理解为一级目录;
”TypeX“是子节点,可以理解为二级目录;
”myLover“是属性,”yxx“是属性值,属性值必须在双引号之内,属性写在尖括号内,多个属性时,也要全部写在尖括号内;
“sex”“school”等是三级节点,可以理解为三级目录;
”girl“”“Xian”等是文本;
在使用DOM读取之前,先看一下在XML模块中的Qt方法与该xml文件之间的对应关系。
在这里插入图片描述
下面在贴上使用DOM读的效果图,上述xml中的信息都可以被获取,可与上幅图片对比看。
在这里插入图片描述
在介绍源码之前,有几点说明如下。
1.在映射图中可以清楚的看到,除了一级目录外的次级目录(包括二级、三级以及之后的)的节点都保存在QDomNode类中,但是节点的属性、属性值、文本都只有在QDomElement类中才提供读取的方法。因此,读取节点的属性(值)以及文本需要将QDomNode类转换成QDomElement,通常的做法是,使用childNodes方法,获取次级目录中节点的个数,将其保存在QDomNodeList中,遍历这个列表,将每一个索引值都转换成QDomElement进而获取属性(值)、文本。
2.使用QDomDocument类之前先在pro文件中写入 QT += xml
3.本案例中由于疏忽直到写到现在才发现,未在三级目录中添加属性值的读取,不过不妨大碍,与二级目录中读取属性(值)的方法一致。
4.str.toUtf8().data(),这个操作将会有QString类型转换成char *类型,这样做的好处是,使用qDebug打印数据到控制台时,将不带双引号。
5.DOM读的源码是,将读功能封装成了一个函数,函数执行时,会弹出文件选择框,过滤除xml格式的其他文件,用户打开xml将在控制台打印各级目录信息,属性信息以及文本信息。上述效果截图中正是打开的上述的xml文件。

void Widget::domRead()
{
QString fileName = QFileDialog::getOpenFileName(this,"get xml file",
                                                    "C:/Users/Jack_Chen/Desktop","xml(*.xml)");
    if(fileName.isEmpty()){
        return;
    }
    myFile->setFileName(fileName);
    bool ret =myFile->open(QIODevice::ReadOnly|QIODevice::Text);
    if(!ret){
        QMessageBox::warning(this,"warning","打开文件失败!");
        return;
    }
    //对xml文件操作
    QDomDocument doc("yxx");//定义doc对象,初始化名字
    bool isLot = doc.setContent(myFile);//将文件与QDomDocument类关联
    if(!isLot){
        //关联xml文件失败
        myFile->close();
        QMessageBox::warning(this,"waring","关联文件失败");
        return;
    }
    myFile->close();
    QDomElement firstElem = doc.documentElement();//获取到了<begin>一级目录
    qDebug()<<"一级目录<begin>: "<<firstElem.nodeName();
    QDomNodeList secondList = firstElem.childNodes();//获取全部二级目录<Type1><Type2><Typ3>
    for (int i = 0; i < secondList.count(); ++i) {
        QString str = QString("      第 %1 个二级目录节点:").arg(i+1);
        qDebug()<<str.toUtf8().data()<<secondList.at(i).nodeName();//将QString转换成char *,使用qDebug输出没有引号
        QDomElement secondElem = secondList.at(i).toElement();//获取二级目录节点的属性值管理者domElement
        if(secondElem.hasAttribute("myLover")){
            //输出二级目录节点的属性值
            qDebug()<<"      "<<secondElem.nodeName().append("的属性值myLover为").toUtf8().data()<<secondElem.attribute("myLover");
        }
        else{
            qDebug()<<"      "<<secondElem.nodeName().append("该节点无属性值").toUtf8().data();
        }
        QDomNodeList thirdList = secondList.at(i).childNodes();//获取三级目录<具体值></具体值>
        for(int j = 0;j<thirdList.length();j++ ){
            QDomElement thirdElement=thirdList.at(j).toElement();
            QString str_1 = QString("            %1中第 %2 个三级目录节点 %3,他的文本值为 %4:")
                    .arg(secondList.at(i).nodeName(),QString::number(j+1),thirdList.at(j).nodeName(),thirdElement.text());
            qDebug()<<str_1.toUtf8().data();//将QString转换成char *,使用qDebug输出没有引号
        }
    }

Dom方法写XML

写XML文档应该按照XML自身的格式来写,首先写第一行关于版本和编码的描述,然后加入各级目录节点的同时,加入与节点对应的属性值和文本。最后使用QDomDocument类提供的save方法,将QTextStream类与文件关联进行保存。源码部分与效果图粘贴如下。

void Widget::domWrite()
{
    //add instruction
    QDomDocument doc;
    QDomProcessingInstruction instruction = doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");//写xml中的第一行说明
    doc.appendChild(instruction);

    //add 第一级目录节点
    QDomElement firstNode = doc.createElement("Begin");
    doc.appendChild(firstNode);

    //add 第二级目录节点
    QDomElement secondNode = doc.createElement("Type");
    //为二级目录添加属性值
    QDomAttr secondAttr = doc.createAttribute("MyLover");
    secondAttr.setValue("yxx");
    secondNode.setAttributeNode(secondAttr);
    firstNode.appendChild(secondNode);//一级目录下添加二级节点
        //add 第三级目录节点 添加text文本值
        QDomElement thirdNode_1 = doc.createElement("sex");
        secondNode.appendChild(thirdNode_1);
        QDomText t1 = doc.createTextNode("girl");
        thirdNode_1.appendChild(t1);
        QDomElement thirdNode_2 = doc.createElement("school");
        secondNode.appendChild(thirdNode_2);
        QDomText t2 = doc.createTextNode("Xian");
        thirdNode_2.appendChild(t2);
        QDomElement thirdNode_3 = doc.createElement("age");
        secondNode.appendChild(thirdNode_3);
        QDomText t3 = doc.createTextNode("1996");
        thirdNode_3.appendChild(t3);
        QDomElement thirdNode_4 = doc.createElement("special");
        secondNode.appendChild(thirdNode_4);
        QDomText t4 = doc.createTextNode("beautiful");
        thirdNode_4.appendChild(t4);
    QString fileName = QFileDialog::getSaveFileName(this,"Save xml file",
                                                        "C:/Users/Jack_Chen/Desktop","xml(*.xml)");
    if(fileName.isEmpty()){
        return;
    }
    myFile->setFileName(fileName);
    bool ret =myFile->open(QIODevice::WriteOnly|QIODevice::Text);
    if(!ret){
        QMessageBox::warning(this,"warning","保存文件失败!");
        return;
    }
    QTextStream stream(myFile);//使用QTextStream类与文件关联进行保存xml!
    stream.setCodec("UTF-8");//编码格式
    doc.save(stream,4);//4代表的是缩进个数
    myFile->close();
    QMessageBox::information(this,"save tip","xml文件保存成功!");
}

保存xml文件如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Begin>
    <Type MyLover="yxx">
        <sex>girl</sex>
        <school>Xian</school>
        <age>1996</age>
        <special>beautiful</special>
    </Type>
</Begin>

流方法读写XML

QXmlStreamReader方法读XML

关联QXmlStreamReader类与文件类,然后用QXmlStreamReader类来操作,但切记,未操作完不能close文件类,否则无法正确读取。该类根据标记读取,读取到不同的标记会返回不同的值,与DOM思想完全不一样,但是不支持随机读取。标记的划分是根据XML语法中的属性(值)文本,开始结束关键字进行的。贴出代码与运行效果。
代码:

void Widget::streamRead()
{
    QString fileName = QFileDialog::getOpenFileName(this,"get xml file",
                                                    "C:/Users/Jack_Chen/Desktop","xml(*.xml)");
    if(fileName.isEmpty()){
        return;
    }
    myFile->setFileName(fileName);
    bool ret =myFile->open(QIODevice::ReadOnly|QIODevice::Text);
    if(!ret){
        QMessageBox::warning(this,"warning","打开文件失败!");
        return;
    }
    QXmlStreamReader readxml(myFile);
    while(!readxml.atEnd()){//直到读完停止读
        if(readxml.hasError()){//如果有错误
           QMessageBox::warning(this,"warning","读取文件失败!");
           break;
        }
          QXmlStreamReader::TokenType type = readxml.readNext();//指定读取标记类型
           switch ((int)type) {
           case QXmlStreamReader::ProcessingInstruction:
               qDebug()<<"ProcessingInstruction"<<readxml.text();
               break;
           case QXmlStreamReader::StartDocument://第一句话
               qDebug()<<"StartDocument"<<"输出版本编码信息"<<readxml.documentVersion()<<readxml.documentEncoding();
               break;
           case QXmlStreamReader::StartElement://属性值
           {
               qDebug()<<readxml.name().toString().append("!!!");
               QString str = readxml.attributes().value("myLover").toString();
               if(!str.isEmpty()){
                   qDebug()<<"输出属性值"<<readxml.name()<<str;
               }
               break;
           }
           case QXmlStreamReader::EndElement://endof element
//               qDebug()<<"EndElement";
               break;
           case QXmlStreamReader::EndDocument://末尾
               qDebug()<<"EndDocument";
               break;
           case QXmlStreamReader::Characters://text文本值
           {
               QString ss = readxml.text().toString();
               if(!readxml.isWhitespace()){//如果读到的字符全部是空格返回true
                    qDebug()<<"输出文本值"<<ss;
               }
               break;
           }
           }
        }
    }

打开的xml文件为本贴前文最上面部分的xml文件,效果如下:
在这里插入图片描述

QXmlStreamWriter方法写XML

流方法的思想除了数据还有标记的概念,通过标记区分位置,因此除了写数据之外还要写一些标记。跟读的思想完全一样,只不过具体的函数不太一样。直接贴代码

void Widget::streamWrite()
{
    QString fileName = QFileDialog::getSaveFileName(this,"Save xml file",
                                                        "C:/Users/Jack_Chen/Desktop","xml(*.xml)");
    if(fileName.isEmpty()){
        return;
    }
    myFile->setFileName(fileName);
    bool ret =myFile->open(QIODevice::WriteOnly|QIODevice::Text);
    if(!ret){
        QMessageBox::warning(this,"warning","保存文件失败!");
        return;
    }
   QXmlStreamWriter stream(myFile);
   stream.setAutoFormatting(true);//设置自动对齐
   stream.writeStartDocument();//开始印记
   //add 一级目录
     stream.writeStartElement("begin");
        //add 二级目录节点
        stream.writeStartElement("Type");
        //添加属性值 myLover
        stream.writeAttribute("myLover","yxx");
        //add 三级目录节点
            stream.writeStartElement("sex");
            //add text
            stream.writeCharacters("girl");
            stream.writeEndElement();

            stream.writeStartElement("school");
            //add text
            stream.writeCharacters("Xian");
            stream.writeEndElement();

            stream.writeStartElement("age");
            //add text
            stream.writeCharacters("1996");
            stream.writeEndElement();

            stream.writeStartElement("special");
            //add text
            stream.writeCharacters("beautiful");
            stream.writeEndElement();

        stream.writeEndElement();
     stream.writeEndElement();
   stream.writeEndDocument();//结束印记
    myFile->close();
    QMessageBox::information(this,"save tip","xml文件保存成功!");
}

写完打开文件得到xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<begin>
    <Type myLover="yxx">
        <sex>girl</sex>
        <school>Xian</school>
        <age>1996</age>
        <special>beautiful</special>
    </Type>
</begin>
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-12-10 11:27:06  更:2021-12-10 11:29:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 4:31:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码