从0到1使用C++操作MSXML

发布于:2025-04-14 ⋅ 阅读:(26) ⋅ 点赞:(0)

1. 引言

MSXML(Microsoft XML Core Services)是微软提供的一套用于处理XML的COM组件库,广泛应用于Windows平台的XML解析、验证、转换等操作。本文将详细介绍如何从零开始,在C++中使用MSXML解析和操作XML文件,包含完整的代码示例及逐行注释,帮助初学者快速上手。


2. 准备工作

2.1 环境要求

  • Windows 操作系统(MSXML 是 Windows 特有组件)
  • Visual Studio(推荐 2015 或更高版本)
  • 基础C++知识(COM组件基本概念)

2.2 引入MSXML库

在代码中引入MSXML头文件,并链接对应的库:

#include <msxml6.h>   // MSXML 6.0(最新稳定版)
#include <comdef.h>   // 用于COM智能指针(_bstr_t, _variant_t)
#pragma comment(lib, "msxml6.lib")  // 链接MSXML库

3. 初始化COM环境

MSXML基于COM(Component Object Model),使用前必须初始化COM库:

#include <objbase.h>  // CoInitializeEx 所需头文件

int main() {
    // 初始化COM库(单线程模式)
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (FAILED(hr)) {
        printf("Failed to initialize COM. Error: %08X\n", hr);
        return 1;
    }

    // 后续代码...

    // 释放COM库
    CoUninitialize();
    return 0;
}

逐行解析:

  1. CoInitializeEx(NULL, COINIT_APARTMENTTHREADED):初始化COM,指定单线程单元(STA)模式。
  2. FAILED(hr):检查COM初始化是否成功。
  3. CoUninitialize():程序结束时释放COM资源。

4. 加载并解析XML文件

4.1 创建MSXML DOM对象

IXMLDOMDocument2* pXMLDoc = NULL;
hr = CoCreateInstance(
    __uuidof(DOMDocument60),  // 使用MSXML 6.0
    NULL,
    CLSCTX_INPROC_SERVER,
    __uuidof(IXMLDOMDocument2),
    (void**)&pXMLDoc
);
if (FAILED(hr) || pXMLDoc == NULL) {
    printf("Failed to create XML DOM instance. Error: %08X\n", hr);
    CoUninitialize();
    return 1;
}

逐行解析:

  1. CoCreateInstance:创建MSXML DOM对象。
  2. __uuidof(DOMDocument60):指定使用MSXML 6.0。
  3. CLSCTX_INPROC_SERVER:组件运行在进程内。

4.2 加载XML文件

VARIANT_BOOL bSuccess = VARIANT_FALSE;
hr = pXMLDoc->load(_variant_t(L"example.xml"), &bSuccess);
if (FAILED(hr) || bSuccess != VARIANT_TRUE) {
    printf("Failed to load XML file. Error: %08X\n", hr);
    pXMLDoc->Release();
    CoUninitialize();
    return 1;
}

逐行解析:

  1. pXMLDoc->load:加载XML文件(example.xml)。
  2. _variant_t(L"example.xml"):将文件名转换为COM兼容的VARIANT类型。
  3. bSuccess:返回加载是否成功。

5. 读取XML数据

5.1 获取XML根节点

