XML解析之SAX方式

XML文件解析方式之一是SAX方式,SAX解析方式会逐行地去扫描XML文档,当遇到标签时会触发解析处理器,采用事件处理的方式解析XML (Simple API for XML) 。SAX是一个用于处理XML事件驱动的“推”模型,虽然不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。

SAX解析不像DOM那样建立一个完整的文档树,而是在读取文档时激活一系列事件,这些事件被推给事件处理器,然后由事件处理器提供对文档内容的访问。常见的事件处理器有三种基本类型:

  • 用于访问XML DTD内容的DTDHandler;
  • 用于低级访问解析错误的ErrorHandler;
  • 用于访问文档内容的ContentHandler,这也是最普遍使用的事件处理器。

  解析器读取输入文档并在处理文档时将每个事件推给文档处理器(MyContentHandler)。

   与DOM相比,SAX解析器能提供更好的性能优势,它提供对XML文档内容的有效低级访问。SAX模型最大的优点是内存消耗小,因为整个文档无需一次加载到内存中,这使SAX解析器可以解析大于系统内存的文档。另外,你无需像在DOM中那样为所有节点创建对象。最后,SAX“推”模型可用于广播环境,能够同时注册多个ContentHandler,并行接收事件,而不是在一个管道中一个接一个地进行处理。

  SAX的缺点是必须实现多个事件处理程序以便能够处理所有到来的事件,同时你还必须在应用程序代码中维护这个事件状态,因为SAX解析器不能交流元信息,如DOM的父/子支持,所以你必须跟踪解析器处在文档层次的哪个位置。如此一来,你的文档越复杂,你的应用逻辑就越复杂。虽然没有必要一次将整个文档加载到内存中,但SAX解析器仍然需要解析整个文档,这点和DOM一样。也许SAX面临的最大问题是它没有内置如XPath所提供的那些导航支持。再加上它的单遍解析,使它不能支持随机访问。这一限制也表现在名字空间上: 对有继承名字空间的元素不做注解。这些限制使SAX很少被用于操作或修改文档。

  那些只需要单遍读取内容的应用程序可以从SAX解析中大大受益。很多B2B和EAI应用程序将XML用做封装格式,接收端用这种格式简单地接收所有数据。这就是SAX明显优于DOM的地方:因高效而获得高吞吐率。在SAX 2.0 中有一个内置的过滤机制,可以很轻松地输出一个文档子集或进行简单的文档转换。

 一、SAX解析方式的步骤

SAX解析可分四个步骤进行:

  1. 得到xml文件对应的资源,可以是xml的输入流,文件或uri
  2. 得到SAX解析工厂(SAXParserFactory)
  3. 由解析工厂生产一个SAX解析器(SAXParser)
  4. 传入输入流和handler给解析器,调用parse()解析

二、SAX的常用接口介绍

1、ContentHandler接口

 该接口封装了一些对事件处理的方法,当XML解析器开始解析XML输入文档时,它会遇到某些特殊的事件,比如文档的开头和结束、元素开头和结束、以及元素中的字符数据等事件。当遇到这些事件时,XML解析器会调用ContentHandler接口中相应的方法来响应该事件。ContentHandler接口的方法有以下几种:

  void startDocument()
  void endDocument()
  void startElement(String uri, String localName, String qName, Attributes atts)
  void endElement(String uri, String localName, String qName)
  void characters(char[ ] ch, int start, int length)

2、ErrorHandler接口

  ErrorHandler接口是SAX错误处理程序的基本接口。如果SAX应用程序需要实现自定义的错误处理,则它必须实现此接口,然后解析器将通过此接口报告所有的错误和警告。该接口的方法如下:

  void error(SAXParseException exception)
  void fatalError(SAXParseException exception)
  void warning(SAXParseException exception)

3、DTDHandler接口

DTDHandler用于接收基本的DTD相关事件的通知,仅包括DTD事件的注释和未解析的实体声明部分。SAX解析器可按任何顺序报告这些事件,而不管声明注释和未解析实体时所采用的顺序;但是,必须在文档处理程序的startDocument()事件之后,在第一个startElement()事件之前报告所有的DTD事件。DTDHandler接口包括以下两个方法:

  void startDocumevoid notationDecl(String name, String publicId, String systemId) nt()
  void unparsedEntityDecl(String name, String publicId, String systemId, String notationName)

4、EntityResolver接口

EntityResolver接口是用于解析实体的基本接口,该接口只有一个方法,如下:

  public InputSource resolveEntity(String publicId, String systemId)

  解析器将在打开任何外部实体前调用此方法。此类实体包括在DTD内引用的外部DTD子集和外部参数实体和在文档元素内引用的外部通用实体等。如果SAX应用程序需要实现自定义处理外部实体,则必须实现此接口。

