許多開發者初次接觸 C++Builder 的 TXMLDocument 組件時,都會感到困惑:明明 VB / C# 操作 MSXML DOM 極為順手,為何在 C++Builder 中卻處處碰壁?核心原因在於思維慣性——VCL 的類設計直觀易懂,而 MSXML 是基於 COM 的介面導向模型,方法命名、錯誤處理、生命週期管理與 VCL 風格截然不同。本文將以一個「日程提醒」小程式為例,手把手帶你跨過這道坎。
<?xml version="1.0" encoding="GB2312"?>
<VTip>
<Tip>
<Mode>0</Mode>
<Time>2003/4/25 08:01:46</Time>
<Content>洗衣服</Content>
</Tip>
<Tip>
<Mode>1</Mode>
<Time>2003/4/25 17:30:00</Time>
<Content>陪女朋友吃飯</Content>
</Tip>
</VTip>
採用 GB2312 編碼避免中文亂碼;結構扁平化,無屬性、無命名空間,降低解析複雜度。
// XMLDoc 為 TXMLDocument 元件實例
XMLDoc->LoadFromFile(WideString(ExtractFilePath(Application->ExeName) + "Tip.xml"));
XMLDoc->Active = true;
FillList(); // 刷新 UI 列表
void __fastcall TfrmMain::FillList()
{
lstMain->Items->BeginUpdate();
lstMain->Items->Clear();
_di_IXMLNode root = XMLDoc->DocumentElement; // 取得根節點 <VTip>
_di_IXMLNodeList tips = root->ChildNodes; // 取得所有 <Tip> 節點集合
for (int i = 0; i < tips->Count; ++i) {
_di_IXMLNode tip = tips->Get(i); // 第 i 個 <Tip>
_di_IXMLNodeList fields = tip->ChildNodes; // Mode, Time, Content
TListItem *item = lstMain->Items->Add();
item->Caption = "";
item->ImageIndex = fields->Get(0)->GetText().ToInt() + 5; // Mode 決定圖示
item->SubItems->Add(fields->Get(1)->GetText()); // Time
item->SubItems->Add(fields->Get(2)->GetText()); // Content
}
lstMain->Items->EndUpdate();
}
關鍵點:_di_IXMLNode 是介面智慧指標,自動管理參考計數,無需手動 Release;ChildNodes 返回 IXMLNodeList,支援索引與迭代。
bool __fastcall TfrmMain::AddTask(int mode, TDateTime &date, TDateTime &time, AnsiString content)
{
_di_IXMLNode root = XMLDoc->DocumentElement;
_di_IXMLNode tip = root->AddChild("Tip"); // 建立 <Tip>
_di_IXMLNode n = tip->AddChild("Mode");
n->SetText(WideString(mode));
n = tip->AddChild("Time");
n->SetText(WideString(date.DateString() + " " + time.TimeString()));
n = tip->AddChild("Content");
n->SetText(WideString(content));
return true; // 記得稍後呼叫 XMLDoc->SaveToFile() 持久化
}
void __fastcall TfrmMain::DeleteSelected()
{
int idx = lstMain->Selected->Index;
_di_IXMLNode root = XMLDoc->DocumentElement;
if (root->ChildNodes->Delete(idx) != -1) { // 返回被刪除節點索引,-1 表示失敗
lstMain->Items->Delete(idx); // 同步更新 UI
}
}
_di_IXMLNode 離開作用域自動釋放,切勿手動 Release() 或轉為裸指標長期持有。AddChildNS、GetChildNodes 等帶 NS 後綴的方法。IXMLReader 流式讀取。EXMLDocError,外層務必 try/__finally 保護。// 儲存變更
XMLDoc->SaveToFile(WideString(ExtractFilePath(Application->ExeName) + "Tip.xml"));
// 多執行緒安全:每個執行緒建立獨立 TXMLDocument 實例,或使用 Critical Section 保護共用實例
// MSXML DOM 物件本身非執行緒安全(Free-threaded Marshaler 除外)
掌握 TXMLDocument 核心在於理解「介面導向」與「樹狀節點操作」兩大思維。通過本文的完整增刪改查範例,你已具備在 C++Builder 中駕馭 XML 配置文件、資料交換的實戰能力。下一步可嘗試 XPath 查詢、XSLT 轉換或 Schema 驗證,進一步釋放 XML 的威力。