microsoft / AL

Home of the Dynamics 365 Business Central AL Language extension for Visual Studio Code. Used to track issues regarding the latest version of the AL compiler and developer tools available in the Visual Studio Code Marketplace or as part of the AL Developer Preview builds for Dynamics 365 Business Central.
MIT License
748 stars 245 forks source link

SelectTokens to Select multiple JsonTokens using a JPath expression #4306

Open ModigeMathias opened 5 years ago

ModigeMathias commented 5 years ago

I see SelectToken to select a single JsonToken, but I do not see SelectTokens to select a list or array of JsonTokens.

For example if one were to select all order_lines having line_no > 20000 in the following JsonToken: { "order_no": "Test01", "order_line": [ { "line_no": 10000, "item_no": "0000" }, { "line_no": 20000, "item_no": "0001" }, { "line_no": 30000, "item_no": "0002" }, { "line_no": 40000, "item_no": "0003" } ] }

Then it could be nice to be able to process it with something like: JsonToken.SelectTokens('order_line[?(@.line_no > 20000)]',JsonArray); foreach JsonToken2 in JsonArray do begin ... end;

mjmatthiesen commented 5 years ago

EDIT: I've tried the below, but no, you cannot do it. The current implementation will only be successful on jsonpaths that return a single result (as far as my testing found).

Can't you already do this?

if (JsonToken.SelectToken('order_line[?(@.line_no > 20000)]', JsonToken)) then begin
  JsonArray := JsonToken.AsArray();
  foreach JsonToken in JsonArray do begin
    // processing
  end;
ModigeMathias commented 5 years ago

SelectToken gives an error, if the JPath expression returns more than one token... I tested in Cu7 and have not tried in latest... Maybe this has already been adjusted?

mjmatthiesen commented 5 years ago

Maybe this has already been adjusted?

It hasn't, see my edit. It was my mistake. It's logical that it wouldn't work since it's newtonsoft's json.net under the hood, and that has a separate method for it... which is silly anyway, but it is what it is.

ModigeMathias commented 5 years ago

Yep, I saw the edit after. Aha, I thought the methods looked familiar.

mxdevos commented 1 year ago

Hi there, I just stumbled upon this as I encountered the exact same issue today, I query a webshop for a customer and the json it gives me back holds order related informations and some of the nested elements can contain multiple tokens that hold the same values in the current root object some example json would be:

{
    "included": [
        {
            "id": 12345,
            "type": "order_product",
            "attributes": {
                "label": "some_product_name"
            }
        },
        {
            "id": 54321,
            "type": "customer",
            "attributes": {
                "first_name": "Jon",
                "last_name": "Doe",
            }
        },
        {
            "id": 54321,
            "type": "customer",
            "attributes": {
                "first_name": "Jon",
                "last_name": "Doe"
            }
        }
    ]
}

when I now use a filter JPath expression to just give me the attributes where the id = 54321 and the type = "customer", I would receive an runtime error when using the .SelectToken() method on the JsonObject, JsonArray and JsonToken AL datatypes and not catching the return type to handle the error. My query looks like this:

SanitizedQuery := StrSubstNo('$.included[?(@.id==%1 && @.type==''%2'')].attributes', 54321, 'customer');

Is there a specific reason why the AL native data types for JSON handling do not support the SelectTokens method, because that would make it possible to select the tokens if multiple of the same tokens exist, or an array of the same tokens and so on. I know that you could iterate over the actual included json array and check every object itself if it matches that condition, that could result in iterating many times before even getting to the right json object in my scenario. And I think the solution when just using the .SelectTokens method would also result in neat code instead of iterating over the json array structure itself. So would it possible to implement the .SelectJsonTokens methods of the underlying NewtonSoftJson C# classes for the native AL data types?

pri-kise commented 1 year ago

Since this is feature request: Here is the Idea to vote for this missing feature: https://experience.dynamics.com/ideas/idea/?ideaid=8e2a7975-e87e-ee11-a81c-6045bd8043ad