惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
Arctic Wolf
博客园 - 聂微东
F
Fortinet All Blogs
云风的 BLOG
云风的 BLOG
小众软件
小众软件
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Cloudflare Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
Y
Y Combinator Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园_首页
L
LangChain Blog
A
About on SuperTechFans
阮一峰的网络日志
阮一峰的网络日志
I
Intezer
T
The Blog of Author Tim Ferriss
Security Latest
Security Latest
C
CXSECURITY Database RSS Feed - CXSecurity.com
Know Your Adversary
Know Your Adversary
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
P
Palo Alto Networks Blog
Scott Helme
Scott Helme
S
Secure Thoughts
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
P
Privacy & Cybersecurity Law Blog
O
OpenAI News
H
Heimdal Security Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Help Net Security
Help Net Security
C
Cyber Attacks, Cyber Crime and Cyber Security
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
G
Google Developers Blog
博客园 - Franky
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
K
Kaspersky official blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Tor Project blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tenable Blog
Google Online Security Blog
Google Online Security Blog
PCI Perspectives
PCI Perspectives

博客园 - 秋·风

【aarch64-win64】DonAlfredo终于修复fpc将TSmallPoint赋值为一个负数,并将TSmallPoint赋值给TPoint时得到一个655xx的数值的bug lazarus编译时提示链接出错的处理方法 mORMot2两个BUG 【aarch64-win64】发现fpc aarch64-win64 将TSmallPoint赋值为一个负数,并赋值给TPoint时得到一个655xx的数值的bug 修复aarch64 win64下lazarus不弹出SourceTabPopUpMenu fpc aarch64-win64版编译应用时遇到一个奇怪的bug 在windows 11 on arm64系统编译lazarus出错的处理方法 修复TDBMemo只读不能使用Ctrl+C复制文字的Bug freepascal打补丁后已支持windows 11 on arm64(lazarus aarch64 windows版也可以运行了) 查看libc.so.6的版本号 Lazarus移动版启动程序 fpc 3.2.2交叉编译i386-linux链接出错 lazarus鸿蒙开发13:使用鸿蒙原生API画图--lazarus侧关键代码 lazarus鸿蒙开发12:使用鸿蒙原生API画图--鸿蒙侧关键代码 lazarus鸿蒙开发11:使用鸿蒙原生接口画图 lazarus鸿蒙开发10:lazarus一键编译、打包助手 lazarus鸿蒙开发9:使用命令行编译DevEco Studio应用 lazarus鸿蒙开发8:在DevEco Studio的日志窗口显示日志信息 lazarus鸿蒙开发7:在 Windows 上为 OpenHarmony (LoongArch64) 编译 Qt 5.15.12 SDK 指南 lazarus鸿蒙开发6:鸿蒙project配置 lazarus鸿蒙开发5:编译ohos_hap_project lazarus鸿蒙开发4:编译OHOS_QT_Lazarus lazarus鸿蒙开发3:编译libLazarusOHOS_Wrapper.so lazarus鸿蒙开发2:编译鸿蒙版本Qt5pas lazarus鸿蒙开发1:编译QT 5.12.12 鸿蒙版 fpc/lazarus for x86_64/aarch64鸿蒙版(绿色版 2026.06.03更新) fastreport报表编辑器在aarch64等非x86_64 CPU第一次打开慢的解决方案 linux/windows双系统可用的打包程序 使用FPC自带的纯 Pascal 实现的 Zlib 替代品——paszlib QFLazarus使用说明 忽略lazarus console in/output窗显示的转义序列 编译fpc遇到的怪事(2026-05-20更新) 取消树莓派的系统双击桌面图标时出现弹窗的选择提示 银河麒麟v11安装lazarus的方法 【小技巧】lazarus的应用设置某个form不在任务栏显示(linux) 用lazarus封装了linux的rsync fastreport在windows11(lazarus)报表设计时出现的问题 用lazarus编写的deb打包工具 龙芯deepin 25系统使用旧世界软件的方法 SimpleJSON for lazarus 中文转全拼音和首字母 lazarus扩展IDE宏的方法 调整lazarus gtk2编辑控件背景颜色 fpc/lazarus可用的宏 Lazarus IDE宏列表 【原创控件】PopupMenu和MainMenu自绘单元 【原创控件】PopupMenu自绘 【原创控件】lazarus自定义mainmenu菜单栏(2026-02-26 增加菜单项图标尺寸参数) cudaText存在段落长度超过一定字数时会出现字符重叠的问题 lazarus编写的程序在Ubuntu任务栏/快捷栏不显示设定的图标 lazarus实现拖放文件 在uos使用lazarus调试时遇到的问题 【原创控件】lazarus IDE界面备份和恢复插件(2026-02-07增加恢复默认布局及官方已集成到lazarus) lazarus for arm32编译so链接出错
SimpleXML-for-lazarus
秋·风 · 2026-04-02 · via 博客园 - 秋·风

