Qt之解析XML元素(QXmlStreamReader)

簡述

對於 XML 的內容,通常情況下,我們只關心 XML 元素的解析。這時,可以通過 QXmlStreamReader 中的便利函數 readNextStartElement() 來實現。

詳細介紹

之前使用的方式主要使用 readNext() 來讀取下一個標記,並返回對應的類型。

QXmlStreamReader xml;
...
while (!xml.atEnd()) {
    xml.readNext();
    ... // 做處理
}
if (xml.hasError()) {
    ... // 做錯誤處理
}

這對於讀取註釋、字符、DTD、結束標籤等類型比較方便。當只關心 XML 元素的解析,這時,此種方式就顯得比較複雜了,下面介紹一種簡單方式。

在介紹之前,先明確一個概念:

  • 當前元素:
    當前元素是匹配最近解析的開始元素的元素,其中匹配的結束元素尚未到達。當解析器到達結束元素時,當前元素將成爲父元素。

下面,主要用到 QXmlStreamReader 的兩個接口:

bool readNextStartElement()

讀取,直到當前元素的下一個開始元素。當達到開始元素時,返回 true;當達到結束元素或發生錯誤時,返回 false。

void skipCurrentElement()

讀取,直到當前元素的結尾,跳過任何子節點。此函數對於跳過未知元素非常有用。

使用

爲了便於演示,使用上節生成的格式化 XML(Blogs.xml):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--純正開源之美,有趣、好玩、靠譜。。。-->
<?xml-stylesheet type="text/css" href="style.css"?>
<!DOCTYPE Blogs [ <!ENTITY Copyright "Copyright 2016《Qt實戰一二三》"> <!ELEMENT Blogs (Blog)> <!ELEMENT Blog (作者,主頁,個人說明)> <!ELEMENT 作者     (#PCDATA)> <!ELEMENT 主頁     (#PCDATA)> <!ELEMENT 個人說明  (#PCDATA)> ]>
<Blogs Version="1.0">
    <Blog>
        <作者>一去丶二三裏</作者>
        <主頁>http://blog.csdn.net/liang19890820</主頁>
        <個人說明>青春不老,奮鬥不止!</個人說明>&Copyright;<![CDATA[<Qt分享&&交流>368241647</Qt分享&&交流>]]>&gt;<Empty/>
    </Blog>
</Blogs>

封裝一個解析類 XMLReader,XMLReader.h 如下所示:

#ifndef XMLREADER_H
#define XMLREADER_H
 
#include <QXmlStreamReader>
 
class XMLReader
{
public:
    XMLReader();
    bool read(QIODevice *device);
    QString errorString() const;  // 錯誤信息
 
private:
    void readXBEL();  // 讀取根元素 <Blogs>
    void readBlog();  // 讀取元素 <Blog>
    void readAuthor();  // 讀取元素 <作者>
    void readHOME();   // 讀取元素 <主頁>
    void readInstruction();  // 讀取元素 <個人說明>
 
    QXmlStreamReader xml;
};
 
#endif // XMLREADER_H

XMLReader.cpp 如下所示:

#include "XMLReader.h"
#include <QDebug>
 
#define ROOT_ELEMENT "Blogs"
#define BLOG_ELEMENT "Blog"
#define AUTHOR_ELEMENT QString::fromLocal8Bit("作者")
#define HOME_ELEMENT QString::fromLocal8Bit("主頁")
#define INSTRUCTION_ELEMENT QString::fromLocal8Bit("個人說明")
#define VERSION_ATTRIBUTE "Version"
 
XMLReader::XMLReader()
{
 
}
 
bool XMLReader::read(QIODevice *device)
{
    xml.setDevice(device);
 
    if (xml.readNextStartElement()) {
        QString strName = xml.name().toString();
        if (strName== ROOT_ELEMENT) {  // 獲取根元素
            QXmlStreamAttributes attributes = xml.attributes();
            if (attributes.hasAttribute(VERSION_ATTRIBUTE)) {  // 存在屬性 Version
                QString strVersion = attributes.value(VERSION_ATTRIBUTE).toString();
                if (strVersion == "1.0") {  // 可以作爲版本兼容性判斷
                    qDebug() << "Version : " << strVersion;
                    readXBEL();
                } else {
                    xml.raiseError("The file is not an XBEL version 1.0 file.");
                }
            }
        } else {
            xml.raiseError("XML file format error.");
        }
    }
 
    return !xml.error();
}
 
// 錯誤信息
QString XMLReader::errorString() const
{
    return QString("Error:%1  Line:%2  Column:%3")
            .arg(xml.errorString())
            .arg(xml.lineNumber())
            .arg(xml.columnNumber());
}
 
// 讀取根元素 <Blogs>
void XMLReader::readXBEL()
{
    Q_ASSERT(xml.isStartElement() && xml.name().toString() == ROOT_ELEMENT);
 
    while (xml.readNextStartElement()) {
        if (xml.name().toString() == BLOG_ELEMENT) {
            readBlog();
        } else {
            xml.skipCurrentElement();  // 跳過當前元素
        }
    }
}
 
// 讀取元素 <Blog>
void XMLReader::readBlog()
{
    Q_ASSERT(xml.isStartElement() && xml.name().toString() == BLOG_ELEMENT);
 
    while (xml.readNextStartElement()) {
        if (xml.name().toString() == AUTHOR_ELEMENT)
            readAuthor();
        else if (xml.name().toString() == HOME_ELEMENT)
            readHOME();
        else if (xml.name().toString() == INSTRUCTION_ELEMENT)
            readInstruction();
        else
            xml.skipCurrentElement();  // 跳過當前元素
    }
}
 
// 讀取元素 <作者>
void XMLReader::readAuthor()
{
    Q_ASSERT(xml.isStartElement() && xml.name().toString() == AUTHOR_ELEMENT);
 
    QString strAuthor = xml.readElementText();
    qDebug() << QString::fromLocal8Bit("作者:%1").arg(strAuthor);
}
 
// 讀取元素 <主頁>
void XMLReader::readHOME()
{
    Q_ASSERT(xml.isStartElement() && xml.name().toString() == HOME_ELEMENT);
 
    QString strHome = xml.readElementText();
    qDebug() << QString::fromLocal8Bit("主頁:%1").arg(strHome);
}
 
// 讀取元素 <個人說明>
void XMLReader::readInstruction()
{
    Q_ASSERT(xml.isStartElement() && xml.name().toString() == INSTRUCTION_ELEMENT);
 
    QString strInstruction = xml.readElementText();
    qDebug() << QString::fromLocal8Bit("個人說明:%1").arg(strInstruction);
}

使用時,調用 readXML() 即可。

#include <QFile>
#include "XMLReader.h"
 
// 解析 XML
void readXML() {
    QString strFile("Blogs.xml");
    QFile file(strFile);
    if (!file.open(QFile::ReadOnly | QFile::Text)) {  // 以只讀模式打開
        qDebug() << QString("Cannot read file %1(%2).").arg(strFile).arg(file.errorString());
        return;
    }
 
    XMLReader reader;
    if (!reader.read(&file)) {
        qDebug() << QString("Parse error in file %1(%2).").arg(strFile).arg(reader.errorString());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章