在DOM接口规范中,有四个基本的接口:Document,Node,NodeList以及NamedNodeMap。在这四个基本接口中,Document接口是对文档进行操作的入口,它是从Node接口继承过来的。Node接口是其他大多数接口的父类,象Documet,Element,Attribute,Text,Comment等接口都是从Node接口继承过来的。NodeList接口是一个节点的集合,它包含了某个节点中的所有子节点。NamedNodeMap接口也是一个节点的集合,通过该接口,可以建立节点名和节点之间的一一映射关系,从而利用节点名可以直接访问特定的节点。下面将对这四个接口分别做一些简单的介绍。

1、Document接口

Document接口代表了整个XML/HTML文档,因此,它是整棵文档树的根,提供了对文档中的数据进行访问和操作的入口。

由于元素、文本节点、注释、处理指令等都不能脱离文档的上下文关系而独立存在,所以在Document接口提供了创建其他节点对象的方法,通过该方法创建的节点对象都有一个ownerDocument属性,用来表明当前节点是由谁所创建的以及节点同Document之间的联系。

在DOM树中,Document节点是DOM树中的根节点,也即对XML文档进行操作的入口节点。通过Docuemt节点,可以访问到文档中的其他节点,如处理指令、注释、文档类型以及XML文档的根元素节点等等。另外,在一棵DOM树中,Document节点可以包含多个处理指令、多个注释作为其子节点,而文档类型节点和XML文档根元素节点都是唯一的。

关于Document接口的IDL(Interface Definition Language接口定义语言)定义和其中一些比较常用的属性和方法的详细介绍可以在MSDN中找到。

2、Node接口

Node接口在整个DOM树中具有举足轻重的地位,DOM接口中有很大一部分接口是从Node接口继承过来的,例如,Element、Attr、CDATASection等接口,都是从Node继承过来的。在DOM树中,Node接口代表了树中的一个节点。

3、NodeList接口

NodeList接口提供了对节点集合的抽象定义,它并不包含如何实现这个节点集的定义。NodeList用于表示有顺序关系的一组节点,比如某个节点的子节点序列。另外,它还出现在一些方法的返回值中,例如GetNodeByName。

在DOM中,NodeList的对象是"live"的,换句话说,对文档的改变,会直接反映到相关的NodeList对象中。例如,如果通过DOM获得一个NodeList对象,该对象中包含了某个Element节点的所有子节点的集合,那么,当再通过DOM对Element节点进行操作(添加、删除、改动节点中的子节点)时,这些改变将会自动地反映到NodeList对象中,而不需DOM应用程序再做其他额外的操作。

NodeList中的每个item都可以通过一个索引来访问,该索引值从0开始。

4、NamedNodeMap接口

实现了NamedNodeMap接口的对象中包含了可以通过名字来访问的一组节点的集合。不过注意,NamedNodeMap并不是从NodeList继承过来的,它所包含的节点集中的节点是无序的。尽管这些节点也可以通过索引来进行访问,但这只是提供了枚举NamedNodeMap中所包含节点的一种简单方法,并不表明在DOM规范中为NamedNodeMap中的节点规定了一种排列顺序。

NamedNodeMap表示的是一组节点和其唯一名字的一一对应关系,这个接口主要用在属性节点的表示上。

与NodeList相同,在DOM中,NamedNodeMap对象也是"live"的。

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方法来设置和获得节点的属性。

四、程序实现

下面通过一个具体的实例来说明在VC++中如何利用MSXML解析XML文档。

()源XML文档(xmlfile.xml)如下:

<?xml version="1.0" encoding="GB2312"?>

<Device id="10041" name="设备1">

<Type>13</Type>

<TypeName>保护</TypeName>

</Device>

我们在源文档中查找"Device",将其"name"属性设置为"测试设备",为其添加"Model"节点,并设置其文本为"3"。

()源程序如下:

CoInitialize(NULL);// 初始化COM。

CComPtr<IXMLDOMDocument> spXMLDOM;

// 创建解析器实例。

HRESULT hr = spXMLDOM.CoCreateInstance (_uuidof(DOMDocument));

VARIANT_BOOL bSuccess = false;

// 装载XML文档。

Hr = spXMLDOM->load(CComVariant(L"xmlfile.xml"),&bSuccess);

CComBSTR  bstrSS(L"Device");

CComPtr<IXMLDOMNode> spDevice;

Hr = spXMLDOM->selectSingleNode(bstrSS,&spDevice); //搜索"Device"。

