Skip to content

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

@paciox

Description

@paciox

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": "jane.doe@example.com" }, "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": "jane.doe@example.com" }, "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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions