設置 | 登錄 | 註冊

作者共發了10篇帖子。

【代碼】C++使用msxml6來讀取XML字符串(程序未使用任何MFC或ATL類庫)

1樓 巨大八爪鱼 2016-2-7 13:13
【運行效果】

2樓 巨大八爪鱼 2016-2-7 13:14
【程序代碼】
// ConsoleApplication3.cpp : 定義控制台應用程式的入口點。
//

#include "stdafx.h"

// 包含variant_t和bstr_t等工具類
#include <comutil.h>
#pragma comment(lib, "comsuppw.lib")

// msxml6類庫
#include <MsXml6.h>
#pragma comment(lib, "msxml6.lib")

// 標準C++輸入輸出
#include <iostream>
using namespace std;

void read(IXMLDOMDocument *pXMLDoc);

int _tmain(int argc, _TCHAR* argv[])
{
    // 初始化COM
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (FAILED(hr))
        return 1;

    // 創建XML文檔對象
    IXMLDOMDocument *pXMLDoc;
    hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pXMLDoc));
    if (SUCCEEDED(hr))
    {
        wchar_t *xmlstr = L"<?xml version=\"1.0\" encoding=\"utf-8\"?><book id=\"448\"><name>JavaScript開發技術大全</name><price>$65</price></book>"; // 因為bstr要求字符串是寬字符,所以最好在定義字符串的時候就用wchar_t
        VARIANT_BOOL flag;
        pXMLDoc->loadXML(xmlstr, &flag);
        if (flag == VARIANT_TRUE)
            read(pXMLDoc);
        else
            cout << "解析XML字符串失敗" << endl;
        pXMLDoc->Release();
    }
    else
        cout << "創建XMLDOMDocument對象失敗" << endl;

    CoUninitialize();
    system("pause");
    return 0;
}

void read(IXMLDOMDocument *pXMLDoc)
{
    //-----------------------------------------------------------
    IXMLDOMElement *root;
    BSTR name;
    pXMLDoc->get_documentElement(&root); // 獲取根節點<book>
    root->get_nodeName(&name); // 得到根節點的名稱,但是數據類型為BSTR,不能直接在C++中使用
    string str = bstr_t(name); // 用bstr_t類把BSTR對象轉換為標準C++的std::string字符串對象
    cout << "根節點的名稱是: " << str.c_str() << endl; // str.c_str()就是char *字符串
    //-----------------------------------------------------------



    //-----------------------------------------------------------
    IXMLDOMNode *name_node;
    BSTR text;
    root->get_firstChild(&name_node); // 獲取<book>下的第一個節點: <name>
    name_node->get_text(&text); // 獲取<name>節點中的文字,獲得的類型是BSTR,仍然不能直接使用
    string text_str = bstr_t(text); // 把BSTR通過bstr_t類轉換成標準C++的string字符串對象
    cout << "<name>節點的內容是: " << text_str.c_str() << endl; //用string類的.c_str()方法就可以得到string對象中保存的char *字符數組


    variant_t value;
    root->getAttribute(L"id", &value);
    string str3 = bstr_t(value); // 這裡把variant_t類型轉換成std::string類型
    cout << "根節點的id屬性值是: " << str3.c_str() << endl;

    int num = atoi(str3.c_str()); // 用atoi函數可以把char *轉換成int
    cout << "把這個數字乘上2後是: " << num * 2 << endl;
    name_node->Release();
    //-----------------------------------------------------------


    //-----------------------------------------------------------
    IXMLDOMNode *price_node;
    IXMLDOMNodeList *list;
    root->get_childNodes(&list); // 獲取<book>下的所有子節點
    list->get_item(1, &price_node); // 第二個子節點就是<price>節點

    BSTR price;
    price_node->get_text(&price);
    str3 = bstr_t(price); // 這裡直接使用上面定義過的string str3變量
    cout << "<price>節點的內容是: " << str3.c_str() << endl;
   
    str3[0] = '+';
    cout << "修改字符串後的內容是: " << str3.c_str() << endl;

    list->Release();
    price_node->Release();
    //-----------------------------------------------------------

    root->Release();
}
3樓 巨大八爪鱼 2016-2-7 13:24
【補充】
如果由於種種原因只能獲得char *類型的字符串,那麼在loadXML的時候用bstr_t轉換一下就行了:
char *xmlstr = "<?xml version=\"1.0\" encoding=\"utf-8\"?><book id=\"448\"><name>JavaScript開發技術大全</name><price>$65</price></book>";
VARIANT_BOOL flag;
pXMLDoc->loadXML(bstr_t(xmlstr), &flag);
4樓 巨大八爪鱼 2016-2-7 14:06
【示例2】
從xml文件中讀取:
int _tmain(int argc, _TCHAR* argv[])
{
    // 初始化COM
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (FAILED(hr))
        return 1;

    // 創建XML文檔對象
    IXMLDOMDocument *pXMLDoc;
    hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pXMLDoc));
    if (SUCCEEDED(hr))
    {
        // 打開文件
        FILE *fp;
        fopen_s(&fp, "data.xml", "r");
       
        // 獲取文件大小
        fseek(fp, 0, SEEK_END);
        int filesize = ftell(fp);
        fseek(fp, 0, SEEK_SET);

        // 讀取文件內容
        char *xmlstr = new char[filesize + 1];
        fread(xmlstr, filesize, 1, fp);
        xmlstr[filesize] = '\0'; // 在字符數組末尾加\0
        fclose(fp);
        //cout << xmlstr << endl;
       
        // 解析xml字符串
        VARIANT_BOOL flag;
        pXMLDoc->loadXML(bstr_t(xmlstr), &flag);
        if (flag == VARIANT_TRUE)
            read(pXMLDoc);
        else
            cout << "解析XML字符串失敗" << endl;
        pXMLDoc->Release();

        delete[] xmlstr;
    }
    else
        cout << "創建XMLDOMDocument對象失敗" << endl;

    CoUninitialize();
    system("pause");
    return 0;
}
XML文件的內容:

編碼為ANSI,文件大小為113位元組。

5樓 巨大八爪鱼 2016-2-7 14:28
MSXML6還提供了一個load方法來讀取外部XML文件。如果用這種方法讀取XML文件的話,就必須把上面的data.xml以UTF-8編碼重新保存,不能再用ANSI編碼保存的那個文件了。保存後的文件名為data_utf8.xml,文件大小為122位元組。

【示例3】
IXMLDOMDocument *pXMLDoc;
hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pXMLDoc));
if (SUCCEEDED(hr))
{
    VARIANT_BOOL flag;
    pXMLDoc->load(variant_t("data_utf8.xml"), &flag);
    if (flag == VARIANT_TRUE)
        read(pXMLDoc);
    else
        cout << "解析XML文件失敗" << endl;
    pXMLDoc->Release();
}
else
    cout << "創建XMLDOMDocument對象失敗" << endl;
6樓 巨大八爪鱼 2016-2-18 13:04
【補充】
BSTR類型的變量用完之後最好調用SysFreeString函數釋放一下空間。
另外,本來MSDN說BSTR str = L"something";,要改成:
BSTR str = SysAllocString(L"haha");
SysFreeString(str);
才對,否則傳入COM函數後函數會執行失敗。
但是在MSXML中,貌似就算不用SysAllocString,傳入函數後也不會出錯。
7樓 巨大八爪鱼 2016-2-18 13:42
將BSTR轉換成char *時,還有一種不使用bstr_t類的方法:
BSTR b_title;
title_node->get_text(&b_title);

char *title = _com_util::ConvertBSTRToString(b_title);
cout << title << endl;
delete[] title;
SysFreeString(b_title);
8樓 巨大八爪鱼 2016-6-20 22:16
【關於BSTR字符串】
錯誤的寫法:
BSTR MyBstr = L"I am a happy BSTR";
正確的寫法:
BSTR MyBstr = SysAllocString(L"I am a happy BSTR");
...
SysFreeString(b_title);
注意只能用L"",不能寫成TEXT('")或_T('")

wchar_t *字符串的構成:
【wchar_t寬字符列表】【一個\0結尾】
其中指針指向開頭
BSTR字符串的構成:
【4位元組的字符串長度標識】【wchar_t寬字符列表】【兩個\0結尾】
其中指針指向wchar_t寬字符列表的開頭
9樓 巨大八爪鱼 2016-6-20 22:17
BSTR s = SysAllocString(L"I am a happy BSTR");
s指向I這個字符, 而不是開頭的字符串長度標識。

詳細資料:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms221069(v=vs.85).aspx
10樓 巨大八爪鱼 2016-6-20 22:20
因此,如果要把BSTR轉換成char *,可以把BSTR視為wchar_t *
這樣問題就歸結為:將wchar_t *轉換到char *

一般情況下,wchar_t *的編碼是UTF16,而char *的編碼是ANSI(Windows下),所以,可以用Windows自帶的API函數:WideCharToMultiByte來實現。

內容轉換:

回覆帖子
內容:
用戶名: 您目前是匿名發表。
驗證碼:
看不清?換一張
©2010-2025 Purasbar Ver3.0 [手機版] [桌面版]
除非另有聲明,本站採用知識共享署名-相同方式共享 3.0 Unported許可協議進行許可。