Jump to content
PizzaProgram

TSuperObjectIter ObjectFindFirst problem

Recommended Posts

Hi,

 

I'm trying this function the first time and it would be really great, if it would find the string I'm looking for.

Here is my code:

procedure TFrm_Ntak.gmb_jsonTesztClick(Sender: TObject);
var
    o : ISuperObject;

    function stat_search(what: string): string;
    var
        JsonSearch  : TSuperObjectIter;
    begin
        Result := '';

        if ObjectFindFirst(o, JsonSearch) then begin
            repeat
                if JsonSearch.key = what then begin
                    Result := JsonSearch.val.AsString;
                    Break;
                end;
            until not ObjectFindNext(JsonSearch);
        end;

        ObjectFindClose( JsonSearch );
    end;

begin
    o := SO('{"messageAnswers":[{"id":"fe134b3e-...","successfullMsgs":[{"type":"DAILYCLOSING","rmsID":"fe134b3e-..."}],"status":"SUCCESS"}]}');

    ShowMessage( stat_search('status') );
end;

 

Instead of showing :

   SUCCESS

it gives back no result.

 

I can see, that the trouble is caused by the ARRAY, but I simply don't get it, why an "universal search" function can not handle that?

So what can I do?

I don't know the EXACT form of the json it needs to digest, there can be multiple embedded arrays, or who knows what ...

 but I need to search for this specific value.

 

Tried to search on stackoverflow + in ICS samples too, no success.

 

Thanks for any help ! 😉

Share this post


Link to post

There is only one key in the top level of the JSON string, "messageAnswers". Hence, iterating over the keys doesn't find "status". If you don't know what you're looking for, you're going to have to do a recursive search throughout the entire structure.

Share this post


Link to post
5 hours ago, Joseph MItzen said:

you're going to have to do a recursive search

Yes, that's what I wrote too: I know that.

To rephrase my question:

 

 - Is there no "ready to use" function for that?

  > if not, WHY ?

 - Nobody has a finished version? Nobody ever needed such a thing? I can not imagine that!

Edited by PizzaProgram

Share this post


Link to post
7 hours ago, PizzaProgram said:

 - Nobody has a finished version? Nobody ever needed such a thing? I can not imagine that!

When you're parsing JSON, you should have some idea of what it is you're parsing. This SuperObject library is more of a low-level parsing library rather than a very high level one.

Share this post


Link to post
4 hours ago, FPiette said:

Ask the developer!

Before asking, read the SuperObject documentation.

To be fair, that's precious little documentation. It's more like a few examples. I haven't used this library before and when checking I found that even the source code wasn't documented at all. 😞

 

 

Share this post


Link to post
7 hours ago, PizzaProgram said:

 - Nobody has a finished version? Nobody ever needed such a thing? I can not imagine that!

I know how to write a function that does this IF one can tell what the type is of a parsed element. But from the minimal "documentation" I see that the user can typecast an element but I don't see a way to check if something is an object or array. If there's no ability to do that, then I'm not sure if one can do this type of search with SuperObject... well, maybe with some ugly exception-handling.... I'll have to test this out later today.

 

Share this post


Link to post
13 hours ago, Joseph MItzen said:

I don't see a way to check if something is an object or array

Use one of the functions:

function ObjectIsType(const obj: ISuperObject; typ: TSuperType): boolean;
function ObjectGetType(const obj: ISuperObject): TSuperType;

 

  • Thanks 1

Share this post


Link to post

If you build the OverbyteIcsHttpRestTst sample application and access your JSON URL, you'll see the sample parses the JSON into a ListView, you can click on an object and it will expand that into another window, mostly done in the DisplayJson procedure using SuperObject DataType.

 

Angus

 

 

  • Like 1

Share this post


Link to post

Sorry for the late response, I've already wrote it myself.

Although it would be great to put it directly into: unit OverbyteIcsSuperObject;

Should be changed to an universal one, not just "string".

The result should be a Boolean.

 

function SearchInAll(inWhat: ISuperObject; const findThis : string): string;
// returns '' if not found
var
    JsonSearch  : TSuperObjectIter;
    i   : integer;