三、Xerces C++ SAX解析XML文档

1、编译xerces

https://blog.csdn.net/t18438605018/article/details/117478843

2、在工程中使用xerces

  1. 编译xerces成功后,在生成目录会生成xerces-c_3_1D.dll,xerces-c_3_1D.lib。(如果是release模式,就不会有后面的D)
  2. 新建VS工程,添加C++/include目录和link/xerces-c_3_1D.lib,拷贝xerces-c_3_1D.dll到工程生成目录
  3. 添加测试程序
// MySAXHandler.h
#pragma once  
#include <xercesc/sax2/DefaultHandler.hpp>  
#include <xercesc/sax2/Attributes.hpp>

XERCES_CPP_NAMESPACE_USE

class MySAX2Handler : public DefaultHandler
{
public:
	MySAX2Handler();
	~MySAX2Handler();
public:
	void startElement(
		const   XMLCh* const    uri,
		const   XMLCh* const    localname,
		const   XMLCh* const    qname,
		const   Attributes&     attrs);
	void characters(
		const   XMLCh* const    chars,
		const XMLSize_t       length);
	void endElement(
		const XMLCh* const uri,
		const XMLCh* const localname,
		const XMLCh* const qname);
	void fatalError(const SAXParseException&);
};

// MySAXHandler.cpp

#include "MySAXHandler.h"
#include <iostream>

MySAX2Handler::MySAX2Handler()
{
}

MySAX2Handler::~MySAX2Handler()
{
}

void MySAX2Handler::startElement(
	const   XMLCh* const    uri,
	const   XMLCh* const    localname,
	const   XMLCh* const    qname,
	const   Attributes&     attrs)
{
	char* message = XMLString::transcode(qname);
	std::cout << "start element: " << message << std::endl;
	XMLString::release(&message);
}

void MySAX2Handler::fatalError(const SAXParseException& exception)
{
	char* message = XMLString::transcode(exception.getMessage());
	std::cout << "Fatal Error: " << message
		<< " at line: " << exception.getLineNumber()
		<< std::endl;
	XMLString::release(&message);
}

void MySAX2Handler::characters(const XMLCh* const chars, const XMLSize_t length)
{
}

void MySAX2Handler::endElement(
	const XMLCh* const uri,
	const XMLCh* const localname,
	const XMLCh* const qname) 
{
	char* message = XMLString::transcode(qname);
	std::cout << "end element: " << message << std::endl;
	XMLString::release(&message);
}
// main.cpp
#include <xercesc/util/PlatformUtils.hpp>  
#include <xercesc/sax2/SAX2XMLReader.hpp>  
#include <xercesc/sax2/DefaultHandler.hpp>  
#include <xercesc/sax2/XMLReaderFactory.hpp>  
#include <xercesc/util/XMLString.hpp>  
#include <iostream>

#include "MySAXHandler.h"

int main(int argc, char*  args[])
{
	try 
	{
		XMLPlatformUtils::Initialize();
	}
	catch (const XMLException& toCatch)
	{
		char* message = XMLString::transcode(toCatch.getMessage());
		std::cout << "Error during initialization! :\n";
		std::cout << "Exception message is: \n"
			<< message << "\n";
		XMLString::release(&message);
		return 1;
	}

	const char* xmlFile = "./data/personal.xml";
	SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();
	parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
	parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);   // optional
	parser->setFeature(XMLUni::fgXercesDynamic, false);
	parser->setFeature(XMLUni::fgXercesSchema, true);
	parser->setFeature(XMLUni::fgXercesSchemaFullChecking, true);

	MySAX2Handler* defaultHandler = new MySAX2Handler();
	parser->setContentHandler(defaultHandler);
	parser->setErrorHandler(defaultHandler);
	parser->setEntityResolver(defaultHandler);

	try
	{
		parser->parse(xmlFile);
	}
	catch (const XMLException& toCatch)
	{
		char* message = XMLString::transcode(toCatch.getMessage());
		std::cout << "Exception message is: \n"
			<< message << "\n";
		XMLString::release(&message);
		return -1;
	}
	catch (const SAXParseException& toCatch)
	{
		char* message = XMLString::transcode(toCatch.getMessage());
		std::cout << "Exception message is: \n"
			<< message << "\n";
		XMLString::release(&message);
		return -1;
	}
	catch (...) 
	{
		std::cout << "Unexpected Exception \n";
		return -1;
	}
	//defaultHandler->OutputPsList();
	delete parser;
	delete defaultHandler;
	XMLPlatformUtils::Terminate();
	system("PAUSE");
	return 0;

}

运行结果:

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值