4

I'm using Json.Net's SelectToken method to query JSON using JSONPath with expressions like:

JToken acme = o.SelectToken("$.Manufacturers[?(@.Name == 'Acme Co')]");

-- http://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm

Does JSONPath support XPath style String Functions?
By String Functions, I mean those described in How to use like in XPath?

For example, is there syntax for the contains() method?

I've tried:

o.SelectToken("$.Manufacturers[?(contains(@.Name, 'Acme')]");

but JSON.Net complains of a syntax error (it doesn't like contains).

dbc
  • 104,963
  • 20
  • 228
  • 340
Philip Pittle
  • 11,821
  • 8
  • 59
  • 123
  • 1
    If by "JSONPath" you mean "the JSONPath supported by SelectToken and SelectTokens in Json.NET", the answer looks to be "no". If it did, there would be an appropriate `ScanFilter` [here](https://github.com/JamesNK/Newtonsoft.Json/tree/master/Src/Newtonsoft.Json/Linq/JsonPath), but there isn't. [`QueryFilter`](https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Linq/JsonPath/QueryFilter.cs) is closest but [QueryExpression](https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs) doesn't have it. – dbc Dec 10 '15 at 00:22
  • @dbc - Thanks for checking the source. I guess you're saying if I want it, I'll need to build it? – Philip Pittle Dec 10 '15 at 01:16
  • Or find some other package that does it. – dbc Dec 10 '15 at 04:46

1 Answers1

1

Json.NET Release 11 introduced the regex operator =~ for JSONPath queries. Using it you can do string pattern matching including contains() matches. For example:

  • To match a value containing the string Acme use =~ /Acme/:

    o.SelectToken("$.Manufacturers[?(@.Name =~ /Acme/)]")
    
  • To match a value containing the word Acme, bracket it with \b:

    o.SelectToken("$.Manufacturers[?(@.Name =~ /\\bAcme\\b/)]")
    
  • To do a case-insensitive match on a string containing acme, preface the case-insensitive portion with (?i):

    o.SelectToken("$.Manufacturers[?(@.Name =~ /(?i)acme/)]")
    

    (?-i) ends case-insensitive matching.

  • To match a value that does not contain Acme, use =~ /^(?!.*Acme).*$/):

    o.SelectToken("$.Manufacturers[?(@.Name =~ /^(?!.*Acme).*$/)]")
    

    See: C# Regex to match a string that doesn't contain a certain string?.

  • To match strings starting with Acme, insert ^ at the beginning of the regex:

    o.SelectToken("$.Manufacturers[?(@.Name =~ /^Acme/)]")
    
  • To match strings ending with Acme, add $ at the end of the regex:

    o.SelectToken("$.Manufacturers[?(@.Name =~ /Acme$/)]")
    
  • To match strings with a specified length N, use =~ /(?s)^.{N}$/):

    o.SelectToken("$.Manufacturers[?(@.Name =~ /(?s)^.{7}$/)]")
    

    Here (?s) specifies single line mode (which forces newlines to be included in the character count), . matches any character, the quantifier .{7} requires exactly 7 matches of the preceding token ., and ^ and $ match the beginning and end of the string (which prevents the regex from matching strings longer than 7 characters).

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340