Qt之XML读写

一、简介

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

猜你喜欢

转载自blog.csdn.net/wei375653972/article/details/86635958
今日推荐