CComQIPtr<IXMLDOMElement>  spDev;

spDev = spDevice;

// 设置"Device"的"name"属性。

Hr = spDev ->setAttribute(CComBSTR(L"name"),CComVariant("测试设备"));

CComPtr<IXMLDOMNode> spModelNode;

// 创建"Model"节点。

Hr = spXMLDOM->createNode(CComVariant(NODE_ELEMENT),ComBSTR

("Model"),NULL,& spModelNode);

CComPtr<IXMLDOMNode> spInsertedNode;

Hr = spDevice->appendChild (spModelNode,&spInsertedNode);

// 添加新节点到"Device"节点下面。

CString strID="3";

// 设置"Model"的文本。

hr=spInsertedNode->put_text(strID.AllocSysString());

/ /保存文档。

hr=spXMLDOM->save(CComVariant("xmlfile.xml"));

// 结束对COM的使用。

CoUninitialize();

因为篇幅的原因,上述代码的每步操作并未对返回的HRESULT类型进行判断,也未进行异常的捕获处理,在实际的编程中读者应根据返回的hr进行决断,以决定程序的流程,同时应进行异常的捕获处理。

()修改后的XML文档如下

<?xml version="1.0" encoding="GB2312"?>

<Device id="10041" name="测试设备">

<Type>13</Type>

<TypeName>保护</TypeName>

<Model>3</Model>

</Device>

MFC程序示例:

1、目标文档:

<book id="bk101">

<author>lizlex</author>

<title>XML Developer's Guide</title>

</book>

2、步骤:

(1)在StdAfx.h中引入动态链接库 MSXML.DLL(C:\windows\system32\msxml4.dll)

#import <msxml4.dll>

(2)界面设计:

分别放入三个Text,用于输入数据,与显示文档内容用,并添加关联的成员变量

m_strId, m_strAuthor, m_strTitle;并添加确定按钮。

(3)产生文档的程序片断:

void CXmlparseDlg::OnButtonGenerate()

{

UpdateData();

MSXML2::IXMLDOMDocumentPtr pDoc;

MSXML2::IXMLDOMElementPtr xmlRoot ;

//创建DOMDocument对象

HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40));

if(!SUCCEEDED(hr))

{

MessageBox("无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库!");

return ;

}

//根节点的名称为Book

//创建元素并添加到文档中

xmlRoot=pDoc->createElement((_bstr_t)"Book");

//设置属性

xmlRoot->setAttribute("id",(const char *)m_strId);

pDoc->appendChild(xmlRoot);

MSXML2::IXMLDOMElementPtr pNode;

//添加“author”元素

pNode=pDoc->createElement((_bstr_t)"Author");

pNode->Puttext((_bstr_t)(const char *)m_strAuthor);

xmlRoot->appendChild(pNode);

//添加“Title”元素

pNode=pDoc->createElement("Title");

pNode->Puttext((const char *)m_strTitle);

xmlRoot->appendChild(pNode);

//保存到文件

//如果不存在就建立,存在就覆盖

pDoc->save("d:\\he.xml");

}

(4)读取XML文档的程序片断:

void CXmlparseDlg::OnButtonLoad()

{

MSXML2::IXMLDOMDocumentPtr pDoc;

HRESULT hr;

hr=pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40));

if(FAILED(hr))

{

MessageBox("无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库!");

return ;

}

//加载文件

pDoc->load("d:\\he.xml");

MSXML2::IXMLDOMNodePtr pNode;

//在树中查找名为Book的节点,"//"表示在任意一层查找

pNode=pDoc->selectSingleNode("//Book");

MSXML2::DOMNodeType nodeType;

//得到节点类型

pNode->get_nodeType(&nodeType);

//节点名称

CString strName;

strName=(char *)pNode->GetnodeName();

//节点属性,放在链表中

MSXML2::IXMLDOMNamedNodeMapPtr pAttrMap=NULL;

MSXML2::IXMLDOMNodePtr   pAttrItem;

_variant_t variantValue;

pNode->get_attributes(&pAttrMap);

long count;

count=pAttrMap->get_length(&count);

pAttrMap->get_item(0,&pAttrItem);

//取得节点的值

pAttrItem->get_nodeTypedValue(&variantValue);

m_strId=(char *)(_bstr_t)variantValue;

UpdateData(FALSE);

}

在VC中应用MSXML DOM 的一些基本实现方法:

已知变量

MSXML2::IXMLDOMDocument *pDoc;

MSXML2::IXMLDOMNode *pChild, *pParent;

