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

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.0NULL,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. 完整代码示例

演示1

#include <msxml6.h>
#include <comdef.h>
#include <objbase.h>
#include <stdio.h>int main() {// 初始化COMHRESULT 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;}// 加载XMLVARIANT_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);}// 保存XMLhr = 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;
}

演示2

// Windows 头文件,提供基础API支持
#include <windows.h>// MSXML 6.0 接口定义头文件
#include <msxml6.h>// COM 基础功能头文件,包含CoInitialize等函数
#include <objbase.h>// 标准输入输出头文件
#include <stdio.h>// 添加以下头文件
#include <comutil.h>// 添加以下链接库
#pragma comment(lib, "comsuppw.lib")// 链接器指令:自动链接必要的库文件
#pragma comment(lib, "msxml6.lib")  // MSXML 6.0 库
#pragma comment(lib, "ole32.lib")   // COM 基础库int main() {/****************************************************************** 第一部分:COM库初始化和XML文档对象创建*****************************************************************/// 初始化COM库,所有使用COM技术的程序都必须先调用此函数// 参数NULL表示使用默认的线程模型(单线程公寓STA)HRESULT hr = CoInitialize(NULL);if (FAILED(hr)) {printf("错误:COM库初始化失败。错误代码 = 0x%08x\n", hr);return -1;}// 创建XML文档对象指针,初始化为NULLIXMLDOMDocument2* pXMLDoc = NULL;// 使用CoCreateInstance创建MSXML DOM文档对象// 参数说明:// CLSID_DOMDocument60 - MSXML 6.0 DOM文档的类ID// NULL - 不进行聚合// CLSCTX_INPROC_SERVER - 创建进程内服务器// IID_IXMLDOMDocument2 - 请求的接口ID// (void**)&pXMLDoc - 接收接口指针的地址hr = CoCreateInstance(CLSID_DOMDocument60,NULL,CLSCTX_INPROC_SERVER,IID_IXMLDOMDocument2,(void**)&pXMLDoc);// 检查创建是否成功if (FAILED(hr) || pXMLDoc == NULL) {printf("错误:创建DOM文档对象失败。错误代码 = 0x%08x\n", hr);CoUninitialize();  // 释放COM库return -1;}/****************************************************************** 第二部分:设置文档属性*****************************************************************/// 设置异步加载为FALSE(同步加载)// VARIANT_FALSE表示禁用异步加载hr = pXMLDoc->put_async(VARIANT_FALSE);// 设置验证文档结构(如果文档有DTD或Schema)// VARIANT_TRUE表示开启验证hr = pXMLDoc->put_validateOnParse(VARIANT_TRUE);// 设置不解析外部资源(如外部DTD)// VARIANT_FALSE表示不解析外部资源hr = pXMLDoc->put_resolveExternals(VARIANT_FALSE);// 设置保留空白字符// VARIANT_TRUE表示保留空白字符(如缩进、换行等)hr = pXMLDoc->put_preserveWhiteSpace(VARIANT_TRUE);/****************************************************************** 第三部分:创建和加载XML文档*****************************************************************/// 创建一个包含XML内容的BSTR字符串// BSTR是COM中使用的字符串类型,以长度前缀和null结尾BSTR bstrXML = SysAllocString(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"L"<bookstore>\n"L"  <book category=\"cooking\">\n"L"    <title lang=\"en\">Everyday Italian</title>\n"L"    <author>Giada De Laurentiis</author>\n"L"    <year>2005</year>\n"L"    <price>30.00</price>\n"L"  </book>\n"L"  <book category=\"children\">\n"L"    <title lang=\"en\">Harry Potter</title>\n"L"    <author>J.K. Rowling</author>\n"L"    <year>2005</year>\n"L"    <price>29.99</price>\n"L"  </book>\n"L"  <book category=\"web\">\n"L"    <title lang=\"en\">Learning XML</title>\n"L"    <author>Erik T. Ray</author>\n"L"    <year>2003</year>\n"L"    <price>39.95</price>\n"L"  </book>\n"L"</bookstore>");// 用于接收加载是否成功的变量VARIANT_BOOL vbIsSuccessful;// 将XML字符串加载到文档对象中hr = pXMLDoc->loadXML(bstrXML, &vbIsSuccessful);// 释放BSTR内存(COM编程中必须手动释放分配的内存)SysFreeString(bstrXML);// 检查XML加载是否成功if (FAILED(hr) || vbIsSuccessful != VARIANT_TRUE) {printf("错误:加载XML字符串失败。\n");// 获取解析错误对象IXMLDOMParseError* pXMLError = NULL;BSTR bstrError = NULL;// 获取解析错误信息hr = pXMLDoc->get_parseError(&pXMLError);if (SUCCEEDED(hr)) {// 获取错误原因描述pXMLError->get_reason(&bstrError);printf("错误原因: %S\n", bstrError);// 释放错误描述字符串SysFreeString(bstrError);// 释放错误对象pXMLError->Release();}// 清理资源pXMLDoc->Release();CoUninitialize();return -1;}/****************************************************************** 第四部分:演示从文件加载XML(补充功能)*****************************************************************/// 创建另一个XML文档对象用于演示文件加载IXMLDOMDocument2* pXMLDocFromFile = NULL;hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&pXMLDocFromFile);if (SUCCEEDED(hr) && pXMLDocFromFile != NULL) {// 设置文档属性(同上)pXMLDocFromFile->put_async(VARIANT_FALSE);pXMLDocFromFile->put_validateOnParse(VARIANT_TRUE);// 创建VARIANT变量来指定文件名VARIANT varFileName;VariantInit(&varFileName);  // 初始化VARIANTvarFileName.vt = VT_BSTR;   // 设置类型为BSTR// 分配文件名(假设当前目录下有books.xml文件)varFileName.bstrVal = SysAllocString(L"books.xml");// 从文件加载XMLhr = pXMLDocFromFile->load(varFileName, &vbIsSuccessful);// 清理VARIANTVariantClear(&varFileName);if (SUCCEEDED(hr) && vbIsSuccessful == VARIANT_TRUE) {printf("成功从文件加载XML文档。\n");// 这里可以添加对加载文档的操作...} else {printf("警告:从文件加载XML失败,可能文件不存在。\n");}// 释放文档对象pXMLDocFromFile->Release();}/****************************************************************** 第五部分:遍历XML文档*****************************************************************/// 获取文档根元素IXMLDOMElement* pRootElem = NULL;hr = pXMLDoc->get_documentElement(&pRootElem);if (SUCCEEDED(hr) && pRootElem != NULL) {// 获取根元素名称BSTR bstrRootName;hr = pRootElem->get_nodeName(&bstrRootName);if (SUCCEEDED(hr)) {printf("根元素名称: %S\n", bstrRootName);SysFreeString(bstrRootName);}/****************************************************************** 演示创建处理指令(补充功能)*****************************************************************/// 创建处理指令节点IXMLDOMProcessingInstruction* pPI = NULL;BSTR bstrTarget = SysAllocString(L"xml-stylesheet");BSTR bstrData = SysAllocString(L"type=\"text/xsl\" href=\"style.xsl\"");hr = pXMLDoc->createProcessingInstruction(bstrTarget, bstrData, &pPI);if (SUCCEEDED(hr) && pPI != NULL) {// 将处理指令插入到文档开头IXMLDOMNode* pInsertedNode = NULL;hr = pXMLDoc->insertBefore(pPI, _variant_t(pRootElem), &pInsertedNode);if (SUCCEEDED(hr)) {printf("成功添加处理指令。\n");pInsertedNode->Release();}pPI->Release();}SysFreeString(bstrTarget);SysFreeString(bstrData);/****************************************************************** 演示创建注释(补充功能)*****************************************************************/// 创建注释节点IXMLDOMComment* pComment = NULL;BSTR bstrComment = SysAllocString(L"这是一个示例XML文档");hr = pXMLDoc->createComment(bstrComment, &pComment);if (SUCCEEDED(hr) && pComment != NULL) {// 将注释插入到根元素之前IXMLDOMNode* pInsertedComment = NULL;hr = pXMLDoc->insertBefore(pComment, _variant_t(pRootElem), &pInsertedComment);if (SUCCEEDED(hr)) {printf("成功添加注释节点。\n");pInsertedComment->Release();}pComment->Release();}SysFreeString(bstrComment);/****************************************************************** 遍历book节点*****************************************************************/// 获取所有book元素IXMLDOMNodeList* pBooks = NULL;BSTR bstrTagName = SysAllocString(L"book");hr = pRootElem->getElementsByTagName(bstrTagName, &pBooks);SysFreeString(bstrTagName);if (SUCCEEDED(hr) && pBooks != NULL) {// 获取book元素数量long bookCount;pBooks->get_length(&bookCount);printf("找到 %d 本书\n", bookCount);// 遍历每本书for (long i = 0; i < bookCount; i++) {IXMLDOMNode* pBook = NULL;hr = pBooks->get_item(i, &pBook);if (SUCCEEDED(hr) && pBook != NULL) {// 获取整本书的XML内容BSTR bstrBookXML;pBook->get_xml(&bstrBookXML);printf("\n第 %d 本书:\n%S\n", i + 1, bstrBookXML);SysFreeString(bstrBookXML);// 获取book元素的属性IXMLDOMNamedNodeMap* pAttrs = NULL;pBook->get_attributes(&pAttrs);if (pAttrs != NULL) {// 获取category属性IXMLDOMNode* pCategoryAttr = NULL;BSTR bstrAttrName = SysAllocString(L"category");hr = pAttrs->getNamedItem(bstrAttrName, &pCategoryAttr);SysFreeString(bstrAttrName);if (SUCCEEDED(hr) && pCategoryAttr != NULL) {VARIANT varValue;VariantInit(&varValue);// 获取属性值pCategoryAttr->get_nodeValue(&varValue);printf("  类别: %S\n", varValue.bstrVal);// 清理VARIANTVariantClear(&varValue);pCategoryAttr->Release();}pAttrs->Release();}/****************************************************************** 演示克隆节点(补充功能)*****************************************************************/// 克隆当前book节点(深拷贝,包括所有子节点)IXMLDOMNode* pClonedBook = NULL;hr = pBook->cloneNode(VARIANT_TRUE, &pClonedBook);if (SUCCEEDED(hr) && pClonedBook != NULL) {// 可以在此处操作克隆的节点...printf("  成功克隆本书节点。\n");pClonedBook->Release();}/****************************************************************** 遍历子节点*****************************************************************/IXMLDOMNodeList* pChildNodes = NULL;pBook->get_childNodes(&pChildNodes);if (pChildNodes != NULL) {long childCount;pChildNodes->get_length(&childCount);for (long j = 0; j < childCount; j++) {IXMLDOMNode* pChild = NULL;hr = pChildNodes->get_item(j, &pChild);if (SUCCEEDED(hr) && pChild != NULL) {// 获取子节点名称BSTR bstrChildName;pChild->get_nodeName(&bstrChildName);// 特别处理price节点if (wcscmp(bstrChildName, L"price") == 0) {BSTR bstrPrice;pChild->get_text(&bstrPrice);printf("  价格: %S\n", bstrPrice);SysFreeString(bstrPrice);}SysFreeString(bstrChildName);pChild->Release();}}pChildNodes->Release();}pBook->Release();}}pBooks->Release();}/****************************************************************** 演示删除节点(补充功能)*****************************************************************/// 查找要删除的节点(例如第一本书)IXMLDOMNode* pBookToRemove = NULL;BSTR bstrXPathRemove = SysAllocString(L"//book[1]");hr = pXMLDoc->selectSingleNode(bstrXPathRemove, &pBookToRemove);SysFreeString(bstrXPathRemove);if (SUCCEEDED(hr) && pBookToRemove != NULL) {// 从父节点中删除子节点IXMLDOMNode* pRemovedNode = NULL;hr = pRootElem->removeChild(pBookToRemove, &pRemovedNode);if (SUCCEEDED(hr)) {printf("\n成功删除第一本书。\n");pRemovedNode->Release();}pBookToRemove->Release();}pRootElem->Release();}/****************************************************************** 第六部分:执行XPath查询*****************************************************************/// 查找价格大于35的书BSTR bstrXPath = SysAllocString(L"//book[price>35.00]");IXMLDOMNodeList* pExpensiveBooks = NULL;hr = pXMLDoc->selectNodes(bstrXPath, &pExpensiveBooks);SysFreeString(bstrXPath);if (SUCCEEDED(hr) && pExpensiveBooks != NULL) {long expensiveCount;pExpensiveBooks->get_length(&expensiveCount);printf("\n找到 %d 本价格高于35.00的书\n", expensiveCount);// 遍历查询结果for (long i = 0; i < expensiveCount; i++) {IXMLDOMNode* pBook = NULL;hr = pExpensiveBooks->get_item(i, &pBook);if (SUCCEEDED(hr) && pBook != NULL) {// 在每本书中查找title节点BSTR bstrTitleXPath = SysAllocString(L"title");IXMLDOMNode* pTitle = NULL;// 注意:这里需要将pBook转换为IXMLDOMElement接口hr = ((IXMLDOMElement*)pBook)->selectSingleNode(bstrTitleXPath, &pTitle);SysFreeString(bstrTitleXPath);if (SUCCEEDED(hr) && pTitle != NULL) {BSTR bstrTitle;pTitle->get_text(&bstrTitle);printf("  高价书标题: %S\n", bstrTitle);SysFreeString(bstrTitle);pTitle->Release();}pBook->Release();}}pExpensiveBooks->Release();}/****************************************************************** 第七部分:修改XML内容*****************************************************************/// 查找所有book节点BSTR bstrAllBooksXPath = SysAllocString(L"//book");IXMLDOMNodeList* pAllBooks = NULL;hr = pXMLDoc->selectNodes(bstrAllBooksXPath, &pAllBooks);SysFreeString(bstrAllBooksXPath);if (SUCCEEDED(hr) && pAllBooks != NULL) {long bookCount;pAllBooks->get_length(&bookCount);for (long i = 0; i < bookCount; i++) {IXMLDOMNode* pBook = NULL;hr = pAllBooks->get_item(i, &pBook);if (SUCCEEDED(hr) && pBook != NULL) {// 创建discount元素IXMLDOMElement* pDiscountElem = NULL;BSTR bstrDiscountTag = SysAllocString(L"discount");hr = pXMLDoc->createElement(bstrDiscountTag, &pDiscountElem);SysFreeString(bstrDiscountTag);if (SUCCEEDED(hr) && pDiscountElem != NULL) {// 设置discount元素的文本内容BSTR bstrDiscountValue = SysAllocString(L"10%");hr = pDiscountElem->put_text(bstrDiscountValue);SysFreeString(bstrDiscountValue);// 将新元素添加到book节点IXMLDOMNode* pInsertedNode = NULL;hr = pBook->appendChild(pDiscountElem, &pInsertedNode);if (SUCCEEDED(hr) && pInsertedNode != NULL) {pInsertedNode->Release();}pDiscountElem->Release();}/****************************************************************** 演示替换节点(补充功能)*****************************************************************/// 查找year节点BSTR bstrYearPath = SysAllocString(L"year");IXMLDOMNode* pYearNode = NULL;hr = ((IXMLDOMElement*)pBook)->selectSingleNode(bstrYearPath, &pYearNode);SysFreeString(bstrYearPath);if (SUCCEEDED(hr) && pYearNode != NULL) {// 创建新的year节点IXMLDOMElement* pNewYearElem = NULL;BSTR bstrYearTag = SysAllocString(L"year");hr = pXMLDoc->createElement(bstrYearTag, &pNewYearElem);SysFreeString(bstrYearTag);if (SUCCEEDED(hr) && pNewYearElem != NULL) {// 设置新的年份值(原年份+1)BSTR bstrOldYear;pYearNode->get_text(&bstrOldYear);int year = _wtoi(bstrOldYear) + 1;wchar_t newYear[10];swprintf(newYear, 10, L"%d", year);BSTR bstrNewYear = SysAllocString(newYear);pNewYearElem->put_text(bstrNewYear);SysFreeString(bstrNewYear);SysFreeString(bstrOldYear);// 替换节点IXMLDOMNode* pReplacedNode = NULL;hr = pBook->replaceChild(pNewYearElem, pYearNode, &pReplacedNode);if (SUCCEEDED(hr)) {printf("  成功更新第%d本书的出版年份。\n", i+1);pReplacedNode->Release();}pNewYearElem->Release();}pYearNode->Release();}pBook->Release();}}pAllBooks->Release();}/****************************************************************** 第八部分:保存修改后的XML*****************************************************************/// 创建VARIANT变量来指定输出文件名VARIANT varOutputFile;VariantInit(&varOutputFile);  // 初始化VARIANTvarOutputFile.vt = VT_BSTR;   // 设置类型为BSTRvarOutputFile.bstrVal = SysAllocString(L"modified_books.xml");// 保存XML文档到文件hr = pXMLDoc->save(varOutputFile);if (FAILED(hr)) {printf("错误:保存修改后的XML文件失败。\n");} else {printf("\n修改后的XML已保存到 modified_books.xml\n");}// 清理VARIANT变量VariantClear(&varOutputFile);/****************************************************************** 第九部分:清理资源*****************************************************************/// 释放XML文档对象pXMLDoc->Release();// 反初始化COM库CoUninitialize();// 暂停控制台窗口(方便查看输出)system("pause");return 0;
}

8. 总结

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 系统下用 VMware 安装 CentOS 7 虚拟机超详细教程(包含VMware和镜像安装包)

前言 资源 一、准备工作 &#xff08;一&#xff09;下载 VMware Workstation &#xff08;二&#xff09;下载 CentOS 7 镜像 二、安装 VMware Workstation&#xff08;比较简单&#xff0c;按下面走即可&#xff09; 三、创建 CentOS 7 虚拟机 四、安装 CentOS 7 系统…

应用安全系列之四十五:日志伪造(Log_Forging)之三

1、简介 针对Java的日志系统有多种&#xff0c;本文主要描述如何通过修改配置文件来解决logback和log4j的日志伪造问题。 2、logback 2.1、系统提供的解决方案 在logback.xml中配置编码器自动转义特殊字符&#xff1a; 复制 <configuration><appender name"C…

(五)循环链表、双向链表

循环链表 介绍 在单选链表基础上&#xff0c;下一个节点指向前一个节点&#xff0c;最后一个节点指向起点 封装循环链表 为了让循环链表可以继承自单向链表&#xff0c;对其进行重构 给其增加一个tail属性&#xff08;尾节点&#xff09;&#xff0c;对各方法进行重写整理 …

仙剑奇侠传98柔情版游戏秘籍

战斗秘技&#xff1a;在战斗中输入 “cheat”&#xff0c;然后输入 “v” 直接取胜&#xff1b;输入 “y” 敌人不攻击。另外&#xff0c;在战斗中按 “XJPXZ123” 加 “shift” 键&#xff0c;攻击力增加 1000&#xff05;。等级提升秘籍&#xff1a;当李逍遥等级到达 99 级时…

常见的归一化(Normalization)方法

本文详解深度学习中常见的归一化方法。 【归一化是将数据按比例缩放&#xff0c;使之落入一个特定的区间】目录 1. 批量归一化&#xff08;Batch Normalization&#xff0c;BN&#xff09;1.1 数学原理1.2 代码示例 2. 层归一化&#xff08;Layer Normalization&#xff0c;LN&…

行星际激波在日球层中的传播:Propagation of Interplanetary Shocks in the Heliosphere (参考文献部分)

行星际激波在日球层中的传播&#xff1a;Propagation of Interplanetary Shocks in the Heliosphere &#xff08;第一部分&#xff09;-CSDN博客 行星际激波在日球层中的传播&#xff1a;Propagation of Interplanetary Shocks in the Heliosphere &#xff08;第二部分&…

大模型可视化应用敏捷开发方案:Dify+Echarts

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 Moe模式&#xff1a;或将是最好的大模型应用开发路径一文带你了解大模型RAG详细记录…

23种GoF设计模式

GoF&#xff08;Gang of Four&#xff09;设计模式是由四位计算机科学家 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著的书籍《Design Patterns: Elements of Reusable Object-Oriented Software》中提出的设计模式 目录 一、创建型模式&#xff08;Cre…

Losson 4 NFS(network file system(网络文件系统))

网络文件系统&#xff1a;在互联网中共享服务器中文件资源。 使用nfs服务需要安装:nfs-utils 以及 rpcbind nfs-utils : 提供nfs服务的程序 rpcbind &#xff1a;管理nfs所有进程端口号的程序 nfs的部署 1.客户端和服务端都安装nfs-utils和rpcbind #安装nfs的软件rpcbind和…

C++ 入门六:多态 —— 同一接口的多种实现之道

在面向对象编程中&#xff0c;多态是最具魅力的特性之一。它允许我们通过统一的接口处理不同类型的对象&#xff0c;实现 “一个接口&#xff0c;多种实现”。本章将从基础概念到实战案例&#xff0c;逐步解析多态的核心原理与应用场景&#xff0c;帮助新手掌握这一关键技术。 …

关于C使用Windows API获取系统管理员权限和对文本属性的操作,以及windows API的核心操作

关于windows系统的操作程序开发&#xff0c;本文介绍一部分重要的文本属性操作&#xff0c;和运行计次器。 获取系统管理员权限 #include <windows.h> VOID ManagerRun(LPCSTR exe, LPCSTR param, INT nShow) { //注意&#xff1a;会跳出提示。SHELLEXECUTEINFO ShExec…

