### XML 编程实例

前
1.什么是 XML?
首先，我想各位应该都已经大概知道什么是 XML 了。如果，你对什么是 XML 还没有一个概念的话，你可以看一些相关的材料，我就不多说了。
2.为什么要用 XML?
首先，写的程序需要传送很多的数据结构，比如表格，目录树等等。要在以往，我想自己会去定义一个数据结构。这是相当麻烦的一件事情，而且当这个结构需要不断更新，有很大的灵活性时，那就更让人头疼了，更别说通用性和跨平台了。这时候，XML 对树形结构数据的强大表达能力就显示出来了。比如一个表格数据。
<TABLE>
<TR>
<TD> 11</TD>
<TD>12</TD>
</TR>
<TR>
<TD> 21</TD>
<TD>22</TD>
</TR>
</TABLE>
11
12
21
22
以上的描述，很简单明了，通用性和跨平台是很显见的。当然，代价也是有的，那就是用于表达信息的数据变大了。这就要求你在性能和可扩展性之间进行权衡了。
再次，XML 现在已经开始流行起来了，其前身（说类似更合适）HTML 就是一个明证，更不用说微软的.NET 计划就是架构在 XML 上面的。
最后，因为 XML 的流行，已经有了越来越多的开发工具(SDK)，比如 XML Parser 就有很多种。利用这些工具，我们就可以更快的进行开发，从而减少不必要的麻烦----比如自己定义一套规范，还要开发相关的操作工具等等，麻烦，而且不易与外界进行交流。
3．使用什么开发工具
这里，我们面向的是程序员，犹指 VC++的程序员。我们的选择很多，不过选择 Microsoft 的 XML Parser SDK 应该是不错的，至少文档很详尽（在这一点上，微软做得一直不错）。当然还有很多别的选择，比如 Apache.org 上的 eXcel。更详细的信息，请看 www.ibm.com/xml。
基本概念
XML 的编程模式
前面我们说过，XML 对树的表达能力是很强大的，我们完全可以把一个 XML 文档用一个树来表达，对于文档的操作就是对树的操作，这就是 DOM（文档对象模型）。然而，DOM 对 XML 文档的处理有许多的毛病，比如速度慢等，于是有了另一种模型 SAX.
下面，我们分别详细的对这两种模型进行说明。
DOM 模型
DOM 模型需要对整个 XML 文档进行扫描，然后解析生成一个对象树，XML 文档中的所有标签和属性都是用对象来表示，而不是一个孤立的文本。因为是对象，所以有一个上下文，有一个包含关系。
基本是这样的
Doc
Element
Note
Text
Doc 是指整个树对象，包括了基本的属性。
Element 是指的一个标签，可以包含属性(Attribute)和子节点（ChilNode）的节点对象。
Note 也是一个标签，不过不能包含子节点和属性。
Text 就是简单的文本。
既然是树操作，就要包含节点的添、删和浏览等基本的功能。利用这些功能，就可以完全对 XML 文档进行操作了。对象级的操作，比起直接对文本操作要容易得多，也要直观得多。
SAX 模型
我们说了，DOM 模型的缺点就是速度慢，和浪费内存。因为在许多的情况下，我们并不需要对整个的 XML 文档进行扫描。而仅仅需要其中的某些信息，这时候就没有必有生成一个庞大的树结构了，特别是当文件很大的时候。
SAX 模型，就是对 XML 文档边扫描，边处理。类似于许多的程序设计思想，SAX 是事件驱动的。这个意思是说，它可以在处理的过程中生成不同的消息，并调用相应的函数进行处理。并可以在中途退出，这一点非常重要。比如网页在下载的过程中，就可以一边下载，一边把已下部分进行解析显示。
根据不同的情况，我们采用不同的方法进行处理。
应该说明的是，XML 的这些模型都是标准化组织定义的，而不是某个公司的规范。所以，程序的移植应该比较的方便。
XML 编程举例
由于 Microft XML Parser 的文档比较的全面，而且和 Visual C++的结合比较紧密，我们这里就以这样的组合来进行举例，对于别的语言，可以举一反三。
对 Microsoft XML Parser 的一点说明：
所有的对象都是 COM 对象。为此，我们使用 SmartPointer 来减少 AddRef,ReleaseRef 的麻烦。同样，因为使用的字符串统一是 BSTR 类型的，内存的释放也是一个比较麻烦的事情，所以用_bstr_t 类来对 BSTR 数据类型进行封装，可以减少不必要的麻烦。
DOM 模型：
前面已经说了，对于 DOM 模型来说，整个 XML 文件被解析成一个树形的结构。所有的标签、属性等都被当作对象来看待。所以，必须了解清楚对象的含义，及其相互关系，方能正确操作。
为了先有一个感性认识，让我们开始吧。（为了方便说明，代码里基本上没有异常处理）
生成一个 XML 文本
假设我们要创建一个如下的 XML 文本
<China>
<Beijing> -11 </Beijing>
<Shanghai weather=”Cloudy”> 9 </Shanghai>
</China>
我们首先应该先创建一个 Document 对象，如下：MSXML::IXMLDOMDocumentPtr pDoc;
pDoc.CreateInstance(__uuidof(MSXML::DOMDocument));
如果创建成功，那么我们就会得到一个 XMLDOMDocument 对象实例。
下一步就是添加 根节点 DocumentElement，记住 XML 只有一个根。
创建 Element 对象 作为根节点
MSXML::IXMLDOMElementPtr pDocElement=pDoc->createElement("China");
把根节点插入到目录树中
pDoc->appendChild(pDocElement);
好了，生成一个树根了，我们现在来看一看结果：
用 pDoc -> xml 可以取得整个 DOM 对象的文本
因为树根下没有任何东西，所以只显示<China/>
现在，我们要在树根下插入子节点，并设置节点文本(Text)
MSXML::IXMLDOMElementPtr pNewChildElement;
pNewChildElement=pDoc->createElement("Beijing");
pNewChildElement->Puttext("-11");
pDocElement->appendChild(pNewChildElement);
这时候整个的 XML 文本应该为
<China>
<Beijing> -11 </Beijing>
</China>
再增加一个子节点，并设置节点属性(Attribute)pNewChildElement=pDoc->createElement("Shanghai");
pNewChildElement->Puttext("9");
pNewChildElement->setAttribute("Weather",_variant_t("Cloudy")); pDocElement->appendChild(pNewChildElement);
于是，我们就可以得到预期的 XML 文本了。
其他的操作：
删除操作：
从父节点来删除子节点 pDocElement->removeChild(pNewChildElement)
存盘操作：
pDoc->Save();
装载已有 XML 文本
如果我们已经有了一个 XML 文件，想对其进行解析，那么可以使用 Document 对象的 Load 或 LoadXML 来进行加载，并在加载的同时进行语法分析。
如果加载成功，那么就会在内存中生成一个树形结构。利用 DOM 模型，我们就可以进行各种操作。最常见的是，我们需要寻找特定的信息，并进行处理。
查找定位
使用 SelectSingleNode (XPath),SelectNodes(XPath)来定位标签，取得对应的 Node(s)对象。
XPath
XPath 是类似于文件路径名的字符串，也像 SQL 的查询语句,可以限定查找范围。
找到指定对象，我们就可各种处理了，添加、删除、取值等等。
小结：上面仅仅是对 DOM 模型的编程进行了简单的介绍，以期快速入门。要详细了解，还必须查阅 SDK 的文档。如果可能，将在以后介绍 SAX 模型、XSLT 对 XML 的转换等。
相关链接：要使用 MSXML Parser ，你必须先下载其 SDK 和运行库。
http://download.microsoft.com/download/xml/Install/3.0/WIN98Me/EN-US/msxml3.exe
http://download.microsoft.com/download/xml/SDK/3.0/WIN98Me/EN-US/xmlsdk.exe
//-------------下面是代码实例-----------
#include "stdafx.h"
#include "iostream.h"
#include "msxml.h"
#include "atlbase.h"
#import "msxml.dll" //引入类型库
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
int Exit();
void LoadFromString();
void CreateXML();
//XML 文本模板
_bstr_t XMLTemple="<China><Beijing> -11 </Beijing><Shanghai Weather=\"Cloudy\"> 9 </Shanghai></China>";
int main()
{
cout << " XML 编程--示范程序 " << endl;
CoInitialize(NULL); //初始化 COM 环境
cout << "------生成新的 XML 文本 ------" << endl;
CreateXML();
cout << "------读取已有 XML 文本 ------" << endl;
LoadFromString();
return Exit();
}
void CreateXML()
{
MSXML::IXMLDOMDocumentPtr pDoc;
HRESULT hr =pDoc.CreateInstance(__uuidof(MSXML::DOMDocument));
if(!SUCCEEDED(hr))
{
cout << "无法创建 DOMDocument 对象，请检查是否安装了 MS XML Parser 运行库!" << endl;
Exit();
}
MSXML::IXMLDOMElementPtr pDocElement=pDoc->createElement("China");
pDoc->appendChild(pDocElement);
cout << "生成树根：\n" << pDoc->xml << endl;
MSXML::IXMLDOMElementPtr pNewChildElement;
pNewChildElement=pDoc->createElement("Beijing");
pNewChildElement->Puttext("-11");
pDocElement->appendChild(pNewChildElement);
cout << "添加节点：\n" << pDoc->xml << endl;
pNewChildElement=pDoc->createElement("Shanghai");
pNewChildElement->Puttext("9");
pNewChildElement->setAttribute("Weather",_variant_t("Cloudy"));
pDocElement->appendChild(pNewChildElement);
cout << "再添加节点：\n" << pDoc->xml << endl;
pDocElement->removeChild (pNewChildElement);
cout << "把刚加入的节点删除：\n" << pDoc->xml << endl;
}
void LoadFromString()
{
MSXML::IXMLDOMDocumentPtr pDoc;
HRESULT hr =pDoc.CreateInstance(__uuidof(MSXML::DOMDocument));
if(!SUCCEEDED(hr))
{
cout << "无法创建 DOMDocument 对象，请检查是否安装了 MS XML Parser 运行库!" << endl;
Exit();
}
pDoc->loadXML(XMLTemple);
cout << "读取结果：\n" << pDoc->xml << endl;
MSXML::IXMLDOMElementPtr pDocElement=pDoc->GetdocumentElement();
MSXML::IXMLDOMElementPtr pElement=pDocElement->selectSingleNode("Shanghai");
pDocElement->removeChild(pElement);
cout << "定位删除 Shanghai 节点：\n" << pDoc->xml << endl;
cout << "保存结果 Save .....(模拟而已)" << endl;
cout << "\n 好了，就这么简单" << endl;
}
int Exit()
{
getchar();
return 1;
}