XML提供了不同或不相似的系统之间表达或交流信息的功能强大和灵活的方式。XML也是基于文本格式的,它在许多方面与HTML相似。例如,XML文档中也包含有开始(例如<font>)、结束(例如</font>)标志。与HTML不同的是,我们可以在XML中使用任何喜欢的标志━━使用多少标志或如何给它们命名都由我们自己来定。
MXXMLWriter组件基础知识
创建XML文档的最大困难在于,XML文档应该符合一些基本的格式规则━━例如确保其中的元素不会重迭。尽管我们可以很容易地保证新的XML文档符合XML规格所定义的基本格式,但使用第三方的组件来管理它的输出会更加简单和安全。在本篇文章中我们将介绍的是MXXMLWriter,它是微软的MS XML Parser 3.0的一部分。
说起解析器,我们一般会想到在其输入端需要输入一些数据,然后在其输出端得到一系列的符号。微软的XML Parser与规则解析器的作用非常相似,它在输入端接受一个XML文档,然后在输出端生成一个XML文档对象模型(DOM)━━XML文档的一种基于对象的表达方式,或者生成一系列的Simple API for XML(SAX)事件。无论生成哪种输出格式,其输入都是XML文档。
MXXMLWriter是微软XML parser的一部分,对于通过编程方式创建XML文档非常有用。使用MXXMLWriter比自己动手创建XML文档有许多好处,其中包括:
·MXXMLWriter产生的XML文档符合W3C XML 1.0 Namespace推荐标准,我们无需关心输出格式,因为解析器能够为我们解决这一切。
·我们可以将MXXMLWriter的输出与SAX Content Handler绑定在一块儿,以较少的内存快速进行处理。
·基于界面的编程模式使我们的代码更容易阅读和维护,我们可以将输出发送给一个支持IStream界面的String或COM对象。
处理XML文档的基础知识
在能够使用MXXMLWriter组件创建新的XML文档之前,我们需要了解一些处理XML文档的基本知识,因为MXXMLWriter希望使用它的应用程序能够成为SAX事件提供者。
处理XML文档有二种方式:使用文档对象模型(DOM)或者Simple API for XML(SAX)。二种方法在各种应用中各有优、缺点,DOM在XML文档查询方面有优势,SAX在快速处理超大型XML文档方面有优势,而且能够使我们完全控制解析的过程。
使用DOM处理XML文档
当将XML文档加载至DOM中时,XML解析器会读取整个文档,在内存中创建许多表达这一文档的对象。下面的图1显示了一个简单的XML文档片段和DOM如何在内存中表示它:
图1显示,Document类的实例表示一个XML文档(图1中的第一部分),XML文档中包含有节点(图1中的第二部分),这些节点是DOM Node对象的实例。(图1中的第三部分)。
一旦DOM已经将全部XML文档读入内存,DOM就为你处理XML文档作好所有的准备了。我们可以通过使用循环重复处理其中的内容、使用XPath表达式查询特定的节点或随机访问DOM树的任意部分对DOM中的元素进行操作。关健是我们的应用程序能够对XML文档进行完整的控制,可以从文档在内存中的表示中提取所需要的信息。
使用SAX处理XML文档
SAX编程模式与DOM编程模式完全不同。通过让应用程序截获XML解析器在处理XML文档时产生的事件,SAX可以使应用程序更接近XML解析器。由于事件是被推送到应用程序中的,因此,它提供的是一种“推”编程模式,应用程序无需象在使用DOM时那样作为一个控制点。
,XML Reader(图2中的第一部分)负责读取XML文档。XML Reader请求了我们提供的一个组件,它在读取XML文档时调用了其界面中的方法。(图2中的第二部分)我们的应用程序(图2中的第三部分)则使用组件的输出。
在图2中,一个包含有ISAXXMLReader的组件被用作XML Reader。要使用SAX处理XML文档,需要在ISAXContentHandler界面中注册一个组件。当XML Reader遇到文档中的元素时,它调用ISAXContentHandler方法处理startDocument、startElement等元素和提供有关XML Reader读取的元素信息的字符。图3显示了一个事件的序列,该事件序列是XML Reader在处理样例文件(图1、2中出现的)时生成的。
使用MXXMLWriter创建XML文档
MXXMLWriter是SAX的消费者,意味着使用MXXMLWriter的应用程序是SAX的提供者,MXXMLWriter使用SAX事件编写出正确格式的XML文档。
本篇文章中的例子代码是一个能够读取以“,”分割的文件并产生XML文档的控制台应用程序,它产生的XML文档显示在屏幕上,我们可以将其输出捕捉到文本文件中,并保存在磁盘上。例子代码使用STL(标准模板库)对文件的读取进行管理。下面的表1显示了MXXMLWriter的具体代码,它能够建立指向ISAXContentHandler等界面的指针:
Listing 1 - Instanciating MXXMLWriter// MSXML2::IMXWriterPtr是一个智能化指针
MSXML2::IMXWriterPtr pXMLWriter;
pXMLWriter.CreateInstance(__uuidof(MSXML2::MXXMLWriter));
// ISAXContentHandler是一个由MXXMLWriter使用的界面
MSXML2::ISAXContentHandlerPtr pContentHandler;
pContentHandler=pXMLWriter; //calls QI for ISAXContentHandler on pXMLWriter
//ISAXErrorHandler是一个由MXXMLWriter使用的界面
MSXML2::ISAXErrorHandlerPtr pErrorHandler;
pErrorHandler=pXMLWriter; //calls QI for ISAXErrorHandler on pXMLWriter
// ISAXDTDHandler也是由MXXMLWriter使用的界面
MSXML2::ISAXDTDHandlerPtr pDTDHandler;
pDTDHandler=pXMLWriter; //calls QI for ISAXDTDHandler on pXMLWriter
//将输出内容输出到一个字符串中
pXMLWriter->put_output(CComVariant(L""));
一旦MXXMLWriter完成了,程序就会读取文本文件,并生成供MXXMLWriter处理的SAX事件。程序如下面的表2所示:
表2:生成供MXXMLWriter使用的事件
std::getline(fileIn,lineFromFile);
while(fileIn.good())
{
npos=lineFromFile.find_first_of(",",nlast);
//确定当前行有一个“,”号;
//如果没有发现,find_first_of返回std::wstring::npos
if(npos!=std::wstring::npos){
wElementName=A2W(lineFromFile.substr(nlast,npos-nlast).c_str());
// startElement元素
pContentHandler->startElement(L"",0,L"",0,
const_cast<wchar_t*>(wElementName.c_str()),
wElementName.length(),NULL);
nlast= ++npos;
// 获取当前行的其他部分(元素值)
wElementValue=A2W(lineFromFile.substr(nlast).c_str());
// 字符
pContentHandler->characters(
const_cast<wchar_t*>(