You are not logged in.
Pages: 1
Hello, everyone
I want to store and retrieve the data of an object with a list property in a json string. However I have a hard time getting this to work. I would appreciate some hints were I can find examples or if it is a good practice using a list instead of an array at all.
Thanks and best regards
My current failing example code:
TItem = Record
Name: String;
End;
TStorage = Class
Private
fPlace: RawUtf8;
fItems: IList < TItem > ;
Published
Property Place: RawUtf8 Read fPlace Write fPlace;
Property Items: IList < TItem > Read fItems Write fItems;
End;
[...]
Procedure TForm1.Button1Click(Sender: TObject);
Var
Storage: TStorage;
Item: TItem;
Begin
Storage := TStorage.Create;
Storage.Place := 'Ocean';
Storage.Items := Collections.NewPlainList < TItem > ;
Item.Name := 'Foo';
Storage.Items.Add(Item);
Item.Name := 'Bar';
Storage.Items.Add(Item);
Memo1.text := ObjectToJson(Storage, [woHumanReadable]); //does not print Items
End;
Last edited by DirkH (2025-09-26 11:10:29)
Offline
Offline
Thank you for you answer,
I'm lost in some rabbit hole Every hour I'm working with it I'm more confused.
I'm using Lazarus 4.2 FPC 3.2.2
At least for now I put everything into records, and used TArray instead of IList. My best guess so far is documented at https://github.com/D-H-R/mormot_json/bl … /unit1.pas.
I know that RecordSaveJson is supposed to do base64 encoding, I wasn't able to get s.th. else running
As you might have expected I need a human readable format.
Can you please point out to me which classes (for data holding) and functions for the "toJson" I should use for a first approach.
Thank you so much.
Last edited by DirkH (2025-09-27 10:45:49)
Offline
FPC does not have RTTI about extended record.
This is a FPC limitation. (the FPC trunk supports extended records RTTI and mORMot can use it).
So you need to follow
https://synopse.info/forum/viewtopic.php?pid=36191
A quick search in the forum find it, and also similar answers like:
https://synopse.info/forum/viewtopic.php?id=6994
Even grok is almost write about this point:
https://grok.com/share/c2hhcmQtMg%3D%3D … b7156e9191
"Almost" because the source code and text definition format is incorrect But at least you have the idea.
And it is really funny how grok is even more hallucinating, the more you give him corrections.
Offline
I have provided you with examples there last day: D-H-R/mormot_json/issues/1
And it is really funny how grok is even more hallucinating, the more you give him corrections.
I admit I feel like the more thinking they try to do, the more they tend to hallucinate...
Offline
Thanks to both of you and especially flydev for this turnkey solution - superb!
Now I'm running into the next Issue I dont understand. Since JSON creation works so great I'm trying to read it back.
ObjLoadJson works fine if JSON and Object structure exactly match. However I need to tolerate if it is (slightly) modified by the user or if there is an update in the structure I need to read an old one or introduce new fields.
I wanted to do that with TDocVaraiant, but I cant Acces fields in the "measurementData" array of objects.
TDocVariantData(item).S['note'] fails in mormot.core.variants TDocVariantData.GetValueIndex because it expects cardinal(VType) = DocVariantVType, which is in my case (16396 = 271, obviously fail -> result-1)
procedure TForm1.Button9Click(Sender: TObject);
Var
doc: variant;
item: variant;
Begin
doc := _Json('{"text":"Some general Description","measurementData":[{"id":47,"note":"erster Teil","values":[1.1,1.2,1.3]},{"id":11,"note":"zweiter Teil","values":[2.1,2.2,2.3]}]}');
item := TDocVariantData(doc).A['measurementData'].Value[1];
Memo2.Lines.Clear;
Memo2.lines.add('Raw second element: ' + VariantToUtf8(TDocVariantData(doc).A['measurementData'].Value[1])); //returns {"id":11,"note":"zweiter Teil","values":[2.1,2.2,2.3]}
Memo2.lines.add('note: ' + TDocVariantData(item).S['note']); //fails "property note not found"
End;
Offline
Personal taste, I feel more comfortable using IDocDict/List. Maybe take a look at this blog post if it helps (check the advanced features: filtering, searching):
Offline
As documented, do not use TDocVariantData() but _Safe() when trans-typing such values.
Or use item: PDocVariantData directly instead of a local variant value.
Since you seem to be lost in variant/TDocVariant internals (those are not easy to grasp), consider IDocList/IDocDict instead, as FlyDev proposed.
Offline
I have not yet all my use cases covered but the question how to access "note" from the inner ojbect is solved:
I used IDocList / Dict and it works like a breeze
dict := DocDict('{"text":"Some general Annot. Description","measurementData":[{"id":47,"note":"erster Teil","values":[1.1,1.2,1.3]},{"id":11,"note":"zweiter Teil","values":[2.1,2.2,2.3]}]}');
Memo2.lines.add('oneliner note' + dict.GetL('measurementData').GetD(1).GetS('note'));
Last edited by DirkH (2025-10-01 14:02:23)
Offline
Note you can just write:
Memo2.lines.add('oneliner note' + dict.L['measurementData'].D[1].S['note']);
or
dict.PathDelim := '.';
Memo2.lines.add('oneliner note' + dict.S['measurementData.1.note']);
Note that you could also use TDocVariantData.GetVariantByPath or P[]:
var doc: variant;
begin
doc := _JsonFast('{...}');
Memo2.lines.add('oneliner note' + _Safe(doc)^.P['measurementData.1.note']);
or, using a TDocVariantData
var doc: TDocVariantData;
begin
doc.InitJson('{...}');
Memo2.lines.add('oneliner note' + doc.P['measurementData.1.note']);
Offline
Thanks a lot!
Somehow my brain doesn't like the square braces for this purpose. It seems to be linked to "access array / list element by position / memory offset" (I have to look at much C Code for embedded Systems). I think in this place the GetS() is exactly the same. Are there other places where it's worth to untie my brains knot ?
dict.PathDelim := '.';
Memo2.lines.add('short oneliner: ' + dict.GetS('measurementData.1.note'));
Best regards
Last edited by DirkH (2025-10-02 08:02:26)
Offline
Pages: 1