QT开发(四十三)——SAX方式解析XML

QT开发(四十三)——SAX方式解析XML

一、SAX简介

SAX是Simple API for XML的简写,是一种解析XML文件的替代方法,不是由W3C官方所提出的标准,是一种事件驱动的XML API,接近于底层,速度较快,但不便于随机访问任意节点。

SAX解析的核心是事件处理机制,具有占用内存少,效率高等特点。

SAX采用事件机制的方式来解析XML文档。使用SAX解析器对XML文档进行解析时,SAX解析器根本不创建任何对象,只是在遇到XML文档的各种标签如文档开始、元素开始、文本、元素结束时触发对应的事件,并将XML元素的内容封装成事件传出去。而程序员则负责提供事件监听器来监听这些事件,从而触发相应的事件处理方法,并通过这些事件处理方法实现对XML文档的访问。

SAX解析事件一共有4种,需要分别设置4种监听器:

A、ContentHandler:监听XML文档内容处理事件的监听器

B、DTDHander:监听DTD处理事件的监听器

C、EntityResolver:监听实体处理事件的监听器

D、ErrorHandler:监听解析错误的监听器

QT的QtXml模块中提供了一个基于SAX的XML解析器QXmlSimpleReader类。当解析器解析一个XML的元素时,解析器会依次调用如下事件处理函数:startElement(),characters(),endElement()。可以在 startElement()中获得元素名(如“title”)和属性,在characters()中获得元素中的文本(如“Qt”),在endElement()中进行一些结束读取该元素时想要进行的操作。而所有的这些事件处理函数都可以通过继承QXmlDefaultHandler类来重写。

二、QXmlSimpleReader

1、QXmlSimpleReader简介

QXmlSimpleReader类提供了简单XML解析器的实现。

XML读取器适合大部分应用程序,能够解析良构XML,但不能解析任何外部实体。

QXmlSimpleReader类最容易的使用模式是创建一个实例,定义一个输入源,指定读取器使用的处理器,解析数据。

当读取器遇到内容中的某种类型或是输入源中发现错误,处理器会采取行动。读取器必须被告知需要哪一种事件类型的处理器。对于大多数应用程序来说,可以自定义一个继承于QXmlDefaultHandler类的处理器类,使用自定义的处理器处理错误和内容事件。

如果至少连错误和内容处理器都没有设置,解析器将会默认什么都不做。

处理输入源最方便的方式是使用带指定输入源参数的parse()函数以单通道的方式读取输入源。如果一次读取不能解析整个输入源(比如XML文件太大或是正在网络上传输),XML文件可以被解析器分块读取。分块读取解析可以通过告知prase()函数以递增方式工作,随后调用parseContinue()函数,直到所有数据被解析完成来实现。

实现递增解析通常的方式是连接信号readyRead()到网络应答的槽函数,并且处理收到的数据。

解析行为可以通过使用setFeature()函数和setProperty()函数进行调整。

2、QXmlSimpleReader成员函数

[virtual] void QXmlSimpleReader::setContentHandler(QXmlContentHandler *handler)

设置内容处理器到handler

[virtual] void QXmlSimpleReader::setErrorHandler(QXmlErrorHandler *handler)

设置错误处理器到handler,如果handler为0,清空错误处理器

[virtual] void QXmlSimpleReader::setDTDHandler(QXmlDTDHandler *handler)

[virtual] void QXmlSimpleReader::setDeclHandler(QXmlDeclHandler *handler)

[virtual] void QXmlSimpleReader::setEntityResolver(QXmlEntityResolver *handler)

[virtual] void QXmlSimpleReader::setLexicalHandler(QXmlLexicalHandler *handler)

[virtual] void QXmlSimpleReader::setFeature(const QString &name, bool enable)

[virtual] void QXmlSimpleReader::setProperty(const QString &name, void *value)

[virtual] QXmlErrorHandler *QXmlSimpleReader::errorHandler() const

返回错误处理器,如果没有设置,返回0

[virtual] QXmlContentHandler *QXmlSimpleReader::contentHandler() const

返回内容处理器,如果没有设置,返回0

[virtual] bool QXmlSimpleReader::hasFeature(const QString &name) const

如果读取器有名为name的特性,返回true

三、QXmlDefaultHandler

1、QXmlDefaultHandler简介

QXmlDefaultHandler类提供了所有XML处理器类的实现,集成了特定处理器类的特性,使QXmlReader子类自定义处理器类有了一个便捷的切入点,特别是QXmlSimpleReader类。从基类中继承的虚函数都会在QXmlDefaultHandler类中重写。通过继承QXmlDefaultHandler类,重写相关虚函数,开发人员能够专注于处理器相关部分的实现。

在解析期间,XML读取器必须被告知要使用哪一种事件的处理器。这就意味着,QXmlDefaultHandler虽然提供了从基类继承来的函数的默认实现,我们仍然可以对特殊的事件使用指定的处理器。

例如,QXmlDefaultHandler继承了QXmlContentHandler和QXmlErrorHandler,因此通过继承QXmlDefaultHandler,我们可以使用QXmlContentHandler和QXmlErrorHandler的处理器。

xmlReader.setContentHandler(handler);

xmlReader.setErrorHandler(handler);

由于读取器将会通知解析错误的处理器,需要重写QXmlErrorHandler::fatalError()函数,当错误发生时需要停止解析。

bool Handler::fatalError (const QXmlParseException & exception)

{

qWarning() << "Fatal error on line" << exception.lineNumber()

<< ", column" << exception.columnNumber() << ‘:‘

<< exception.message();

return false;

}

fatalError()函数返回false会告诉解析器停止解析,。要继续使用同一个读取器需要创建一个新的处理器实例,设置使用它的读取器。

审查从QXmlDefaultHandler类继承来的某些函数和思考为什么在自定义处理器类中要重写这些函数是有用的。自定义处理器类为了准备新内容的处理器通常会重写QXmlContentHandler::startDocument()函数。通过重写QXmlContentHandler::startElement(), QXmlContentHandler::endElement(), and QXmlContentHandler::characters()函数,文档元素和文本会被处理。一旦文档已经完全被读取,需要重写QXmlContentHandler::endDocument()函数为了在内容上做某些终结或是确认。

2、QXmlDefaultHandler成员函数

[virtual] bool QXmlDefaultHandler::characters(const QString &ch)

当解析完了字符数据中的垃圾数据时,读取器会调用本函数

[virtual] bool QXmlDefaultHandler::comment(const QString &ch)

[virtual] bool QXmlDefaultHandler::endElement(const QString &namespaceURI, const QString &localName, const QString &qName)

[virtual] bool QXmlDefaultHandler::error(const QXmlParseException &exception)

[virtual] QString QXmlDefaultHandler::errorString() const

[virtual] bool QXmlDefaultHandler::fatalError(const QXmlParseException &exception)

[virtual] bool QXmlDefaultHandler::processingInstruction(const QString &target, const QString &data)

[virtual] bool QXmlDefaultHandler::startDocument()

[virtual] bool QXmlDefaultHandler::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts)

[virtual] bool QXmlDefaultHandler::endDocument()

[virtual] bool QXmlDefaultHandler::endEntity(const QString &name)

[virtual] bool QXmlDefaultHandler::endPrefixMapping(const QString &prefix)

[virtual] bool QXmlDefaultHandler::startEntity(const QString &name)

[virtual] bool QXmlDefaultHandler::startPrefixMapping(const QString &prefix, const QString &uri)

void characters(char[] ch,int start,int length)

SAX解析器处理字符数据时触发该方法

void endDocument():

SAX解析器处理文档结束时触发该方法

void endElement(String uri,String localName,String qName):

SAX解析器处理元素结束时触发该方法

void endPrefixMapping(String prefix)

SAX解析器处理元素里命名空间属性(即xmlns:prefix属性)结束时触发该方法

void ignorableWhitesapce(char[] ch,int start,int length)

SAX解析器处理元素内容中可忽略的空白时触发该方法

void skippedEntity(String name)

SAX解析器跳过实体时触发该方法

void startDocument():

SAX解析器开始处理文档时触发该方法

void startElement(String uri,String localName,String qName,Attributes atts):

SAX解析器开始处理元素时触发该方法

void startPrefixMapping(String prefix,String uri)

SAX解析器开始处理元素里命名空间属性(即xmlns:prefix属性)时触发该方法

void parse(InputSource input)

解析InputSource输入源中的XML文档

void parse(String systemId)

解析系统URI所代表的XML文档

四、SAX读取XML文档实例

1、QXmlSimpleReader解析器解析过程

QT中提供了一个基于SAX的简单的XML解析器QXmlSimpleReader,QXmlSimpleReader解析器需要QXmlInputSource为其提供数据,QXmlInputSource会使用相应的编码来读取XML文档的数据。在进行解析之前,还需要使用setContentHandler()来设置事件处理器,使用setErrorHandler()来设置错误处理器,使用参数this, 表明使用本类作为处理器,也就是在解析过程中出现的各种事件都会使用本类的startElement()等事件处理函数来进行处理,而出现错误时会使用本类的fatalError()函数来处理。最后,调用了parse()函数来进行解析,parse()函数会在解析成功时返回true,否则返回false。

2、工程实例

建立工程,在工程文件中添加XML模块支持。

自定义继承自QXmlDefaultHandler的类,类名为SAX_XML。重写QXmlDefaultHandler类的startElement()、endElement()、characters()和fatalError()函数,定义readXML()函数用来读入XML文件,QListWidget部件用来显示解析后的XML文档内容,currentText字符串变量用于暂存字符数据。

SAX_XML类文件如下:

sax_xml.h文件:

#ifndef SAX_XML_H
#define SAX_XML_H
#include <QXmlDefaultHandler>
#include <QListWidget>
#include <QString>
 
class SAX_XML : public QXmlDefaultHandler
{
public:
    SAX_XML();
    ~SAX_XML();
    bool readXML(const QString & fileName);
protected:
    bool characters(const QString &ch);
    bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
    bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts);
    bool fatalError(const QXmlParseException &exception);
private:
    QListWidget *list;
    QString currentText;
};
 
#endif // SAX_XML_H

sax_xml.cpp文件:

#include "sax_xml.h"
#include <QDebug>
 
SAX_XML::SAX_XML()
{
    list = new QListWidget;
    list->show();
}
 
bool SAX_XML::readXML(const QString &fileName)
{
    QFile file(fileName);
    // 读取文件内容
    QXmlInputSource inputSource(&file);
    // 建立QXmlSimpleReader对象
    QXmlSimpleReader reader;
    // 设置内容处理器
    reader.setContentHandler(this);
    // 设置错误处理器
    reader.setErrorHandler(this);
    // 解析文件
    return reader.parse(inputSource);
}
 
bool SAX_XML::characters(const QString &ch)
{
    currentText = ch;
    return true;
}
 
bool SAX_XML::endElement(const QString &namespaceURI, const QString &localName, const QString &qName)
{
    if (qName == "title" || qName == "author")
        list->addItem("        " + qName + " : " + currentText);
    return true;
}
 
bool SAX_XML::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts)
{
    if (qName == "library")
        list->addItem(qName);
    else if (qName == "book")
        list->addItem("    " + qName + atts.value("id"));
    return true;
}
 
bool SAX_XML::fatalError(const QXmlParseException &exception)
{
    qDebug() << exception.message();
    return false;
}
 
 SAX_XML::~SAX_XML()
 {
     delete list;
 }

Main.cpp文件:

#include "sax_xml.h"
#include <QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    SAX_XML reader;
    reader.readXML("test.xml");
 
    return a.exec();
}
时间: 2025-01-06 02:27:02

QT开发(四十三)——SAX方式解析XML的相关文章

Android系列之网络(四)----SAX方式解析XML数据

?[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4044170.html 联系方式:[email protected] [系列]Android系列之网络:(持续更新) Android系列之网络(一)----使用HttpClient发送HTTP请求(通过get方法获取数据) Android系列之网络(二)----HTTP请求头与响应头 Androi

XML —— SAX方式解析XML

1. SAX 方式解析 XML 原理 SAX 的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束.元素(element) 开始与结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同 样的扫描,直至文档结束. 优点:相对于DOM方式消耗资源比较少,适合大文件解析: 缺点:只能读取不能修改:开发复杂: 2. SAX 方式解析 XML 示例 扫描文档 import javax.xml.parsers.SAXParser; import javax.xml

XML引入,DOM 方式解析XML 原理,SAX 方式解析XML

XML 简介 Xml(eXtensible Markup Language) 即可扩展标记语言.提供了一套跨平台.跨网络.跨程序的语言的数据描述方式,使用XML 可以方便地实现数据交换.系统配置.内容管理等常见功能. 元素VS 节点 节点包括元素节点.属性节点.文本节点:元素一定是节点,但是节点不一定是元素: <?xml version="1.0" encoding="UTF-8"?> <emp> <empName empNo=&quo

SAX方式解析xml文件查看天气

1.SAX方式解析xml文件的步骤: ①创建解析器工厂对象 ②使用当前配置的工厂参数创建SAXParser对象 ③解析xml文件 ④利用DefaultHandler创建事件驱动者 2.对于标签对象进行引用怎么办? ①定义当前解析的标签:private String tagName=null; ②在startElement()方法中赋值tagName:this.tagName=qName; ③在endElement()方法中将tagName赋值为空:this.tagName=null; ④在cha

通过Sax方式解析xml文件

说明:此案例使用的是通过Dom方式解析xml文件这篇文章里的City类和china.xml文件. 1. 因为xml文件有两种格式,一是上面那篇文章里的那种元素节点里只包含属性节点,另一种就是元素节点里包含元素节点和文本节点,于是在china.xml中添加如下代码,以实现两种方式的解析: <city> <cityname>杭州</cityname> <pyName>zhejiang</pyName> <quName>浙江</quN

网络相关系列之四:数据解析之SAX方式解析XML数据

一.XML和Json数据的引入: 通常情况下.每一个须要訪问网络的应用程序都会有一个自己的server.我们能够向server提交数据,也能够从server获取数据.只是这个时候就有一个问题,这些数据是以什么格式在网络上传输的呢?一般我们都会在网络上传输一些格式化后的数据,这样的数据会有一定的结构规格和语言,当还有一方收到数据消息后就能够依照同样的结构规格进行解析.从而取出它想要的那部分内容. 在网络上数据传输最经常使用的格式:XML和Json.本文就来学习一下XML数据的解析,Json格式的数

SAX方式解析XML文件的方法分析

SAX(Simple API for XML)SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束.元素(element)开始与结束.文档(document)结束等地方时通知事件处理方法,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束.SAX解析方式适用于大型文档,因为他的解析是逐行进行不用像DOM中那样为所有节点创建对象,这样效率大大提高,所以虽然它不是W3C标准,但它却得到了广泛认可. 这是一个需要解析的XML文件: <?xml versio

在iOS 开发中用GDataXML(DOM方式)解析xml文件

因为GDataXML的内部实现是通过DOM方式解析的,而在iOS 开发中用DOM方式解析xml文件,这个时候我们需要开启DOM,因为ios 开发中是不会自动开启的,只有在mac 开发中才自动开启的.我们需要做如下配置: 当配置玩这个操作之后,再次进行编译的时候,系统还是报错,是因为我们还需要进行如下操作:

java中用SAX方式解析xml文件

SAX是Simple API for XML的缩写,它并不是由W3C官方所提出的标准.SAX是一种轻量型的方法,不像DOM解析时,把XML文档全部载入内存中,在PC上操作,Dom还有优势,但在手机中端上则无优势,因为手机内存和硬件都比不上PC强.使用 SAX 是比较安全的,并且 Android 提供了一种传统的 SAX 使用方法,以及一个便捷的 SAX 包装器.SAX采用基于事件驱动的处理方式,它将XML文档转换成一系列的事件,由单独的事件处理器来决定如何处理. 在SAX接口中,事件源是org.