Web 项目实战:构建属于自己的博客系统

目录 项目效果演示 代码 Gitee 地址 1. 准备工作 1.1 建表 1.2 引入 MyBatis-plus 依赖 1.3 配置数据库连接 1.4 项目架构 2. 实体类准备 - pojo 包 2.1 dataobject 包 2.2 request 包 2.3 response 包 2.3.1 统一响应结果类 - Result 2.3.2 用户登录响应类 2.3.3…

从“被动跳闸”到“主动预警”:智慧用电系统守护老旧小区安全

安科瑞顾强 近年来&#xff0c;老旧小区电气火灾事故频发&#xff0c;成为威胁居民生命财产安全的重要隐患。据统计&#xff0c;我国居住场所火灾伤亡人数远超其他场所&#xff0c;仅今年一季度就发生8.3万起住宅火灾&#xff0c;造成503人遇难。这些建筑多建于上世纪&#x…

【深入浅出 Git】:从入门到精通

这篇文章介绍下版本控制器。 【深入浅出 Git】&#xff1a;从入门到精通 Git是什么Git的安装Git的基本操作建立本地仓库配置本地仓库认识工作区、暂存区、版本库的概念添加文件添加文件到暂存区提交文件到版本库提交文件演示 理解.git目录中的文件HEAD指针与暂存区objects对象 …

