本文根据霍亚飞老师的《Qt Creator快速入门》(第三版)整理。
读取过程及方式简析:
一、DOM(Document Object Model)方式(可读取,可修改)
XML文档有且只有一个根元素
说明、元素、属性和文本都由QDomNode来表示
类名 含义
QDomProcessingInstruction XML说明
QDomElement 表示元素的类
QDomAttr 表示元素属性的类
QDomText 表示文本的类
QDomNode 表示一个节点的类(便捷接口isProcessingInstruction,isElement,isAttr,isText
toProcessingInstruction,toElement,toAttr,toText)
QDomDocument 表示一个XML文档
读取文件大概操作:
1、使用QFile打开XML文件;
2、使用setContent()函数将文件内容加载到QDomDocument中;
3、使用firstChild()函数获取第一个节点,即XML文件说明,该函数属于QDomNode类,故也可通过该函数获取根节点的第一个子节点;
4、使用QDomDocument::documentElement()获取根元素;
5、使用QDomNode::nodeName()获取节点名称,QDomNode::nodeValue()获取节点值,
QDomElement::tagName()获取标签名,QDomElement::attribute("attr name")获取属性attr name的值,
QDomElement::text()获取元素文本名
6、使用QDomNode::nextSibling()转到下一个兄弟节点,QDomElement::childNodes()获取该节点的所有子节点列表
二、SAX(Simple API for XML)方式(读取方便)
1、继承自QXmlDefaultHandler类;
2、主要处理函数 bool startElement(const QString &namespaceURI,const QString &localName,
const QString &qName,const QXmlAttributes &atts);
bool endElement(const QString &namespaceURI,const QString &localName,
const QString &qName); //qName为标签名
bool characters(const QString &ch); //ch为解析当前节点所得到的文本
bool fatalError(const QXmlParseException &exception); //QXmlParseException 为异常类型
3、处理函数readFile(QString fileName)主要思路:
1)读取文件内容
QFile lv_file(fileName);
QXmlnputSource lv_inputSource(&lv_file);
2) 建立QXmlSimpleReader对象
QXmlSimpleReader lv_reader;
3) 设置内容处理器
lv_reader.setContentHandler(this);
4) 设置错误处理器
lv_reader.setErrorHandler(this);
5) 解析文件
return lv_reader.parse(lv_inputSource);
代码:
方式一读取显示XML文件实例:
//.pro文件 注意读取XML文件要添加一句 : QT += xml
QT += core
QT -= gui
CONFIG += c++11
QT += xml
TARGET = myDOM1
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
//main.cpp文件
#include <QCoreApplication>
#include <QtXml>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//新建QDomDocument类对象,代表一个XML文档
QDomDocument lv_doc;
QFile lv_file("../myDOM1/my.xml");
if ( !lv_file.open(QIODevice::ReadOnly))
{
return 0;
}
//将文件内容读到doc中
if ( !lv_doc.setContent(&lv_file) )
{
lv_file.close();
return 0;
}
//关闭文件
lv_file.close();
//获取lv_doc的第一个节点,即XML说明
QDomNode lv_firstNode = lv_doc.firstChild();
//输出XML说明,nodeName()为“xml",nodeValue()为版本和编码信息
qDebug()<<qPrintable(lv_firstNode.nodeName())<<qPrintable(lv_firstNode.nodeValue());
//返回根元素
QDomElement lv_docElem = lv_doc.documentElement();
//返回根节点的第一个子节点
QDomNode lv_n = lv_docElem.firstChild();
//如果节点不为空,转到下一个节点
while( !lv_n.isNull() )
{
//如果节点是元素
if ( lv_n.isElement() )
{
//将其转为元素
QDomElement lv_e = lv_n.toElement();
//返回元素标记和id属性的值
qDebug()<<qPrintable(lv_e.tagName())<<" "<<qPrintable(lv_e.attribute("id"));
//获取元素lv_e的所有子节点的列表
QDomNodeList lv_list = lv_e.childNodes();
//遍历该列表
for ( int i = 0; i < lv_list.count(); ++i)
{
QDomNode lv_node = lv_list.at(i);
if ( lv_node.isElement() )
{
qDebug()<<" "<<qPrintable(lv_node.toElement().tagName())
<<" "<<qPrintable(lv_node.toElement().text());
}
}
}
//转到下一个兄弟节点
lv_n = lv_n.nextSibling();
}
return a.exec();
}
方式一读取显示及修改XML文件实例:
//.pro文件
QT += core gui
QT += xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = myDOM2
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
//mainWindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void doXml(const QString operate);
private slots:
void on_showAllBtn_clicked();
void on_addBtn_clicked();
void on_findBtn_clicked();
void on_deleteBtn_clicked();
void on_updateBtn_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
//mainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtXml>
#include <QFile>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QDomDocument lv_doc;
//添加处理指令即XML说明
QDomProcessingInstruction lv_instruction;
lv_instruction = lv_doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
lv_doc.appendChild(lv_instruction);
//添加根元素
QDomElement lv_root = lv_doc.createElement("书库");
lv_doc.appendChild(lv_root);
//添加第一个图书元素及其子元素
QDomElement lv_book = lv_doc.createElement("图书");
QDomAttr lv_id = lv_doc.createAttribute("编号");
QDomElement lv_title = lv_doc.createElement("书名");
QDomElement lv_author = lv_doc.createElement("作者");
QDomText lv_text;
lv_id.setValue(QString("1"));
lv_book.setAttributeNode(lv_id);
lv_text = lv_doc.createTextNode("Qt");
lv_title.appendChild(lv_text);
lv_text = lv_doc.createTextNode("shiming");
lv_author.appendChild(lv_text);
lv_book.appendChild(lv_title);
lv_book.appendChild(lv_author);
lv_root.appendChild(lv_book);
//添加第二个图书元素及其子元素
lv_book = lv_doc.createElement("图书");
lv_id = lv_doc.createAttribute("编号");
lv_title = lv_doc.createElement("书名");
lv_author = lv_doc.createElement("作者");
lv_id.setValue(QString("2"));
lv_book.setAttributeNode(lv_id);
lv_text = lv_doc.createTextNode("Linux");
lv_title.appendChild(lv_text);
lv_text = lv_doc.createTextNode("yafei");
lv_author.appendChild(lv_text);
lv_book.appendChild(lv_title);
lv_book.appendChild(lv_author);
lv_root.appendChild(lv_book);
QFile lv_file("my.xml");
if ( !lv_file.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
return ;
}
//将文档保存到文件,4为子元素缩进字符数
QTextStream lv_out(&lv_file);
lv_doc.save(lv_out,4);
lv_file.close();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::doXml(const QString operate)
{
ui->listWidget->clear();
ui->listWidget->addItem(tr("没有找到相关内容"));
QFile lv_file("my.xml");
if ( !lv_file.open(QIODevice::ReadOnly) )
{
return ;
}
QDomDocument lv_doc;
if ( !lv_doc.setContent(&lv_file) )
{
lv_file.close();
return ;
}
//以标签名进程查找
QDomNodeList lv_list = lv_doc.elementsByTagName("图书");
for ( int i = 0; i < lv_list.size(); ++i)
{
QDomElement lv_e = lv_list.at(i).toElement();
if ( lv_e.attribute("编号") == ui->bookNumLineEdit->text())
{
//如果“编号”属性值与所查找的相同
if ( operate == "delete")
{
QDomElement lv_root = lv_doc.documentElement();
//从根节点上删除该节点
lv_root.removeChild(lv_list.at(i));
QFile lv_file("my.xml");
if ( !lv_file.open(QIODevice::WriteOnly | QIODevice::Truncate) )
{
return;
}
QTextStream lv_out(&lv_file);
lv_doc.save(lv_out,4);
lv_file.close();
ui->listWidget->clear();
ui->listWidget->addItem(tr("删除成功!"));
}
else if ( operate == "update")
{
QDomNodeList lv_child = lv_list.at(i).childNodes();
//将塔子节点的首个子节点(就是文本节点)的内容更新
lv_child.at(0).toElement().firstChild().setNodeValue(ui->bookNameLineEdit->text());
lv_child.at(1).toElement().firstChild().setNodeValue(ui->authorLineEdit->text());
QFile lv_file("my.xml");
if ( !lv_file.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
return;
}
QTextStream lv_out(&lv_file);
lv_doc.save(lv_out,4);
lv_file.close();
ui->listWidget->clear();
ui->listWidget->addItem(tr("更新成功"));
}
else if ( operate == "find")
{
ui->listWidget->clear();
ui->listWidget->addItem(lv_e.tagName() + lv_e.attribute("编号"));
QDomNodeList lv_list = lv_e.childNodes();
for ( int i = 0; i < lv_list.size(); ++i)
{
QDomNode lv_node = lv_list.at(i);
if ( lv_node.isElement())
{
ui->listWidget->addItem(" " + lv_node.toElement().tagName() + " : "
+ lv_node.toElement().text());
}
}
}
}
}
}
void MainWindow::on_showAllBtn_clicked()
{
//先清空显示
ui->listWidget->clear();
QFile lv_file("my.xml");
if ( !lv_file.open(QIODevice::ReadOnly) )
{
return ;
}
QDomDocument lv_doc;
if ( !lv_doc.setContent(&lv_file))
{
lv_file.close();
return ;
}
lv_file.close();
QDomElement lv_docElem = lv_doc.documentElement(); //获取根元素
QDomNode lv_n = lv_docElem.firstChild();
while ( !lv_n.isNull() ) //遍历根节点及其子节点
{
if ( lv_n.isElement() )
{
QDomElement lv_e = lv_n.toElement();
ui->listWidget->addItem(lv_e.tagName()+lv_e.attribute("编号"));
QDomNodeList lv_list = lv_e.childNodes();
for ( int i = 0; i < lv_list.size(); ++i )
{
QDomNode lv_node = lv_list.at(i);
ui->listWidget->addItem(" "+lv_node.toElement().tagName()+":"+lv_node.toElement().text());
}
}
lv_n = lv_n.nextSibling();
}
}
void MainWindow::on_addBtn_clicked()
{
//先清空显示,然后显示“无法添加!”,这样如果添加失败则会显示“无法添加!”
ui->listWidget->clear();
ui->listWidget->addItem(tr("无法添加!"));
QFile lv_file("my.xml");
if ( !lv_file.open(QIODevice::ReadOnly) )
{
return;
}
QDomDocument lv_doc;
if ( !lv_doc.setContent(&lv_file))
{
lv_file.close();
return;
}
lv_file.close();
QDomElement lv_root = lv_doc.documentElement(); //获取根节点
QDomElement lv_book = lv_doc.createElement("图书");
QDomAttr lv_id = lv_doc.createAttribute("编号");
QDomElement lv_title = lv_doc.createElement("书名");
QDomElement lv_author = lv_doc.createElement("作者");
QDomText lv_text;
//我们获得了最后一个孩子节点的编号,然后加上1,便是新的编号
QString lv_num = lv_root.lastChild().toElement().attribute("编号");
int lv_count = lv_num.toInt() + 1;
lv_id.setValue(QString::number(lv_count));
lv_book.setAttributeNode(lv_id);
lv_text = lv_doc.createTextNode(ui->bookNameLineEdit->text());
lv_title.appendChild(lv_text);
lv_text = lv_doc.createTextNode(ui->authorLineEdit->text());
lv_author.appendChild(lv_text);
lv_book.appendChild(lv_title);
lv_book.appendChild(lv_author);
lv_root.appendChild(lv_book);
if ( !lv_file.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
return ;
}
QTextStream lv_out(&lv_file);
lv_doc.save(lv_out,4);
lv_file.close();
//最后显示为“添加成功!“
ui->listWidget->clear();
ui->listWidget->addItem(tr("添加成功!"));
}
void MainWindow::on_findBtn_clicked()
{
doXml("find");
}
void MainWindow::on_deleteBtn_clicked()
{
doXml("delete");
}
void MainWindow::on_updateBtn_clicked()
{
doXml("update");
}
//main.cpp文件
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
方式二读取显示XML实例:
//mySAX.pro
QT += xml widgets
HEADERS += \
mysax.h
SOURCES += \
mysax.cpp \
main.cpp
//mysax.h
#ifndef MYSAX_H
#define MYSAX_H
#include <QXmlDefaultHandler>
class QListWidget;
class MySAX : public QXmlDefaultHandler
{
public:
MySAX();
~MySAX();
bool readFile(const QString &fileName);
protected:
bool startElement(const QString &namespaceURI,const QString &localName,
const QString &qName,const QXmlAttributes &atts);
bool endElement(const QString &namespaceURI,const QString &localName,
const QString &qName);
bool characters(const QString &ch);
bool fatalError(const QXmlParseException &exception);
private:
QListWidget *m_list;
QString m_currentText;
};
#endif // MYSAX_H
//mysax.cpp
#include "mysax.h"
#include <QtXml>
#include <QListWidget>
MySAX::MySAX()
{
m_list = new QListWidget;
m_list->show();
}
MySAX::~MySAX()
{
delete m_list;
m_list = NULL;
}
bool MySAX::readFile(const QString &fileName)
{
QFile lv_file(fileName);
//读取文件内容
QXmlInputSource lv_inputSource(&lv_file);
//建立QXmlSimpleReader对象
QXmlSimpleReader lv_reader;
//设置内容处理器
lv_reader.setContentHandler(this);
//设置错误处理器
lv_reader.setErrorHandler(this);
//解析文件
return lv_reader.parse(lv_inputSource);
}
bool MySAX::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts)
{
//已解析完一个元素的起始标签
if ( qName == "library") //根节点(根元素)
{
m_list->addItem(qName);
}
else if ( qName == "book") //图书节点(次层节点)
{
m_list->addItem(" " + qName + atts.value("id"));
}
return true;
}
bool MySAX::endElement(const QString &namespaceURI, const QString &localName, const QString &qName)
{
//已经解析完一个元素的结束标签 qName是标签名
if ( qName == "title" || qName == "author")
{
m_list->addItem(" " + qName + " : " + m_currentText);
}
return true;
}
bool MySAX::characters(const QString &ch)
{
//已解析完一块字符数据
m_currentText = ch;
return true;
}
bool MySAX::fatalError(const QXmlParseException &exception)
{
//错误处理
qDebug()<<exception.message();
return false;
}
//main.cpp
#include "mysax.h"
#include <QApplication>
int main(int argc,char *argv[])
{
QApplication app(argc,argv);
MySAX sax;
sax.readFile("../mySAX/my.xml");
return app.exec();
}