SimpleXML参照SimpleJson的用法

https://github.com/szlbz/SimpleXML-for-lazarus

注意:读写时不要加根节点名称

如xml.Nodes['Stu']就可以,不要用xml.Nodes['Students/Stu']:

xml := ParseXML('<Students><Stu>甲</Stu><Stu>乙</Stu><Stu>丙</Stu></Students>');
list := xml.Nodes['Stu'];

1. 从零构建 XML (动态创建)

通过解析一个空根节点来作为起点,然后动态添加子节点和文本。

procedure TForm1.Button5Click(Sender: TObject);
var
  xml, userNode: IXmlNode;
begin
  // 1. 初始化一个空的根节点
  xml := ParseXML('<Users/>');

  // 2. 添加子元素并设置文本
  userNode := xml.AddNode('User');
  userNode.AddText('张三');

  // 3. 给刚才的 User 节点添加属性
  userNode.SetAttribute('Age', '25');
  userNode.SetAttribute('City', '北京');

  // 4. 再添加一个用户 (使用链式调用风格)
  xml.AddNode('User').SetAttribute('Age', '30');

  xml.SaveToFile('Created.xml');
end;

2. 属性的读取与修改 (Attribute)

除了通过路径 @attr 访问属性,还可以直接通过属性索引器操作。

procedure TForm1.Button6Click(Sender: TObject);
var
  xml: IXmlNode;
begin
  xml := ParseXML('<config version="1.0" debug="true"/>');

  // 读取属性
  ShowMessage(xml.Attribute['version']); // 返回 "1.0"

  // 修改属性
  xml.Attribute['version'] := '2.0';
  xml.Attribute['author'] := 'ZhangSan'; // 新增属性

  ShowMessage(xml.ToXML);
  // 输出: <config version="2.0" debug="true" author="ZhangSan"/>
end;

3. 子节点的直接访问 (Node 与 Nodes)

不使用路径字符串,而是通过面向对象的方式访问层级。

procedure TForm1.Button7Click(Sender: TObject);
var
  xml: IXmlNode;
begin
  xml := ParseXML('<root><name>李四</name><age>28</age></root>');

  // 获取单个子节点 (返回第一个匹配的)
  ShowMessage(xml.Node['name'].Text); // 返回 "李四"

  // 修改单个子节点的文本
  xml.Node['age'].Text := '29';

  // 删除特定子节点
  xml.RemoveChild('age');
end;

4. 遍历同名节点列表 (IXmlNodeList)

当 XML 中有多个同名标签时,可以通过 Nodes 获取列表进行遍历。

procedure TForm1.Button8Click(Sender: TObject);
var
  xml: IXmlNode;
  list: IXmlNodeList;
  i: Integer;
begin
  xml := ParseXML('<Students><Stu>甲</Stu><Stu>乙</Stu><Stu>丙</Stu></Students>');

  list := xml.Nodes['Stu'];
  for i := 0 to list.Count - 1 do
  begin
    ShowMessage(list[i].Text); // 依次弹出:甲、乙、丙
  end;

  // 批量删除
  // xml.RemoveAllChildren('Stu');
end;

5. 带索引的路径访问 (类 XPath)

当有多个同名节点时,可以通过 [index] 精确定位(注意:索引从 0 开始)。

procedure TForm1.Button9Click(Sender: TObject);
var
  xml: IXmlNode;
  value: string;
begin
  xml := ParseXML('<root><item id="1">A</item><item id="2">B</item></root>');

  // 直接从 item 开始写(因为 xml 已经是 root 了)
  value := xml.GetS('item[1]/text()'); // 返回 "B"
  ShowMessage(value);

  // 获取第一个 item 的 id 属性
  value := xml.GetS('item[0]/@id'); // 返回 "1"
  ShowMessage(value);
end;

6. 强类型赋值与取值 (自动类型转换)

框架内置了 Integer、Int64、Double、Boolean、TDateTime 的自动转换,省去了手动 StrToInt 等操作。

procedure TForm1.Button10Click(Sender: TObject);
var
  xml: IXmlNode;
begin
  xml := ParseXML('<Data/>');

  // 写入各种类型
  xml.SetI('Data/Count', 100);        // 存为 "100"
  xml.SetF('Data/Price', 19.99);      // 存为 "19.99" (自动处理小数点)
  xml.SetB('Data/IsValid', True);     // 存为 "true"
  xml.SetD('Data/CreateTime', Now);   // 存为 ISO 8601 格式 "2023-10-27T14:30:00.000"

  // 读取各种类型 (如果转换失败会返回默认值 0/False/0.0)
  ShowMessage(IntToStr(xml.GetI('Data/Count')));
  ShowMessage(BoolToStr(xml.GetB('Data/IsValid'), True));
end;

7. 节点拷贝

完全克隆一个节点及其所有子节点,生成一个独立的副本,互不影响。

procedure TForm1.Button11Click(Sender: TObject);
var
  xml, clonedXml: IXmlNode;
begin
  xml := ParseXML('<root><a>1</a></root>');

  clonedXml := xml.Clone;

  // 修改克隆体,不影响原对象
  clonedXml.Node['a'].Text := '2';

  ShowMessage(xml.Text);        // 输出 1
  ShowMessage(clonedXml.Text);  // 输出 2
end;

8. 将 XML 扁平化为键值对

这是一个非常实用的功能,它将复杂的树形结构拍平成一维的 Path-Value 数组,非常适合用于日志记录、数据库存储或前端表格展示。

procedure TForm1.Button12Click(Sender: TObject);
var
  xml: IXmlNode;
  flatItems: TXmlFlatItems;
  item: TXmlFlatItem;
begin
  xml := ParseXML('<root><user id="1"><name>张三</name></user></root>');

  flatItems := xml.Flatten;

  for item in flatItems do
  begin
    // item.Path  : 路径,如 "root/user[0]/@id", "root/user[0]/name/text()"
    // item.Value : 值,如 "1", "张三"
    Memo1.Lines.Add(Format('%s = %s', [item.Path, item.Value]));
  end;
  // 输出结果:
  // root/user[0]/@id = 1
  // root/user[0]/name/text() = 张三
end;

9. 序列化输出控制

提供了两种输出方式:紧凑(无换行无空格)和格式化(带缩进,便于人工阅读)。

procedure TForm1.Button13Click(Sender: TObject);
var
  xml: IXmlNode;
begin
  xml := ParseXML('<root><a><b>Text</b></a></root>');

  // 紧凑输出(适合网络传输,体积小)
  ShowMessage(xml.ToXML);
  // <root><a><b>Text</b></a></root>

  // 格式化输出(适合保存为配置文件,便于阅读)
  ShowMessage(xml.Format);
  // {
  //   <root>
  //     <a>
  //       <b>Text</b>
  //     </a>
  //   </root>
  // }
end;

10.使用 LoadXMLFromFile 读取该文件、解析内容、修改并另存为新文件的完整 Demo

假设你有一个名为 config.xml 的配置文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<Settings>
  <App>MyApp</App>
  <Window Width="800" Height="600" />
  <Users>
    <User>Admin</User>
    <User>Guest</User>
  </Users>
</Settings>
procedure TForm1.Button14Click(Sender: TObject);
var
  xml: IXmlNode;
  userList: IXmlNodeList;
  w, h: Integer;
begin
  try
    // 1. 从文件加载 XML
    // 注意:如果文件不存在或格式错误,这里会抛出异常
    xml := LoadXMLFromFile('config.xml');

    // 2. 读取普通节点的文本
    ShowMessage('当前应用名称: ' + xml.GetS('App'));

    // 3. 读取节点的属性 (路径直接写 Window/@Width)
    w := xml.GetI('Window/@Width');
    h := xml.GetI('Window/@Height');
    ShowMessage(Format('窗口大小: %d x %d', [w, h]));

    // 4. 获取列表并遍历
    userList := xml.Nodes['Users/User']; // 获取 Users 下的所有 User 节点
    ShowMessage(Format('共有 %d 个用户', [userList.Count]));
    if userList.Count > 0 then
      ShowMessage('第一个用户是: ' + userList[0].Text);

    // 5. 动态修改数据
    xml.SetS('App', 'MyApp Pro');      // 修改应用名称
    xml.SetI('Window/@Width', 1024);   // 修改窗口宽度

    // 6. 将修改后的内容另存为新文件
    xml.SaveToFile('config_new.xml');
    ShowMessage('修改完成并已保存为 config_new.xml');

  except
    on E: Exception do
    begin
      // 捕获并提示错误(例如文件找不到、XML语法错误等)
      ShowMessage('加载XML失败: ' + E.Message);
    end;
  end;
end;