Qt使用XML模块,在.pro文件中添加 QT += xml
Qt 提供了三种读写 XML 文档的方法:
QXmlStreamReader/QXmlStreamWriter:
一种快速的基于流的方式访问良格式 XML 文档,特别适合于实现一次解析器(所谓“一次解析器”,可以理解成我们只需读取文档一次,然后像一个遍历器从头到尾一次性处理 XML 文档,期间不会有反复的情况,也就是不会读完第一个标签,然后读第二个,读完第二个又返回去读第一个,这是不允许的);
DOM(Document Object Model):
将整个 XML 文档读入内存,构建成一个树结构,允许程序在树结构上向前向后移动导航,这是与另外两种方式最大的区别,也就是允许实现多次解析器(对应于前面所说的一次解析器)。DOM 方式带来的问题是需要一次性将整个 XML 文档读入内存,因此会占用很大内存;
SAX(Simple API for XML):
提供大量虚函数,以事件的形式处理 XML 文档。这种解析办法主要是由于历史原因提出的,为了解决 DOM 的内存占用提出的(在现代计算机上,这个一般已经不是问题了).基本不使用了.
QXmlStreamReader/QXmlStreamWriter
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
写操作
void writeStartDocument();
//写文档头,作用类似于创建一个xml文档,并在文档开头部分写入版本信息和编码信息默认为:
<?xml version="1.0" encoding="UTF-8"?>
void writeEndDocument();
//当调用这个函数时,即表示文档信息写入完毕
void writeStartElement(const QString &qualifiedName);
//写入开始记号 比如<COMMAND>
void writeEndElement();
//写入结束记号 比如</COMMAND>
void writeTextElement(const QString &qualifiedName, const QString &text);
//写入文本信息 <OBJECT>USER</OBJECT>
void writeAttribute(const QString &qualifiedName, const QString &value);
//写入文本的属性 <USER NAME="root" PASSWORD="123456"/>
QFile file(fileName);
if(file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QXmlStreamWriter writer(&file);
writer.setAutoFormatting(true);
writer.writeStartDocument();
writer.writeStartElement("COMMAND");
writer.writeTextElement("OBJECT", "USER");
writer.writeTextElement("ACTION", "LOGIN");
writer.writeStartElement("DATA");
writer.writeStartElement("USER");
writer.writeAttribute("NAME", "root");
writer.writeAttribute("PASSWORD", "123456");
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
file.close();
}
<?xml version="1.0" encoding="UTF-8"?>
<COMMAND>
<OBJECT>USER</OBJECT>
<ACTION>LOGIN</ACTION>
<DATA>
<USER NAME="root" PASSWORD="123456"/>
</DATA>
</COMMAND>
读操作
readNext(): 从xml输入流中读取下一个记号。
name(): 记号的名称,即<名称></名称>
isStartElement():判断当前已读取的记号是否为开始元素,开始元素即<>
注意:像上面的 <OBJECT>USER</OBJECT>也是
isEndElement():判断当前已读取的记号是否为结束元素,结束元素即</>
readElementText():读取当前记号对应的文本值,<>文本值</>
atEnd():判断是否为文件结尾
QXmlStreamAttributes attributes() const; 获取含有属性节点的属性
inline bool hasAttribute(const QString &qualifiedName); //
QStringRef value(const QString &qualifiedName) const;//获取属性的值
int StreamParseXml::readXml()
{
if(fileName.isEmpty()) return -2;
QFile *file = new QFile(fileName);
if(!file->open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::information(NULL, QString("title"), QString("open error!"));
return -1;
}
reader = new QXmlStreamReader(file);
while(!reader->atEnd() && !reader->hasError()) {
QXmlStreamReader::TokenType token = reader->readNext();
if(token == QXmlStreamReader::StartDocument) {
continue;
}
if (reader->isStartElement() && reader->name() == "OBJECT") {
QString elementText = reader->readElementText();
if (elementText == "USER") {
parseUserInformation();
break;
}
}
}
if (reader->hasError()) {
qDebug() << reader->errorString();
//QMessageBox::information(NULL, QString("parseXML"), reader->errorString());
}
reader->clear();
delete reader;
reader = NULL;
return 0;
}
void StreamParseXml::parseUserInformation()
{
QString elementString = getValue("ACTION");
if (elementString == "LOGIN") {
while(!reader->atEnd()) {
reader->readNext();
if (reader->name() == "USER") {
QXmlStreamAttributes attributes = reader->attributes();
if(attributes.hasAttribute("NAME")) {
qDebug() << "USER=" << attributes.value("NAME").toString();
}
if(attributes.hasAttribute("PASSWORD")) {
qDebug() << "PASSWORD=" << attributes.value("PASSWORD").toString();
}
}
}
}
}
QString StreamParseXml::getValue(const QString &name)
{
while(!reader->atEnd()) {
reader->readNext();
if (reader->isStartElement() && reader->name() == name) {
return reader->readElementText();
}
}
return "";
}
QDomDocument
引用头文件
#include <QDomDocument>
QDomDocument类代表整个的XML文件。概念上讲:它是文档树的根节点,并提供了文档数据的基本访问方法。由于元素、文本节点、注释、指令执行等等不可能脱离一个文档的上下文,所以文档类也包含了需要用来创建这些对象的工厂方法。
DOM类中最常使用的是QDomNode、QDomDocument、QDomElement和QDomText。
QDomDocument::setContent()完成XML文档的设置,他从QFile对象中读取XML数据并检测XML文档的编码。
写操作
结合QFile、QTextStream类一起使用。
常用的函数:
QDomProcessingInstruction createProcessingInstruction(const QString& target, const QString& data);//创建版本和编码格式
QDomNode appendChild(const QDomNode& newChild);//添加数据到节点
QDomElement createElement(const QString& tagName);//创建节点
QDomText createTextNode(const QString& data);//创建节点的文本
QDomAttr createAttribute(const QString& name);//创建属性
QDomAttr setAttributeNode(const QDomAttr& newAttr);//节点关联属性
void save(QTextStream&, int, EncodingPolicy=QDomNode::EncodingFromDocument) const;//把整个QDomDocument以QTextStream形式保存到本地文件。
int DomDocument::writeXml()
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
return -2;
QTextStream out(&file);
QDomDocument doc;
QDomText text;
QDomElement element;
QDomAttr attr;
QDomProcessingInstruction instruction;
instruction = doc.createProcessingInstruction( "xml", "version = \'1.0\' encoding=\'UTF-8\'" );
doc.appendChild( instruction );
QDomElement root = doc.createElement( "COMMAND" );
doc.appendChild(root);
element = doc.createElement( "OBJECT" );
text = doc.createTextNode( "USER" );
element.appendChild(text);
root.appendChild(element);
element = doc.createElement( "ACTION" );
text = doc.createTextNode( "LOGIN" );
element.appendChild(text);
root.appendChild(element);
element = doc.createElement( "DATA" );
root.appendChild(element);
QDomElement userElement = doc.createElement( "USERINFO" );
attr = doc.createAttribute( "NAME" );
attr.setValue("root");
userElement.setAttributeNode(attr);
attr = doc.createAttribute( "PASSWORD" );
attr.setValue("123456");
userElement.setAttributeNode(attr);
element.appendChild(userElement);
doc.save(out, 4); //each line space of file is 4
return 0;
}
读操作
结合QFile类一起使用。使用setContent函数进行关联。
bool setContent(QIODevice* dev, bool namespaceProcessing, QString *errorMsg=nullptr, int *errorLine=nullptr, int *errorColumn=nullptr );QFile和QDomDocument关联,从QFile对象中读取XML数据。
QDomElement documentElement() const; //获取dom树的根标签
QString tagName() const; //获取根/子标签的标签名字,对应于createElement函数的参数
QString text() const; //获取根/子标签的文本,对应于createTextNode函数的参数
QDomNode firstChild() const;//根/子标签下的子标签
QDomNode nextSibling() const; //下一个标签
bool isNull() const; //判断标签是否为空,用于是否标签到最后面结束了。
QDomElement toElement() const; //把QDomNode 转换成QDomElement ,即基类转换成子类
bool hasAttribute(const QString& name) const; //判断标签节点是否有属性
对应于createAttribute函数操作
QDomAttr attributeNode(const QString& name);//获取标签节点的属性
QString name() const;//获取标签节点的属性名称
QString value() const;//获取标签节点的属性值
int DomDocument::readXml()
{
QDomDocument doc;
QFile file(fileName);
QString error = "";
int row = 0, column = 0;
if (!file.open(QIODevice::ReadOnly)) return -2;
if(!doc.setContent(&file, false, &error, &row, &column)){
qDebug() << "parse file failed:" << row << "---" << column <<":" <<error;
file.close();
return -1;
}
file.close();
QDomElement root = doc.documentElement();
QDomNode node = root.firstChild(); //得到COMMAND标签
while(!node.isNull()) {
QDomElement element = node.toElement(); // try to convert the node to an element.
if(!element.isNull()) {
qDebug()<<element.tagName() << ":" << element.text();
QDomNode nodeson = element.firstChild(); //得到OBJECT标签
while(!nodeson.isNull()) {
QDomElement elementson = nodeson.toElement();
if(!elementson.isNull()) {
qDebug()<< "---" <<elementson.tagName();
if (elementson.hasAttribute("NAME")) {
qDebug()<< "---" << "NAME=" << elementson.attributeNode("NAME").value();
}
if (elementson.hasAttribute("PASSWORD")) {
qDebug()<< "---" << "PASSWORD=" << elementson.attributeNode("PASSWORD").value();
}
}
nodeson = nodeson.nextSibling();
}
}
node = node.nextSibling();
}
return 0;
}