Delphi/C++ Builder怎么解析XML

9次阅读

Delphi和c++ Builder解析xml主要依赖IXMLDocument/TXMLDocument,底层用MSXML或libxml2;VCL内置支持轻量但不支持XPath 1.0全功能;需注意Active设置、编码声明、节点遍历方式及COM线程安全。

Delphi/C++ Builder怎么解析XML

Delphi 和 C++ Builder 解析 XML 主要靠 IXMLDocument(Delphi)或 IXMLDocument / TXMLDocument(C++ Builder),底层依赖 MSXML(windows)或开源库(如 libxml2,需手动集成)。默认安装的 VCL 框架已内置轻量级 XML 支持,够用但不支持 XPath 1.0 全功能或命名空间高级解析。

Delphi 中用 TXMLDocument 加载和遍历节点

推荐使用设计时组件 TXMLDocument(VCL)或运行时创建 IXMLDocument 接口。注意:必须设置 Active := True 才能加载内容,否则 DocumentElementnil

  • LoadFromFile()LoadFromXML() 都会触发解析,但前者要求文件存在且编码匹配(建议 UTF-8 + bom
  • 节点遍历优先用 Childnodes 而非 FirstChild,避免忽略文本节点或注释
  • 获取属性值用 Node.Attributes['attrname'],不是 Node.AttributeNodes['attrname'].Text(后者在某些版本中返回空)
  • 中文内容乱码常见于未声明编码或 BOM 缺失 —— 在 XML 字符串开头加
var   XML: IXMLDocument;   Root, Node: IXMLNode; begin   XML := LoadXMLData('你好');   Root := XML.DocumentElement;   Node := Root.ChildNodes['item'];   if Node <> nil then     ShowMessage(Node.Text); // 输出:你好     ShowMessage(Node.Attributes['id']); // 输出:1 end;

C++ Builder 中 TXMLDocument 的典型用法

C++ Builder 的 TXMLDocument封装类,比纯接口更易用,但需注意构造方式和内存管理。不能直接 new,应通过窗体设计器拖入或用 new TXMLDocument(NULL) 创建(Owner 为 NULL 时需手动 Free())。

  • 调用 LoadFromFile() 前必须设 Active = false,否则抛异常 “XML document already active”
  • DocumentElement->ChildNodes->Nodes[i] 是访问子节点的常用路径,Nodes[] 索引从 0 开始,不跳过空白文本节点
  • 属性读取用 Node->Attributes->GetNodeValue("attr"),不是 Node->GetAttribute("attr")(后者在较新版本中已弃用)
  • 若 XML 含命名空间(如 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"),默认解析器会忽略前缀,无法用 ChildNodes['xsi:schemaLocation'] 直接访问
TXMLDocument* XML = new TXMLDocument(this); XML->Active = false; XML->LoadFromFile("data.xml"); XML->Active = true; IXMLNode* Root = XML->DocumentElement; IXMLNode* Item = Root->ChildNodes->Nodes[0]; if (Item)   Memo1->Lines->Add(Item->Text);   Memo1->Lines->Add(Item->Attributes->GetNodeValue("id"));

遇到“access violation”或“Interface not supported”错误怎么办

这类错误基本源于 COM 接口生命周期失控或线程误用。Delphi/C++ Builder 的 XML 组件基于 MSXML(windows 平台),要求 COM 初始化(VCL 应用通常自动完成),但控制台程序或子线程中需手动调用 CoInitialize(nil)

立即学习C++免费学习笔记(深入)”;

  • 在非主线程中使用 IXMLDocument 前,必须先调用 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)
  • 不要跨线程传递 IXMLNode 指针 —— 接口引用计数在线程间不同步,极易崩溃
  • 释放顺序:先置 Active = false,再 Free 或让接口变量离开作用域;重复 FreeRelease 会导致 AV
  • 如果 XML 内容来自网络或不可信来源,务必用 try..except 包裹 LoadFromXML(),MSXML 对格式错误极其敏感(如未闭合标签、非法字符)

需要 XPath 或更健壮解析时怎么选

原生 TXMLDocument 不支持 XPath 查询(SelectNodes() 返回空),也不支持 DTD 验证或 XSLT。真有这些需求,别硬改,直接换:

  • Windows 下可用 MSXML2.DOMDocument60 COM 对象(需 import 类型库),支持完整 XPath 1.0 和命名空间前缀绑定
  • 跨平台方案:集成 libxml2(C++ Builder 可用静态链接版),Delphi 有第三方封装如 XmlParsergitHub 开源)
  • 简单场景下,正则提取 + StringReplace 处理固定结构 XML,比引入大库更快更稳(仅限无嵌套、无转义、无 CDATA 的配置片段)

真正麻烦的从来不是“怎么解析”,而是“XML 本身是否规范”——比如服务端返回的响应混用了   实体但没声明 DTD,或者时间字段用了 2024-05-20T14:30:00+08:00 格式却漏了时区声明。这些细节不处理,接口再漂亮也白搭。

text=ZqhQzanResources