Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] How to use functions in loops (#each and so on) when values comes from JSON? #592

Open
paciox opened this issue Sep 21, 2024 · 0 comments
Labels

Comments

@paciox
Copy link

paciox commented Sep 21, 2024

I have this test json:
{ "partyEvent": { "partyName": "Sweet Treats Fiesta", "day": "Saturday", "hour": "5:00 PM", "date": "2024-09-28", "address": { "street": "123 Party Lane", "city": "Funville", "state": "CA", "zip": "90210" }, "theme": "Desserts Extravaganza", "host": { "name": "Jane Doe", "contact": "[email protected]" }, "participants": [ { "name": "Alice Smith", "role": "Guest", "RSVP": true }, { "name": "John Johnson", "role": "Guest", "RSVP": false }, { "name": "Emily Davis", "role": "Caterer", "RSVP": true } ], "menu": { "items": [ { "id": "0001", "type": "donut", "name": "Cake", "ppu": 0.55, "batters": { "batter": [ { "id": "1001", "type": "Regular" }, { "id": "1002", "type": "Chocolate" }, { "id": "1003", "type": "Blueberry" }, { "id": "1004", "type": "Devil's Food" } ] }, "topping": [ { "id": "5001", "type": "None" }, { "id": "5002", "type": "Glazed" }, { "id": "5005", "type": "Sugar" }, { "id": "5007", "type": "Powdered Sugar" }, { "id": "5006", "type": "Chocolate with Sprinkles" }, { "id": "5003", "type": "Chocolate" }, { "id": "5004", "type": "Maple" } ] }, { "id": "0002", "type": "donut", "name": "Raised", "ppu": 0.55, "batters": { "batter": [ { "id": "1001", "type": "Regular" } ] }, "topping": [ { "id": "5001", "type": "None" }, { "id": "5002", "type": "Glazed" }, { "id": "5005", "type": "Sugar" }, { "id": "5003", "type": "Chocolate" }, { "id": "5004", "type": "Maple" } ] }, { "id": "0003", "type": "donut", "name": "Old Fashioned", "ppu": 0.55, "batters": { "batter": [ { "id": "1001", "type": "Regular" }, { "id": "1002", "type": "Chocolate" } ] }, "topping": [ { "id": "5001", "type": "None" }, { "id": "5002", "type": "Glazed" }, { "id": "5003", "type": "Chocolate" }, { "id": "5004", "type": "Maple" } ] } ] } } }

And I want to convert it to this one:

{ "eventoFesta": { "nomeFesta": "Sweet Treats Fiesta", "giorno": "Saturday", "ora": "5:00 PM", "data": "2024-09-28", "indirizzo": { "via": "123 Party Lane", "città": "Funville", "stato": "CA", "cap": "90210" }, "tema": "Desserts Extravaganza", "ospite": { "nome": "Jane Doe", "contatto": "[email protected]" }, "personeInvitate": { "partecipanti": [ { "nome": "Alice Smith", "ruolo": "Guest", "RSVP": true }, { "nome": "John Johnson", "ruolo": "Guest", "RSVP": false }, { "nome": "Emily Davis", "ruolo": "Caterer", "RSVP": true } ] } } }

through this template that it will simply map the first one through the second one:
var template = """ { "eventoFesta": { "nomeFesta": "{{jsonpath '$.partyEvent.partyName'}}", "giorno": "{{jsonpath '$.partyEvent.day'}}", "ora": "{{jsonpath '$.partyEvent.hour'}}", "data": "{{jsonpath '$.partyEvent.date'}}", "indirizzo": { "via": "{{jsonpath '$.partyEvent.address.street'}}", "città": "{{jsonpath '$.partyEvent.address.city'}}", "stato": "{{jsonpath '$.partyEvent.address.state'}}", "cap": "{{jsonpath '$.partyEvent.address.zip'}}" }, "tema": "{{jsonpath '$.partyEvent.theme'}}", "ospite": { "nome": "{{jsonpath '$.partyEvent.host.name'}}", "contatto": "{{jsonpath '$.partyEvent.host.contact'}}" }, "personeInvitate": { "partecipanti": [ {{#each (jsonpath '$.partyEvent.participants')}} { "nome": "{{jsonpath '$.name'}}", "ruolo": "{{jsonpath '$.role'}}", "RSVP": {{jsonpath '$.RSVP'}} }{{#unless @last}},{{/unless}} {{/each}} ] } } } """;

Since we are dealing with JSON, I wrote an helper, which is "jsonpath":

`
using HandlebarsDotNet;
using Json.Path;
using System.Text.Json.Nodes;

namespace _01_BaseSKStuff.BaseUtils.JsonUtils
{
internal static class PathEvaluator
{
internal static HandlebarsHelper PathTrasversalHelper => (writer, context, parameters) =>
{
if (parameters.Length == 0)
{
writer.Write(null);
return;
}

        var data = JsonNode.Parse(context.Value.ToString());
        var paramValue = parameters[0].ToString();

        if (data is null || paramValue is null)
        {
            writer.Write(null);
            return;
        }

        var value = EvaluatePath(data, paramValue);

        writer.Write(value);
    };

    public static string? EvaluatePath(JsonNode jsonNode, string rulePath)
    {
        var jsonPath = JsonPath.Parse(rulePath);
        var pathResult = jsonPath.Evaluate(jsonNode);

        if (pathResult is null || pathResult.Matches.Count != 1) return null;

        return pathResult.Matches.Select(x => x.Value?.ToString()).First();
    }
}

}
`

This just takes the first element of a json path, traversing it with the syntax "$.thisproperty.thischildproperty"

It actually maps everything good except for the #each helper that does not seem to like what it returns, which is a JsonArray[].

How to make this work?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant