小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

使用 MSXML 分析器處理 XML 文檔

 shaolong007 2005-09-29
 

使用 MSXML 分析器處理 XML 文檔

發(fā)布日期: 8/6/2004 | 更新日期: 8/6/2004

Kenn Scribner

Kenn Scribner 近期有關(guān) XML MSXML DOM 分析器的文章中,僅介紹了該分析器的部分功能。這些文章將 XML 作為一種技術(shù)進行了說明,但是并沒有介紹 XML 分析器本身?,F(xiàn)在,Kenn 將回過頭來介紹 MSXML 分析器,并講解處理 XML 文檔和節(jié)點所需的基本知識:搜索特定的節(jié)點、插入節(jié)點和檢索節(jié)點值。

*

MSXML 分析器基于 XML 文檔對象模型,對于查看表 1 中所示的各種文檔對象來說,它非常重要。這些對象直接出自 XML 規(guī)范本身。MSXML 還可以進一步將 XML DOM 對象合并到 COM 中。因此,弄清楚哪個 XML DOM 對象對應(yīng)于哪個 MSXML COM 接口非常容易。例如,IXMLDOMNode 代表稱為 Node 的 DOM 對象。

表 1. XML DOM 對象及其用途
DOM 對象 用途

DOMImplementation

一個查詢對象,用于確定 DOM 支持的級別

DocumentFragment

表示樹的一部分(可進行剪切/粘貼操作)

Document

表示樹中的頂級節(jié)點

NodeList

用于訪問 XML 節(jié)點的 Iterator 對象

Node

用于擴展帶核心 XML 標記的元素

NamedNodeMap

命名空間支持和迭代通過屬性節(jié)點集合

CharacterData

文本操作對象

Attr

表示元素的屬性

Element

表示 XML 元素的節(jié)點(可用于訪問屬性)

Text

表示給定元素或?qū)傩詫ο蟮奈谋緝?nèi)容

CDATASection

用于屏蔽 XML 部分,使其不受分析和驗證

Notation

包含基于 DTD 或架構(gòu)內(nèi)的表示法

Entity

表示已分析或未分析的實體

EntityReference

表示實體引用節(jié)點

ProcessingInstruction

表示處理指令

雖然有時比較容易混淆,但是 XML 文檔對象可以是(并且通常是)多態(tài)的。即,“節(jié)點”同時也是一個“元素”。當您試圖確定需要何種 DOM 對象來執(zhí)行何種操作時,這有時會造成混淆??梢允褂?#8220;文檔”對象來創(chuàng)建 DOM“節(jié)點”,但是,如果要向新創(chuàng)建的節(jié)點添加屬性,就必須通過其作為“元素”的一面來訪問它。如果說存在一種將對象和操作關(guān)聯(lián)在一起的神奇模式,那么我還沒能從自己的日常工作中將它提煉出來。我發(fā)現(xiàn)自己仍需要不斷參考 MSDN 文檔來查看哪個 COM 接口提供了所需的方法以執(zhí)行我試圖完成的任務(wù)。各種對象方法看上去的確是按邏輯分組的,這也正是我對 DOM 當初的開發(fā)模式的推斷(通過分組邏輯操作)。

因此,其中的訣竅就在于從 MSXML 分析器檢索適當?shù)?DOM 對象,這一操作的具體實現(xiàn)就是 COM 對象。操作的基本模式將是:首先實例化 MSXML COM 對象本身的一個副本,然后從該副本請求或以其他方式獲取指向附加 XML DOM 對象(本身也是 COM 對象)的指針。

MSXML DOM 試驗應(yīng)用程序

創(chuàng)建一個漂亮的應(yīng)用程序,演示眾多的 MSXML 功能,這很簡單,但實際上,附加的代碼只會畫蛇添足。相反,我選擇了開發(fā)一個簡單的基于控制臺的應(yīng)用程序,該應(yīng)用程序執(zhí)行四種基本操作:

從磁盤加載一個 XML 文件。

搜索特定的節(jié)點,并向該節(jié)點插入一個子節(jié)點。

搜索另一個節(jié)點,并顯示該節(jié)點內(nèi)包含的(文本)值。

將修改后的 XML 文檔保存回磁盤中。

為了進一步簡化,我硬編碼了 XML 文檔文件的名稱和 XML 節(jié)點本身。當然,如果這是一個真實的應(yīng)用程序,您可能很少(或者永遠不會)采用這樣的方法。但是在本例中,進行這些權(quán)衡,是為了簡化圍繞在 MSXML 功能兩邊的代碼。

像平常一樣,在示例應(yīng)用程序中,我選擇了使用 ATL 來包裝許多與 COM 有關(guān)的活動。您肯定看到我使用了 CComPtr 和 CComQIPtr 對象,但是我還額外加入了幾個 CComBSTR 和 CComVariant 對象。如果您不熟悉它們,只需要記住它們是用于處理一些細節(jié)的模板,這些細節(jié)對于本文的主旨來說并非至關(guān)重要,但是從更廣的角度講,還是比較重要的。真正重要的是看到如何搜索 XML 節(jié)點,添加新的(具有屬性的)節(jié)點,以及顯示節(jié)點內(nèi)包含的文本。

我的基于控制臺的應(yīng)用程序可以在附帶的 下載文件中找到,它將加載一個名為 xmldata.xml 的 XML 文檔文件(假定其與可執(zhí)行文件位于同一個目錄中),并假定該文檔包含以下 XML 數(shù)據(jù):

<?xml version="1.0"?>
<xmldata>
   <xmlnode />
   <xmltext>Hello, World!</xmltext>
</xmldata>

我們將首先搜索 xmlnode 節(jié)點,如果找到了該節(jié)點,我們將插入一個新的(帶有屬性的)節(jié)點作為其子級。生成的 XML 文檔將為:

<?xml version="1.0"?>
<xmldata>
   <xmlnode>
      <xmlchildnode xml="fun" />
   </xmlnode>
   <xmltext>Hello, World!</xmltext>
</xmldata>

打印 節(jié)點內(nèi)包含的信息 ("Hello, World!") 之后,我們將把該新 XML 文檔保存到名為 updatedxml.xml 的文件中。然后,就可以使用文本編輯器或 Internet Explorer 5.x 來查看結(jié)果?,F(xiàn)在讓我們轉(zhuǎn)到代碼。

應(yīng)用程序首先初始化了 COM 運行庫,然后創(chuàng)建了 MSXML 分析器的一個實例:

CComPtr<IXMLDOMDocument> spXMLDOM;
HRESULT hr = spXMLDOM.CoCreateInstance(
                __uuidof(DOMDocument));
if ( FAILED(hr) ) 
    throw "Unable to create XML parser object";
if ( spXMLDOM.p == NULL ) 
    throw "Unable to create XML parser object";

如果創(chuàng)建分析器實例成功,接下來,我們將把 XML 文檔加載到分析器中:

VARIANT_BOOL bSuccess = false;
hr = spXMLDOM->load(CComVariant(L"xmldata.xml"),
                    &bSuccess);
if ( FAILED(hr) ) 
   throw "Unable to load XML document into the parser";
if ( !bSuccess ) 
   throw "Unable to load XML document into the parser";

搜索節(jié)點與文檔對象有關(guān),因此,我們將使用 IXMLDOMDocument::selectSingleNode() 來根據(jù)其名稱查找特定的 XML 節(jié)點。其他的技巧很多,但是如果準確地知道要查找的節(jié)點的名稱,這是最直接的方法:

CComBSTR bstrSS(L"xmldata/xmlnode");
CComPtr<IXMLDOMNode> spXMLNode;
hr = spXMLDOM->selectSingleNode(bstrSS,&spXMLNode);
if ( FAILED(hr) ) 
   throw "Unable to locate ‘xmlnode‘ XML node";
if ( spXMLNode.p == NULL ) 
   throw "Unable to locate ‘xmlnode‘ XML node";

一些您應(yīng)當了解的其他方法包括 IXMLDOMDocument::nodeFromID() 和 IXMLDOMElement::getElementsByTagName(),使用它們可以獲得文檔中的節(jié)點的列表。您還可以將文檔作為樹來進行訪問,并依次通過它(獲取子節(jié)點,獲取同輩節(jié)點等)。

任一種情況下,搜索的結(jié)果都是一個 MSXML 節(jié)點對象 IXMLDOMNode。文檔中必須存在該節(jié)點,否則搜索將失敗。我的應(yīng)用程序使用該節(jié)點作為一個全新 XML 節(jié)點的父級,該新節(jié)點是由 XML 文檔對象創(chuàng)建的:

CComPtr<IXMLDOMNode> spXMLChildNode;
hr = spXMLDOM->createNode(CComVariant(NODE_ELEMENT),
                          CComBSTR("xmlchildnode"),
                          NULL,
                          &spXMLChildNode);
if ( FAILED(hr) ) 
   throw "Unable to create ‘xmlchildnode‘ XML node";
if ( spXMLChildNode.p == NULL ) 
   throw "Unable to create ‘xmlchildnode‘ XML node";

如果分析器可以創(chuàng)建該節(jié)點,下一步就是將它放到 XML 樹中。IXMLDOMNode::appendChild() 正是完成這一任務(wù)的方法:

CComPtr<IXMLDOMNode> spInsertedNode;
hr = spXMLNode->appendChild(spXMLChildNode,
                            &spInsertedNode);
if ( FAILED(hr) ) 
   throw "Unable to move ‘xmlchildnode‘ XML node";
if ( spInsertedNode.p == NULL ) 
   throw "Unable to move ‘xmlchildnode‘ XML node";

如果父節(jié)點的確將新創(chuàng)建的節(jié)點插入為其子級,將返回另一個 IXMLDOMNode 實例,該實例表示新的子節(jié)點。實際上,該新子節(jié)點和傳遞給 appendChild() 的節(jié)點是同一個 XML 節(jié)點。由于在存在問題時附加的子節(jié)點的指針將為 Null,因此,檢查該指針很有用。

到目前為止,我找到了一個特定的節(jié)點,并為它創(chuàng)建了一個新的子節(jié)點,下面,讓我們看看如何處理屬性。假定您要將該屬性添加到新的子節(jié)點:

xml="fun"

這并不難,但是您必須從 IXMLDOMNode 切換到 IXMLDOMElement,以便訪問該子節(jié)點的元素特征。在實踐中,這意味著您必須查詢 IXMLDOMNode 接口的相關(guān) IXMLDOMElement 接口,查明后,再調(diào)用 IXMLDOMElement::setAttribute():

CComQIPtr<IXMLDOMElement> spXMLChildElement;
spXMLChildElement = spInsertedNode;
if ( spXMLChildElement.p == NULL ) 
   throw "Unable to query for ‘xmlchildnode‘ XML _
element interface";

hr = spXMLChildElement->setAttribute(CComBSTR(L"xml"),
                                CComVariant(L"fun"));
if ( FAILED(hr) ) 
   throw "Unable to insert new attribute";

此時,已經(jīng)修改了 XML 樹,并創(chuàng)建了所需的樹。應(yīng)用程序可以在這個時候?qū)⑽臋n保存到磁盤,或者執(zhí)行其他任務(wù)?,F(xiàn)在,讓我們來搜索另一個節(jié)點并顯示該節(jié)點所包含的值(文本)。您已經(jīng)了解了如何搜索節(jié)點,因此,我們將直接講解數(shù)據(jù)提取。

提取節(jié)點數(shù)據(jù)的關(guān)鍵在于使用 IXMLDOMNode::get_nodeTypedValue()??梢允褂?Microsoft 數(shù)據(jù)類型架構(gòu)來標識節(jié)點所包含的數(shù)據(jù),因此可以方便地存儲浮點值、整數(shù)、字符串或該架構(gòu)所支持的任何數(shù)據(jù)類型??梢允褂?dt:type 屬性來指定數(shù)據(jù)類型,如下所示:

<model dt:type="string">SL-2</model>
<year dt:type="int">1992</year>

如果特定的節(jié)點具有指定的數(shù)據(jù)類型,就可以使用 get_nodeTypedValue() 以該格式提取數(shù)據(jù)。如果未指定數(shù)據(jù)類型,將假定數(shù)據(jù)為文本,分析器將返回具有 BSTR 數(shù)據(jù)的 VARIANT。在本例中,這沒有任何問題,因為我們要搜索的節(jié)點是一個實際上包含一個字符串的文本節(jié)點。在需要時,始終可以使用 atoi() 等方法將字符串轉(zhuǎn)換為其他形式。本例中,我們只是提取該字符串數(shù)據(jù)并顯示它:

CComVariant varValue(VT_EMPTY);
hr = spXMLNode->get_nodeTypedValue(&varValue);
if ( FAILED(hr) ) 
   throw "Unable to retrieve ‘xmltext‘ text";

if ( varValue.vt == VT_BSTR ) {
   // Display the results...since we‘re not using the
   // wide version of the STL, we need to convert the
   // BSTR to ANSI text for display...
   USES_CONVERSION;
   LPTSTR lpstrMsg = W2T(varValue.bstrVal);
   std::cout << lpstrMsg << std::endl;
} 
else {
   // Some error
   throw "Unable to retrieve ‘xmltext‘ text";
} 

如果能夠檢索與節(jié)點關(guān)聯(lián)的值,并且該值為 BSTR(預(yù)期的數(shù)據(jù)類型),我們將在屏幕上顯示該文本。如果不能,將顯示一條錯誤消息,不過,根據(jù)情況而定,可以方便地采取其他操作。

最后一項與 XML 有關(guān)的操作是將已更新的 XML 樹保存到磁盤,這一任務(wù)是使用 IXMLDOMDocument::save() 完成的:

hr = spXMLDOM->save(CComVariant("updatedxml.xml"));
if ( FAILED(hr) ) 
   throw "Unable to save updated XML document";

完成保存后,向屏幕寫一條簡短說明,并退出。

這個示例應(yīng)用程序無論如何都算不上漂亮。您可以讓自己的應(yīng)用程序執(zhí)行很多其他功能,但我希望您通過這個簡短的示例了解到了如何從 C++ 程序使用 MSXML 分析器。該分析器本身是一個復(fù)雜的軟件,無論怎樣強調(diào)使用 MSDN Library 作為參考,都不能算是過份。該分析器公開了許多接口,這些接口通常會公開許多方法。即便如此,我在自己的項目中仍頻繁地使用該分析器,在親自編寫了一些代碼并進行試驗后,我發(fā)現(xiàn)這個軟件制作很精良 并且便于使用。我希望您也同樣會發(fā)現(xiàn)該分析器和一般意義上的 XML 具有廣泛的用途。

要了解有關(guān) Visual C++ Developer 和 Pinnacle Publishing 的更多信息,請訪問他們的 Web 站點,網(wǎng)址為: http://www./

注:這不是 Microsoft Corporation 的網(wǎng)站。Microsoft 對該網(wǎng)站內(nèi)容不承擔(dān)責(zé)任。

本文復(fù)制自 Visual C++ Developer 的 2000 年 11 月刊。版權(quán)所有 2000,Pinnacle Publishing, Inc.(除非另行說明)。保留所有權(quán)利。Visual C++ Developer 是 Pinnacle Publishing, Inc. 獨立發(fā)行的產(chǎn)品。未經(jīng) Pinnacle Publishing, Inc. 事先同意,不得以任何形式使用或復(fù)制本文的任何部分(評論文章中的簡短引用除外)。要聯(lián)系 Pinnacle Publishing, Inc.,請致電 1-800-788-1900。

轉(zhuǎn)到原英文頁面


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多