從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.pswp.cn/pingmian/76638.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76638.shtml
英文地址,請注明出處:http://en.pswp.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…