• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-2  評(píng)論-2  文章-0  trackbacks-0
              2007年3月31日
            原文地址:http://msdn.microsoft.com/msdnmag/issues/07/04/Xml/Default.aspx?loc=zh

            ??? 盡管 .NET Framework 不斷取得成功,Microsoft 仍然認(rèn)真對(duì)待本機(jī) C++ 開(kāi)發(fā)。通過(guò)引入 XmlLite(適合于用本機(jī) C++ 編寫(xiě)的應(yīng)用程序的高性能、低開(kāi)銷(xiāo) XML 讀取器和寫(xiě)入器)說(shuō)明了這一點(diǎn)。

            托管代碼通過(guò) System.Xml 命名空間廣泛支持 XML,而依賴(lài)于 COM 的傳統(tǒng) Visual Basic? 和 C++ 應(yīng)用程序可以訪問(wèn) Microsoft? XML 核心服務(wù) (MSXML) 中的類(lèi)似功能。但是,這些并沒(méi)有為需要快速精簡(jiǎn)的 XML 分析器的本機(jī) C++ 開(kāi)發(fā)人員提供富有吸引力的選項(xiàng)。開(kāi)始使用 XmlLite 吧。

            本文將探討您可以對(duì) XmlLite 執(zhí)行的操作。但是,首先,為設(shè)定預(yù)期,我希望快速回顧一下 XmlLite 未提供的內(nèi)容,至少是此初始版本中未提供的內(nèi)容。對(duì)于初學(xué)者,它既未提供文檔對(duì)象模型 (DOM) 實(shí)現(xiàn),也未提供 XML 架構(gòu)或文檔類(lèi)型定義 (DTD) 驗(yàn)證。它還缺少對(duì)高級(jí)工具的支持,例如基于光標(biāo)的導(dǎo)航(如 XPath)、樣式表和序列化。但是,通過(guò)建立在 XmlLite 之上的功能,可以根據(jù)需要填補(bǔ)任何空白,Microsoft .NET Framework 中的幾乎所有 XML 功能同樣都建立在 XmlReader 和 XmlWriter 類(lèi)之上。

            那么,XmlLite 提供了哪些內(nèi)容?簡(jiǎn)單地說(shuō),它提供了非緩存的只進(jìn)分析器(提供接收式編程模型)和非緩存的只進(jìn) XML 生成器。已證明這兩者是非常有價(jià)值的功能。


            為什么推出新的 XML 分析器?

            開(kāi)發(fā)人員日益熟悉他們每天使用的庫(kù),通過(guò)廣泛使用 XML,他們肯定會(huì)詢(xún)問(wèn)有關(guān)新推出的 XML 分析器的一些疑難問(wèn)題。要了解這一新分析器的價(jià)值,讓我們首先考慮一下 XML 分析器當(dāng)今的情形。

            很自然地,如果應(yīng)用程序已經(jīng)利用 .NET Framework,則決定通常是很簡(jiǎn)單的:只需使用 System.Xml 即可。為證明這一點(diǎn),XmlLite 的設(shè)計(jì)基于 .NET Framework 中 XmlReader 和 XmlWriter 類(lèi)的設(shè)計(jì)。從以 C++ 編寫(xiě)的托管應(yīng)用程序使用 XmlLite 通常沒(méi)有優(yōu)勢(shì)。XmlLite 的功能畢竟比 XmlReader 和 XmlWriter 類(lèi)提供的功能要少得多。(圖?1 中的表略述 XmlLite 中的主要類(lèi)型如何映射到 .NET Framework 中的主要類(lèi)型。)另一方面,如果應(yīng)用程序僅使用本機(jī)代碼,那么就 Microsoft 技術(shù)而言,MSXML 在傳統(tǒng)上是所選的解決方案。

            MSXML 提供了兩個(gè)差異很大的 XML 分析器。第一個(gè)分析器是在各種情形下可用的 DOM 實(shí)現(xiàn)。如果使用較小的 XML 文檔且需要隨機(jī)訪問(wèn) XML 文檔進(jìn)行內(nèi)存中讀取和寫(xiě)入,則 DOM 實(shí)現(xiàn)是一種合理的選擇。MSXML 的更高版本引入了“用于 XML 的簡(jiǎn)單 API (SAX2)”的實(shí)現(xiàn)。它實(shí)際上是否簡(jiǎn)單是有爭(zhēng)議的。使用 SAX2 時(shí)(甚至在開(kāi)始之前),您需要實(shí)現(xiàn)至少兩個(gè) COM 接口:一個(gè)用于接收 XML 文檔中各個(gè)節(jié)點(diǎn)的通知,另一個(gè)用于接收分析錯(cuò)誤的通知。

            將 SAX2 實(shí)現(xiàn)添加到 MSXML 的原因如下:與 DOM 實(shí)現(xiàn)不同,SAX2 分析器以數(shù)據(jù)流形式讀取 XML 文檔,并通知您何時(shí)到達(dá)各個(gè)節(jié)點(diǎn)。這意味著,您的應(yīng)用程序的內(nèi)存使用量并不隨所分析文檔的大小而增加。

            SAX2 存在的問(wèn)題以及 .NET Framework 不提供其實(shí)現(xiàn)的原因在于 SAX2 模型的內(nèi)在復(fù)雜性。它要求實(shí)現(xiàn)接口或事件,并強(qiáng)制開(kāi)發(fā)人員使用更為間接的編程模型,要求開(kāi)發(fā)人員管理注定會(huì)使應(yīng)用程序變得復(fù)雜的其他狀態(tài)。相反,.NET Framework 中的 XmlReader 和 XmlWriter 類(lèi)以及 XmlLite 的 IXmlReader 和 IXmlWriter 接口提供了簡(jiǎn)單易懂的分析器,可以直接在函數(shù)中使用,而不必管理任何外部狀態(tài)或通知。

            由于其設(shè)計(jì)的簡(jiǎn)明性,XmlLite 能夠提供相當(dāng)好的性能,即使與 MSXML SAX2 實(shí)現(xiàn)相比也是如此。雖然 SAX2 分析器可以比 DOM 實(shí)現(xiàn)更好地處理大型文檔,但是與 XmlLite 相比就遜色了。

            簡(jiǎn)單地說(shuō),XmlLite 優(yōu)于 MSXML,且它更易于從本機(jī) C++ 使用。MSXML 仍將是 Visual Basic 和基于 COM 的腳本語(yǔ)言的最可行解決方案,但是現(xiàn)在本機(jī) Visual C++? 最終具有了專(zhuān)門(mén)為它設(shè)計(jì)的 XML 分析器。雖然 Windows Vista? 和更高版本中附帶有 XmlLite,但是一個(gè)更新對(duì)于 Windows? XP 和 Windows Server? 2003 的 32 位和 64 位版本也是可用的。因?yàn)槲瓷婕?COM 注冊(cè),所以此更新包應(yīng)該不會(huì)導(dǎo)致 MSXML 通常造成的有關(guān)安裝和版本控制的難題。

            Back to top

            COM“Lite”

            XmlLite 不僅是易記的名稱(chēng);事實(shí)上,它是一個(gè)輕型 XML 分析器。XmlLite 利用了 COM 的精華,即編程規(guī)范和約定,并拋棄了復(fù)雜的和可能不必要的部分,如 COM 注冊(cè)、運(yùn)行時(shí)服務(wù)、代理、線程模型、封送處理等。

            從 XmlLite.dll 導(dǎo)出的函數(shù)創(chuàng)建 XML 讀取器和寫(xiě)入器。通過(guò)鏈接到 XmlLite.lib 并包括 Windows SDK 中的 XmlLite.h 頭文件,可以訪問(wèn)它們。生成的 COM 樣式接口使用熟悉的 IUnknown 接口方法進(jìn)行生存期管理。COM IStream 接口也起到一定作用并表示存儲(chǔ)器。除此之外,沒(méi)有 COM 的依賴(lài)項(xiàng);無(wú)需注冊(cè)任何 COM 類(lèi)或甚至調(diào)用強(qiáng)制性的 CoInitialize 函數(shù)。活動(dòng)模板庫(kù) (ATL) CComPtr 類(lèi)處理剩余的一小部分 COM。但是,您確實(shí)需要關(guān)注線程安全,因?yàn)槌鲇趩尉€程方案中的性能,XmlLite 不是線程安全的。

            我在以下示例中使用 COM_VERIFY 宏,以便清晰地識(shí)別方法在何處返回需要檢查的 HRESULT。可以將此替換為相應(yīng)的錯(cuò)誤處理 - 不管該操作引發(fā)異常還是您自己返回 HRESULT。

            Back to top

            讀取 XML

            XmlLite 提供了返回 IXmlReader 接口實(shí)現(xiàn)的 CreateXmlReader 函數(shù):

            CComPtr<IXmlReader> reader;
            COM_VERIFY(::CreateXmlReader(__uuidof(IXmlReader),
                                         reinterpret_cast<void**>(&reader),
                                         0));
            

            雖然是可選的,但是 CComPtr 類(lèi)模板確保迅速釋放接口指針。

            CreateXmlReader 接受接口標(biāo)識(shí)符 (IID) 以及指向 void 指針的指針。這是 COM 編程中的常見(jiàn)模式,允許調(diào)用方指定要返回的接口指針的類(lèi)型。我的示例使用 __uuidof 運(yùn)算符,該運(yùn)算符是 Microsoft 特定的關(guān)鍵字,用于提取與類(lèi)型關(guān)聯(lián)的 GUID。在這種情況下,它用于檢索接口的 IID。CreateXmlReader 的最后一個(gè)參數(shù)接受可選的 IMalloc 實(shí)現(xiàn)以允許調(diào)用方控制內(nèi)存分配。

            創(chuàng)建讀取器后,需要指示讀取器將用作輸入的存儲(chǔ)器。IStream 接口表示存儲(chǔ)器,這樣就可以將 XmlLite 與可能設(shè)計(jì)的任何流實(shí)現(xiàn)一起使用:

            CComPtr<IStream> stream;
            
            // Create stream object here...
            
            COM_VERIFY(reader->SetInput(stream));
            

            (我將在本文的后面部分中討論流。)

            設(shè)置 XML 讀取器的輸入后,可以通過(guò)重復(fù)調(diào)用 Read 方法進(jìn)行讀取。Read 方法接受一個(gè)可選參數(shù),該參數(shù)在每次成功調(diào)用時(shí)返回節(jié)點(diǎn)類(lèi)型。Read 方法返回 S_OK 以指示已從流中成功讀取下一個(gè)節(jié)點(diǎn),返回 S_FALSE 以指示已到達(dá)流的結(jié)尾處。以下是如何依次枚舉節(jié)點(diǎn)的一個(gè)示例:

            HRESULT result = S_OK;
            XmlNodeType nodeType = XmlNodeType_None;
            
            while (S_OK == (result = reader->Read(&nodeType)))
            {
                // Get node-specific info
            }
            

            要枚舉當(dāng)前節(jié)點(diǎn)的屬性,請(qǐng)使用 MoveToFirstAttribute 和 MoveToNextAttribute 方法。如果已成功地重新定位讀取器,則這兩種方法都返回 S_OK;如果不存在更多的屬性,則返回 S_FALSE。以下示例說(shuō)明如何依次枚舉給定節(jié)點(diǎn)的屬性:

            for (HRESULT result = reader->MoveToFirstAttribute(); 
                 S_OK == result;
                 result = reader->MoveToNextAttribute())
            {
                // Get attribute-specific info
            }
            

            調(diào)用 IXmlReader 的 Read 方法時(shí),它會(huì)將任何節(jié)點(diǎn)屬性自動(dòng)存儲(chǔ)在內(nèi)部集合中。這樣,您就可以使用 MoveToAttributeByName 方法,按名稱(chēng)將讀取器移動(dòng)到特定的屬性。但是,枚舉屬性并將其存儲(chǔ)在應(yīng)用程序特定的數(shù)據(jù)結(jié)構(gòu)中,效率通常更高。請(qǐng)注意,您還可以使用 GetAttributeCount 方法確定當(dāng)前節(jié)點(diǎn)中的屬性數(shù)。

            確定節(jié)點(diǎn)或?qū)傩院螅@取其信息就很簡(jiǎn)單了。以下示例演示如何獲取給定節(jié)點(diǎn)的命名空間 URI 和本地名稱(chēng):

            PCWSTR namespaceUri = 0;
            UINT namespaceUriLength = 0;
            
            COM_VERIFY(reader->GetNamespaceUri(&namespaceUri, 
                                               &namespaceUriLength));
            
            PCWSTR localName = 0;
            UINT localNameLength = 0;
            
            COM_VERIFY(reader->GetLocalName(&localName, 
                                            &localNameLength));
            

            返回字符串值的所有 IXmlReader 方法都遵循此模式。第一個(gè)參數(shù)接受指向?qū)捵址羔槼A康闹羔槨5诙€(gè)參數(shù)是可選的;如果它不為零,則它將返回以字符度量的字符串長(zhǎng)度(不包括空結(jié)束符)。

            以下是強(qiáng)調(diào)性能的另一個(gè)示例。僅在將讀取器移動(dòng)到其他節(jié)點(diǎn)或以某種其他方式(如通過(guò)設(shè)置新的輸入流或釋放 IXmlReader 接口)使當(dāng)前節(jié)點(diǎn)無(wú)效之前,從 IXmlReader 方法返回的字符串指針才是有效的。換句話說(shuō),IXmlReader 不會(huì)將流的副本返回給調(diào)用方。

            與其在 .NET Framework 中的對(duì)應(yīng)方不同,IXmlReader 未提供讀取鍵入內(nèi)容的任何方法。例如,如果特定的元素或?qū)傩园瑪?shù)字或日期,則您需要首先獲取其字符串表示形式,然后根據(jù)需要自己進(jìn)行轉(zhuǎn)換。.NET Framework 的 XmlReader 類(lèi)中存在的許多其他 helper 方法也不存在于 IXmlReader 中,但是可以作為 helper 函數(shù)編寫(xiě)。XmlLite 確實(shí)符合最小接口設(shè)計(jì)的 C++ 理論。

            圖?2 顯示使用 IXmlReader 讀取 XML 文檔時(shí)涉及的對(duì)象和抽象。但是,請(qǐng)牢記,IStream 可以抽取任何存儲(chǔ),此處顯示的文件僅僅是一個(gè)常見(jiàn)示例。

            圖 2 讀取器
            圖 2?讀取器
            Back to top

            寫(xiě)入 XML

            XmlLite 提供了返回 IXmlWriter 接口實(shí)現(xiàn)的 CreateXmlWriter 函數(shù):

            CComPtr<IXmlWriter> writer;
            
            COM_VERIFY(::CreateXmlWriter(__uuidof(IXmlWriter),
                                         reinterpret_cast<void**>(&writer),
                                         0));
            

            創(chuàng)建寫(xiě)入器后,需要指示寫(xiě)入器將用作輸出的存儲(chǔ)器:

            CComPtr<IStream> stream;
            
            // Create stream object here
            
            COM_VERIFY(writer->SetOutput(stream));
            

            開(kāi)始寫(xiě)入之前,可以修改寫(xiě)入器屬性。XmlWriterProperty 枚舉定義可用的屬性。例如,您可能希望指定是否縮進(jìn) XML 輸出以便于讀者閱讀(使用 SetProperty 方法可以做到這一點(diǎn)):

            COM_VERIFY(writer->SetProperty(XmlWriterProperty_Indent, TRUE));
            

            然后可以開(kāi)始使用 IXmlWriter 方法寫(xiě)入基礎(chǔ)流。XmlLite 支持 XML 片段。如果計(jì)劃寫(xiě)入完整的 XML 文檔,則應(yīng)該從調(diào)用 WriteStartDocument 方法(它負(fù)責(zé)寫(xiě)入 XML 聲明)開(kāi)始。聲明取決于所用的編碼,但是默認(rèn)編碼為 UTF-8,它在大多數(shù)情況下都應(yīng)該是合適的。(稍后將介紹文本編碼。)提供了許多 WriteXxx 方法,用于寫(xiě)入各種節(jié)點(diǎn)類(lèi)型、屬性和值。

            請(qǐng)考慮以下示例:

            COM_VERIFY(writer->WriteStartDocument(XmlStandalone_Omit));
            COM_VERIFY(writer->WriteStartElement(0, L"html", 
                                                 L"http://www.w3.org/1999/xhtml"));
            
            COM_VERIFY(writer->WriteStartElement(0, L"head", 0));
            COM_VERIFY(writer->WriteElementString(0, L"title", 0, L"My Web Page"));
            COM_VERIFY(writer->WriteEndElement()); // </head>
            
            COM_VERIFY(writer->WriteStartElement(0, L"body", 0));
            COM_VERIFY(writer->WriteElementString(0, L"p", 0, L"Hello world!"));
            
            COM_VERIFY(writer->WriteEndDocument());
            

            WriteStartDocument 方法處理將 XML 聲明寫(xiě)入流的操作。它只有一個(gè)參數(shù),該參數(shù)接受來(lái)自 XmlStandalone 枚舉的值,指示是否出現(xiàn)獨(dú)立的文檔聲明,如果是這樣,則指示它保存的值。寫(xiě)入 XML 片段時(shí),通常省略對(duì) WriteStartDocument 的調(diào)用。

            WriteStartElement 方法接受以下三個(gè)參數(shù):第一個(gè)參數(shù)指定元素的可選命名空間前綴,第二個(gè)參數(shù)指定元素的本地名稱(chēng),第三個(gè)參數(shù)指定可選的命名空間 URI。WriteElementString 是 XmlLite 提供的非常方便的方法之一。用于寫(xiě)入 XHTML 文檔標(biāo)題的以下代碼等效于上一示例中使用的 WriteElementString:

            COM_VERIFY(writer->WriteStartElement(0, L"title", 0));
            COM_VERIFY(writer->WriteString(L"My Web Page"));
            COM_VERIFY(writer->WriteEndElement());
            

            顯然,WriteElementString 方法不是絕對(duì)必要的,但它確實(shí)很有用。

            最后,WriteEndDocument 方法用于關(guān)閉文檔。您可能已注意到,未顯式關(guān)閉 body 和 html 元素。WriteEndDocument 會(huì)自動(dòng)關(guān)閉任何打開(kāi)的元素。就此而言,釋放寫(xiě)入器也會(huì)關(guān)閉任何剩余的元素。但是,如果您不小心,則未顯式關(guān)閉此類(lèi)元素的做法可能會(huì)導(dǎo)致錯(cuò)誤,因?yàn)榱鞯纳嫫诤蛯?xiě)入器的生存期通常可以不同。要說(shuō)的是,如果需要確保已將所有要寫(xiě)入的內(nèi)容寫(xiě)入基礎(chǔ)流,則只需調(diào)用 IXmlWriter 的 Flush 方法即可。

            圖?3 顯示使用 IXmlWriter 寫(xiě)入 XML 文檔時(shí)涉及的對(duì)象和抽象流。請(qǐng)牢記,IStream 可以抽取任何存儲(chǔ),此處的文件僅僅是一個(gè)常見(jiàn)示例。

            圖 3 寫(xiě)入器
            圖 3?寫(xiě)入器
            Back to top

            使用流

            到此為止,我對(duì)流進(jìn)行的介紹并不多。與一些功能更全面的 XML 庫(kù)不同,XmlLite 未提供任何支持從公共存儲(chǔ)位置(如文件或通過(guò)網(wǎng)絡(luò)協(xié)議)讀取和向其寫(xiě)入的功能。正因?yàn)檫@一點(diǎn),對(duì)于希望從其讀取或向其寫(xiě)入的任何存儲(chǔ)器,您都需要提供 IStream 實(shí)現(xiàn)。實(shí)現(xiàn) IStream 接口并不復(fù)雜,但是在許多情況下,您不需要執(zhí)行此操作,因?yàn)閷?shí)現(xiàn)可能已存在。

            CreateStreamOnHGlobal 函數(shù)提供由虛擬內(nèi)存支持的 IStream 實(shí)現(xiàn)。第一個(gè)參數(shù)是使用 GlobalAlloc 函數(shù)創(chuàng)建的可選內(nèi)存句柄。但是,只需傳遞零,CreateStreamOnHGlobal 即可為您創(chuàng)建內(nèi)存對(duì)象。以下示例創(chuàng)建一個(gè)由系統(tǒng)內(nèi)存支持且將根據(jù)需要?jiǎng)討B(tài)增長(zhǎng)的 IStream 實(shí)現(xiàn):

            CComPtr<IStream> stream;
            COM_VERIFY(::CreateStreamOnHGlobal(0, TRUE, &stream));
            

            釋放流將釋放內(nèi)存。

            SHCreateStreamOnFile 函數(shù)提供了另一個(gè)有用的 IStream 實(shí)現(xiàn)。它創(chuàng)建由文件支持的 IStream:

            CComPtr<IStream> stream;
            COM_VERIFY(::SHCreateStreamOnFile(L"D:\\Sample.xml",
                                              STGM_WRITE | STGM_SHARE_DENY_WRITE,
                                              &stream));
            

            Back to top

            讀取時(shí)的文本編碼

            雖然默認(rèn)情況下 XmlLite 使用 UTF-8 進(jìn)行寫(xiě)入,但是如果在讀取時(shí)嘗試檢測(cè)文本編碼,則可以覆蓋此行為。首先,讓我們看一下您將自動(dòng)獲取的信息。對(duì)于給定的流,IXmlReader 將通過(guò)作為 XML 前同步碼的字節(jié)順序標(biāo)記來(lái)檢測(cè)編碼提示。IXmlReader 還將允許在 XML 聲明中指定的任何編碼。期望任何 XML 分析器都具有這兩個(gè)特征。如果具有可能未定義任何編碼信息的輸入流,而且 XmlLite 無(wú)法試探性地確定正使用的編碼,則可以將 IXmlReader 定向到特定的編碼(如果給定了代碼頁(yè)或編碼名稱(chēng))。

            可以假借 IXmlReaderInput 接口創(chuàng)建 XML 讀取器輸入對(duì)象,而不是將流直接傳遞到 IXmlReader。提供了兩個(gè)用于創(chuàng)建包裝輸入流的輸入對(duì)象的函數(shù)。CreateXmlReaderInputWithEncodingCodePage 函數(shù)接受代碼頁(yè)編號(hào)形式的代碼。CreateXmlReaderInputWithEncodingName 函數(shù)接受使用其規(guī)范名稱(chēng)的編碼。除此之外,這兩個(gè)函數(shù)具有完全相同的簽名。概括一下,通常可以對(duì) XML 讀取器的輸入流進(jìn)行如下設(shè)置:

            CComPtr<IStream> stream;
            
            // Create stream object here
            
            COM_VERIFY(reader->SetInput(stream));
            

            要覆蓋編碼,請(qǐng)將代碼更改為:

            CComPtr<IStream> stream;
            
            // Create stream object here
            
            CComPtr<IXmlReaderInput> input;
            
            COM_VERIFY(::CreateXmlReaderInputWithEncodingName(stream,
                                                              0, // default allocator
                                                              L"ISO-8859-8",
                                                              TRUE, // hint
                                                              0, // base URI
                                                              &input));
            
            COM_VERIFY(reader->SetInput(input));
            

            第一個(gè)參數(shù)指示 XML 讀取器將從其讀取的流。第二個(gè)參數(shù)接受可選的 IMalloc 實(shí)現(xiàn)。如果提供的話,則它將覆蓋 XML 讀取器自己的實(shí)現(xiàn)。第三個(gè)參數(shù)指定編碼名稱(chēng)。msdn2.microsoft.com/ms752827.aspx 上的文檔列出了本機(jī)支持的編碼;要支持其他編碼,可以提供 IMultiLanguage2 接口實(shí)現(xiàn)。下一個(gè)參數(shù)指示是否必須使用指定的編碼或者它是否僅僅是一個(gè)提示。如果指定 TRUE,則指示分析器嘗試使用建議的編碼,但是如果它失敗,則可以隨意嘗試試探性地確定實(shí)際的編碼。如果指定 FALSE,則指示分析器嘗試建議的編碼;如果它與輸入流不匹配,則返回錯(cuò)誤。下一個(gè)參數(shù)接受可能用于解析外部實(shí)體的可選基本 URI。最后一個(gè)參數(shù)返回表示要傳遞到 SetInput 方法的輸入對(duì)象的接口指針。

            Back to top

            寫(xiě)入時(shí)的文本編碼

            XML 寫(xiě)入器將基于傳遞到 SetOutput 方法的對(duì)象確定要使用的編碼。如果該對(duì)象實(shí)現(xiàn) IStream 接口或者甚至實(shí)現(xiàn)有限的 ISequentialStream 接口,則 XML 寫(xiě)入器將使用 UTF-8 編碼。可以創(chuàng)建 XML 寫(xiě)入器輸出對(duì)象來(lái)覆蓋此行為。提供了兩個(gè)用于創(chuàng)建包裝輸出流的輸出對(duì)象的函數(shù)。CreateXmlWriterOutputWithEncodingCodePage 函數(shù)接受代碼頁(yè)編號(hào)形式的編碼,而 CreateXmlWriterOutputWithEncodingName 函數(shù)接受使用其規(guī)范名稱(chēng)的編碼。除此之外,這兩個(gè)函數(shù)具有完全相同的簽名。通常,可以對(duì) XML 寫(xiě)入器的輸出流進(jìn)行如下設(shè)置:

            CComPtr<IStream> stream;
            
            // Create stream object here
            
            COM_VERIFY(writer->SetOutput(stream));
            

            要覆蓋默認(rèn)編碼,請(qǐng)編寫(xiě)以下代碼:

            CComPtr<IStream> stream;
            
            // Create stream object here
            
            CComPtr<IXmlWriterOutput> output;
            
            COM_VERIFY(::CreateXmlWriterOutputWithEncodingName(stream,
                                                               0,
                                                               L"ISO-8859-8",
                                                               &output));
            
            COM_VERIFY(writer->SetOutput(output));
            

            第一個(gè)參數(shù)指示 XML 寫(xiě)入器將寫(xiě)入的流。第二個(gè)參數(shù)接受可選的 IMalloc 實(shí)現(xiàn)。如果提供的話,則它將覆蓋 XML 寫(xiě)入器自己的實(shí)現(xiàn)。第三個(gè)參數(shù)指定編碼名稱(chēng)。最后一個(gè)參數(shù)返回表示要傳遞到 SetOutput 方法的輸出對(duì)象的接口指針。

            Back to top

            處理大數(shù)據(jù)值

            為了在讀取大數(shù)據(jù)值時(shí)限制內(nèi)存使用,XML 讀取器提供了按數(shù)據(jù)塊讀取值的機(jī)制。IXmlReader ReadValueChunk 方法讀取的字符數(shù)不超過(guò)規(guī)定的最大字符數(shù),在預(yù)料到后續(xù)調(diào)用時(shí)向前移動(dòng)讀取器。以下示例說(shuō)明如何重復(fù)調(diào)用 ReadValueChunk 以讀取大數(shù)據(jù)值:

            CString value;
            
            WCHAR chunk[256] = { 0 };
            HRESULT result = S_OK;
            UINT charsRead = 0;
            
            while (S_OK == (result = reader->ReadValueChunk(chunk,
                                                            countof(chunk),
                                                            &charsRead)))
            {
                value.Append(chunk, charsRead);
            }
            

            當(dāng)不再有數(shù)據(jù)可用時(shí),ReadValueChunk 返回 S_FALSE。在此示例中,我要將數(shù)據(jù)塊寫(xiě)入 CString 對(duì)象。這僅僅是為了說(shuō)明如何管理數(shù)據(jù)塊的長(zhǎng)度,顯然這在實(shí)際中會(huì)抵消數(shù)據(jù)分塊的優(yōu)勢(shì)。

            Back to top

            安全注意事項(xiàng)

            以 XML 為中心的應(yīng)用程序必須總是處理來(lái)自不可信源的 XML。XmlLite 提供了許多工具以保護(hù)應(yīng)用程序免受已知漏洞和將來(lái)漏洞的攻擊。

            XML 文檔可以包含對(duì)外部實(shí)體的引用。一些 XML 分析器自動(dòng)解析這些實(shí)體。雖然此方法可能很有用,但是,如果未仔細(xì)編寫(xiě) XML 解析程序以緩解各種威脅,則此方法可能會(huì)造成安全漏洞的攻擊。XmlLite 既不自動(dòng)解析外部實(shí)體,也不提供 XML 解析程序。要提供自己的實(shí)現(xiàn)(如有必要),請(qǐng)實(shí)現(xiàn) IXmlResolver 接口并將 XmlReaderProperty_XmlResolver 屬性與 IXmlReader SetProperty 方法一起使用,以指示讀取器使用您的解析程序。

            XML 文檔可能還包含 DTD 處理說(shuō)明。雖然 XmlLite 不支持文檔驗(yàn)證(使用 XML 架構(gòu)或 DTD),但是它支持 DTD 實(shí)體擴(kuò)展和默認(rèn)屬性。由于這些 DTD 可以包含對(duì)外部實(shí)體的引用,因此它們可能會(huì)使您的應(yīng)用程序受到各種攻擊。默認(rèn)情況下,XmlLite 禁用 DTD 處理。通過(guò)將 XmlReaderProperty_DtdProcessing 屬性設(shè)置為 DtdProcessing_Parse 值,可以允許 DTD 處理。此外,還存在由 XmlReaderProperty_MaxEntityExpansion 控制的 DTD 實(shí)體擴(kuò)展攻擊(也稱(chēng)為 billion laughs 攻擊)的內(nèi)置緩解措施。此屬性的默認(rèn)值為 100,000。

            攻擊者可以利用使用 XML 的應(yīng)用程序的另一種方法是,創(chuàng)建名稱(chēng)非常長(zhǎng)的文檔。如果未能阻止,則這可能用盡巨大的內(nèi)存并允許拒絕服務(wù)攻擊。我已經(jīng)提示了可以執(zhí)行的方法。緩解此類(lèi)威脅的一種明顯方法是,按數(shù)據(jù)塊讀取大數(shù)據(jù)值,如上一部分所述。另一種有用的方法是,提供限制內(nèi)存分配的自定義 IMalloc 實(shí)現(xiàn)。如果輸入流支持隨機(jī)訪問(wèn),則還可以指示 XML 讀取器使用 XmlReaderProperty_RandomAccess 屬性來(lái)避免緩存屬性。這將減少用于讀取開(kāi)始元素標(biāo)記的內(nèi)存量,但是也可能降低分析速度,因?yàn)榉治銎鞅仨殎?lái)回查找以便在請(qǐng)求時(shí)檢索各個(gè)屬性值。

            如果 XML 層次結(jié)構(gòu)過(guò)深,則也可能快速用盡系統(tǒng)資源。要阻止攻擊者提供層次結(jié)構(gòu)過(guò)深的 XML 文檔,可以使用 XmlReaderProperty_MaxElementDepth 屬性限制分析器將允許的深度。此屬性默認(rèn)為 256。

            Back to top

            總結(jié)

            XmlLite 為本機(jī) C++ 應(yīng)用程序提供了功能強(qiáng)大的 XML 分析器。它著重于性能,知道它所使用的系統(tǒng)資源,為控制這些特征提供了很大的靈活性。XmlLite 支持所有的常見(jiàn)文本編碼,是一種非常有用的實(shí)用工具,可以簡(jiǎn)化本機(jī) C++ 應(yīng)用程序中的 XML 使用。有關(guān)詳細(xì)信息,請(qǐng)參閱 msdn2.microsoft.com/ms752872.aspx 上的 XmlLite 文檔。

            posted @ 2007-03-31 16:50 Canny 閱讀(1062) | 評(píng)論 (2)編輯 收藏
              2007年3月17日

            整型:
            C++ 基本整型 為? char?、 short、? int、? long? 其中每種類(lèi)型都有有符號(hào)版本和無(wú)符號(hào)版本。因此總共有8種類(lèi)型可供選擇。
            C++ 對(duì)長(zhǎng)度的規(guī)定
            short 至少 16位
            int 至少和short 一樣長(zhǎng)
            long 至少32位,且至少要和int 一樣長(zhǎng)。

            無(wú)符號(hào)版本? 在 前面添加關(guān)鍵字? unsigned
            unsigned short?????????? unsigned int?? unsigned long???????????? ,如果 只是 unsigned? 就是? unsigned int 的簡(jiǎn)寫(xiě)。

            posted @ 2007-03-17 19:28 Canny| 編輯 收藏
            僅列出標(biāo)題  
            99re这里只有精品热久久| 久久久精品国产sm调教网站 | 久久夜色精品国产www| 久久久久亚洲AV无码专区桃色 | 999久久久免费国产精品播放| 亚洲一区二区三区日本久久九| 久久久久这里只有精品 | 久久人人爽人人爽AV片| 亚洲精品国产第一综合99久久| 少妇高潮惨叫久久久久久| 久久99国产精品久久久| 亚洲性久久久影院| 久久亚洲精品视频| 亚洲精品乱码久久久久久中文字幕 | 伊人 久久 精品| 丰满少妇人妻久久久久久4| 国产色综合久久无码有码| 久久精品国产只有精品66| 色欲综合久久躁天天躁蜜桃| 理论片午午伦夜理片久久| 久久se精品一区二区| 亚洲国产另类久久久精品黑人| 精品久久久久一区二区三区| 狠狠88综合久久久久综合网| 色综合久久无码中文字幕| 超级97碰碰碰碰久久久久最新| 国产精品美女久久久久AV福利| 亚洲色欲久久久综合网东京热| 亚洲精品无码久久久| 久久播电影网| 国产福利电影一区二区三区久久久久成人精品综合 | 国产精品久久久久影院色| 久久久久av无码免费网| 久久久国产精品| 欧美色综合久久久久久| 久久无码国产| 婷婷久久综合| 久久久久久精品免费看SSS| 久久综合久久美利坚合众国 | 日本久久久久久中文字幕| 国产一级持黄大片99久久|