MSXML2::IXMLDOMNode *pNod;

MSXML2::IXMLDOMElement *pEle;

初始化指针:

MSXML2::IXMLDOMDocument *pDocument=NULL;

MSXML2::IXMLDOMNodeList *pNodeList=NULL;

MSXML2::IXMLDOMNamedNodeMap *pNodeMap=NULL;

MSXML2::IXMLDOMNode *pNode=NULL

MSXML2::IXMLDOMText *pText=NULL;

MSXML2::IXMLDOMElement *pElement=NULL;

MSXML2::IXMLDOMProcessingInstruction *pProcessingInstruction=NULL;

MSXML2::IXMLDOMComment *pComment=NULL;

MSXML2::IXMLDOMParseError *pObjError = NULL;

已知数据:

BSTR bstrText, bstrName;

int  type;

**)创建新文档

// hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, 

//  IID_IXMLDOMDocument,(void**)&m_pXMLDoc);

HRESULT hr=CoCreateInstance(__uuidof(MSXML2::DOMDocument40),NULL,CLSCTX_INPROC_SERVER,

  __uuidof(MSXML2::IXMLDOMDocument),(void**)&m_pXMLDoc);

    hr = pDocument->put_async(VARIANT_FALSE); 

    hr = pDocument->put_validateOnParse(VARIANT_FALSE);

hr = pDocument->put_resolveExternals(VARIANT_FALSE);

a)添加子节点到父节点

pParent->appendChild(pChild, &pNode)

b)创建节点

VARIANT vtype;

vtype.vt = VT_I4;

V_I4(&vtype) = (int)type;

pDoc->createNode(vtype, bstrName, NULL, &pNode);

c)创建元素节点

pDoc->createElement(bstrName,pElement);

(pElement)->put_text(bstrText);

d)创建文本子节点,并添加到父节点中

pDoc->createTextNode(bstrText,&pText);

pParent->appendChild(pText,& pNode)

e)创建// Create a processing instruction element.

BSTR bstrTarget = SysAllocString(L"xml");

BSTR bstrData = SysAllocString(L"version='1.0'");

pDoc ->createProcessingInstruction(bstrTarget, bstrData, &pProcessingInstruction);

SysFreeString(bstrTarget);

SysFreeString(bstrData);

f)创建注释节点

pDoc->createComment(bstrText, &pComment);

g)元素节点属性值

得到属性值

VARIANT v;

pEle->getAttribute(bstrName,&v);

CString str = v.bstrVal;

设置属性值

CComVariant v(str);

pEle->setAttribute(bstrName, v);

h)节点属性值

VARIANT v;

CString str;

long mCount;

得到节点属性集

hr=pNod->get_attributes(&pNodeMap);

hr=pNodeMap->get_length(&mCount); 

得到节点属性

hr=pNodeMap->getNamedItem(bstrName,&pNode);

pNodeMap->get_item(i,&pNode);

得到节点属性值

hr=pNode->get_nodevalue(&v);

str =v.bstrVal;

删除节点属性

MSXML2::IXMLDOMNode *moldNode;

mNodeMape->removeNamedItem(bstrName,&moldNode);

if (moldNode!=NULL) moldNode->Release();

i)节点

(1)得到节点、节点集

根据节点名称

pDoc->getElementsByTagName(bstrName,&pNodeList);

pNodeList->get_item(0,&pNode);

得到子节点集

hr=pNod->get_childNodes(&mNodeList);

long mCount;

MSXML2::IXMLDOMNode *pNodeSub;

mNodeList->get_length(&mCount);

hr=pNode->get_firstChild(&pNodeSub);

删除子节点(包含删除节点属性、子节点、当前节点)

删除当前子节点

pNodeList->get_item(i,&pNode);

pNod->removeChild(pNode,&moldNode);

moldNode->Release();

(2)根据节点得到节点名称

pNod->get_nodeName(&bstrName);

(3)根据节点得到节点值

VARIANT v;

hr=pNod->get_nodevalue(&v);

j)XML文件操作

加载

VARIANT_BOOL status;

VARIANT vFileName;

(1)

pDoc->loadXML(bstrName,&status);

(2)

V_BSTR(&vFileName) = strFileName.AllocSysString();

V_VT(&vFileName) = VT_BSTR;

vResult = pDoc->load(vFileName,&status);

保存

BSTR pBFName = mFileName.AllocSysString();

CComVariant v(pBFName);

hr=pDoc->save(v);

BSTR bstr = NULL;

pDoc->get_xml(&bstr);