IXMLDOMElement* pRoot = NULL;
hr = pXMLDoc->get_documentElement(&pRoot);
if (FAILED(hr) {
    printf("Failed to get root element. Error: %08X\n", hr);
    pXMLDoc->Release();
    CoUninitialize();
    return 1;
}

逐行解析:

  1. get_documentElement:获取XML的根节点。

5.2 遍历子节点

IXMLDOMNodeList* pNodes = NULL;
hr = pRoot->get_childNodes(&pNodes);
if (FAILED(hr)) {
    printf("Failed to get child nodes. Error: %08X\n", hr);
    pRoot->Release();
    pXMLDoc->Release();
    CoUninitialize();
    return 1;
}

long length = 0;
pNodes->get_length(&length);  // 获取子节点数量

for (long i = 0; i < length; i++) {
    IXMLDOMNode* pNode = NULL;
    pNodes->get_item(i, &pNode);  // 获取第i个节点

    BSTR nodeName;
    pNode->get_nodeName(&nodeName);  // 获取节点名称
    printf("Node %d: %S\n", i, nodeName);

    SysFreeString(nodeName);  // 释放BSTR内存
    pNode->Release();  // 释放节点
}
pNodes->Release();

逐行解析:

  1. get_childNodes:获取所有子节点。
  2. get_length:获取子节点数量。
  3. get_item(i, &pNode):获取第i个节点。
  4. get_nodeName:获取节点名称(返回BSTR,需手动释放)。

6. 修改XML数据

6.1 修改节点属性

IXMLDOMElement* pFirstChild = NULL;
pNodes->get_item(0, (IXMLDOMNode**)&pFirstChild);  // 获取第一个子节点

// 设置属性
hr = pFirstChild->setAttribute(
    _bstr_t(L"newAttr"),  // 属性名
    _variant_t(L"newValue")  // 属性值
);
if (FAILED(hr)) {
    printf("Failed to set attribute. Error: %08X\n", hr);
}
pFirstChild->Release();

逐行解析:

  1. setAttribute:设置节点属性,使用_bstr_t_variant_t封装字符串。

6.2 保存修改后的XML

hr = pXMLDoc->save(_variant_t(L"modified.xml"));
if (FAILED(hr)) {
    printf("Failed to save XML. Error: %08X\n", hr);
}

逐行解析:

  1. save:保存XML到新文件。

7. 完整代码示例

#include <msxml6.h>
#include <comdef.h>
#include <objbase.h>
#include <stdio.h>

int main() {
    // 初始化COM
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (FAILED(hr)) {
        printf("COM init failed. Error: %08X\n", hr);
        return 1;
    }

    // 创建DOM对象
    IXMLDOMDocument2* pXMLDoc = NULL;
    hr = CoCreateInstance(
        __uuidof(DOMDocument60),
        NULL,
        CLSCTX_INPROC_SERVER,
        __uuidof(IXMLDOMDocument2),
        (void**)&pXMLDoc
    );
    if (FAILED(hr) || !pXMLDoc) {
        printf("Failed to create DOM. Error: %08X\n", hr);
        CoUninitialize();
        return 1;
    }

    // 加载XML
    VARIANT_BOOL bSuccess = VARIANT_FALSE;
    hr = pXMLDoc->load(_variant_t(L"example.xml"), &bSuccess);
    if (FAILED(hr) || bSuccess != VARIANT_TRUE) {
        printf("Failed to load XML. Error: %08X\n", hr);
        pXMLDoc->Release();
        CoUninitialize();
        return 1;
    }

    // 获取根节点
    IXMLDOMElement* pRoot = NULL;
    hr = pXMLDoc->get_documentElement(&pRoot);
    if (FAILED(hr)) {
        printf("Failed to get root. Error: %08X\n", hr);
        pXMLDoc->Release();
        CoUninitialize();
        return 1;
    }

    // 遍历子节点
    IXMLDOMNodeList* pNodes = NULL;
    hr = pRoot->get_childNodes(&pNodes);
    if (FAILED(hr)) {
        printf("Failed to get child nodes. Error: %08X\n", hr);
        pRoot->Release();
        pXMLDoc->Release();
        CoUninitialize();
        return 1;
    }

    long length = 0;
    pNodes->get_length(&length);
    for (long i = 0; i < length; i++) {
        IXMLDOMNode* pNode = NULL;
        pNodes->get_item(i, &pNode);

        BSTR nodeName;
        pNode->get_nodeName(&nodeName);
        printf("Node %d: %S\n", i, nodeName);

        SysFreeString(nodeName);
        pNode->Release();
    }

    // 修改节点属性
    IXMLDOMElement* pFirstChild = NULL;
    pNodes->get_item(0, (IXMLDOMNode**)&pFirstChild);
    hr = pFirstChild->setAttribute(_bstr_t(L"newAttr"), _variant_t(L"newValue"));
    if (FAILED(hr)) {
        printf("Failed to set attribute. Error: %08X\n", hr);
    }

    // 保存XML
    hr = pXMLDoc->save(_variant_t(L"modified.xml"));
    if (FAILED(hr)) {
        printf("Failed to save XML. Error: %08X\n", hr);
    }

    // 释放资源
    pFirstChild->Release();
    pNodes->Release();
    pRoot->Release();
    pXMLDoc->Release();
    CoUninitialize();

    return 0;
}

8. 总结

本文详细介绍了如何在C++中使用MSXML进行XML解析、遍历、修改和保存,并提供了完整的代码示例和逐行注释。关键点包括:

  1. 初始化COM环境CoInitializeEx)。
  2. 创建MSXML DOM对象CoCreateInstance)。
  3. 加载XML文件load)。
  4. 遍历和修改节点get_childNodes, setAttribute)。
  5. 保存XMLsave)。

通过本教程,可以快速掌握MSXML的基本用法,并应用于实际项目中。


网站公告

今日签到

点亮在社区的每一天
去签到