2017-10-14 41 views
1

如果有任何一種靈魂在那裏請通過以下源代碼並告訴我爲什麼MSXML「加載」函數無法加載此XML。傳遞字節的SAFEARRAY來加載MSXML的函數

這裏我試圖使用MSXML解析器的「加載」函數加載UTF-8編碼的XML。我有一個BSTR [UTF-16編碼]作爲參數,所以我試圖將它轉換成SAFEARRAY字節,以便我可以將它傳遞到MSXML的「加載」功能。但問題是加載函數無法加載這個XML。如果有人能提供解決方案,我會非常感激。

#include <windows.h> 
#include <objsafe.h> 
#include <objbase.h> 
#include <atlbase.h> 
#include <string> 
#include <comutil.h> 
#include <msxml2.h> 
#include <iostream> 

using namespace std; 

#define STATUS_SUCCESS 0 
#define STATUS_FAIL -1 

long LoadXmlData(BSTR xmlDoc) 
{ 
HRESULT hr = S_OK; 
CComPtr <IXMLDOMDocument> xmlDomDoc = NULL; 
CComPtr <IXMLDOMElement> docRoot = NULL; 
VARIANT_BOOL isParseSucess = FALSE; 

CoInitialize(NULL); 
hr = xmlDomDoc.CoCreateInstance(__uuidof(DOMDocument30)); 
if (FAILED(hr)) 
{ 
    return STATUS_FAIL; 
} 

BYTE HUGEP *pByte; 
int len = WideCharToMultiByte(CP_UTF8, 0, xmlDoc, -1, NULL, 0, NULL, NULL); 
SAFEARRAYBOUND rgsabound[1]; 
rgsabound[0].cElements = len; 
rgsabound[0].lLbound = 0; 

SAFEARRAY* psa = SafeArrayCreate(VT_UI1, 1, rgsabound); 
if (psa != NULL) 
{ 
    hr = SafeArrayAccessData(psa, (void HUGEP**)&pByte); 
    if (!FAILED(hr)) 
    { 
     if (len > 0) 
     { 
      WideCharToMultiByte(CP_UTF8, 0, xmlDoc, -1, (LPSTR)&pByte[0], len, NULL, NULL); 
      //cout << "Converted Byte Array: " << pByte << endl << endl; 
     } 
     else 
     { 
      return STATUS_FAIL; 
     } 
     SafeArrayUnaccessData(psa); 
    } 
} 

VARIANT v; 
VariantInit(&v); 
V_VT(&v) = VT_ARRAY | VT_UI1; 
V_ARRAY(&v) = psa; 

hr = xmlDomDoc->load(v, &isParseSucess); 
//hr = xmlDomDoc->loadXML(xmlDoc, &isParseSucess); //can't use this function because XML is encoded in UTF-8 

if (FAILED(hr) || (!isParseSucess)) 
{ 
    return STATUS_FAIL; 
} 
else 
{ 
    return STATUS_SUCCESS; 
} 
} 

int main() 
{ 
BSTR xmlDoc = SysAllocString(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?> <response> </response> "); 
long ret = LoadXmlData(xmlDoc); 
if (ret == STATUS_SUCCESS) 
{ 
    cout << "MSXML: loading the XML succeeded"; 
} 
else 
{ 
    cout << "MSXML: loading the XML failed"; 
} 
//string str; 
//getline(cin, str); 
return 0; 
} 

PS:如果有人試圖編譯這個源你可以得到一個鏈接錯誤第一次加comsuppw.lib在VS設置的連接依賴。而且XML是UTF-8編碼的,所以我不能在MSXML中使用「LoadXML」函數。

+1

您的代碼有很多問題。 1)你*必須*使用'loadXml',沒有其他可能。 2)這不是因爲你在文本流中放置了「utf-8」,而是utf-8。你這樣定義的xmlDoc BSTR實際上是unicode(所以你可以直接在loadXml中使用它)。 3)那麼你的原始UTF-8字符串在哪裏?它在技術上如何定義?字節數組輸入,其他? –

回答

1

XML文件是UTF-8,但也沒有必要,因爲當Windows功能將自動UTF-16和UTF-8之間進行轉換需要在這裏轉換(除非輸入/輸出BYTE* ...)

BSTR需求清理。您可以使用自動清理的CComBSTR(str)

您可以使用const wchar_t*將字符串傳遞給您自己的函數。 COM等需要BSTR

正如評論中指出的那樣,IXMLDOMDocument::load需要一個文件名作爲輸入。在這種情況下使用IXMLDOMDocument::loadXML

#include <iostream> 
#include <windows.h> 
#include <atlbase.h> 
#include <msxml2.h> 

long LoadXmlData(const wchar_t* content) 
{ 
    HRESULT hr = S_FALSE; 
    CComPtr<IXMLDOMDocument> doc = NULL; 
    CComPtr<IXMLDOMElement> docRoot = NULL; 

    hr = doc.CoCreateInstance(__uuidof(DOMDocument30)); 
    if(FAILED(hr)) 
     return S_FALSE; 

    VARIANT_BOOL is_success = FALSE; 
    CComBSTR arg(content); 
    hr = doc->loadXML(arg, &is_success); 

    //if you are loading from a file: 
    //hr = doc->load(CComVariant(L"c:\\test\\test.xml"), &is_success); 

    if(FAILED(hr) || !is_success) 
     return S_FALSE; 

    //if save is needed: 
    //doc->save(CComVariant(L"c:\\test\\test.xml")); 
    return S_OK; 
} 

int main() 
{ 
    CoInitialize(NULL); 

    //ελληνική γλώσσα Greek text for testing 
    CComBSTR data(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?><response>ελληνική γλώσσα</response>"); 
    long ret = LoadXmlData(data); 
    if(ret == S_OK) 
     std::cout << "MSXML: loading the XML succeeded\n"; 
    else 
     std::cout << "MSXML: loading the XML failed\n"; 

    CoUninitialize(); 
    return 0; 
}