How to get the first element when filter in jsonpath?

雨燕双飞 提交于 2019-12-08 16:08:13

问题


So I'm working on the below json:

{
   "id": "",
   "owner": "some dude",
   "metaData": {
      "request": {
         "ref": null,
         "contacts":[
            {
               "email": null,
               "name": null,
               "contactType": "R"
            },
            {
               "email": null,
               "name": "Dante",
               "contactType": "S"
            }
         ]
      }
   }
}

I want to retrieve the name of contact has type S and only the first one that returned.

Using jsonpath with this path "$..contacts[?(@.contactType == 'S')].name" always return an array of string because a filter operation always return result as an array.

So I tried "$..contacts[?(@.contactType == 'S')].name[0]" and "$..contacts[?(@.contactType == 'S')][0].name" but no luck. Those path returns empty results.

So my question is, is there any way to get only first element when using filter in jsonpath. I'm currently using jayway jsonpath v2.2.0.


回答1:


The quickest solution I found was just comparing it with a list, so like this in your scenario:

.andExpect(jsonPath("$..contacts[?(@.contactType == 'S')].name", equalTo(Arrays.asList("Dante"))))

(Assuming you are trying to compare some result in a test of course)




回答2:


If you use jsonpath with MockMvc class from spring-test, then you may write the following dummy matcher:

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.core.IsEqual;

import net.minidev.json.JSONArray;

public class FirstMatcher<T> extends BaseMatcher<T> {

    private final Matcher<?> matcher;

    public static <T> FirstMatcher<T> matcher(Matcher<T> matcher) {
        return new FirstMatcher<T>(matcher);
    }

    public static FirstMatcher<Object> value(Object value) {
        return new FirstMatcher<Object>(value);
    }

    public FirstMatcher(Matcher<T> matcher) {
        this.matcher = matcher;
    }

    public FirstMatcher(Object value) {
        this.matcher = new IsEqual<Object>(value); 
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("first matcher");
    }

    @Override
    public boolean matches(Object item) {
        if (!(item instanceof JSONArray)) {
            return false;
        }

        JSONArray array = (JSONArray)item;
        if (array.isEmpty()) {
            return false;
        }

        Object obj = array.get(0);
        return matcher.matches(obj);
    }

}

And use the following way:

mockMvc.
    perform(get(url).
            accept(MediaType.APPLICATION_JSON).accept(MediaType.TEXT_PLAIN).accept(MediaType.ALL)).
    andExpect(status().isOk()).
    andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).
    andExpect(jsonPath("$.properties[?(@.propertyName == 'name1')].description").value(FirstMatcher.matcher(IsNull.nullValue()))).
    andExpect(jsonPath("$.properties[?(@.propertyName == 'name2')].required").value(FirstMatcher.value(true)));

P.S. Since net.minidev.json.JSONArray subclasses java.util.List, one may cast to List or even Iterable rather than to net.minidev.json.JSONArray. :)



来源:https://stackoverflow.com/questions/41529564/how-to-get-the-first-element-when-filter-in-jsonpath

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!