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

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

87 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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

No packages published

Languages