这不是一个问题,因为我已经找到了解决方案.我花了很多时间,这就是我想在这里解释的原因.
Msxml基于COM,所以即使你有一些有用的类来处理内存分配问题,它也不是很容易在C中使用.但是编写一个新的XML解析器要困难得多,所以我想使用msxml.
问题:
我能够在互联网上找到足够的例子,在CComPtr的帮助下使用msxml(智能指针避免必须手动调用每个IXMLDOMNode的Release()),CComBSTR(将C字符串转换为字符串的COM格式)和CComVariant .这3个有用的类是ATL类,需要#include< atlbase.h>.
问题:Visual Studio 2008 Express(免费版)不包含ATL.
解:
使用comutil.h和comdef.h,其中包含一些简单的帮助器类:
> _bstr_t或多或少取代CComBSTR
> _variant_t或多或少取代CComVariant
> _com_ptr_t通过使用_COM_SMARTPTR_TYPEDEF间接替换CComPtr
小例子:
- #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();
- }
解决方法
也许尝试使用#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....