Qt之xml文件解析

Qt之XML文件解析

XML简介

​ 和HTML的语法很相似,但不同之处在于: HTML 被设计用来显示数据,其关注的是数据的外观,XML 被设计用来传输和存储数据,其关注的是数据的内容,因此,XML主要用来作为数据的存储和共享。

​ XML文档是一种树的结构,从根部扩展到枝叶。以下是一个XML示例

<?xml version="1.0" encoding="UTF-8"?>
<root>
	<!--写入矩形图元的信息-->
	<class name="Rect">
		<object name="obj1">
			<x1>10</x1>
			<y1>10</y1>
			<x2>50</x2>
			<y1>50</y1>
			<linewidth>2</linewidth>
			<scale>0</scale>
			<rotate>0</rotate>
		</object>
	</class>
</root>

其中第一行 是XML 声明。它定义 XML 的版本和所使用的编码格式,<root> </root>为根节点的起始(在XML中可以自定义节点名称),<class> </class>为子元素,其中name为其属性,值为Rect;每一个子元素都可以拥有子元素,故class的子元素为object,依次类推; 所有的元素都可以有文本内容和属性,如x1的文本为10,x2的文本为50。

写XML文件

​ 使用QT自带的模块QXmlStreamWriter

1. 构造函数

​ QXmlStreamWriter有三种构造方式,分别是

QXmlStreamWriter::QXmlStreamWriter([QString](qstring.html) **string*);
QXmlStreamWriter::QXmlStreamWriter([QByteArray](qbytearray.html) **array*);
QXmlStreamWriter::QXmlStreamWriter([QIODevice](qiodevice.html) **device*)

第一种和第二种分别是创建一个QString和QByteArray对象,然后将xml流写入到其中,第三种则是创建一个文件设备将xml流写入其中,一般来说,第三种常用。

2. 属性

autoFormatting:bool量,表示是否自动格式化文档,其相关读写函数为:

void setAutoFormatting(bool enable)
bool autoFormatting() const

autoFormattingIndent:int变量,当自动格式化为真时,它表示缩进的空格或者制表符的数量,相关读写函数为:

int autoFormattingIndent() const
void setAutoFormattingIndent(int spacesOrTabs)

一般4个空格等于一个制表符,也就是说setAutoFormattingIndent(4)的效果与setAutoFormattingIndent(-1)的效果是一样的。

3. 方法

​ 这里只介绍常用的一些方法。

1、自动格式化代码

void QXmlStreamWriter::setAutoFormatting(bool enable)

2、 设置文档编码

void QXmlStreamWriter::setCodec(QTextCodec *codec);
void QXmlStreamWriter::setCodec(const char *codecName)

​ 默认是utf-8,其它支持的编码格式如下:

Big5
Big5-HKSCS
CP949
EUC-JP
EUC-KR
GB18030
HP-ROMAN8
IBM 850
IBM 866
IBM 874
ISO 2022-JP
ISO 8859-1 to 10
ISO 8859-13 to 16
Iscii-Bng, Dev, Gjr, Knd, Mlm, Ori, Pnj, Tlg, and Tml
KOI8-R
KOI8-U
Macintosh
Shift-JIS
TIS-620
TSCII
UTF-8
UTF-16
UTF-16BE
UTF-16LE
UTF-32
UTF-32BE
UTF-32LE
Windows-1250 to 1258

3、设置自动缩进值

void setAutoFormattingIndent(int spacesOrTabs)

4、开始写xml文档时,需要先设置xml的版本和所使用的编码,一般为1.0版本,编码为utf-8,相关函数为:

void QXmlStreamWriter::writeStartDocument();
void QXmlStreamWriter::writeStartDocument(const QString &version);
void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalone)

与其相对应的,关闭文档写入需要调用函数

void QXmlStreamWriter::writeEndDocument();

5、xml文档为树结构,其有一个根节点,根节点下面都挂在着许多元素,节点元素设置都为以下函数

void QXmlStreamWriter::writeStartElement(const QString &namespaceUri, const QString &name);
void QXmlStreamWriter::writeStartElement(const QString &qualifiedName)

与其相对应的,关闭节点或元素需要调用函数

void QXmlStreamWriter::writeEndElement()

6、每一个元素都可以有若干个属性,写入带有名称和值的属性

void QXmlStreamWriter::writeAttribute(const QString &namespaceUri, const QString &name, const QString &value);
void QXmlStreamWriter::writeAttribute(const QString &qualifiedName, const QString &value);
void QXmlStreamWriter::writeAttribute(const QXmlStreamAttribute &attribute);
void QXmlStreamWriter::writeAttributes(const QXmlStreamAttributes &attributes);

7、写文本

void QXmlStreamWriter::writeCharacters(const QString &text);

8、写入带有名称和文本的元素

void QXmlStreamWriter::writeTextElement(const QString &namespaceUri, const QString &name, const QString &text);
void QXmlStreamWriter::writeTextElement(const QString &qualifiedName, const QString &text);

9、写注释

void QXmlStreamWriter::writeComment(const QString &text);

还有一些方法就不一一介绍了,以上已经可以写出一个完整的xml文档。

4. 示例

​ 将一些图元的信息写入到xml文件中。

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>
#include <QFileDialog>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowTitle("Xml Demo");
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_btnRead_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, "Save this file As"
                                                    , "./", "Xml(*.xml)");
    qDebug() << fileName;

    QFile file(fileName);

    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug() << "Save failed";
        return;
    }

    QXmlStreamReader reader(&file);
    QXmlStreamReader::TokenType token;
    QXmlStreamAttributes attribute;
    QString str, attrStr;
    while (!reader.atEnd()) {
          token = reader.readNext();
          if(token == QXmlStreamReader::StartElement)
          {
              str =  reader.name().toString();
              if(QString::compare(str, "root") == 0)
              {
                  qDebug() << "这是一级节点:"<< str;
                  qDebug() << "----------------";
              }
              else if(QString::compare(str, "class") == 0)
              {

                  attribute = reader.attributes();
                  if(attribute.hasAttribute("name"))
                  {
                      attrStr.clear();
                      attrStr = attribute.value("name").toString();
                  }
                  qDebug() << "************************************************";
                  qDebug() << "这是二级节点:"<< str << ", 属性为" << attrStr;
              }
              else if(!QString::compare(str, "object"))
              {
                  attribute = reader.attributes();
                  if(attribute.hasAttribute("name"))
                  {
                      attrStr.clear();
                      attrStr = attribute.value("name").toString();
                  }
                  qDebug() << "这是三级节点:" << ", 属性为" << attrStr;

              }
              else if(QString::compare(str, "x1") == 0)
              {

                  qDebug() << attrStr << "对象的x1值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "x2") == 0)
              {
                  qDebug() << attrStr << "对象的x2值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "y1") == 0)
              {
                  qDebug() << attrStr << "对象的y1值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "y2") == 0)
              {
                  qDebug() << attrStr << "对象的y2值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "linewidth") == 0)
              {
                  qDebug() << attrStr << "对象的linewidth值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "scale") == 0)
              {
                  qDebug() << attrStr << "对象的scale值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "rotate") == 0)
              {
                  qDebug() << attrStr << "对象的rotate值为:" << reader.readElementText();
                  qDebug() << "----------------";
              }
          }
          else if(token == QXmlStreamReader::Comment)
          {
              qDebug() << reader.text().toString(); /* xml注释 */
          }
          else if(token == QXmlStreamReader::Invalid)
          {
              qDebug() << "读取失败:" << reader.errorString();
          }

    }
}

void MainWindow::on_btnWrite_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, "Save File",
                                                    "./untitled.xml","Xml(*.xml)");
    qDebug() << fileName;

    QFile file(fileName);

    if (!file.open(QIODevice::WriteOnly))
    {
        qDebug() << "Save failed";
        return;
    }

    /* 打开文件成功,开始写入 */
    QXmlStreamWriter writer(&file);

    writer.setCodec("utf-8");
    writer.writeStartDocument("1.0");
    writer.setAutoFormatting(true);
    writer.setAutoFormattingIndent(-1);

    writer.writeStartElement("root");
        writer.writeComment("写入矩形图元的信息");
        writer.writeStartElement("class");
        writer.writeAttribute("name", "Rect");
            writer.writeStartElement("object");
            writer.writeAttribute("name", "obj1");
                writer.writeTextElement("x1", QString::number(10));
                writer.writeTextElement("y1", QString::number(10));
                writer.writeTextElement("x2", QString::number(50));
                writer.writeTextElement("y1", QString::number(50));
                writer.writeTextElement("linewidth", QString::number(2));
                writer.writeTextElement("scale", QString::number(0));
                writer.writeTextElement("rotate", QString::number(0));
            writer.writeEndElement();

            writer.writeStartElement("object");
            writer.writeAttribute("name", "obj2");
                writer.writeTextElement("x1", QString::number(20));
                writer.writeTextElement("y1", QString::number(30));
                writer.writeTextElement("x2", QString::number(50));
                writer.writeTextElement("y1", QString::number(60));
                writer.writeTextElement("linewidth", QString::number(2));
                writer.writeTextElement("scale", QString::number(0));
                writer.writeTextElement("rotate", QString::number(90));

            writer.writeEndElement();
        writer.writeEndElement();

        writer.writeComment("写入线图元的信息");
        writer.writeStartElement("class");
        writer.writeAttribute("name", "Line");
            writer.writeStartElement("object");
            writer.writeAttribute("name", "obj1");
                writer.writeTextElement("x1", QString::number(10));
                writer.writeTextElement("y1", QString::number(10));
                writer.writeTextElement("x2", QString::number(50));
                writer.writeTextElement("y1", QString::number(50));
                writer.writeTextElement("linewidth", QString::number(2));
                writer.writeTextElement("scale", QString::number(0));
                writer.writeTextElement("rotate", QString::number(0));
            writer.writeEndElement();

            writer.writeStartElement("object");
            writer.writeAttribute("name", "obj2");
                writer.writeTextElement("x1", QString::number(10));
                writer.writeTextElement("y1", QString::number(10));
                writer.writeTextElement("x2", QString::number(50));
                writer.writeTextElement("y1", QString::number(50));
                writer.writeTextElement("linewidth", QString::number(2));
                writer.writeTextElement("scale", QString::number(0));
                writer.writeTextElement("rotate", QString::number(0));
            writer.writeEndElement();
        writer.writeEndElement();

        writer.writeComment("写入椭圆图元信息");
        writer.writeStartElement("class");
        writer.writeAttribute("name", "Ellipse");
        writer.writeCharacters("无椭圆图元");
        writer.writeEndElement();
    writer.writeEndElement();
    writer.writeEndDocument();
    file.close();
}

最后构成的xml文档如下:

<?xml version="1.0" encoding="UTF-8"?>
<root>
	<!--写入矩形图元的信息-->
	<class name="Rect">
		<object name="obj1">
			<x1>10</x1>
			<y1>10</y1>
			<x2>50</x2>
			<y1>50</y1>
			<linewidth>2</linewidth>
			<scale>0</scale>
			<rotate>0</rotate>
		</object>
		<object name="obj2">
			<x1>20</x1>
			<y1>30</y1>
			<x2>50</x2>
			<y1>60</y1>
			<linewidth>2</linewidth>
			<scale>0</scale>
			<rotate>90</rotate>
		</object>
	</class>
	<!--写入线图元的信息-->
	<class name="Line">
		<object name="obj1">
			<x1>10</x1>
			<y1>10</y1>
			<x2>50</x2>
			<y1>50</y1>
			<linewidth>2</linewidth>
			<scale>0</scale>
			<rotate>0</rotate>
		</object>
		<object name="obj2">
			<x1>10</x1>
			<y1>10</y1>
			<x2>50</x2>
			<y1>50</y1>
			<linewidth>2</linewidth>
			<scale>0</scale>
			<rotate>0</rotate>
		</object>
	</class>
	<!--写入椭圆图元信息-->
	<class name="Ellipse">无椭圆图元</class>
</root>

读XML文件

​ 使用QT自带的模块QXmlStreamReader

1. 构造函数

可以通过

QXmlStreamReader(const char *data)
QXmlStreamReader(const QString &data)
QXmlStreamReader(const QByteArray &data)
QXmlStreamReader(QIODevice *device)
QXmlStreamReader()

2. 属性

namespaceProcessing:bool变量,指是否处理命名空间,相关读写函数为

bool namespaceProcessing() const
void setNamespaceProcessing(bool)

3. 方法

1、设置文件设备,如果你使用了无参的构造,则可以通过下面这个函数来设置要读取的文件

void setDevice(QIODevice *device)

2、读取下一个下一个标记

QXmlStreamReader::TokenType QXmlStreamReader::readNext();

读取xml文档主要就用这一个函数,通过其返回值 QXmlStreamReader::TokenType来判断读取的是什么元素,枚举TokenType如下

    enum TokenType {
        NoToken = 0,
        Invalid,
        StartDocument,
        EndDocument,
        StartElement,
        EndElement,
        Characters,
        Comment,
        DTD,
        EntityReference,
        ProcessingInstruction
    };

  • NoToken:没有读取到任何信息
  • Invalid:读取失败,错误信息保存在error()errorString()
  • StartDocument:读取到的为xml文档版本号documentVersion()和编码格式documentEncoding()
  • EndDocument:读取到文档结束的位置
  • StartElement:读取到的为一个节点,节点命名空间和名字分别保存在namespaceUri()name()中,其属性值保存在attribute()中。
  • EndElement:读取到该节点的结束位置
  • Characters:读取的内容为字符,保存在text()
  • Comment:读取的内容为注释,保存在text()
  • DTD:读取的内容为DTD,保存在text()
  • EntityReference:无法解析的实体引用
  • ProcessingInstruction

3、读取开始节点中的文本

QString QXmlStreamReader::readElementText(QXmlStreamReader::ReadElementTextBehaviour behaviour = ErrorOnUnexpectedElement)

这个函数用在当读取的标记为StartElement之后,直接调用这个函数可以更方便的获取其内容

示例

​ 读取上面写入的文档,示例代码为:

void MainWindow::on_btnRead_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, "Save this file As"
                                                    , "./", "Xml(*.xml)");
    qDebug() << fileName;

    QFile file(fileName);

    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug() << "Save failed";
        return;
    }

    QXmlStreamReader reader(&file);
    QXmlStreamReader::TokenType token;
    QXmlStreamAttributes attribute;
    QString str, attrStr;
    while (!reader.atEnd()) {
          token = reader.readNext();
          if(token == QXmlStreamReader::StartElement)
          {
              str =  reader.name().toString();
              if(QString::compare(str, "root") == 0)
              {
                  qDebug() << "这是根节点:"<< str;
                  qDebug() << "----------------";
              }
              else if(QString::compare(str, "class") == 0)
              {

                  attribute = reader.attributes();
                  if(attribute.hasAttribute("name"))
                  {
                      attrStr.clear();
                      attrStr = attribute.value("name").toString();
                  }
                  qDebug() << "************************************************";
                  qDebug() << "这是元素:"<< str << ", 属性为" << attrStr;
              }
              else if(!QString::compare(str, "object"))
              {
                  attribute = reader.attributes();
                  if(attribute.hasAttribute("name"))
                  {
                      attrStr.clear();
                      attrStr = attribute.value("name").toString();
                  }
                  qDebug() << "这是元素:" << str << ", 属性为" << attrStr;

              }
              else if(QString::compare(str, "x1") == 0)
              {

                  qDebug() << attrStr << "对象的x1值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "x2") == 0)
              {
                  qDebug() << attrStr << "对象的x2值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "y1") == 0)
              {
                  qDebug() << attrStr << "对象的y1值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "y2") == 0)
              {
                  qDebug() << attrStr << "对象的y2值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "linewidth") == 0)
              {
                  qDebug() << attrStr << "对象的linewidth值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "scale") == 0)
              {
                  qDebug() << attrStr << "对象的scale值为:" << reader.readElementText();
              }
              else if(QString::compare(str, "rotate") == 0)
              {
                  qDebug() << attrStr << "对象的rotate值为:" << reader.readElementText();
                  qDebug() << "----------------";
              }
          }
          else if(token == QXmlStreamReader::Characters)
          {
//              qDebug() << reader.text().toString(); /* 会把换行符和制表符也给读出来 */
          }
          else if(token == QXmlStreamReader::Comment)
          {
              qDebug() << reader.text().toString(); /* xml注释 */
          }
          else if(token == QXmlStreamReader::Invalid)
          {
              qDebug() << "读取失败:" << reader.errorString();
          }
    }
}

打印输出结果如下:

"H:/robot_plus/tests/Xml/XML/bin/untitled1.xml"
这是根节点: "root"
----------------
"写入矩形图元的信息"
************************************************
这是元素: "class" , 属性为 "Rect"
这是元素: "object" , 属性为 "obj1"
"obj1" 对象的x1值为: "10"
"obj1" 对象的y1值为: "10"
"obj1" 对象的x2值为: "50"
"obj1" 对象的y1值为: "50"
"obj1" 对象的linewidth值为: "2"
"obj1" 对象的scale值为: "0"
"obj1" 对象的rotate值为: "0"
----------------
这是元素: "object" , 属性为 "obj2"
"obj2" 对象的x1值为: "20"
"obj2" 对象的y1值为: "30"
"obj2" 对象的x2值为: "50"
"obj2" 对象的y1值为: "60"
"obj2" 对象的linewidth值为: "2"
"obj2" 对象的scale值为: "0"
"obj2" 对象的rotate值为: "90"
----------------
"写入线图元的信息"
************************************************
这是元素: "class" , 属性为 "Line"
这是元素: "object" , 属性为 "obj1"
"obj1" 对象的x1值为: "10"
"obj1" 对象的y1值为: "10"
"obj1" 对象的x2值为: "50"
"obj1" 对象的y1值为: "50"
"obj1" 对象的linewidth值为: "2"
"obj1" 对象的scale值为: "0"
"obj1" 对象的rotate值为: "0"
----------------
这是元素: "object" , 属性为 "obj2"
"obj2" 对象的x1值为: "10"
"obj2" 对象的y1值为: "10"
"obj2" 对象的x2值为: "50"
"obj2" 对象的y1值为: "50"
"obj2" 对象的linewidth值为: "2"
"obj2" 对象的scale值为: "0"
"obj2" 对象的rotate值为: "0"
----------------
"写入椭圆图元信息"
************************************************
这是元素: "class" , 属性为 "Ellipse"

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340