k)错误处理

BSTR bstr = NULL;

pDoc->get_parseError(&pObjError);

pObjError->get_reason(&bstr);

AfxMessageBox(_T("Failed to load DOM from books.xml. %S\n"),*bstr);

MSXML使用教程的更多相关文章

  1. Ajax 完整教程。。转载

    Ajax 完整教程 第 1 页 Ajax 简介 Ajax 由 HTML.JavaScript™ 技术.DHTML 和 DOM 组成,这一杰出的方法可以将笨拙的 Web 界面转化成交互性的 Ajax 应 ...

  2. Angular2入门系列教程7-HTTP(一)-使用Angular2自带的http进行网络请求

    上一篇:Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数 感觉这篇不是很好写,因为涉及到网络请求,如果采用真实的网络请求,这个例子大家拿到手估计还要自己写一个web ...

  3. Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数

    上一篇:Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数 之前介绍了简单的路由以及传参,这篇文章我们将要学习复杂一些的路由以及传递其他附加参数.一个好的路由系统可以使我们 ...

  4. Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数

    上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...

  5. Angular2入门系列教程4-服务

    上一篇文章 Angular2入门系列教程-多个组件,主从关系 在编程中,我们通常会将数据提供单独分离出来,以免在编写程序的过程中反复复制粘贴数据请求的代码 Angular2中提供了依赖注入的概念,使得 ...

  6. Angular2入门系列教程1-使用Angular-cli搭建Angular2开发环境

    一直在学Angular2,百忙之中抽点时间来写个简单的教程. 2016年是前端飞速发展的一年,前端越来越形成了(web component)组件化的编程模式:以前Jquery通吃一切的田园时代一去不复 ...

  7. wepack+sass+vue 入门教程(三)

    十一.安装sass文件转换为css需要的相关依赖包 npm install --save-dev sass-loader style-loader css-loader loader的作用是辅助web ...

  8. wepack+sass+vue 入门教程(二)

    六.新建webpack配置文件 webpack.config.js 文件整体框架内容如下,后续会详细说明每个配置项的配置 webpack.config.js直接放在项目demo目录下 module.e ...

  9. wepack+sass+vue 入门教程(一)

    一.安装node.js node.js是基础,必须先安装.而且最新版的node.js,已经集成了npm. 下载地址 node安装,一路按默认即可. 二.全局安装webpack npm install ...

随机推荐

  1. Delphi编译的程序如何获取管理员权限

    1.制作manifest文件 <?xml version="1.0" encoding="UTF-8" standalone="yes" ...

  2. Binding ConvererParameter

    WPF中ConverterParameter不可以绑定,可以通过如下扩展来实现ConverterParameter的Binding: 1.自定义ConverterBindableBinding和Mul ...

  3. 查看数据库中没有进行comment的字段

    为落实数据库规范,既每个表字段都需要有comment注释,所以需要过滤生产表中没有comment的字段,搜索出还不错的过滤语句 show full columns from table where C ...

  4. 【CMD】

    1.dir 2. set (不带参数) 查看环境变量. SET [variable=[string]] variable  指定环境变量名. string    指定要指派给变量的一系列字符串. 3.

  5. Extjs中引入JSP页面

    有的时候,我们可能要在某个panel中动态的引入一个jsp页面.但是ext中貌似没有这样的方法,所以这时候需要我们自定义一个组件来完成我们的需求. 1.首先定义我们的penel. Ext.define ...

  6. 我们的html

    http://files.cnblogs.com/files/eeroom/mac-Bootstrap.rar http://files.cnblogs.com/files/eeroom/CSharp ...

  7. adb catlog>d:\log.txt日志级别

    W,警告 I,通知 D,调试 E,错误 V, 到最细的日志 功能测试可以看W和E,性能测试I比较有用

  8. kafka 订单应用需求

    kafka的介绍就不说了,网上会找到一大堆. 为了公司做报表需要对卡券订单的销售情况做总结,所以每次下单的时候都要给卡券活动模块传递一次消息,并把订单的信息发送给活动,活动做相应的数据操作,因为数据量 ...

  9. android技巧(五)一个异步+接口回调的例子

    public class DataBaseUtils { // 当前数据库地址 private String DB_PATH; // 备份后数据库保存地址 private String DB_BACK ...

  10. NOIP 考前 高斯消元练习

    POJ 1830 列出n个方程右边为最后的情况 每一行代表第几个灯的情况,每一行代表是否按第几个按钮写出方程即可. #include <cstdio> #include <cstri ...