begin
    Result := '';
    if inWhat = nil then Exit;

    if ObjectFindFirst(inWhat, JsonSearch) then begin
        repeat
            if JsonSearch.key = findThis then
                Result := JsonSearch.val.AsString
            else
            if JsonSearch.val.DataType = stObject then
                Result := js_keres( JsonSearch.val, findThis )
            else
            if JsonSearch.val.DataType = stArray then begin
                for i := 0 to JsonSearch.val.AsArray.Length -1 do begin
                    Result := js_keres( JsonSearch.val.AsArray.O[i], findThis );
                    if Result <> '' then Break;
                end;
            end;
            if Result <> '' then Break;
        until not ObjectFindNext(JsonSearch);
    end;

    ObjectFindClose( JsonSearch );
end;

 

Edited by PizzaProgram

Share this post


Link to post
47 minutes ago, PizzaProgram said:

A leftover from half-translation.

Fixed. 

Please also fix your message. You can edit it.

Share this post


Link to post
On 11/13/2022 at 8:54 PM, FPiette said:

Please also fix your message.

Sorry, but which message? Did I spell something wrong? My English is not perfect.

Share this post


Link to post
27 minutes ago, PizzaProgram said:

Sorry, but which message? Did I spell something wrong? My English is not perfect.

I mean the code you posted and which contains unknown function js_keres.

Share this post


Link to post

Hmmm...

 That's strange!

I've replaced all occurrences, wrote: "fixed" on Sunday.

Now I see: the code is reverted back, all js_keres naming are back! :classic_ohmy:

 

Maybe some browser-cashing problem. Restarted Firefox.

I'm fixing again...

Share this post


Link to post

No, can not EDIT. That function is Disabled. Maybe that was the problem before >> it showed the Edit button on that day, but did not really allow it.

 

Here is it again:

function SearchInAll(inWhat: ISuperObject; const findThis : string): string;
// returns '' if not found
var
    JsonSearch  : TSuperObjectIter;
    i   : integer;
begin
    Result := '';
    if inWhat = nil then Exit;

    if ObjectFindFirst(inWhat, JsonSearch) then begin
        repeat
            if JsonSearch.key = findThis then
                Result := JsonSearch.val.AsString
            else
            if JsonSearch.val.DataType = stObject then
                Result := SearchInAll( JsonSearch.val, findThis )
            else
            if JsonSearch.val.DataType = stArray then begin
                for i := 0 to JsonSearch.val.AsArray.Length -1 do begin
                    Result := SearchInAll( JsonSearch.val.AsArray.O[i], findThis );
                    if Result <> '' then Break;
                end;
            end;
            if Result <> '' then Break;
        until not ObjectFindNext(JsonSearch);
    end;

    ObjectFindClose( JsonSearch );
end;

 

  • Like 1

Share this post


Link to post
On 11/13/2022 at 5:27 PM, PizzaProgram said:

Should be changed to an universal one, not just "string".

The result should be a Boolean.

Can you maybe rewrite it, so it may serve every kind of value?

I've never done such thing, so can not help.

 

Something with VarArray ... or like:

function SearchInAll(const inWhat: ISuperObject; findThisarray[1..1] of const; var foundValue: TSuperValue): Boolean;

Edit: added "foundValue" for adding back the Result, if Boolean = True;

Edited by PizzaProgram

Share this post


Link to post

I was thinking how to enhance the practical usage of this ISuperObject component, because it is great, but lack of "easy-to-use" methods.

So why not enhance the original methods a bit too, to search in Arrays too ?

function ObjectFindFirst(const obj: ISuperObject; var F: TSuperObjectIter; const inArrayToo: Boolean = False): boolean;

...

function ObjectFindNext(var F: TSuperObjectIter; const inArraysToo: Boolean = False): boolean;

 

At the FindFirst it would be necessary, because it is possible that the whole JSON is an array. {[{..},{..}]}

I've looked into the iterator code, but sadly I do not understand how this whole FPath[FDepth] := h; thing works.

Can not understand the concept and there are no comments in the code.

So I can not do it myself.

 

What is your opinion? Can / Would you like to enhance it?

Share this post


Link to post

Sorry, I don't have the time to enhance your code, unless there is a specific application for it.  Nor do I change anything for which there are no tests.

 

Angus

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×