目前共有10篇帖子。 內容轉換:不轉換▼
 
點擊 回復
747 9
【代码】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来实现。

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
(快捷鍵:Ctrl+Enter)
 

本帖信息

點擊數:747 回複數:9
評論數: ?
作者: 巨大八爪鱼
最後回復:巨大八爪鱼
最後回復時間:2016-6-20 22:20
 
©2010-2024 Arslanbar Ver2.0
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。