Search code examples
c#jsonxpathjson.netjsonpath

String Functions in JSONPath


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).


Solution

  • 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.