Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSONPath expression to get a value from an array on condition or just the first value

Tags:

json

jsonpath

Given JSON structured like this:

{
   "name":"Some Guy",
   "emails":[
      {
         "description":"primary",
         "status":"UNVERIFIED",
         "email":"[email protected]"
      },
      {
         "description":"home",
         "status":"VERIFIED",
         "email":"[email protected]"
      },
      {
         "description":"away",
         "status":"VERIFIED",
         "email":"[email protected]"
      }
   ]
}

I would like a JSONPath expression to get the first email with status VERIFIED and if there are none, then just get the first email in the array. So, given the example above, the result would be [email protected]. Given this example:

{
   "name":"Some Guy",
   "emails":[
      {
         "description":"primary",
         "status":"UNVERIFIED",
         "email":"[email protected]"
      },
      {
         "description":"home",
         "status":"UNVERIFIED",
         "email":"[email protected]"
      }
   ]
}

the result would be [email protected].

Is this possible with a JSONPath expression?

like image 561
jhericks Avatar asked Jan 04 '17 18:01

jhericks


1 Answers

You effectively have 2 JSONPath expressions, where the second one (first email) should be evaluated only if the first one (first verified email) returns nothing, so I don't think you can evaluate them both at the same time, in a single expression.

You can apply them one after the other, though:

public static String getEmail(String json) {
    Configuration cf = Configuration.builder().options(Option.SUPPRESS_EXCEPTIONS).build();
    DocumentContext ctx = JsonPath.using(cf).parse(json);
    List<String> emails = ctx.read("$.emails[?(@.status == 'VERIFIED')].email");
    if (!emails.isEmpty()) {
        return emails.get(0);
    }
    return ctx.read("$.emails[0].email");
}

If the email array is empty, ctx.read("$.emails[0].email") will return null instead of throwing an exception, thanks to the option SUPPRESS_EXCEPTIONS.


If you don't know the number of paths in advance:

public static String getEmail(String json, String[] paths) {
    Configuration cf = Configuration.builder().options(Option.ALWAYS_RETURN_LIST, Option.SUPPRESS_EXCEPTIONS).build();
    DocumentContext ctx = JsonPath.using(cf).parse(json);
    for (String path : paths) {
        List<String> emails = ctx.read(path);
        if (!emails.isEmpty()) {
            return emails.get(0);
        }
    }
    return null;
}

The option ALWAYS_RETURN_LIST means the return type is a list, even when you have one or zero results.

like image 135
approxiblue Avatar answered Oct 21 '22 22:10

approxiblue