it编程 > 编程语言 > Delphi

mORMot2 生成和解析 JSON

185人参与 2024-05-12 Delphi

mormot2 生成和解析json

本文非完全原创,

前综合示例,整个示例是建立在mormot特有的实现模式的基础上,非常用的序列化反序列化,但又有别于字符串拼接,据说效率极高。

unit unit1;
 
interface
 
uses
  windows, messages, sysutils, variants, classes, graphics, controls,
  forms, dialogs, stdctrls,
  mormot.core.perf,
  mormot.core.data,
  mormot.core.text,
  mormot.core.json,
  mormot.core.variants,
  mormot.core.base,
  mormot.core.log ;
 
type
  tform1 = class(tform)
    button1: tbutton;
    button2: tbutton;
    button3: tbutton;
    memo1: tmemo;
    procedure button1click(sender: tobject);
    procedure button2click(sender: tobject);
    procedure button3click(sender: tobject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  form1: tform1;
 
implementation
 
{$r *.dfm}

解析json:

下面是最基本的方法,如何定位!这里用到了 getvaluebypath 函数。

procedure tform1.button1click(sender: tobject);
//解析json
var
  js: tdocvariantdata;//这个类型就是mormot利用variant扩展的特有方案
  json: string;
begin
  json := '{"tt":"1"}';
  js.initjson(json); //从字符串到variant
  caption := js.getvaluebypath(['tt']);//定位
end;

通过 docvariantdata(getvaluebypath (xxx)).value[ ] 可以访问对于array或者list可以访问元素值

对于 tdocvariantdata类型的变量可以通过特征属性函数直接访问【u[]:rawutf8;s[]:string;b[]:boolean;i[]:int64;d[]:double;o[]:pdocvariantdata;o_[] a[]:pdocvariantdata; a_[] _[]】

(*
{
  "blockcount":3,
  "blocks":[
    {"fieldcount":1, "fields":[{"name":"姓名", "value":["张1", "张2","张三"]}]},
    {"fieldcount":1, "fields":[{"name":"单位", "value":["华2", "张2","张三"]}]},
    {"fieldcount":1, "fields":[{"name":"单位", "value":["华拓", "张2","张三"]}]}
  ]
}
*)
 
procedure tform1.button2click(sender: tobject);
//解析json
var
  js, js2, js3: tdocvariantdata;
begin
  js.initjsonfromfile('tt.json');
  caption := docvariantdata(js.getvaluebypath(['blocks'])).value[0]; //{"fieldcount":1, "fields":[{"name":"姓名", "value":["张1", "张2","张三"]}]}
  js2.initjson(caption);
  caption := docvariantdata(js2.getvaluebypath(['fields'])).value[0]; //{"name":"姓名", "value":["张1", "张2","张三"]}
  js3.initjson(caption);
  caption := js3.u['name'] + docvariantdata(js3.getvaluebypath(['value'])).value[0]; //姓名张1
  caption := docvariantdata(docvariantdata(js.a['blocks'].value[1]).a['fields'].value[0]).a['value'].value[0]; //华2
end;

生成json:

(*
{"name":"str0","age":0,"list":[1,"hello",5,{"name":"咏南中间件","age":99}]}
{"name":"str1","age":1,"list":[1,"hello",5,{"name":"咏南中间件","age":99}]}
*)
procedure tform1.button3click(sender: tobject);
//生成json
var
  jo: variant;
  i: int64;
begin
  tdocvariant.new(jo);
  i := 0;
  while i < 2 do
  begin
    jo.name := 'str' + inttostr(i);
    jo.age := i;
    jo.list := _json('[1,"hello",5,{"name":"咏南中间件","age":99}]');
    memo1.lines.add(variantsavejson(jo));
    inc(i);
  end;
end;
 
end.

关于tdocvariantdata:

利用tdocvariantdata做json解析, 就是在这个文档(json文档,文档泛指json)中查找一个项目,并返回其值。

对于数组类型的文档:

avariant := tdocvariant.newarray(['one',2,3.0]);
for i := 0 to tdocvariantdata(avariant).count-1 do
  avalue := tdocvariantdata(avariant).value[i];

对于对象类型的文档:

avariant := tdocvariant.newobject(['name','john','year',1972]);
assert(avariant.name=tdocvariantdata(avariant)['name']);
assert(avariant.year=tdocvariantdata(avariant)['year']);

由于变体的执行内部实现(较慢的_dispinvoke()函数),执行以下操作会稍快一些:

avalue := tdocvariantdata(avariant).value['name'];
// 或者
avalue := _safe(avariant).value['name'];

// 而不是
avalue := avariant.name;

当然,如果想通过索引访问内容(通常是dvarray),使用values[]和names[]属性会比使用变体索引的伪属性更快:

with tdocvariantdata(avariant) do
for i := 0 to count-1 do
writeln(values[i]); //这里是values

比以下代码更快:

with tdocvariantdata(avariant) do
  for i := 0 to count-1 do
  writeln(value[i]);

这又比以下代码更快:

for i := 0 to avariant.count-1 do
writeln(avariant._(i));

此属性将值作为varbyref返回(就像对任何tdocvariant实例的变体后期绑定一样),因此您可以这样写:

var
  doc: tdocvariantdata; // 栈上分配的变量
begin
  doc.initjson('{arr:[1,3]}');
  assert(doc.count=2);
  doc.value['arr'].add(7); // 由于doc.value['arr']是varbyref,因此可以工作
  writeln(doc.tojson); // 将输出 '{"arr":[1,3,7]}'
end;

关于tdocvariant:

当然,以下是对注释区域的翻译,同时我使用 markdown 语法来高亮代码,并去掉了行注释标志:


这是一个自定义的变体类型,用于存储任何基于json/bson文档的内容。

tdocvariant.newfast(avariant);

avariant.name := 'john';

avariant.age := 35;

writeln(avariant.name, ' is ', avariant.age, ' years old');
avariant._count // 等同于 docvariantdata(avariant).count,访问元素数量

avariant._kind  // 等同于 ord(docvariantdata(avariant).kind),访问变体的类型(以整数的形式)

avariant._json  // 等同于 docvariantdata(avariant).json,访问变体的json表示

avariant._(i)   // 等同于 docvariantdata(avariant).value[i],使用索引访问元素的值

avariant.value(i)   // 另一种通过索引访问值的方式,更明确

avariant.value(aname) // 等同于 docvariantdata(avariant).value[aname],使用名字访问元素的值

avariant.name(i) // 等同于 docvariantdata(avariant).name[i],访问元素的名字

avariant.add(aitem) // 等同于 docvariantdata(avariant).additem(aitem),向变体中添加一个元素

avariant._ := aitem // 另一种添加元素的方式,语法更简洁

avariant.add(aname, avalue) // 等同于 docvariantdata(avariant).addvalue(aname, avalue),向变体中添加一个命名值对

avariant.exists(aname) // 等同于 docvariantdata(avariant).getvalueindex(aname)>=0,检查一个名字是否存在于变体中

avariant.delete(i) // 等同于 docvariantdata(avariant).delete(i),通过索引删除一个元素

avariant.delete(aname) // 等同于 docvariantdata(avariant).delete(aname),通过名字删除一个元素

avariant.nameindex(aname) // 等同于 docvariantdata(avariant).getvalueindex(aname),通过名字获取元素的索引
assert(_json('["one",2,3]')._json = '["one",2,3]');
assert(_json('["one",2,3]') = '["one",2,3]');

后综合示例

弄明白mormot的json,实际就是变体类型应用,他的快在于variant本身,同时也受限于variant有上限,估计通过优化提升不了太多。

这是一个用于存储基于json/bson文档的内容的自定义变体类型。

功能特性:

示例代码和注释:

// 创建一个新的变体实例
var avariant: tdocvariant;
tdocvariant.newfast(avariant);

// 设置和获取属性
avariant.name := 'john'; // 设置名字属性
avariant.age := 35;     // 设置年龄属性
writeln(avariant.name, ' is ', avariant.age, ' years old'); // 输出属性

// 访问伪属性和伪方法
writeln('count: ', avariant._count);        // 元素数量
writeln('kind: ', avariant._kind);          // 变体类型(整数形式)
writeln('json: ', avariant._json);          // 变体的json表示
writeln('value at index 1: ', avariant._(1)); // 通过索引访问元素值

// 添加元素和值
avariant.add('city');                      // 添加一个元素
avariant.add('country', 'usa');             // 添加一个命名值对

// 检查元素是否存在并删除
if avariant.exists('country') then
  writeln('country exists.');
avariant.delete('country');                // 通过名字删除元素

// json序列化和反序列化示例
var jsonstring: string;
jsonstring := avariant._json;               // 序列化为json字符串
// ... 此处可以保存或传输 jsonstring ...
avariant := _json(jsonstring);             // 从json字符串反序列化

// 验证json字符串直接转码功能
assert(_json('["one",2,3]') = '["one",2,3]');

注意:

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

mORMot2 获取数据集1

05-12

Delphi 实现刘谦春晚魔术

05-12

mORMot 1.18 第07章 简单的读写操作

05-12

delphi redisclient测试

05-12

mORMot 1.18 第06章 概念

05-12

mormot2 笔记(二) Http服务的简单搭建

05-12

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论