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.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;
}
逐行解析:
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. 完整代碼示例
演示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解析、遍歷、修改和保存,并提供了完整的代碼示例和逐行注釋。關鍵點包括:
- 初始化COM環境(
CoInitializeEx
)。 - 創建MSXML DOM對象(
CoCreateInstance
)。 - 加載XML文件(
load
)。 - 遍歷和修改節點(
get_childNodes
,setAttribute
)。 - 保存XML(
save
)。
通過本教程,可以快速掌握MSXML的基本用法,并應用于實際項目中。