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;
}
逐行解析:
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)
:初始化COM,指定单线程单元(STA)模式。FAILED(hr)
:检查COM初始化是否成功。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;
}
逐行解析:
CoCreateInstance
:创建MSXML DOM对象。__uuidof(DOMDocument60)
:指定使用MSXML 6.0。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;
}
逐行解析:
pXMLDoc->load
:加载XML文件(example.xml
)。_variant_t(L"example.xml")
:将文件名转换为COM兼容的VARIANT
类型。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;
}
逐行解析:
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();
逐行解析:
get_childNodes
:获取所有子节点。get_length
:获取子节点数量。get_item(i, &pNode)
:获取第i
个节点。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();
逐行解析:
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);
}
逐行解析:
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解析、遍历、修改和保存,并提供了完整的代码示例和逐行注释。关键点包括:
- 初始化COM环境(
CoInitializeEx
)。 - 创建MSXML DOM对象(
CoCreateInstance
)。 - 加载XML文件(
load
)。 - 遍历和修改节点(
get_childNodes
,setAttribute
)。 - 保存XML(
save
)。
通过本教程,可以快速掌握MSXML的基本用法,并应用于实际项目中。