最近研究起了使用VC6.0进行解析XML文档,而对于XML文档的解析目前网上主要使用了两种方法:MSXML和CMarkUp类。而我就先从最基本的DOM研究起了。而对于DOM主要采用微软提供的MSXML库,另外好像还有第三方库TinyXML,咱就不研究了。
而对于MSXML的使用,网上别人提供的东西都比较零碎,而且还比较乱,在论坛上问反而被一堆人鄙视,得到的解答少之又少。于是我专门花了一天的时间研究了下,现在小有成果,就感觉整理了一些,以供和我一样初级选手作为入门的资料。当然,在整理过程中还是会出现错误,望大家发现后指正。如果你感觉文章还好的话就留个足迹,顶顶人气哈。
闲话到此为止,下面进入正题:
系统中须保证已经安装了msxml。以下均针对msxml4版本进行的操作,而对msxml6的版本则需要进行相应的改动即可。
编程开发环境Visual C++ 6.0。
在使用msxml之前,第一步要做的就是导入该库。导入msxml4库需要进行以下操作:
#include "msxml.h"
#import "C:/windows/system32/msxml.dll" rename_namespace("xml")
即:首先要包含头文件,然后在导入库,并重新定义了一个命名空间,这样为了以后使用的方面。
因为该库为COM组件,故使用前需要初始化com组件库。
AfxOleInit(); 或是 ::CoInitialize(NULL); // 初始化Com组件。
同时,若不再使用该MSXML组件时,可以释放组件占用的内存。
::CoUninitialize();
以上两步做完之后就可以使用DOM库了。
Document节点代表了整个的XML文档。当DOM解析一个XML文档后,由XML形成的DOM节点树以Document对象的形式展现给应用程序的。由于XMl文档的元素、处理指令、注释等都处于一个XML文档范围之内,Document中包含了用于创建元素、属性、注释、处理指令等其它节点类型的方法。
因此,首先要创建XML文档类对象
xml::IXMLDOMDocumentPtr pDoc;
// 创建DOC类,注意是 ' . ',而不是 ' -> ',尽管它是一个指针。
HRESULT hr = pDoc.CreateInstance(_uuidof(xml::DOMDocument));
if(!SUCCEEDED(hr))
{
AfxMessageBox("无法创建DM对象!");
return;
}
创建完成了Document文档类对象之后就可以进行下一步的创建XML或是解析操作了。
以下介绍一些常用的方法:
1) 创建元素:XMLDOMDocument->createElement(name);
2) 创建节点:XMLDOMDocument->createNode(name);
3) 添加节点:XMLDOMDocument->appendChild();
4) 保存生成XML文档:XMLDOMDocument->save();
5) 加载XML文档:XMLDOMDocument->load("path.xml");
6) 获取根节点:XMLDOMDocument->get_documentElement(&root)
以上几个方法基本上就可以创建和解析一个简单的XML文档了。
DOM是由一组抽象化的接口组成。Node是整个DOM中最基本的数据类型,它代表了一个抽象的节点。XML文档的DOM树上的具体节点类型都是由Node类型派生而来。
其提供的常用属性或方法如下:
(1)子节点操作
(2)查询节点
selectNodes():
运用专门的模式匹配方法匹配要查询的节点,并返回满足要求的节点列表。
selectSingleNode()
运用专门的模式匹配方法匹配要查询的节点,并返回满足要求的第一个节点。
(3)节点名
nodeName:属性,指示了节点的名称。
get_nodeName():返回节点名称。
(4)节点类型
nodeType:属性,指示了节点的类型。
节点类型有:NODE_ELEMENT、NODE_ATTRIBUTE、NODE_TEXT、 NODE_ENTITY、NODE_PROCESSING_INSTRUCTION、 NODE_DOCUMENT、NODE_DOCUMENT_TYPE等。
Get_nodeType():返回该节点的类型。
(5)节点值
(6)节点文本值
(7)节点属性
其中更详细信息请参考MSDN。
文档序需要由Document类创建,如:
xml::IXMLDOMProcessingInstructionPtr head;
head = pDoc->createProcessingInstruction(_bstr_t(_T("xml")),
_bstr_t(_T("version='1.0' encoding='UTF-8'")));
pDoc->appendChild(head); // 将序添加到文档类中。
该节点继承自IXMLDOMNode。其具体属性和方法同IXMLDOMNodePtr,不再细述。
通过属性节点集合实现对命名空间和迭代的支持。IXMLDOMNamedNodeMap为一个节点集,并且支持通过名称或标签值的访问。该集合主要应用于对属性的支持。
如若想解析一个元素的属性,可用以下操作实现:
IXMLDOMNamedNodeMapPtr pAttrMap = NULL;
IXMLDOMElementPtr:proot->get_attributes(&pAttrMap);
long count;
BSTR content, name;
pAttrMap->get_length(&count);
pAttrMap->get_item(0, &pAttrItem);
pAttrItem->get_text(&content);
pAttrItem->get_nodeName(&name);
该类所提供的属性和方法有:
其它见CSDN技术文档。
指示了元素IXMLDOMElement的一个属性。属性继承于IXMLDOMNode类,但不不属于元素的一个子节点,同样也不属于文档树的一个节点。
其具体属性和方法也不做详细介绍,具体可参考CSDN技术文档。
在使用完节点(IXMLDOMNode,包括其子类)之后,需要释放其所占用的资源,否则会造成消耗大量系统内存资源。释放使用如下操作:
Node->Release();
Doc->Release();
xml::IXMLDOMDocumentPtr pDoc; // Document文档类 xml::IXMLDOMElementPtr xmlRoot; // 元素类,用于存放根元素 xml::IXMLDOMNodePtr xmlNode; // 节点类 HRESULT hr = pDoc.CreateInstance(_uuidof(xml::DOMDocument)); if(!SUCCEEDED(hr)) { AfxMessageBox("无法创建DM对象!"); return; } //--------------------------创建序Prolog------------------------------------- xml::IXMLDOMProcessingInstructionPtr head; head = pDoc->createProcessingInstruction(_bstr_t(_T("xml")), _bstr_t(_T("version='1.0' encoding='UTF-8'"))); pDoc->appendChild(head); // 将序添加到文档类中。 //-------------------------创建带有属性的根元素----------------------------- _variant_t varTyp((short)xml::NODE_ELEMENT); xmlRoot = pDoc->createElement("People"); xmlRoot->setAttribute("id",(_bstr_t)(_T(m_ID))); // m_ID为CString型 pDoc->appendChild(xmlRoot); // 将根元素添入文档类中 // -------------------------创建子元素,采用两种方法----------------------- xmlNode = pDoc->createNode(varTyp, "Name", ""); xmlNode->put_text(_bstr_t(_T(m_name))); // m_name为CString型 xmlRoot->appendChild(xmlNode); xmlNode = pDoc->createElement("Profession"); xmlNode->text = (_bstr_t)(_T(m_work)); // m_work为CString型 xmlRoot->appendChild(xmlNode); //-------------------------------------------------------------------- pDoc->save("d://people.xml"); // 保存XML文档
如此得到的XML文档为:
实际中,可能会出现排版问题。比如元素及子元素均放在一行中,这也是我咱是还没解决的。
其中实例如下:
xml::IXMLDOMDocumentPtr pdoc; // XML文档类 BSTR name, content; // 用于保存节点的名称以及节点内容 xml::DOMNodeType type; // 定义节点类型变量 int i; //----------------------------创建文档类--------------------------------- HRESULT hr = pdoc.CreateInstance(_uuidof(xml::DOMDocument)); if(!SUCCEEDED(hr)) { AfxMessageBox("无法创建DOM对象!"); return; } pdoc->load("d://people.xml"); // 导入XML文档 //----------------------------获取根节点------------------------------------ //XML文档元素指针,初始化指向根节点;注意相当于数据库database xml::IXMLDOMElementPtr proot=NULL; hr=pdoc->get_documentElement(&proot); if((!SUCCEEDED(hr))) { AfxMessageBox("获取根节点有误!"); return; } //--------------测试根节点--------------- CString str; proot->get_nodeName(&name); str = name; proot->get_text(&content); str = content; proot->get_nodeType(&type); //------------------获取根节点属性------------------- // 节点属性,放在链表中 xml::IXMLDOMNamedNodeMapPtr pAttrMap = NULL; xml::IXMLDOMNodePtr pAttrItem; proot->get_attributes(&pAttrMap); long count; pAttrMap->get_length(&count); // 节点属性表的属性个数 pAttrMap->get_item(0, &pAttrItem); // 读取第一个属性 pAttrItem->get_text(&content); // 属性值 str = content; pAttrItem->get_nodeName(&name); // 属性名称 str = name; //----------------------------获取根元素的子元素列表--------------------------- //获取子节点链表;注意相当于表table;或者相当于记录recordset xml::IXMLDOMNodeListPtr pnodelist; hr=proot->get_childNodes(&pnodelist); //获取子节点链表中的个数;注意相当于得到记录的个数 long productNum=0; hr=pnodelist->get_length(&productNum); // 计算子元素个数 //----------------------------测试子元素内容以及名称等---------------------------- xml::IXMLDOMNodePtr pnode = NULL; for( i=0; i