一、简介
1、什么是xml:http://www.runoob.com/xml/xml-tutorial.html
2、在Qt中有两种方式来读写xml
1)快速解析:QXmlStreamReader 、 QXmlStreamWriter。这是一种快速的基于流的方式访问 XML 文档,它只需读取文档一次,然后像一个遍历器从头到尾一次性处理 XML 文档,期间不会有反复的情况,也就是不会读完第一个标签,然后读第二个,读完第二个又返回去读第一个。
2)DOM树读写:QDomDocument。将整个 XML 文档读入内存,构建成一个树结构,允许程序在树结构上向前向后移动导航,这是与另外两种方式最大的区别,也就是允许实现多次读写。DOM 方式带来的问题是需要一次性将整个 XML 文档读入内存,因此会占用很大内存;但是因为储存在内存里,所以实现频繁修改比较方便。
3、QXmlStreamReader类
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
m_thread = new ReadXmlThread;
QAction *action = menuBar()->addAction("打开xml");
connect(action,&QAction::triggered,[=]{
QString path = QFileDialog::getOpenFileName(this,"选择文件","F:/","XML(*.xml)");
if(path.isEmpty())
return;
if(m_thread->isRunning()){
QMessageBox::warning(this,"警告","正在解析中...");
}else{
m_thread->setXml(path);
m_thread->start();
}
});
m_browser = new QTextEdit;
setCentralWidget(m_browser);
connect(m_thread,&ReadXmlThread::readContents,this,&MainWindow::readContents);
}
MainWindow::~MainWindow()
{
if(m_thread->isRunning()){
m_thread->quit();
m_thread->wait();
}
delete m_thread;
}
void MainWindow::readContents(const QString str)
{
m_browser->append(str);
}
void MainWindow::closeEvent(QCloseEvent *event)
{
m_thread->stop();
QMainWindow::closeEvent(event);
}
ReadXmlThread::ReadXmlThread(QObject *parent):QThread(parent)
{
}
ReadXmlThread::~ReadXmlThread()
{
qDebug() << __FUNCTION__;
}
void ReadXmlThread::setXml(const QString path)
{
m_xml = path;
}
void ReadXmlThread::stop()
{
m_stop = true;
}
void ReadXmlThread::run()
{
m_stop = false;
qDebug() << m_xml;
//开始解析
QFile file(m_xml);
file.open(QIODevice::ReadOnly);
QXmlStreamReader reader(&file);
QXmlStreamReader::TokenType type;
while(!reader.atEnd()){
//读取当前行的标记类型
type = reader.readNext();
switch(type){
case QXmlStreamReader::NoToken://空行
break;
case QXmlStreamReader::Invalid://无效的标记 出错了
readContents(reader.errorString());
break;
case QXmlStreamReader::StartDocument://xml文档开始
{
QString str;
str += "<?xml";
str += "version=";
str += reader.documentVersion();
str += " encoding=";
str += reader.documentEncoding();
str += " standalone=";
str += reader.isStandaloneDocument()?"yes":"no";
str += "?>";
readContents(str);
}
break;
case QXmlStreamReader::EndDocument://xml文档结束
break;
case QXmlStreamReader::StartElement://元素(节点)开始
{
QString str;
str += "<";
str += reader.name().toString();
//获取元素中的属性
QXmlStreamAttributes attributes = reader.attributes();
if(!attributes.isEmpty()){
foreach (QXmlStreamAttribute attribute, attributes) {
str += " ";
str += attribute.name().toString();
str += "=";
str += attribute.value();
}
}
str += ">";
readContents(str);
}
break;
case QXmlStreamReader::EndElement://元素(节点)结束
{
QString str;
str += "</";
str += reader.name().toString();
str += ">";
readContents(str);
}
break;
case QXmlStreamReader::Characters://元素之间的文本
{
if(!reader.isWhitespace())
readContents(reader.text().toString());
}
break;
case QXmlStreamReader::Comment://注释
{
QString str;
str += "<!--";
str += reader.text().toString();//读取注释文本内容
str += "-->";
readContents(str);
}
break;
case QXmlStreamReader::DTD://文件类型定义
{
QString str = ".";
str += reader.text().toString();
readContents(str);
}
break;
case QXmlStreamReader::EntityReference://表示无法解析的部分
break;
case QXmlStreamReader::ProcessingInstruction://表示一个处理指令
break;
}
if(m_stop){
break;
}
}
file.close();
}
4、QXmlStreamWriter类
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QAction *action = menuBar()->addAction("生成xml");
connect(action,&QAction::triggered,[=]{
QString path = QFileDialog::getSaveFileName(this,"保存xml","F:/","XML(*.xml)");
if(path.isEmpty())
return;
QFile file(path);
file.open(QIODevice::WriteOnly);
//构造xml writer对象
QXmlStreamWriter writer;
writer.setDevice(&file);//绑定输入输出设备
writer.setCodec("utf-8");//默认的是utf-8
writer.setAutoFormatting(true);//自动格式化
//开始写入xml内容
writer.writeStartDocument("1.0",true);//开始文档 xml声明
writer.writeComment("这是一个注释,哈哈哈");//注释
writer.writeProcessingInstruction("xml-stylesheet type=\"text/css\" href=\"style.css\"");//处理指令
writer.writeDTD("<!DOCTYPE Blogs [ <!ENTITY Copyright \"Copyright 2016《Qt实战一二三》\"> <!ELEMENT Blogs (Blog)> <!ELEMENT Blog (作者,主页,个人说明)> <!ELEMENT 作者 (#PCDATA)> <!ELEMENT 主页 (#PCDATA)> <!ELEMENT 个人说明 (#PCDATA)> ]>");
writer.writeStartElement("Blogs");//开始根元素Blogs
writer.writeAttribute("Version","1.0");//根元素内添加一个属性
writer.writeStartElement("blogs");//开始子元素blogs
//有两种方式添加内容
//第一种
writer.writeTextElement("作者","一去二三里");
//第二种
writer.writeStartElement("个人说明");//开始子元素 个人说明
writer.writeCharacters("青春不老,奋斗不止!");
writer.writeEndElement();//结束子元素 个人说明
writer.writeEmptyElement("空元素");
writer.writeEndElement();//结束子元素blogs
writer.writeEndElement();//结束根元素Blogs
writer.writeEndDocument();//结束文档
file.close();
});
}
5、QDomDocument类
QDomDocument类表示整个XML文档。从概念上讲,它是文档树的根,并提供对文档数据的主要访问。最常用的DOM类是QDomNode、QDomDocument、QDomElement和QDomText。解析后的XML在内部由一个对象树表示,可以使用各种QDom类访问该树。所有QDom类只引用内部树中的对象。一旦引用它们的最后一个QDom对象或QDomDocument本身被删除,DOM树中的内部对象将被删除。
QDomDocument类有几个用于创建文档数据的函数,例如createElement()、createTextNode()、createComment()、createCDATASection()、createProcessingInstruction()、createAttribute()和createEntityReference()。其中一些函数的版本支持名称空间,即createElementNS()和createAttributeNS()。createDocumentFragment()函数用于保存文件的部分;这对于处理复杂文档非常有用。
文档的整个内容是用setContent()设置的。根元素通过documentElement()获得。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QAction *write = menuBar()->addAction("生成xml");
QAction *read = menuBar()->addAction("读取xml");
connect(write,&QAction::triggered,[=]{
QString path = QFileDialog::getSaveFileName(this,"选择路径","F:/","XML(*.xml)");
if(path.isEmpty())
return;
QDomDocument doc;
//创建处理指令
QDomProcessingInstruction xmlInstruction =
doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"");
//添加注释
QDomComment comment = doc.createComment("这是一个注释");
//创建处理指令
QDomProcessingInstruction styleInstruction =
doc.createProcessingInstruction("xml-stylesheet","type=\"text/css\" href=\"style.css\"");
doc.appendChild(xmlInstruction);//开始文档(XML 声明)
doc.appendChild(comment);//注释
doc.appendChild(styleInstruction);//处理指令
//根元素
QDomElement root = doc.createElement("Blogs");
root.setAttribute("Version","1.0");
doc.appendChild(root);
//元素
QDomElement child = doc.createElement("blogs");
root.appendChild(child);
//元素 作者 个人说明
QDomElement author = doc.createElement("作者");
QDomElement instruction = doc.createElement("个人说明");
child.appendChild(author);
child.appendChild(instruction);
//元素中的内容
QDomText authorText = doc.createTextNode("一去二三里");
QDomText instructionText = doc.createTextNode("青春不老,奋斗不止!");
author.appendChild(authorText);
instruction.appendChild(instructionText);
//保存xml文件
QFile file(path);
file.open(QIODevice::WriteOnly);
QTextStream out(&file);
doc.save(out,QDomDocument::EncodingFromDocument);
file.close();
});
connect(read,&QAction::triggered,[=]{
QString path = QFileDialog::getOpenFileName(this,"选择文件","F:/","XML(*.xml)");
if(path.isEmpty())
return;
QDomDocument doc("reader");
QFile file(path);
file.open(QIODevice::ReadOnly);
if(!doc.setContent(&file)){
file.close();
return;
}
file.close();//读取完毕后 文件关闭
//开始从内存中读取内容
//先获得根元素
QDomElement root = doc.documentElement();
qDebug() << root.tagName();//返回此元素的标记名称
//读取属性
if(root.hasAttribute("Version")){
qDebug() << root.attribute("Version");
}
//根元素本身就是一个节点 所以要想获得根元素之前的内容 使用下面的函数
QDomNode node = root.previousSibling();//返回前一个节点
while(!node.isNull()){
switch(node.nodeType())
{
case QDomNode::ProcessingInstructionNode :
{
QDomProcessingInstruction instruction = node.toProcessingInstruction();
qDebug() << instruction.target() << instruction.data();
if(instruction.target() == "xml"){
qDebug() << "xml处理指令";
}else if(instruction.target() == "xml-stylesheet"){
qDebug() << "xml-stylesheet 处理指令";
}
}
case QDomNode::CommentNode:
qDebug() << node.toComment().data();
break;
default:
break;
}
node = node.previousSibling();
}
//读取根元素下的内容
QDomNode childNode = root.firstChild();
while(!childNode.isNull()){
if(childNode.isElement()){
QDomElement element = childNode.toElement();
if(!element.isNull()){
qDebug() << element.tagName();
QDomNodeList list = element.childNodes();
for(int i = 0; i < list.size(); ++i){
QDomNode tmpNode = list.at(i);
if(!tmpNode.isNull()){
if(tmpNode.isElement()){
QDomElement tmpElement = tmpNode.toElement();
qDebug() << tmpElement.tagName() << tmpElement.text();
if(tmpElement.tagName() == "作者"){
qDebug() << "作者...";
}else if(tmpElement.tagName() == "个人说明"){
qDebug() << "个人说明...";
}
}
}
}
}
}
childNode = childNode.nextSibling();
}
});
}
实例参考:https://blog.csdn.net/liang19890820/article/details/52805902