在DOM接口規範中,有四個基本的接口:Document,Node,NodeList以及NamedNodeMap。在這四個基本接口中,Document接口是對文檔進行操做的入口,它是從Node接口繼承過來的。Node接口是其餘大多數接口的父類,象Documet,Element,Attribute,Text,Comment等接口都是從Node接口繼承過來的。NodeList接口是一個節點的集合,它包含了某個節點中的全部子節點。NamedNodeMap接口也是一個節點的集合,經過該接口,能夠創建節點名和節點之間的一一映射關係,從而利用節點名能夠直接訪問特定的節點。下面將對這四個接口分別作一些簡單的介紹。node
1、Document接口編程
Document接口表明了整個XML/HTML文檔,所以,它是整棵文檔樹的根,提供了對文檔中的數據進行訪問和操做的入口。windows
因爲元素、文本節點、註釋、處理指令等都不能脫離文檔的上下文關係而獨立存在,因此在Document接口提供了建立其餘節點對象的方法,經過該方法建立的節點對象都有一個ownerDocument屬性,用來代表當前節點是由誰所建立的以及節點同Document之間的聯繫。app
在DOM樹中,Document節點是DOM樹中的根節點,也即對XML文檔進行操做的入口節點。經過Docuemt節點,能夠訪問到文檔中的其餘節點,如處理指令、註釋、文檔類型以及XML文檔的根元素節點等等。另外,在一棵DOM樹中,Document節點能夠包含多個處理指令、多個註釋做爲其子節點,而文檔類型節點和XML文檔根元素節點都是惟一的。async
關於Document接口的IDL(Interface Definition Language接口定義語言)定義和其中一些比較經常使用的屬性和方法的詳細介紹能夠在MSDN中找到。ide
2、Node接口函數
Node接口在整個DOM樹中具備舉足輕重的地位,DOM接口中有很大一部分接口是從Node接口繼承過來的,例如,Element、Attr、CDATASection等接口,都是從Node繼承過來的。在DOM樹中,Node接口表明了樹中的一個節點。工具
3、NodeList接口測試
NodeList接口提供了對節點集合的抽象定義,它並不包含如何實現這個節點集的定義。NodeList用於表示有順序關係的一組節點,好比某個節點的子節點序列。另外,它還出如今一些方法的返回值中,例如GetNodeByName。ui
在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解析相關的事務時節省大量的精力,是一種符合代碼重用思想的強有力編程工具。
3、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方法來設置和得到節點的屬性。
4、程序實現下面經過一個具體的實例來講明在VC++中如何利用MSXML解析XML文檔。
(1)源XML文檔(xmlfile.xml)以下:
<?xml version="1.0" encoding="GB2312"?>
<Device id="10041" name="設備1">
<Type>13</Type>
<TypeName>保護</TypeName>
</Device>
咱們在源文檔中查找"Device",將其"name"屬性設置爲"測試設備",爲其添加"Model"節點,並設置其文本爲"3"。
(2)源程序以下:
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進行決斷,以決定程序的流程,同時應進行異常的捕獲處理。
(3)修改後的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);