利用VC++與MSXML解析XML文檔
一、文檔對象模型(DOM)
DOM是Document Object Model(文檔對象模型)的簡稱,是對XML文檔進行應用開發、編程的應用程序接口(API)。作為W3C公布的一種跨平臺、與語言無關的接口規范,DOM提供了在不同環境和應用中的標準程序接口,可以用任何語言實現。
DOM采用對象模型和一系列的接口來描述XML文檔的內容和結構,即利用對象把文檔模型化。這種對象模型實現的基本功能包括:
● 描述文檔表示和操作的接口;
● 接口的屬性和方法;
● 接口之間的關系以及互操作。
DOM可對結構化的XML文檔進行解析,文檔中的指令、元素、實體、屬性等所有內容個體都用對象模型表示,整個文檔被看成是一個有結構的信息樹,而不是簡單的文本流,生成的對象模型就是樹的節點,對象同時包含了方法和屬性。因此,對文檔的所有操作都是在對象樹上的進行。在DOM中,樹中的一切都是對象,不管是根節點還是實體的屬性。
在DOM中主要有以下三個對象:
● XML文檔對象
XML文檔既是一種對象,同時又代表整個XML文檔。它由根元素和子元素組成。
● XML節點對象
XML節點對象代表的是XML文檔內部的節點,如元素、注釋、名字空間等。
● XML節點列表
XML文檔模塊列表代表了節點的集合。
利用DOM,開發人員可以動態地創建XML文檔,遍歷結構,添加、修改、刪除內容等。其面向對象的特性,使人們在處理XML解析相關的事務時節省大量的精力,是一種符合代碼重用思想的強有力編程工具。
二、DOM的四個基本接口(引用自:http://bbs.xml.org.cn/dispbbs.asp?boardID=11&ID=9220)
在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"的。
三、MSXML
從理論上說,根據XML的格式定義,我們可以自己編寫一個XML的語法分析器,但實際上微軟已經給我們提供了一個XML語法解析器,即一個叫做 MSXML.DLL的動態鏈接庫,實際上它是一個COM(Component Object Model)對象庫,里面封裝了進行XML解析時所需要的所有對象。因為COM是一種以二進制格式出現的和語言無關的可重用對象,所以你可以用任何語言 (比如VB,VC,DELPHI,C++ Builder甚至是腳本語言等等)對它進行調用,在你的應用中實現對XML文檔的解析。
MSXML.DLL所包括的主要COM接口有:
1. IXMLDOMDocument(Document接口)
DOMDocument對象是XML DOM的基礎,你可以利用它所暴露的屬性和方法來瀏覽、查詢和修改XML文檔的內容和結構。DOMDocument表示了樹的頂層節點,它實現了DOM文 檔的所有的基本方法,并且提供了額外的成員函數來支持XSL和XSLT。它創建了一個文檔對象,所有其他的對象都可以從這個文檔對象中得到和創建。
2. IXMLDOMNode(Node接口)
IXMLDOMNode是文檔對象模型(DOM)中的基本對象,元素、屬性、注釋、過程指令和其他的文檔組件都可以認為是IXMLDOMNode。事實上,DOMDocument對象本身也是一個IXMLDOMNode對象。
3. IXMLDOMNodeList
IXMLDOMNodeList實際上是一個節點(Node)對象的集合,節點的增加、刪除和變化都可以在集合中立刻反映出來,可以通過"for.循環 "結構來遍歷所有的節點。
4. IXMLDOMParseError
IXMLDOMParseError接口用來返回在解析過程中所出現的詳細的信息,包括錯誤號、行號、字符位置和文本描述。
在具體應用時可以用DOMDocument的Load方法來裝載XML文檔,用IXMLDOMNode 的selectNodes(查詢的結果有多個,得到存放搜索結果的鏈表)或selectSingleNode(查詢的結果有一個,在有多個的情況下返回找 到的第一個節點)方法進行查詢,用createNode和appendChild方法來創建節點和追加節點,用IXMLDOMElement的 setAttribute和getAttribute方法來設置和獲得節點的屬性。
四、編程舉例
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);
}