2009-01-21 59 views
6

這不是一個真正的問題,因爲我已經找到了解決方案。這花了我很多時間,這就是爲什麼我想在這裏解釋它。如何在沒有變得瘋狂的情況下將Visual Studio 2008 Express(無ATL類)使用msxml?

Msxml基於COM,因此即使在您有用於處理內存分配問題的有用類時,在C++中使用也不是很容易。但是編寫一個新的XML解析器會困難得多,所以我想使用msxml。

問題:

我能在互聯網上找到足夠的例子使用MSXML與CComPtr的幫助(智能指針,以避免手動調用Release()對每個IXMLDOMNode),CComBSTR(將C++字符串轉換爲字符串的COM格式)和CComVariant。這3個有用的課程是ATL課程,需要#include <atlbase.h>

問題:Visual Studio 2008 Express(免費版)不包括ATL。

解決方案:

使用comutil.hcomdef.h,其中包括一些簡單的輔助類:

  • _bstr_t取代或多或少CComBSTR
  • _variant_t取代或多或少CComVariant
  • _com_ptr_t內容替換間接地CComPtr通過使用_COM_SMARTPTR_TYPEDEF

小例子:

#include <msxml.h> 
#include <comdef.h> 
#include <comutil.h> 

// Define some smart pointers for MSXML 
_COM_SMARTPTR_TYPEDEF(IXMLDOMDocument,  __uuidof(IXMLDOMDocument));  // IXMLDOMDocumentPtr 
_COM_SMARTPTR_TYPEDEF(IXMLDOMElement,  __uuidof(IXMLDOMElement));  // IXMLDOMElementPtr 
_COM_SMARTPTR_TYPEDEF(IXMLDOMNodeList,  __uuidof(IXMLDOMNodeList));  // IXMLDOMNodeListPtr 
_COM_SMARTPTR_TYPEDEF(IXMLDOMNamedNodeMap, __uuidof(IXMLDOMNamedNodeMap)); // IXMLDOMNamedNodeMapPtr 
_COM_SMARTPTR_TYPEDEF(IXMLDOMNode,   __uuidof(IXMLDOMNode));   // IXMLDOMNodePtr 

void test_msxml() 
{ 
    // This program will use COM 
    CoInitializeEx(NULL, COINIT_MULTITHREADED); 

    { 
     // Create parser 
     IXMLDOMDocumentPtr pXMLDoc; 
     HRESULT hr = CoCreateInstance(__uuidof (DOMDocument), NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&pXMLDoc); 
     pXMLDoc->put_validateOnParse(VARIANT_FALSE); 
     pXMLDoc->put_resolveExternals(VARIANT_FALSE); 
     pXMLDoc->put_preserveWhiteSpace(VARIANT_FALSE); 

     // Open file 
     VARIANT_BOOL bLoadOk; 
     std::wstring sfilename = L"testfile.xml"; 
     hr = pXMLDoc->load(_variant_t(sfilename.c_str()), &bLoadOk); 

     // Search for node <testtag> 
     IXMLDOMNodePtr pNode; 
     hr = pXMLDoc->selectSingleNode(_bstr_t(L"testtag"), &pNode); 

     // Read something 
     _bstr_t bstrText; 
     hr = pNode->get_text(bstrText.GetAddress()); 
     std::string sSomething = bstrText; 
    } 

    // I'm finished with COM 
    // (Don't call before all IXMLDOMNodePtr are out of scope) 
    CoUninitialize(); 
} 
+0

VS2008 express不包括ATL?這很糟糕。 > :( – 2009-01-21 22:39:54

回答

1

我很高興我發佈了我的問題,雖然我已經有了一個解決方案,因爲我有幾個替代解決方案。謝謝你的答案。

使用另一種解析器如eXpat或可能較小(不那麼強大,但足夠滿足我的需求)TinyXML實際上可能是一個好主意(並使其更容易移植程序到另一個操作系統)。

使用#import指令,顯然是一個簡化COM使用的Microsoft特定擴展,也很有趣,並將我帶到以下網頁MSXML in C++ but as elegant as in C#,它解釋瞭如何儘可能簡化msxml的使用。

1

另一種辦法是使用一個已經完成,另一個such as eXpat XML解析器。它避免了必須使用ATL和COM的複雜性,並且比實現自己的方法更容易。我建議這只是因爲你已經說過,你在看msxml的原因是因爲你不想實現你自己的解析器。

+0

我已經考慮過使用eXpat,但由於msxml已經在電腦上,所以我認爲使用它可以幫助製作更小的程序。但是如果在此之前我已經知道COM的困難,那麼我可能會使用eXpat .. – Name 2009-01-23 19:02:47

7

也許嘗試使用#import聲明。

我用它在VS6項目我都四處張望,你做這樣的事情(只用於說明目的,這爲我工作,但我不宣稱自己是錯誤的證明):

#import "msxml6.dll" 

    ... 

MSXML2::IXMLDOMDocument2Ptr pdoc; 
HRESULT hr = pdoc.CreateInstance(__uuidof(MSXML2::DOMDocument60)); 
if (!SUCCEEDED(hr)) return hr; 

MSXML2::IXMLDOMDocument2Ptr pschema; 
HRESULT hr = pschema.CreateInstance(__uuidof(MSXML2::DOMDocument60)); 
if (!SUCCEEDED(hr)) return hr; 

pschema->async=VARIANT_FALSE; 
VARIANT_BOOL b; 
b = pschema->loadXML(_bstr_t(/* your schema XML here */)); 

MSXML2::IXMLDOMSchemaCollection2Ptr pSchemaCache; 
hr = pSchemaCache.CreateInstance(__uuidof(MSXML2::XMLSchemaCache60)); 
if (!SUCCEEDED(hr)) return hr; 

_variant_t vp=pschema.GetInterfacePtr(); 
pSchemaCache->add(_bstr_t(/* your namespace here */),vp); 

pdoc->async=VARIANT_FALSE; 
pdoc->schemas = pSchemaCache.GetInterfacePtr(); 
pdoc->validateOnParse=VARIANT_TRUE; 
if (how == e_filename) 
    b = pdoc->load(v); 
else 
    b = pdoc->loadXML(bxmldoc); 

pXMLError = pdoc->parseError; 
if (pXMLError->errorCode != 0) 
    return E_FAIL; // an unhelpful return code, sigh.... 
+0

#import是最好的方式去,很容易,很少代碼寫yoourself – galets 2009-01-21 23:57:19

+0

我以前沒有聽說過關於「#import」(與C++我花了更多的時間在Unix下比直到現在在Windows下)。似乎很有趣 – Name 2009-01-23 18:59:59

0

你爲什麼不使用一些MSXML封裝來屏蔽你的COM呢,比如Arabica

+0

感謝您的回答,但我並不想添加一個間接層來使用XML解析器 – Name 2009-01-23 19:06:26

1

您可以使用TinyXML。它是獨立於平臺的開放源代碼。

相關問題