欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Qt解析XML的三種常見(jiàn)方法實(shí)現(xiàn)與比較

 更新時(shí)間:2025年06月19日 08:48:33   作者:小灰灰搞電子  
XML是一種可擴(kuò)展的標(biāo)記語(yǔ)言,用于存儲(chǔ)和傳輸結(jié)構(gòu)化數(shù)據(jù),廣泛應(yīng)用于配置、數(shù)據(jù)交換和Web服務(wù)等領(lǐng)域,本文主要介紹了Qt解析XML的三種常見(jiàn)方法實(shí)現(xiàn)和性能對(duì)比,需要的可以了解下

一、XML概述

XML簡(jiǎn)介

XML(eXtensible Markup Language)是一種可擴(kuò)展的標(biāo)記語(yǔ)言,用于存儲(chǔ)和傳輸結(jié)構(gòu)化數(shù)據(jù)。它被設(shè)計(jì)為兼具人類(lèi)可讀性和機(jī)器可讀性,廣泛應(yīng)用于配置、數(shù)據(jù)交換和Web服務(wù)等領(lǐng)域。

XML核心特性

可擴(kuò)展性:允許用戶(hù)自定義標(biāo)簽和數(shù)據(jù)結(jié)構(gòu)。

平臺(tái)無(wú)關(guān)性:獨(dú)立于編程語(yǔ)言和操作系統(tǒng)。

自描述性:通過(guò)標(biāo)簽和屬性明確描述數(shù)據(jù)內(nèi)容。

XML基本結(jié)構(gòu)

XML文檔由以下部分組成:

  • 聲明:定義XML版本和編碼(如<?xml version="1.0" encoding="UTF-8"?>)。
  • 根元素:文檔的唯一頂層元素(如<root>)。
  • 子元素與屬性:嵌套的標(biāo)簽和鍵值對(duì)(如<book id="1">)。

示例代碼:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book id="101">
    <title>XML Basics</title>
    <author>John Doe</author>
  </book>
</bookstore>

XML與HTML的區(qū)別

目的:HTML用于數(shù)據(jù)展示,XML用于數(shù)據(jù)存儲(chǔ)和傳輸。

標(biāo)簽:HTML標(biāo)簽預(yù)定義,XML標(biāo)簽可自定義。

嚴(yán)格性:XML對(duì)語(yǔ)法要求更嚴(yán)格(如必須閉合標(biāo)簽)。

XML相關(guān)技術(shù)

DTD/XSD:定義文檔結(jié)構(gòu)和驗(yàn)證規(guī)則。

XPath/XQuery:用于XML數(shù)據(jù)查詢(xún)。

XSLT:將XML轉(zhuǎn)換為其他格式(如HTML)。

XML因其靈活性和跨平臺(tái)特性,至今仍在Web服務(wù)、配置文件(如Android布局)和數(shù)據(jù)交換(如SOAP協(xié)議)中廣泛應(yīng)用。

二、Qt中的XML解析方法

1. SAX解析(事件驅(qū)動(dòng)模型)

特點(diǎn):

  • 基于事件的解析方式
  • 不需要將整個(gè)文檔加載到內(nèi)存
  • 順序讀取文檔,遇到元素時(shí)觸發(fā)事件
  • 內(nèi)存效率高,適合大型XML文件

理解Qt的SAX解析機(jī)制

Qt中的SAX(Simple API for XML)解析是一種基于事件驅(qū)動(dòng)的XML解析方式。與DOM解析不同,SAX解析不將整個(gè)XML文檔加載到內(nèi)存,而是逐行讀取并觸發(fā)相應(yīng)的事件。這種方式適合處理大型XML文件,內(nèi)存占用較低。

實(shí)現(xiàn)SAX解析的核心類(lèi)

Qt中SAX解析主要依賴(lài)QXmlSimpleReader和QXmlDefaultHandler類(lèi)。QXmlSimpleReader負(fù)責(zé)讀取XML文檔并觸發(fā)事件,QXmlDefaultHandler則提供處理這些事件的虛函數(shù),用戶(hù)需繼承此類(lèi)并重寫(xiě)關(guān)鍵方法。

#include <QXmlDefaultHandler>
#include <QXmlSimpleReader>
#include <QFile>

自定義處理器類(lèi)

創(chuàng)建一個(gè)繼承自QXmlDefaultHandler的子類(lèi),重寫(xiě)以下常用方法:

class MyXmlHandler : public QXmlDefaultHandler {
public:
    bool startElement(const QString &namespaceURI, 
                     const QString &localName,
                     const QString &qName, 
                     const QXmlAttributes &attrs) override {
        // 處理元素開(kāi)始標(biāo)簽
        return true;
    }

    bool endElement(const QString &namespaceURI,
                   const QString &localName,
                   const QString &qName) override {
        // 處理元素結(jié)束標(biāo)簽
        return true;
    }

    bool characters(const QString &ch) override {
        // 處理元素文本內(nèi)容
        return true;
    }

    bool fatalError(const QXmlParseException &exception) override {
        // 處理錯(cuò)誤
        return false;
    }
};

配置解析流程

建立完整的SAX解析流程需要以下步驟:

QFile file("example.xml");
if (!file.open(QFile::ReadOnly | QFile::Text)) {
    qDebug() << "Cannot open file";
    return;
}

QXmlInputSource source(&file);
QXmlSimpleReader reader;
MyXmlHandler handler;
reader.setContentHandler(&handler);
reader.setErrorHandler(&handler);

???????bool ok = reader.parse(source);
if (!ok) {
    qDebug() << "Parsing failed";
}
file.close();

處理元素屬性

在startElement方法中可以通過(guò)QXmlAttributes參數(shù)獲取元素屬性:

bool startElement(..., const QXmlAttributes &attrs) {
    for (int i = 0; i < attrs.count(); ++i) {
        QString name = attrs.qName(i);
        QString value = attrs.value(i);
        // 處理屬性
    }
    return true;
}

錯(cuò)誤處理機(jī)制

SAX解析過(guò)程中可能出現(xiàn)格式錯(cuò)誤,通過(guò)重寫(xiě)fatalError方法可以捕獲這些異常:

bool fatalError(const QXmlParseException &exception) {
    qDebug() << "Error at line" << exception.lineNumber()
             << ", column" << exception.columnNumber()
             << ":" << exception.message();
    return false;  // 停止解析
}

性能優(yōu)化建議

對(duì)于大型XML文件,可以考慮以下優(yōu)化措施:

  • 避免在事件處理函數(shù)中進(jìn)行復(fù)雜計(jì)算
  • 使用QStringRef代替QString處理文本內(nèi)容
  • 及時(shí)釋放不再需要的資源

這種解析方式適合需要高效處理XML數(shù)據(jù)流的場(chǎng)景,如配置文件讀取、網(wǎng)絡(luò)數(shù)據(jù)傳輸解析等。

2. DOM解析(樹(shù)形模型)

特點(diǎn):

  • 將整個(gè)XML文檔加載到內(nèi)存形成樹(shù)狀結(jié)構(gòu)
  • 可以隨機(jī)訪(fǎng)問(wèn)文檔的任何部分
  • 內(nèi)存消耗較大,適合小型XML文件
  • 支持修改XML文檔

Qt DOM解析XML的基本方法

Qt提供QDomDocument類(lèi)用于DOM方式解析XML。DOM將XML文檔作為樹(shù)結(jié)構(gòu)處理,允許隨機(jī)訪(fǎng)問(wèn)節(jié)點(diǎn),適合小型XML文件或需要頻繁修改的場(chǎng)景。

創(chuàng)建QDomDocument對(duì)象

QDomDocument doc;
QFile file("example.xml");
if (!file.open(QIODevice::ReadOnly)) return;
if (!doc.setContent(&file)) {
    file.close();
    return;
}
file.close();

獲取根元素

QDomElement root = doc.documentElement();
if (root.isNull()) {
    // 處理空文檔情況
}

遍歷子節(jié)點(diǎn)

