Qt之解析XML元素(QXmlStreamReader)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 简述对于 XML 的内容,通常情况下,我们只关心 XML 元素的解析。这时,可以通过 QXmlStreamReader 中的便利函数 readNextStartElement() 来实现。简述详细介绍使用更多参考详细介绍之前使用的方式主要使用 readNext() 来读取下一个标记,并返回对应的类型。QXmlStreamRea

简述

对于 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>

详细说明见:Qt之生成XML(QXmlStreamWriter)

封装一个解析类 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());
    }
}

更多参考

目录
相关文章
|
2月前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
43 3
|
2月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
50 3
|
2月前
|
XML Web App开发 JavaScript
XML DOM 解析器
XML DOM 解析器
|
2月前
|
XML Web App开发 JavaScript
XML DOM 解析器
XML DOM 解析器
|
2月前
|
XML Web App开发 JavaScript
XML DOM 解析器
XML DOM 解析器
|
2月前
|
XML Java 数据格式
手动开发-简单的Spring基于XML配置的程序--源码解析
手动开发-简单的Spring基于XML配置的程序--源码解析
83 0
|
2月前
|
XML Web App开发 JavaScript
XML DOM 解析器
XML DOM 解析器
|
5月前
|
数据安全/隐私保护 C++ 计算机视觉
Qt(C++)开发一款图片防盗用水印制作小工具
文本水印是一种常用的防盗用手段,可以将文本信息嵌入到图片、视频等文件中,用于识别和证明文件的版权归属。在数字化和网络化的时代,大量的原创作品容易被不法分子盗用或侵犯版权,因此加入文本水印成为了保护原创作品和维护知识产权的必要手段。 通常情况下,文本水印可以包含版权声明、制作者姓名、日期、网址等信息,以帮助识别文件的来源和版权归属。同时,为了增强防盗用效果,文本水印通常会采用字体、颜色、角度等多种组合方式,使得水印难以被删除或篡改,有效地降低了盗用意愿和风险。 开发人员可以使用图像处理技术和编程语言实现文本水印的功能,例如使用Qt的QPainter类进行文本绘制操作,将文本信息嵌入到图片中,
191 1
Qt(C++)开发一款图片防盗用水印制作小工具
|
4月前
|
监控 C++ 容器
【qt】MDI多文档界面开发
【qt】MDI多文档界面开发
97 0
|
3月前
|
开发工具 C++
qt开发技巧与三个问题点
本文介绍了三个Qt开发中的常见问题及其解决方法,并提供了一些实用的开发技巧。

推荐镜像

更多