最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

一、XML概述

XML簡(jiǎn)介

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

XML核心特性

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

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

自描述性:通過標(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án)格(如必須閉合標(biāo)簽)。

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

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

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

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解析的核心類

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

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

自定義處理器類

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

class MyXmlHandler : public QXmlDefaultHandler {
public:
    bool startElement(const QString &namespaceURI, 
                     const QString &localName,
                     const QString &qName, 
                     const QXmlAttributes &attrs) override {
        // 處理元素開始標(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方法中可以通過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解析過程中可能出現(xiàn)格式錯(cuò)誤,通過重寫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解析(樹形模型)

特點(diǎn):

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

Qt DOM解析XML的基本方法

Qt提供QDomDocument類用于DOM方式解析XML。DOM將XML文檔作為樹結(jié)構(gòu)處理,允許隨機(jī)訪問節(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);

寫入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)致性能問題。這種情況下可以考慮使用Qt的SAX(QXmlSimpleReader)或流式解析(QXmlStreamReader)方式。

3. QXmlStreamReader(流式解析)

特點(diǎn):

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

QXmlStreamReader 簡(jiǎn)介

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

基本使用方法

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

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

解析流程

通過循環(huán)檢查 reader.readNext() 或直接處理 reader.tokenType() 來遍歷 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 類型

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

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

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

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

// 獲取文本內(nèi)容(需在 Characters 類型時(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ān)內(nèi)容:使用 reader.skipCurrentElement() 跳過不需要的嵌套元素。

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

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

相關(guān)文章

  • OpenCV實(shí)現(xiàn)圖像腐蝕

    OpenCV實(shí)現(xiàn)圖像腐蝕

    這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)圖像腐蝕,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C++條件及循環(huán)語句的綜合運(yùn)用實(shí)例

    C++條件及循環(huán)語句的綜合運(yùn)用實(shí)例

    這篇文章主要介紹了C++條件及循環(huán)語句的綜合運(yùn)用實(shí)例,能夠幫助C++初學(xué)者更好地掌握C++的邏輯語句用法,需要的朋友可以參考下
    2015-09-09
  • C++高性能服務(wù)器框架之協(xié)程調(diào)度模塊

    C++高性能服務(wù)器框架之協(xié)程調(diào)度模塊

    這篇文章主要介紹了C++高性能服務(wù)器框架中的協(xié)程調(diào)度模塊,文中通過代碼示例介紹的非常詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-06-06
  • 使用Matlab繪制七夕咕呱小青蛙

    使用Matlab繪制七夕咕呱小青蛙

    七夕節(jié)到了還不快給你的朋友安排上這只咕呱小青蛙?本文將用Matlab繪制一個(gè)可愛的咕呱小青蛙,感興趣的小伙伴可以動(dòng)手嘗試一下
    2022-08-08
  • C語言中數(shù)據(jù)是如何存儲(chǔ)在內(nèi)存中的

    C語言中數(shù)據(jù)是如何存儲(chǔ)在內(nèi)存中的

    使用編程語言進(jìn)行編程時(shí),需要用到各種變量來存儲(chǔ)各種信息。變量保留的是它所存儲(chǔ)的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個(gè)變量時(shí),就會(huì)在內(nèi)存中保留一些空間。您可能需要存儲(chǔ)各種數(shù)據(jù)類型的信息,操作系統(tǒng)會(huì)根據(jù)變量的數(shù)據(jù)類型,來分配內(nèi)存和決定在保留內(nèi)存中存儲(chǔ)什么
    2022-04-04
  • 數(shù)據(jù)結(jié)構(gòu)順序表操作示例

    數(shù)據(jù)結(jié)構(gòu)順序表操作示例

    這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)順序表操作示例,其中有在第I個(gè)元素前插入數(shù)據(jù)x,元素從0開始計(jì)數(shù)、刪除第i個(gè)元素,元素從0開始計(jì)數(shù)的方法,需要的朋友可以參考下
    2014-03-03
  • 詳解C++編程中數(shù)組的基本用法

    詳解C++編程中數(shù)組的基本用法

    這篇文章主要介紹了C++編程中數(shù)組的基本用法,包括數(shù)組的初始化等基本知識(shí),需要的朋友可以參考下
    2016-01-01
  • C++中操作符的前置與后置有什么區(qū)別

    C++中操作符的前置與后置有什么區(qū)別

    C 語言提供了豐富的操作符,有:算術(shù)操作符,移位操作符,位操作符,賦值操作符,單目操作符,關(guān)系操作符,邏輯操作符,條件操作符等。接下了讓我們?cè)敿?xì)了解掌握它
    2022-05-05
  • C語言由淺入深講解線程的定義

    C語言由淺入深講解線程的定義

    這篇文章主要介紹了C語言中線程的基礎(chǔ)知識(shí),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • C++ 中 std::vector 和 std::list 的區(qū)別詳解

    C++ 中 std::vector 和 std::list 的區(qū)別詳解

    本文詳細(xì)介紹了C++標(biāo)準(zhǔn)庫中的std::vector和std::list的區(qū)別,從底層數(shù)據(jù)結(jié)構(gòu)、內(nèi)存布局與分配策略、操作時(shí)間復(fù)雜度對(duì)比、迭代器有效性與類別、其他特性與成員函數(shù)差異、內(nèi)存占用與緩存性能等方面進(jìn)行了闡述,感興趣的朋友跟隨小編一起看看吧
    2026-03-03

最新評(píng)論

海阳市| 东兰县| 泸水县| 巴彦淖尔市| 邻水| 涞水县| 乃东县| 黎川县| 嘉鱼县| 长海县| 叙永县| 宁国市| 周宁县| 阳朔县| 甘洛县| 巴青县| 云阳县| 封开县| 罗江县| 扎鲁特旗| 缙云县| 永定县| 义乌市| 乐山市| 钦州市| 襄城县| 锡林浩特市| 无锡市| 阿克苏市| 交城县| 新郑市| 祁连县| 正安县| 时尚| 墨脱县| 安福县| 桐庐县| 平远县| 惠来县| 齐齐哈尔市| 长宁县|