JMESPath is a powerful query language that enables processing of JSON payloads. It can be used in .NET, see JmesPath.Net.

Source code:


JSON processing is a common task in the day-to-day work of developers. We are used to working with JSON, but, occasionally, we need something more dynamic and efficient than System.Text.Json and Newtonsoft.Json. JMESPath is a powerful query language that allows you to perform Map/Reduce tasks in a declarative and intuitive manner.

JMESPath is simple to use, the query itself is just a plain string. The benefit of this approach is that you can follow the inversion of control principle and give your users the control of writing JMESPath queries.

💡 For example, the Azure CLI uses the –query parameter to execute a JMESPath query on the results of commands.

public sealed class JmesPath
    public string Transform(string json, string expression);


Read a random example of JSON string from a file:

var source = new StreamReader("./example.json").ReadToEnd();

The content of the file:

  "_id": "63ba60670fe420f2fb346866",
  "isActive": true,
  "balance": "$2,285.51",
  "age": 20,
  "eyeColor": "blue",
  "name": "Eva Sharpe",
  "email": "",
  "phone": "+1 (950) 479-2130",
  "registered": "2023-01-08T08:07:44.1787922+00:00",
  "latitude": 46.325291,
  "longitude": 5.211461,
  "friends": [
      "id": 0,
      "name": "Nielsen Casey",
      "age": 19
      "id": 1,
      "name": "Carlene Long",
      "age": 38

The code below shows the processing of the example payload above. It demonstrates different concepts such as projections, filtering, aggregation, type transformation, etc. I think the syntax is quite intuitive and doesn’t need an explanation.

The processing is quite simple:

var expressions = new (string, string)[]
    ("scalar", "balance"),
    ("projection", "{email: email, name: name}"),
    ("functions", "to_string(latitude)"),
    ("arrays", "friends[*].name"),
    ("filtering", "friends[?age > `20`].name"),
    ("aggregation", "{sum: sum(friends[*].age), names: join(',', friends[*].name)}"),
    ("now. ISO 8601", "now()"),
    ("now. Universal sortable date/time pattern", "now('u')"),
    ("now. Long date pattern", "now('D')"),
    ("format", "date_format(registered, 'd')"),

foreach (var (exampleName, expression) in expressions)
    var result = parser.Transform(source, expression);


The cool thing about JMESPath is it provides a way to add custom functions. See more details:

For example, here is how we can write now() function that accepts .NET string format provider, see the Microsoft docs

public class NowFunction : JmesPathFunction
    private const string DefaultDateFormat = "o";

    public NowFunction() : base("now", minCount: 0, variadic: true) { }

    public override JToken Execute(params JmesPathFunctionArgument[] args)
        var format = args is { Length: > 0 } x
            ? x[0].Token
            : DefaultDateFormat;

        return new JValue(DateTimeOffset.UtcNow.ToString(format.ToString()));


As you can see, JMESPath solves the issues of dynamic JSON processing based on user input quite nicely. It has an extensibility model that opens tons of possibilities.


Oleksii Nikiforov

Jibber-jabbering about programming and IT.