http://hi.baidu.com/nerdwa/blog/item/a8a8454a80f5c51cb2de05a6.html
摘 要:XML文档是近年来比较流行的结构化文档形式,其主要用途不只适用于开发网页,而且在其他场合也有很广泛的应用。本文主要介绍用VC++开发应用程序时对XML文档的解析。
一、 XML 简介
XML(Xtensible Markup Language,即扩展标记语言)的发展起源于1996年。当时,出版界巨头和Web业内人士经过共同讨论,提出了创建SGML(Standard Generalized Markup Language,即标准通用标识语言)子集(HML)的建议。该子集专用于Web,具有可扩展(或可扩充)性,并且能利用结构化标记语言的所有高级功能,但摒弃了SGML的复杂性。XML规范的第一份草稿于1996年11月发布后不久,1997年1月首个XML解析器就面世了。随后,便出现了XML的应用以及新的规范和解析器。
HTML(Hypertext Markup Language)语言是大家所熟悉的开发网页的一种标记语言,但它不是一种编程语言,它的主要标记是针对文档内容本身结构的描述,因机器本身是不能够解析它的内容的。XML语言是SGML语言的子集,它保留了SGML主要的使用功能,同时大大减小了SGML的复杂性。它不仅能表示文档的内容,而且可以表示文档的结构,这样在能够被人类理解的同时,也能够被机器所理解。虽然HTML是SGML的一个应用,XML是SGML的一个子集,但是XML绝不是在HTML上添加某些元素而形成的,它们之间是有很大区别的。最大的区别就是XML允许使用者为某种特殊目的而定义自已的元素。除此之外,另一个最主要的区别就是XML致力解决的问题,正是在使用HTML时所遇到的一些特殊问题。
XML要求遵循一定的严格标准,其分析程序比HTML浏览器对语法和结构的要求更加严格。XML文档每次分析的结果都一致,而HTML在不同的浏览器中可能会作出不同的分析和显示。同时,XML标准是对数据的处理应用,而不只是针对Web页的,它还可涉及到数据库电子商务系统,以及任何显示系统的高级应用。开发者可根据特定的工业需求,利用XML创建自定义的数据结构。这些数据结构和数据库可以在许多设备上查看,而不需要使用自定义的接口在不同的显示设备上查看相同的数据。
XML主要有三个要素:文档类型声明(DTD:Document Type Declaration)或XML Schema(XML大纲)、可扩展样式语言(XSL:eXtensible Stylesheet Language)和可扩展链接语言(XLink:eXtensible Link Language)。DTD和XML大纲规定了XML文件的逻辑结构,定义了XML文件中的元素、元素的属性以及元素与元素属性之间的关系;Namespace(名域)实现了统一的XML文档数据表示以及数据的相互集成;XSL是用于规定XML文档呈现样式的语言,它使得数据与其表现形式相互独立,比如XSL能使Web浏览器改变文档的表示法,如数据显示顺序的变化,不需要再与服务器进行通讯。通过改变样式表,同一个文档可以显示得更大,或者经过折叠只显示外面的一层,或者可以变为打印的格式。而XLink 将进一步扩展目前Web上已有的简单链接。
二、文档对象模型(DOM)
DOM是Document Object Model(文档对象模型)的简称,是对Web文档进行应用开发、编程的应用程序接口(API)。作为W3C公布的一种跨平台、与语言无关的接口规范,DOM提供了在不同环境和应用中的标准程序接口,可以用任何语言实现。
DOM采用对象模型和一系列的接口来描述XML文档的内容和结构,即利用对象把文档模型化。这种对象模型实现的基本功能包括:
● 描述文档表示和操作的接口;
● 接口的行为和属性;
● 接口之间的关系以及互操作。
DOM可对结构化的XML文档进行解析,文档中的指令、元素、实体、属性等所有内容个体都用对象模型表示,整个文档被看成是一个有结构的信息树,而不是简单的文本流,生成的对象模型就是树的节点,对象同时包含了方法和属性。因此,对文档的所有操作都是在对象树上的进行。在DOM中,树中的一切都是对象,不管是根节点还是实体的属性。
在DOM中主要有以下三个对象:
● XML文档对象 XML文档既是一种对象,同时又代表整个XML文档。它由根元素和子元素组成。
● XML节点对象 XML节点对象代表的是XML文档内部的节点,如元素、注释、名字空间等。
● XML节点列表 XML文档模块列表代表了节点的集合。
利用DOM,开发人员可以动态地创建XML文档,遍历结构,添加、修改、删除内容等。其面向对象的特性,使人们在处理XML解析相关的事务时节省大量的精力,是一种符合代码重用思想的强有力编程工具。
三、MSXML
从理论上说,根据XML的格式定义,我们可以自己编写一个XML的语法分析器,但实际上微软已经给我们提供了一个XML语法解析器,即一个叫做MSXML.DLL的动态链接库,实际上它是一个COM(Component Object Model)对象库,里面封装了进行XML解析时所需要的所有对象。因为COM是一种以二进制格式出现的和语言无关的可重用对象,所以你可以用任何语言(比如VB,VC,DELPHI,C++ Builder甚至是剧本语言等等)对它进行调用,在你的应用中实现对XML文档的解析。
MSXML.DLL所包括的主要COM接口有:
1. DOMDocument
DOMDocument对象是XML DOM的基础,你可以利用它所暴露的属性和方法来浏览、查询和修改XML文档的内容和结构。DOMDocument表示了树的顶层节点,它实现了DOM文档的所有的基本方法,并且提供了额外的成员函数来支持XSL和XSLT。它创建了一个文档对象,所有其他的对象都可以从这个文档对象中得到和创建。
2. IXMLDOMNode
IXMLDOMNode是文档对象模型(DOM)中的基本对象,元素、属性、注释、过程指令和其他的文档组件都可以认为是IXMLDOMNode。事实上,DOMDocument对象本身也是一个IXMLDOMNode对象。
3. IXMLDOMNodeList
IXMLDOMNodeList实际上是一个节点(Node)对象的集合,节点的增加、删除和变化都可以在集合中立刻反映出来,可以通过"for...next"结构来遍历所有的节点。
4. IXMLDOMParseError
IXMLDOMParseError接口用来返回在解析过程中所出现的详细的信息,包括错误号、行号、字符位置和文本描述。
在具体应用时可以用DOMDocument的Load方法来装载XML文档,用IXMLDOMNode 的selectNodes(查询的结果有多个,得到存放搜索结果的链表)或selectSingleNode(查询的结果有一个,在有多个的情况下返回找到的第一个节点)方法进行查询,用createNode和appendChild方法来创建节点和追加节点,用IXMLDOMElement的setAttribute和getAttribute方法来设置和获得节点的属性。
四、程序实现
1、XML文档的例子:
<?xml version="1.0" ?>
<xmlDoc>
<天气>睛</天气>
<温度>
<早上>18</早上>
<中午>32</中午>
<晚上>16</晚上>
</温度>
</xmlDoc>
整个文档便是一个文档对象DOMDoccument,
DOMDoccument下的NodeList有两个,像天气,早上,晚上等等就是Node
2、准备活动
#import<msxml3.dll>或#import<msxml14.dll> 注意:不要用#import<msxml.dll>,因为解析时用到的许多方法在msxml 2.0以前版本中是没有的。
3、初始化COM接口
::CoInitialize(NULL);
4、正式编码
注意:
所有代码均要放在COM接口初始化后的{}中,要不会有智能指针的错误。
1)、定义
MSXML2::IXMLDOMDocumentPtr DocPtr; //DOMDocument
MSXML2::IXMLDOMNodePtr NodePtr; //IXMLDOMNode
MSXML2::IXMLDOMNodeListPtr Listptr; //IXMLDOMNodeList
2)、打开文档
HRESULT hr = S_OK;
hr = DocPtr.CreateInstance(__uuidof(MSXML2::DOMDocument40)); //初始化环境
if( !SUCCEEDED(hr))
{
return;
}
DocPtr->preserveWhiteSpace = VARIANT_FALSE; //打开文档
DocPtr->validateOnParse = VARIANT_FALSE;
VARIANT_BOOL vbSuccessful = VARIANT_FALSE;
vbSuccessful = DocPtr->load( COleVariant((LPCSTR)strXmlFilePath));
if(vbSuccessful == VARIANT_FALSE)
{
return;
}
3)、使用所提供的方法处理文档
所用方法读者可以自己去试,功能可以通过名字开知道,参数和返回值函数由定义可以知道,用户可以根据自己需要去自己使用。
4)、以下是我读过一个文档的代码,希望会对使用者有所帮助
CString strXmlFilePath = "E:\\XML20060826\\XML20060826\\sj.xml"; //文件名
int k = 0;
::CoInitialize(NULL);
{
MSXML2::IXMLDOMNodeListPtr ListPtr0; //根层 xml + 站名站号表
MSXML2::IXMLDOMNodeListPtr ListPtr1; //第一层 交路数 + 交路数据...
MSXML2::IXMLDOMNodeListPtr ListPtr2; //第二层 交路号 + 车站数据...
MSXML2::IXMLDOMNodeListPtr Listptr3; //第三层 车站信息
MSXML2::IXMLDOMDocumentPtr DocPtr; //主文档 从此入手
MSXML2::IXMLDOMNodePtr NodePtrJL; //存交路号
MSXML2::IXMLDOMNodePtr NodePtrCZ; //车站数据
HRESULT hr = S_OK;
hr = DocPtr.CreateInstance(__uuidof(MSXML2::DOMDocument40)); //初始化环境
if( !SUCCEEDED(hr))
{
// ::AfxMessageBox("S");
return;
}
DocPtr->preserveWhiteSpace = VARIANT_FALSE; //打开文档
DocPtr->validateOnParse = VARIANT_FALSE;
VARIANT_BOOL vbSuccessful = VARIANT_FALSE;
vbSuccessful = DocPtr->load( COleVariant((LPCSTR)strXmlFilePath));
if(vbSuccessful == VARIANT_FALSE)
{
return;
}
ListPtr0 = DocPtr->GetchildNodes(); //入根层
ListPtr1 = ListPtr0->Getitem(1)->GetchildNodes(); //进入站名站号表结点下
for(long i = 1; i < ListPtr1->Getlength(); i++)
{
ListPtr2 = ListPtr1->Getitem(i)->GetchildNodes(); //进入交路数据结点下
ListPtr2->Getitem(0)->GetfirstChild()->Gettext(); //得交路号
long m = ListPtr2->Getlength();
for(long j = 1; j < ListPtr2->Getlength(); j++)
{
Listptr3 = ListPtr2->Getitem(j)->GetchildNodes(); //车站数据结点下
for(long k = 0; k < Listptr3->Getlength(); k++)
{
try
{
Listptr3->Getitem(k)->GetfirstChild()->Gettext();
//车站号,站名,Up_in ,Up_out, Down_in,Down_out
}
catch(_com_error &Err)//
{
// ::AfxMessageBox(Err.ErrorMessage());
continue;
}
}
}
}
}
}
五、结束语
因为XML文档有着比HTML更严格的语法要求,所以使用和编写一个XML解析器要比编写一个HTML解析器要容易得多。同时因为XML文档不仅可以标记文档的显示属性,更重要的是它标记了文档的结构和包含信息的特征,所以我们可以方便地通过XML解析器来获取特定节点的信息并加以显示或修改,方便了用户对XML文档的操作和维护。同时我们需要注意的是,XML是一种开放的结构体系,并不依赖于任何一家公司,所以开发基于XML的应用必然会得到绝大多数软件开发平台的支持。