Skip to content

JsonPath implementation in .NET standard 2.0 that depends only on System.Text.Json.

License

Notifications You must be signed in to change notification settings

stanac/JsonPathway

Repository files navigation

JsonPathway

.NET Core Nuget Coverage Status


JsonPath implementation in .NET standard 2.0 that depends only on System.Text.Json.

Changes

  • 1.100.1 - fix nuget package
  • 1.100.2 - fix bug #1
  • 2.0.100 - Update System.Text.Json to 5.0.2 and update tests to use .NET 5
  • 2.1.100 - Return clones of JsonElements when executing path so it's safe to dispose JsonDocument
  • 2.1.101 - Fix filter expressions when comparing with null values
  • 2.2.100 - Overloads to execute JsonPath on JsonElement and symbols package
  • 2.3.100 - Support 5.x.x - 6.x.x System.Text.Json versions
  • 2.4.100 - Support 5.x.x - 7.x.x System.Text.Json versions
  • 2.5.100 - Support 5.x.x - 8.x.x System.Text.Json versions

Supported operators

JSONPath Description
$ Root object, optional
. or [] Child operator
[] Array element operator
[,] Multiple array elements
[:] [::] Slice operator
* Wildcard for properties
[*] Wildcard for array elements (useless?)
[?()] Filter for object properties or array elements
@ Current element reference in filter

() script expression is not supported in this implementation

Usage

Install nuget JsonPathway

using JsonPathway;
using System.Text.Json;
using System.Collections.Generic;

// ...
string jsonInput = LoadJson(); // or however you get your JSON string
string path = "$.store.bicycle.color.length"; // $ is optional
IReadOnlyList<JsonElement> result = JsonPath.ExecutePath(path, jsonInput);

// optionally to convert result to JSON use
string resultJson = JsonSerializer.Serialize(result);

Overloads:

IReadOnlyList<JsonElement> ExecutePath(string jsonPathExpression, string json)
IReadOnlyList<JsonElement> ExecutePath(string jsonPathExpression, JsonDocument doc)
IReadOnlyList<JsonElement> ExecutePath(string jsonPathExpression, JsonElement element)
IReadOnlyList<JsonElement> ExecutePath(ExpressionList jsonPathExpression, string json)
IReadOnlyList<JsonElement> ExecutePath(ExpressionList jsonPathExpression, JsonDocument doc)
IReadOnlyList<JsonElement> ExecutePath(ExpressionList jsonPathExpression, JsonElement element)

Both parsed document JsonDocument and ExpressionList that represents parsed path can be reused and should be reused when used multiple times.

string json1 = // ...
string json2 = // ...
string json3 = // ...

string pathString = "$.store.bicycle.color.length";
ExpressionList expression = JsonPathExpression.Parse(pathString);
JsonDocument doc = JsonDocument.Parse(json1);

IReadOnlyList<JsonElement> result1 = JsonPath.ExecutePath(expression, doc);
IReadOnlyList<JsonElement> result2 = JsonPath.ExecutePath(expression, json2);
IReadOnlyList<JsonElement> result3 = JsonPath.ExecutePath(pathString, json3);

Validating input can be done with:

bool valid = JsonPath.IsPathValid(path, out string error);

Examples

For all examples following JSON will be used as input (taken from here):

{ 
  "store": {
    "book": [ 
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

Auto property length

length is supported on both arrays and strings.

For path $.store.bicycle.color.length method ExecutePath returns JSON array [3];

For path $.store.book[?(@.title.length == 21)] resulting JSON array is:

[
  { "category": "fiction",
    "author": "J. R. R. Tolkien",
    "title": "The Lord of the Rings",
    "isbn": "0-395-19395-8",
    "price": 22.99
  }
]

Supported methods

Methods are supported only in filters

Supported string methods

  • toUpper()
  • toLower()
  • toUpperCase() - alias of toUpper()
  • toLowerCase() - alias of toLower()
  • contains(value: string)
  • contains(value: string, ignoreCase: boolean)
  • startsWith(string value)
  • startsWith(string value, ignoreCase: boolean)
  • endsWith(string value)
  • endsWith(string value, ignoreCase: boolean)

Supported array methods

  • contains(element: any)
Supported methods example

Path $.store.book[?(@.author.contains("tolkien", true))] returns

[
  {
    "category": "fiction",
    "author": "J. R. R. Tolkien",
    "title": "The Lord of the Rings",
    "isbn": "0-395-19395-8",
    "price": 22.99
  }
]

Same goes for path $.store.book[?(@.author.contains('tolkien', true))] even though single quotes are not supported by "specification" they are supported by this implementation for string quotes.

Other examples

Following child operators all return same result ([19.95]):

  • $.store.bicycle.price
  • store.bicycle.price
  • $["store"]["bicycle"]["price"]
  • ["store"]["bicycle"]["price"]
  • $['store']['bicycle']['price']
  • ['store']['bicycle']['price']

Which means $ is optional and strings can be quoted with ' and ".

Array operators:

  • $.store.book[0] returns "Sayings of the Century" book
  • $.store.book[-1] returns "The Lord of the Rings" book (last book)
  • $.store.book[*] returns all books

Slice operator [start:end:step] $.store.book[0:4:2] returns books at indexes [0] and [2] (second number "end" is exclusive).

Wildcard can be applied to object properties with .*:

  • $.store.bicycle.* returns ["red",19.95]

Recursive operator can be applied to properties and arrays with .. e.g.

$.store.book.. results in

[
  [
    {
      "category": "reference",
      "author": "Nigel Rees",
      "title": "Sayings of the Century",
      "price": 8.95
    },
    {
      "category": "fiction",
      "author": "Evelyn Waugh",
      "title": "Sword of Honour",
      "price": 12.99
    },
    {
      "category": "fiction",
      "author": "Herman Melville",
      "title": "Moby Dick",
      "isbn": "0-553-21311-3",
      "price": 8.99
    },
    {
      "category": "fiction",
     "author": "J. R. R. Tolkien",
     "title": "The Lord of the Rings",
     "isbn": "0-395-19395-8",
     "price": 22.99
    }
  ],
  {
  	"category": "reference",
  	"author": "Nigel Rees",
  	"title": "Sayings of the Century",
  	"price": 8.95
  },
  {
  	"category": "fiction",
  	"author": "Evelyn Waugh",
  	"title": "Sword of Honour",
  	"price": 12.99
  },
  {
  	"category": "fiction",
  	"author": "Herman Melville",
  	"title": "Moby Dick",
  	"isbn": "0-553-21311-3",
  	"price": 8.99
  },
  {
    "category": "fiction",
    "author": "J. R. R. Tolkien",
    "title": "The Lord of the Rings",
    "isbn": "0-395-19395-8",
    "price": 22.99
  }
]

Filters can be applied to array elements and object property values:

  • $.store.book[?(@.price > 10)] returns:
[
  {
    "category": "fiction",
    "author": "Evelyn Waugh",
    "title": "Sword of Honour",
    "price": 12.99
  },
  {
    "category": "fiction",
    "author": "J. R. R. Tolkien",
    "title": "The Lord of the Rings",
    "isbn": "0-395-19395-8",
    "price": 22.99
  }
]
  • $.store.book[?(@.isbn)] (truthy filter) returns:
[
  {
    "category": "fiction",
    "author": "Herman Melville",
    "title": "Moby Dick",
    "isbn": "0-553-21311-3",
    "price": 8.99
  },
  {
    "category": "fiction",
    "author": "J. R. R. Tolkien",
    "title": "The Lord of the Rings",
    "isbn": "0-395-19395-8",
    "price": 22.99
  }
]

About

JsonPath implementation in .NET standard 2.0 that depends only on System.Text.Json.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages