【1】可扩展标记语言,标准通用标记语言(Extensible Markup Language)的子集,简称XML。
是一种定义电子文档结构和描述其内容的国际标准语言,被设计用来传输和存储数据。
【2】为了避免错误,需要规定 XML 编码,或者将 XML 文档存为 Unicode。
【3】XML文件格式是纯文本格式,在许多方面类似于HTML,XML由XML元素组成.
每个XML元素包括一个开始标记<>,一个结束标记>以及两个标记之间的内容
【4】XML声明是XML文档的第一句,其格式如下:【5】在XML文档中,大小写是有区别的。
【6】在XML中,所有标记必须成对出现,有一个开始标记,就必须有一个结束标记,否则将被视为错误。
【7】XML规定,所有属性值必须加引号(可以是单引号,也可以是双引号,建议使用双引号),否则将被视为错误。
【8】空标记“<”标识开始,以“/>”标识结束,如:比如
【1】XML的简单易于在任何应用程序中读/写数据,这使XML很快成为数据交换的唯一公共语言.
【2】虽然不同的应用软件也支持其他的数据交换格式,但不久之后它们都将支持XML.
【3】那就意味着程序可以更容易的与Windows、Mac OS、Linux以及其他平台下产生的信息结合.
【4】然后可以很容易加载XML数据到程序中并分析它,并以XML格式输出结果。
【1】XML文档有且只有一个根元素
【2】良好格式的XML文档必须有一个根元素[],就是紧接着声明后面建立的第一个元素,其他元素都是这个根元素的子元素.
【3】根元素完全包括文档中其他所有的元素。根元素的起始标记要放在所有其他元素的起始标记之前;
【4】根元素的结束标记要放在所有其他元素的结束标记之后[]。
【1】QXmlStreamReader:一种快速的基于流的方式访问良格式 XML 文档,特别适合于实现一次解析器(所谓“一次解析器”,可以理解成我们只需读取文档一次,然后像一个遍历器从头到尾一次性处理 XML 文档,期间不会有反复的情况,也就是不会读完第一个标签,然后读第二个,读完第二个又返回去读第一个,这是不允许的);
【2】DOM(Document Object Model):将整个 XML 文档读入内存,构建成一个树结构,允许程序在树结构上向前向后移动导航,这是与另外两种方式最大的区别,也就是允许实现多次解析器(对应于前面所说的一次解析器)。DOM 方式带来的问题是需要一次性将整个 XML 文档读入内存,因此会占用很大内存;
【3】SAX(Simple API for XML):提供大量虚函数,以事件的形式处理 XML 文档。这种解析办法主要是由于历史原因提出的,为了解决 DOM 的内存占用提出的(在现代计算机上,这个一般已经不是问题了)。
三种解析方式比较
1、DOM解析XML文档的特点
基于DOM的解析器的核心是在内存中建立和XML文档相对应的树状结构。
XML文件的标记、标记中的文本数据和实体等都是内存中的树状结构的某个节点相对应。
优点:可以方便地操作内存中的树状节点
缺点:如果XML文件较大,或者只需要解析XML文档的一部分数据,就会占用大量的内存空间
2、流方式解析XML文档的特点
QXmlStreamReader使用了递增式的解析器,适合于在整个XML文档中查找给定的标签、读入无法放入内存的大文件以及处理XML的自定义数据。
优点:快速、方便,分块读取XML文件,可读取大文件
缺点:递增式解析器,只能顺序遍历XML文件的元素,不能随机访问
3、QXmlStreamWriter类提供了简单流接口的XML写入器,写入XML文档只需要调用相应的记号写入函数来写入相关数据。
优点:快速、方便
缺点:只能按顺序写入元素,不能删除、修改
【1】QXmlStreamReader类提供了一个快速解析器,通过简单的流API读取格式良好的XML 。
【2】QXmlStreamReader从QIODevice或原始QByteArray读取数据。
QXmlStreamWriter是用于编写XML的QXmlStreamReader的对等物。
像它的相关类一样,它操作由setDevice()指定的QIODevice。
这个API简单明了:对于您想要编写的每个XML标签或事件,编写器提供一个专门的函数。
DOM(Document Object Model)
DOM 是由 W3C 提出的一种处理 XML 文档的标准接口。Qt 实现了 DOM Level 2 级别的不验证读写 XML 文档的方法。
DOM 一次性读入整个 XML 文档,在内存中构造为一棵树(被称为 DOM 树)。
我们能够在这棵树上进行导航,比如移动到下一节点或者返回上一节点,也可以对这棵树进行修改,或者是直接将这颗树保存为硬盘上的一个 XML 文件。
//->XML
//如果读取器一直读取到XML文档的末尾,或者发生了error()并中止了读取,则返回true。 否则,返回false。
bool atEnd() const
//如果发生错误则返回true,否则返回false。
bool hasError();
//获取错误码 返回枚举值
QXmlStreamReader::Error error() const
//获取错误字符串
QString errorString() const
//读取下一个标记并返回其类型
QXmlStreamReader::TokenType readNext()
//获取当前读取器的标记类型
QXmlStreamReader::TokenType tokenType() const
//以字符串的形式返回读取器的当前标记类型
QString tokenString() const
//获取标记
QStringRef name() const
//返回字符、注释、DTD或EntityReference的文本。
QStringRef text() const
//获取当前元素的文本(StartElement和EndElement之间的文本)
QString readElementText(QXmlStreamReader::ReadElementTextBehaviour behaviour = ErrorOnUnexpectedElement)
//获取当前元素的属性
QXmlStreamAttributes attributes() const
//例:QXmlStreamAttributes attrs = xmlReader.attributes();
//例:qDebug()<
//读取当前元素之后的起始元素。 当到达start元素时返回true。 (读取当前元素的子标签)
bool readNextStartElement()
//获取当前元素的属性列表
QXmlStreamAttributes attributes() const
//->DOM
//创建属性
QDomAttr createAttribute(const QString &name)
//为可以插入到文档中的字符串值创建一个新的CDATA部分,例如使用QDomNode::appendChild()
QDomCDATASection createCDATASection(const QString &value)
//为可以插入到文档中的字符串值创建一个新的注释,例如使用QDomNode::appendChild()
QDomComment createComment(const QString &value)
//创建一个新的文档片段,可以用来保存文档的部分,例如,当对文档树进行复杂操作时。
QDomDocumentFragment createDocumentFragment()
//创建一个名为tagName的新元素,可以插入到DOM树中,例如使用QDomNode::appendChild()。
QDomElement createElement(const QString &tagName)
//创建一个名为name的新实体引用,可以插入到文档中,例如使用QDomNode::appendChild()。
QDomEntityReference createEntityReference(const QString &name)
//创建一个可以插入到文档中的新的处理指令,例如使用QDomNode::appendChild()。 该函数将处理指令的目标设置为目标,将数据设置为数据。
QDomProcessingInstruction createProcessingInstruction(const QString &target, const QString &data)
//为可以插入到文档树中的字符串值创建一个文本节点,例如使用QDomNode::appendChild()。
QDomText createTextNode(const QString &value)
QT += core gui xml
#-------------------------------------------------
#
# Project created by QtCreator 2022-11-15T13:40:35
#
#-------------------------------------------------
QT += core gui xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = XML
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
CONFIG += c++11
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include //单属性
#include //属性列表
#include //操作者
#include //文件输入输出设备
#include
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
void parseXml(const QString &filename);
void parseDOM(const QString &filename);
void XmlStreamWriter(const QString &filename);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
XmlStreamWriter("C://Users//DD//Desktop//QT//XML//qxml.xml");//写一个.xml的文件
parseXml("C://Users//DD//Desktop//QT//XML//qxml.xml");//第一种解析方式
parseDOM("C://Users//DD//Desktop//QT//XML//qxml.xml");//第二种解析方式
}
MainWindow::~MainWindow()
{
delete ui;
}
/*
QXmlStreamReader
QXmlStreamReader类提供了一个快速解析器,通过简单的流API读取格式良好的XML 。
QXmlStreamReader从QIODevice或原始QByteArray读取数据。
*/
//xml语法分析 ->按行解析 循环向下直到结束
void MainWindow::parseXml(const QString &filename)
{
QFile file(filename);
if(!file.open(QIODevice::ReadWrite|QIODevice::Text))
{
qDebug()<<"error open "<<filename.toUtf8().data()<<endl;
return;
}
QXmlStreamReader xmlreader(&file);
while(!xmlreader.atEnd() && !xmlreader.hasError())
{
QXmlStreamReader::TokenType kentype = xmlreader.readNext();
if(kentype == QXmlStreamReader::TokenType::StartDocument)//第1行
{
qDebug()<<"xmlreader.documentEncoding() :"<<xmlreader.documentEncoding();//获取字符编码
}
#if (1)
else if(kentype == QXmlStreamReader::TokenType::StartElement)
{
if(xmlreader.name() == "HostName")//第3行
{
qDebug()<<"元素文本="<<xmlreader.readElementText();
}
else if(xmlreader.name() == "Port")//第4行
{
qDebug()<<"元素文本="<<xmlreader.readElementText();
}
else if(xmlreader.name() == "UserName")//第5行
{
qDebug()<<"元素文本="<<xmlreader.readElementText();
}
else if(xmlreader.name() == "PassWord")//第6行
{
qDebug()<<"元素文本="<<xmlreader.readElementText();
}
else if(xmlreader.name() == "DatabaseName")//第7行
{
qDebug()<<"元素文本="<<xmlreader.readElementText();
}
else//第2行 或其他
{
continue;
}
}
#endif
}
}
/*
DOM(Document Object Model)
DOM 是由 W3C 提出的一种处理 XML 文档的标准接口。Qt 实现了 DOM Level 2 级别的不验证读写 XML 文档的方法。
DOM 一次性读入整个 XML 文档,在内存中构造为一棵树(被称为 DOM 树)。
我们能够在这棵树上进行导航,比如移动到下一节点或者返回上一节点,也可以对这棵树进行修改,或者是直接将这颗树保存为硬盘上的一个 XML 文件。
*/
void MainWindow::parseDOM(const QString &filename)
{
QFile file(filename);
if(!file.open(QIODevice::ReadWrite|QIODevice::Text))
{
qDebug()<<"error open "<<filename.toUtf8().data()<<endl;
return;
}
QString err;
int errline;
int errcol;
QDomDocument dom;
if(!dom.setContent(&file,false,&err,&errline,&errcol))
{
qDebug()<<"解析失败";
return;
}
qDebug()<<"err= "<<err<<" errline= "<<errline<<" errcol= "<<errcol<<endl;
//获取版本信息和编码信息
qDebug()<<"节点名="<<dom.firstChild().nodeName()<<"节点值="<<dom.firstChild().nodeValue();
//获取dom树的根元素(标签)
QDomElement root = dom.documentElement();
if(root.tagName() != "root")
{
qWarning("根元素不是root,xml文档有误~");
return;
}else
{
//类比树的结构 进行遍历
QDomElement node = root.firstChild().toElement();
while(!node.isNull())
{
if(node.tagName() == "HostName")
{
qDebug()<<"HostName="<<node.text();
}
else if(node.tagName() == "Port")
{
qDebug()<<"Port="<<node.text();
QDomElement subNode = node.firstChildElement();//模拟本节点下是否还具有其子节点
while(!subNode.isNull())
{
if(subNode.tagName() == "a")
{
qDebug()<<subNode.text();
}
else if(subNode.tagName() == "fuck")
{
qDebug()<<subNode.text();
}
subNode = subNode.nextSiblingElement();
}
}
else if(node.tagName() == "UserName")
{
qDebug()<<"UserName="<<node.text();
}
else if(node.tagName() == "PassWord")
{
qDebug()<<"PassWord="<<node.text();
}
else if(node.tagName() == "DatabaseName")
{
qDebug()<<"DatabaseName="<<node.text();
}
//如果标记名非空,则返回具有标记名标记名的下一个兄弟元素,否则返回任何下一个兄弟元素。如果不存在这样的兄弟姐妹,则返回一个空元素。
node = node.nextSiblingElement();
}
}
}
/*
QXmlStreamWriter是用于编写XML的QXmlStreamReader的对等物。
像它的相关类一样,它操作由setDevice()指定的QIODevice。
这个API简单明了:对于您想要编写的每个XML标签或事件,编写器提供一个专门的函数。
*/
void MainWindow::XmlStreamWriter(const QString &filename)
{
QFile file(filename);
if(!file.open(QIODevice::WriteOnly | QIODevice::Text|QIODevice::Truncate))
{
qWarning("文件打开失败");
return ;
}
QXmlStreamWriter writer(&file);
writer.setAutoFormatting(true);//设置自动格式化 缩进和自动换行等
writer.writeStartDocument("1.0");//Start dom[1]
writer.writeStartElement("root");
writer.writeTextElement("HostName","localhost");
writer.writeTextElement("Port","3306");
writer.writeTextElement("UserName","root");
writer.writeTextElement("PassWord","123456789");
writer.writeStartElement("widget");
writer.writeAttribute("class","QWidget");
writer.writeAttribute("name","MainWindow");
writer.writeComment("helo"); //写注释
writer.writeStartElement("property");
writer.writeAttribute("name","property");
writer.writeStartElement("rect");
writer.writeTextElement("x","0");
writer.writeTextElement("y","0");
writer.writeTextElement("width","640");
writer.writeTextElement("height","480");
writer.writeEndElement(); // end widget
writer.writeEndElement(); // end property
writer.writeEndElement(); // end rect
writer.writeEndElement(); //end ui
writer.writeEndDocument(); //end dom[1]
file.close();
}
<?xml version="1.0" encoding="UTF-8"?>
<root>
<HostName>localhost</HostName>
<Port>3306</Port>
<UserName>root</UserName>
<PassWord>123456789</PassWord>
<widget class="QWidget" name="MainWindow">
<!--helo-->
<property name="property">
<rect>
<x>0</x>
<y>0</y>
<width>640</width>
<height>480</height>
</rect>
</property>
</widget>
</root>
END 2022-11-15