QDomNode node = root.firstChild();
while (!node.isNull()) {
    if (node.isElement()) {
        QDomElement element = node.toElement();
        QString tagName = element.tagName();
        QString text = element.text();
    }
    node = node.nextSibling();
}

讀取元素屬性

QString attrValue = element.attribute("attributeName");
QString attrValue2 = element.attribute("attributeName2", "defaultValue");

創(chuàng)建新XML文檔

QDomDocument newDoc;
QDomElement newRoot = newDoc.createElement("root");
newDoc.appendChild(newRoot);

QDomElement child = newDoc.createElement("child");
child.setAttribute("id", "1");
newRoot.appendChild(child);

寫(xiě)入XML文件

QFile outputFile("output.xml");
if (outputFile.open(QIODevice::WriteOnly)) {
    QTextStream stream(&outputFile);
    doc.save(stream, 4);  // 4表示縮進(jìn)空格數(shù)
    outputFile.close();
}

處理XML命名空間

QDomElement nsElement = doc.createElementNS("http://example.com/ns", "prefix:element");

錯(cuò)誤處理

QString errorMsg;
int errorLine, errorColumn;
if (!doc.setContent(&file, &errorMsg, &errorLine, &errorColumn)) {
    qDebug() << "Error at line" << errorLine << "column" << errorColumn << ":" << errorMsg;
}

DOM解析方式會(huì)一次性加載整個(gè)XML文檔到內(nèi)存,對(duì)于大型XML文件可能導(dǎo)致性能問(wèn)題。這種情況下可以考慮使用Qt的SAX(QXmlSimpleReader)或流式解析(QXmlStreamReader)方式。

3. QXmlStreamReader(流式解析)

特點(diǎn):

  • Qt Core模塊提供的現(xiàn)代解析器
  • 結(jié)合SAX和DOM的優(yōu)點(diǎn)
  • 類(lèi)似SAX的事件驅(qū)動(dòng),但API更簡(jiǎn)單
  • 不需要將整個(gè)文檔加載到內(nèi)存
  • 支持讀取和寫(xiě)入

QXmlStreamReader 簡(jiǎn)介

QXmlStreamReader 是 Qt 提供的流式 XML 解析器,用于高效讀取 XML 數(shù)據(jù)。與 DOM 解析器不同,它逐元素解析,內(nèi)存占用低,適合處理大型 XML 文件。

基本使用方法

初始化與輸入設(shè)置

QXmlStreamReader reader;
reader.addData(xmlData);  // 輸入 XML 數(shù)據(jù)(QString 或 QByteArray)
// 或通過(guò)文件輸入
QFile file("example.xml");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    return;
reader.setDevice(&file);

解析流程

通過(guò)循環(huán)檢查 reader.readNext() 或直接處理 reader.tokenType() 來(lái)遍歷 XML:

while (!reader.atEnd()) {
    QXmlStreamReader::TokenType type = reader.readNext();
    if (type == QXmlStreamReader::StartElement) {
        QString elementName = reader.name().toString();
        if (elementName == "book") {
            QString id = reader.attributes().value("id").toString();
        }
    } else if (type == QXmlStreamReader::Characters) {
        QString text = reader.text().toString().trimmed();
        if (!text.isEmpty()) {
            // 處理文本內(nèi)容
        }
    }
}
if (reader.hasError()) {
    qDebug() << "Error:" << reader.errorString();
}

關(guān)鍵方法與屬性

常用 TokenType 類(lèi)型

  • StartElement:開(kāi)始標(biāo)簽(如 <book>)。
  • EndElement:結(jié)束標(biāo)簽(如 </book>)。
  • Characters:標(biāo)簽之間的文本內(nèi)容。
  • Attribute:標(biāo)簽的屬性(通過(guò) attributes() 訪(fǎng)問(wèn))。

屬性與內(nèi)容獲取

// 獲取當(dāng)前元素名
QString name = reader.name().toString();

// 獲取屬性
QXmlStreamAttributes attrs = reader.attributes();
QString value = attrs.value("attrName").toString();

// 獲取文本內(nèi)容(需在 Characters 類(lèi)型時(shí)處理)
QString text = reader.text().toString();

錯(cuò)誤處理

檢查解析錯(cuò)誤并獲取詳細(xì)信息:

if (reader.hasError()) {
    qDebug() << "Line:" << reader.lineNumber();
    qDebug() << "Column:" << reader.columnNumber();
    qDebug() << "Error:" << reader.errorString();
}

示例:解析嵌套 XML

假設(shè) XML 結(jié)構(gòu)如下:

<library>
    <book id="1">
        <title>Qt Guide</title>
        <author>Alice</author>
    </book>
</library>

解析代碼片段:

while (!reader.atEnd()) {
    reader.readNext();
    if (reader.isStartElement()) {
        if (reader.name() == "book") {
            QString id = reader.attributes().value("id").toString();
        } else if (reader.name() == "title") {
            QString title = reader.readElementText(); // 直接讀取文本
        } else if (reader.name() == "author") {
            QString author = reader.readElementText();
        }
    }
}

性能優(yōu)化建議

避免頻繁字符串轉(zhuǎn)換:reader.name() 返回 QStringView,可直接用于比較。

跳過(guò)無(wú)關(guān)內(nèi)容:使用 reader.skipCurrentElement() 跳過(guò)不需要的嵌套元素。

重用讀取器:清除狀態(tài)后復(fù)用 QXmlStreamReader 對(duì)象以減少開(kāi)銷(xiāo)。

通過(guò)流式解析,QXmlStreamReader 在性能和內(nèi)存效率上表現(xiàn)優(yōu)異,適合處理大型或?qū)崟r(shí) XML 數(shù)據(jù)流。

三、實(shí)例展示

解析下面xml內(nèi)容:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="fiction">
    <title lang="en">Harry Potter</title>
    <author>J.K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
  <book category="non-fiction">
    <title lang="en">The Great Gatsby</title>
    <author>F. Scott Fitzgerald</author>
    <year>1925</year>
    <price>19.99</price>
  </book>
</bookstore>

解析代碼:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFile>
#include <QXmlStreamReader>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}


void parseWithStreamReader(const QString &fileName)
{
    QFile file(fileName);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        // 處理錯(cuò)誤
        qDebug()<<"file open error";
        return;
    }

    QXmlStreamReader xml(&file);
    while (!xml.atEnd() && !xml.hasError())
    {
        QXmlStreamReader::TokenType token = xml.readNext();

        if (token == QXmlStreamReader::StartDocument)
        {
             qDebug() << "Start Document";
        }
        else if(token==QXmlStreamReader::StartElement)
        {
            qDebug() << "Start Element: " << xml.name().toString();
            // 處理不同的元素
            if (xml.name().toString() == "book") {
                qDebug() << "Category: " << xml.attributes().value("category").toString();
            } else if (xml.name().toString() == "title") {
                qDebug() << "Title: " << xml.readElementText();
            } else if (xml.name().toString() == "author") {
                qDebug() << "Author: " << xml.readElementText();
            } else if (xml.name().toString() == "year") {
                qDebug() << "Year: " << xml.readElementText().toInt();
            } else if (xml.name().toString() == "price") {
                qDebug() << "Price: " << xml.readElementText().toDouble();
            }
        }
        else if (token == QXmlStreamReader::EndElement)
        {
            qDebug() << "End Element: " << xml.name().toString();
        }

    }

    if (xml.hasError())
    {
        qDebug()<<"xml error!";
    }

    file.close();
}

void MainWindow::on_pushButton_clicked()
{
    parseWithStreamReader("test.xml");
}

效果展示:

到此這篇關(guān)于Qt解析XML的三種常見(jiàn)方法實(shí)現(xiàn)與比較的文章就介紹到這了,更多相關(guān)Qt解析XML內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++實(shí)現(xiàn)簡(jiǎn)單掃雷游戲

    C++實(shí)現(xiàn)簡(jiǎn)單掃雷游戲

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡(jiǎn)單掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • C++函數(shù)重載的深入解析

    C++函數(shù)重載的深入解析

    在C++中,我們也能夠把具有相同功能的函數(shù)整合到一個(gè)函數(shù)上,而不必去寫(xiě)好多個(gè)函數(shù)名不同的函數(shù),這叫做函數(shù)的重載。以下是對(duì)C++中的函數(shù)重載進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下
    2013-07-07
  • C++中strlen函數(shù)的三種實(shí)現(xiàn)方法

    C++中strlen函數(shù)的三種實(shí)現(xiàn)方法

    在C語(yǔ)言中我們要獲取字符串的長(zhǎng)度,可以使用strlen?函數(shù),strlen?函數(shù)計(jì)算字符串的長(zhǎng)度時(shí),直到空結(jié)束字符,但不包括空結(jié)束字符,因?yàn)閟trlen函數(shù)時(shí)不包含最后的結(jié)束字符的,因此一般使用strlen函數(shù)計(jì)算的字符串的長(zhǎng)度會(huì)比使用sizeof計(jì)算的字符串的字節(jié)數(shù)要小
    2022-05-05
  • C語(yǔ)言中字符串的兩種定義方式詳解

    C語(yǔ)言中字符串的兩種定義方式詳解

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言中字符串的兩種定義方式,小編覺(jué)得這篇文章寫(xiě)的還不錯(cuò),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C語(yǔ)言編程之掃雷小游戲空白展開(kāi)算法優(yōu)化

    C語(yǔ)言編程之掃雷小游戲空白展開(kāi)算法優(yōu)化

    掃雷是電腦上很經(jīng)典的游戲,特意去網(wǎng)上玩了一會(huì),幾次調(diào)試之后,發(fā)現(xiàn)這個(gè)比三子棋要復(fù)雜一些,尤其是空白展開(kāi)算法上和堵截玩家有的一拼,與實(shí)際游戲差別較大,不能使用光標(biāo),下面來(lái)詳解每一步分析
    2021-09-09
  • c語(yǔ)言字符數(shù)組與字符串的使用詳解

    c語(yǔ)言字符數(shù)組與字符串的使用詳解

    本篇文章是對(duì)c語(yǔ)言中字符數(shù)組與字符串的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++簡(jiǎn)明分析講解引用與函數(shù)提高及重載

    C++簡(jiǎn)明分析講解引用與函數(shù)提高及重載

    今天繼續(xù)開(kāi)始對(duì)C++核心編程知識(shí)的分享與系統(tǒng)講解,第一,這里會(huì)提到“引用”方法傳參以及剖析引用的本質(zhì);第二,我們對(duì)函數(shù)來(lái)一個(gè)提高,相當(dāng)于進(jìn)階函數(shù)了,包括函數(shù)的默認(rèn)值,簡(jiǎn)單的提一下函數(shù)的占位參數(shù),函數(shù)重載以及注意事項(xiàng),接下來(lái)上正文
    2022-05-05
  • vs2017智能感知錯(cuò)誤解決代碼標(biāo)紅但編譯通過(guò)問(wèn)題

    vs2017智能感知錯(cuò)誤解決代碼標(biāo)紅但編譯通過(guò)問(wèn)題

    這篇文章主要介紹了vs2017智能感知錯(cuò)誤代碼標(biāo)紅但編譯通過(guò)問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • C語(yǔ)言循環(huán)鏈表的原理與使用操作

    C語(yǔ)言循環(huán)鏈表的原理與使用操作

    無(wú)論是靜態(tài)鏈表還是動(dòng)態(tài)鏈表,有時(shí)在解決具體問(wèn)題時(shí),需要我們對(duì)其結(jié)構(gòu)進(jìn)行稍微地調(diào)整。比如,可以把鏈表的兩頭連接,使其成為了一個(gè)環(huán)狀鏈表,通常稱(chēng)為循環(huán)鏈表
    2022-05-05
  • 淺析C語(yǔ)言位域和位段

    淺析C語(yǔ)言位域和位段

    以下是對(duì)C語(yǔ)言中的位域和位段進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下
    2013-08-08

最新評(píng)論