2017-10-14 39 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; 
}