Mybatis的简单介绍

文章目录 MyBatis 简介 1. MyBatis 核心特点2. MyBatis 核心组件3. MyBatis 基本使用示例(1) 依赖引入&#xff08;Maven&#xff09;(2) 定义 Mapper 接口(3) 定义实体类(4) 在 Service 层调用 4. MyBatis 与 JPA/Hibernate 对比 MyBatis 简介 MyBatis 是一款优秀的 持久层框…

Android Studio 在 Windows 上的完整安装与使用指南

Android Studio 在 Windows 上的完整安装与使用指南—目录 一、Android Studio 简介二、下载与安装1. 下载 Android Studio2. 安装前的依赖准备3. 安装步骤 三、基础使用指南1. 首次启动配置2. 创建第一个项目3. 运行应用4. 核心功能 四、进阶功能配置1. 配置 SDK 和工具2. 自定…

WPF 绑定方式举例

WPF 绑定方式举例 一、如果ItemsControl 控件的ItemsSource要绑定到List类型&#xff0c;可以如下&#xff1a; List<string> Names new List<string>(); Names.Add("aaa"); Names.Add("bbb");<ItemsControl ItemsSource"{Binding …

LangSmith 设置指南

什么是 LangSmith&#xff1f; LangSmith 是 LangChain 团队开发的一个统一开发者平台&#xff0c;用于构建、测试、评估和监控基于大型语言模型&#xff08;LLM&#xff09;的应用程序。它提供了一套工具&#xff0c;帮助开发者更好地理解、调试和改进他们的 LLM 应用。 注册…

手撕TCP内网穿透及配置树莓派

注意&#xff1a; 本文内容于 2025-04-13 15:09:48 创建&#xff0c;可能不会在此平台上进行更新。如果您希望查看最新版本或更多相关内容&#xff0c;请访问原文地址&#xff1a;手撕TCP内网穿透及配置树莓派。感谢您的关注与支持&#xff01; 之前入手了树莓派5&#xff0c;…

Java从入门到“放弃”(精通)之旅——程序逻辑控制④

Java从入门到“放弃”&#xff08;精通&#xff09;之旅&#x1f680;&#xff1a;程序逻辑的完美理解 一、开篇&#xff1a;程序员的"人生选择" 曾经的我&#xff0c;生活就像一段顺序执行的代码&#xff1a; System.out.println("早上8:00起床"); Syste…