兜蛇 发表于 2025-6-5 08:31:23

IDocList/IDocDict JSON for Delphi and FPC

IDocList/IDocDict JSON for Delphi and FPC

【英文原文】
多年来,我们的开源 mORMot 框架提供了多种方法来处理在运行时定义的数组/对象文档的任意组合,例如通过 JSON,具有许多功能和非常高的性能。

我们的 TDocVariant自定义变体类型是处理这类无模式数据的一种强大方式,但一些用户觉得它有些令人困惑。
因此,我们围绕它开发了一套新的接口定义,以简化其使用,同时不牺牲其功能。我们围绕Python列表和字典对它们进行了建模,这已被证明是可行的——当然,也做了一些扩展。
TDocVariant的优缺点

多年来,我们的 TDocVariant可以存储任何基于JSON/BSON的文档内容,即:

[*]面向对象文档的名/值对——在内部被标识为 dvObject子类型;
[*]面向数组文档的值数组(包括嵌套文档)——在内部被标识为 dvArray子类型;
[*]通过嵌套 TDocVariant实例,可以实现上述两者的任意组合。
每个 TDocVariant实例也是一个自定义的变体类型:

[*]因此,您可以将它存储或转换为变体变量;
[*]您可以使用后期绑定来访问其对象属性,这在现代Pascal的严格世界中有点像魔术;
[*]Delphi IDE(和Lazarus 3.x)调试器对其有原生支持,因此可以将变体内容显示为JSON;
[*]如果您在任何类或记录中定义了变体类型,我们的框架将识别 TDocVariant内容,并将其序列化和反序列化为JSON,例如在其ORM、SOA或Mustache/MVC部分中。
这种强大功能也带来了一些缺点:

[*]在变体和其 TDocVariantData记录之间切换可能很棘手,有时需要一些令人困惑的指针引用;
[*]每个 TDocVariant实例都可以用作对其他数据的弱引用,或者维护其自身的内容——在某些极端情况下,不正确的使用可能会导致内存泄漏或GPF问题;
[*]TDocVariant可以是对象/字典或数组/列表,因此找到正确的方法可能很困难,或者在运行时引发异常;
[*]它从一个简单的存储发展成了一个完整的内存引擎,因此高级功能通常被低估;
[*]TDocVariantData记录与大多数Delphi/FPC用户所习惯的类系统相去甚远;
[*]默认情况下,不解析双精度值——只解析货币值——如果你不想损失任何精度,这是有意义的,但也被发现会造成混淆。
抱怨够了。
我们只需让它变得更好。
引入IDocList和IDocDict接口
我们引入了两个高级封装接口类型:

[*]IDocList(或其别名IDocArray)用于存储元素列表;
[*]IDocDict(或其别名IDocObject)用于存储键值对字典。
接口方法和命名遵循通常的Python列表和字典,并在安全且专用于类的IDocList和IDocDict类型中封装它们自己的TDocVariant存储。
您可能会在现代Delphi中这样写:
var
list: IDocList;
dict: IDocDict;
v: variant;
i: integer;
begin
// 从项目创建一个新的列表/数组
list := DocList(); // 默认情况下允许双精度值

// 遍历列表
for v in list do
    Listbox1.Items.Add(v); // 将变量转换为字符串

// 或列表的一个子范围(使用类似Python的负索引)
for i in list.Range(0, -3) do
    Listbox2.Items.Add(IntToStr(i)); // 作为整数

// 搜索某些元素的存在
assert(list.Exists(2));
assert(list.Exists('four'));

// 从JSON中获取一个对象列表,其中包含一个入侵者
list := DocList('[{"a":0,"b":20},{"a":1,"b":21},"to be ignored",{"a":2,"b":22}]');

// 枚举所有对象/字典,忽略非对象元素
for dict in list.Objects do
begin
    if dict.Exists('b') then
      ListBox2.Items.Add(dict['b']);
    if dict.Get('a', i) then
      ListBox3.Items.Add(IntToStr(i));
end;

// 删除一个元素
list.Del(1);
assert(list.Json = '[{"a":0,"b":20},"to be ignored",{"a":2,"b":22}]');

// 提取一个元素
if list.PopItem(v, 1) then
    assert(v = 'to be ignored');

// 转换为JSON字符串
Label1.Caption := list.ToString;
// 显示 '[{"a":0,"b":20},{"a":2,"b":22}]'
end; 以及更多高级功能,如排序、搜索和表达式过滤:
varv: variant;f: TDocDictFields;list, list2: IDocList;dict: IDocDict;beginlist := DocList('[{"a":10,"b":20},{"a":1,"b":21},{"a":11,"b":20}]');// 根据嵌套对象的字段对列表/数组进行排序list.SortByKeyValue(['b', 'a']);assert(list.Json = '[{"a":10,"b":20},{"a":11,"b":20},{"a":1,"b":21}]');    // 使用条件表达式枚举列表/数组 :)for dict in list.Objects('b

饨篦 发表于 2025-10-30 11:41:23

分享、互助 让互联网精神温暖你我

锺冰洁 发表于 2025-11-22 06:53:56

懂技术并乐意极积无私分享的人越来越少。珍惜

黎娅茜 发表于 2025-12-14 16:30:11

用心讨论,共获提升!

师佳思 发表于 2025-12-30 18:10:27

鼓励转贴优秀软件安全工具和文档!

哈妙思 发表于 2026-1-19 11:34:36

很好很强大我过来先占个楼 待编辑

刘凤 发表于 2026-1-22 21:30:47

感谢,下载保存了

劳暄美 发表于 2026-1-23 02:47:07

分享、互助 让互联网精神温暖你我

赶塑坠 发表于 2026-1-25 07:54:41

yyds。多谢分享

缄戈 发表于 2026-1-28 06:24:41

不错,里面软件多更新就更好了

高小雨 发表于 2026-2-1 20:23:57

东西不错很实用谢谢分享

杜优瑗 发表于 2026-2-4 11:01:53

热心回复!

绘纵 发表于 2026-2-7 04:03:23

很好很强大我过来先占个楼 待编辑

喳谍 发表于 2026-2-9 19:50:00

感谢发布原创作品,程序园因你更精彩

丧血槌 发表于 2026-2-10 05:46:22

新版吗?好像是停更了吧。

垢峒 发表于 2026-2-11 02:12:44

感谢分享,下载保存了,貌似很强大

高小雨 发表于 2026-2-11 11:07:37

yyds。多谢分享

笙芝 发表于 2026-2-11 13:13:59

喜欢鼓捣这些软件,现在用得少,谢谢分享!

篙菠 发表于 2026-2-12 01:27:17

谢谢楼主提供!

闹忧踫 发表于 2026-2-12 13:22:49

谢谢分享,辛苦了
页: [1]
查看完整版本: IDocList/IDocDict JSON for Delphi and FPC