一.前言
tuxedo8.1 集成了Apache Xerces C++ Version 1.7 XML Parser。Xerces 1.7既可以SAX事件驱动方式进行逐行解析,又可以DOM通过对象的树状集合访问XML Buffer。
xmlstockapp是Tuxedo 8.1自带的一个用于说明其集成的Xerces 1.7 XML Parser的功能的一个例子。xmlstockapp实现的功能如下:Client读取一个XML文件,把XML文件的内容置于XML Buffer中,向Server端发送请求;Server端应用进程对接收到的XML Buffer数据进行解析,并在XML Buffer中加入一个新的Element后,将新生成的XML Buffer数据传回Client端;Client端收到Server端返回的XML Buffer数据,对之进行解析并将其打印出来。
这个例子看似功能简单,但其源代码却要将近3000行(不包括相关的.h库文件中的代码)。例子的Readme文件和Tuxedo 8.1 OnlineDoc中只介绍了如何运行这个例子,而要能真正通过这个例子举一反三、灵活运用,那是非要读透它的源代码不可。写这篇文章,只是想从这堆略显 纷乱的代码理出一条思路来,仅供参考。
二.Client端程序源代码解析
从xmlstockapp目录下的README.nt文件可知编译Client端程序采用需如下命令行输入:
buildclient -o Client -f Client.cpp -f SAXPrint.cpp -f SAXPrintHandlers.cpp -f %TUXDIR%liblibtxml.lib
很容易看出,Client端程序对XML Buffer的解析采用了SAX解析方式。
1. 先看Client.cpp,一段典型的request/response同步调用,唯一显眼的语句便是parseXMLBuffer(rcvbuf);
这句函数调用,其函数声明为:
extern void parseXMLBuffer (char * rcvbuf);
这是一个在SAXPrint.cpp中定义的外部函数,用于解析XML Buffer的数据并将其打印出来。
2. 再看SAXPrint.cpp和SAXPrint.hpp这两个源文件。
主要分析void parseXMLBuffer(char* xmlbuf)这一函数的实现:
a) 初始化:
XMLPlatformUtils::Initialize();
b) 声明一个SAXParser对象:
SAXParser* parser = new SAXParser;
c) 然后用XML Buffer的地址初始化一个MemBufInputSource对象:
MemBufInputSource* memBufIS = new MemBufInputSource( (const XMLByte*)xmlbuf, strlen(xmlbuf)-1, bufId, true);
d) 然后声明一个SAXPrintHandlers对象:
SAXPrintHandlers handler(encodingName, unRepFlags);
SAXPrintHandlers类在SAXPrintHandlers.hpp和SAXPrintHandlers.cpp中声明和定义。
e) 将handler设为parser的DocumentHandler和ErrorHandler:
parser->setDocumentHandler(&handler);
parser->setErrorHandler(&handler);
SAXPrintHandlers类间接继承了DocumentHandler类和ErrorHandler类。
f) 用SAXParser::parse (const InputSource& source, const bool reuseGrammar = false)方法进行解析:
parser->parse(*memBufIS);
g) 删除SAXParser对象:
delete parser;
h) 中止:
XMLPlatformUtils::Terminate();
3. 再看SAXPrintHandlers.cpp和SAXPrintHandlers.hpp这两个源文件。
SAXPrintHandlers类继承了HandlerBase类和XMLFormatTarget类:
a) HandlerBase类主要表示了SAX默认解析行为的接口,它继承了EntityResolver, DTDHandler, DocumentHandler和ErrorHandler这四个类。其中,DocumentHandler,ErrorHandler和 DTDHandler这三个类的成员方法主要表示了当SAX解析时各种被触发的相应事件的回调(callback)执行函数。
b) XMLFormatTarget类主要对XML数据进行格式化操作。
重载你所需要实现的成员函数,尤其是那些相应SAX解析时各种被触发的事件的回调(callback)执行函数(这很类似于微软MFC的设计思想)。尤其是对DocumentHandler和ErrorHandler这两个类的一些成员方法的重载:
a) 重载DocumentHandler类的成员方法可助你实现在SAX解析器
开始解析XML文档时 [void startDocument();]、
解析到XML文档末尾时 [void endDocument();]、
开始解析XML的一个元素时 [void startElement(const XMLCh* const name, AttributeList& attributes);]、
解析完XML的一个元素时 [void endElement(const XMLCh* const name);]、
解析XML元素中的字符时[void characters(const XMLCh* const chars, const unsigned int length);]
等等这些事件触发的时候你所需要添加的执行动作,方法是把这些执行动作的代码加入这些回调函数中即可。
b) 重载ErrorHandler类的成员方法可助你实现在SAX解析器在解析过程中,在遇到各种异常时触发的事件而执行的回调函数中加入一些客户化的操作(比如打印出异常信息)。可能的异常类型可包括:
void warning(const SAXParseException& exception);
void error(const SAXParseException& exception);
void fatalError(const SAXParseException& exception);
void resetErrors();
小总结:
调用Xerces 1.7的SAX解析器的关键步骤:
继承HandlerBase类,重载其相应的有关SAX解析时事件响应的回调(callback)执行函数,并把客户化的代码加入其中。