使用 Jsonpath 获取列表
Get List by using Jsonpath
我正在使用 Jayway JsonPath 2.1.0 使用 JsonPath 解析 JSON 字符串。
JSON结构如下:
{
"status": "",
"source": "",
"processedRecords": 1,
"totalRecords": 4,
"description": "1 company(ies) added/updated, and 2 company(ies) failed",
"payload": [{
"Added/updated company(ies)": [
"COM001FILE"
]
}, {
"Failed company(ies)": [{
"id": "COM003FILE",
"index": "NA",
"errorMsg": [
[
"INVALID_LOCATION"
]
]
}, {
"id": "COM002FILE",
"index": "NA",
"errorMsg": [
[
"INACTIVE"
],
[
"INVALID_LOCATION",
"INACTIVE"
]
]
}]
}]
}
现在的需求是获取errorMsg
包含INACTIVE
的id列表。为此,我使用了如下所示的过滤器。
Filter resposneFilter = Filter.filter(Criteria.where("errorMsg").is(
"INACTIVE"));
List<Map<String, Object>> respons = JsonPath.parse(response).read(
"$.payload[*]", resposneFilter);
但作为输出,我得到了有效载荷中的所有值。
是否可以得到预期的结果?
考虑到您提供的 JSON 并阅读了 Jayway JsonPath 的文档。我找到了两个可以帮助您解决问题的解决方案。
- 解决方案1可以直接访问errorMsg字段,但是当有多个公司时不适用,因为你必须手动循环
- 解决方案 2 允许构造特定于您的情况并且有些通用的自定义谓词。
解决方案 1
您的过滤器似乎是正确的,如下所示:
Filter responseFilter = Filter.filter(Criteria.where("errorMsg").is("INACTIVE"));
查看您的 JSON,有效负载可以被认为是起点,结构似乎是固定的 payload
数组的第二个值是失败的公司,这就是您感兴趣的因此,我会写 json 路径如下:
Map<String, Object> inactiveFailedCompany =
parse(json).read("$.payload[1].['Failed company(ies)'][1]", responseFilter);
如果您在上面注意到,我已经指定了 payload[1]
并且我假设这就是您的 JSON 的结构。我还指定了['Failed company(ies)'][1]
,那就是访问有INACTIVE
的公司。您显然可以将此解决方案与循环一起使用,以循环遍历 ['Failed company(ies)'][1]
的索引并按如下方式打印 ID:
System.out.println("Company Object > " + inactiveFailedCompany.toString());
//output: Output > {id=COM002FILE, index=NA, errorMsg=[["INACTIVE"],["INVALID_LOCATION","INACTIVE"]]}
System.out.println("Company ID > " + inactiveFailedCompany.get("id"));
//output: COM002FILE
看到上面的解决方案,我觉得不好,因为它不够好,所以我阅读了更多文档并遇到了Roll your own predicate因此解决方案2。
解决方案 2
正如文档中所解释的,我定制了谓词的 apply
方法以满足您的要求,解决方案如下:
Predicate inactiveCompaniesPredicate = new Predicate() {
@Override
public boolean apply(PredicateContext ctx) {
if(ctx.item(Map.class).containsKey("errorMsg") &&
((JSONArray)((JSONArray) ctx.item(Map.class).get("errorMsg")).get(0)).get(0).equals("INACTIVE")) {
return true;
} else {
return false;
}
}
};
现在使用上面的谓词如下:
List<Map<String, Object>> failedCompanies =
parse(json).read("$.payload[1].['Failed company(ies)'][?]", List.class, inactiveCompaniesPredicate);
然后循环遍历公司列表并打印失败公司的ID,如下所示:
for(Map<String, Object> object: failedCompanies) {
System.out.println(object.get("id"));
//output: COM002FILE
}
我想反思谓词中可怕的 if 条件,如下所示:
if 条件的左边部分 - xx
这部分过滤所有包含errorMsg字段的。
if(ctx.item(Map.class).containsKey("errorMsg") && yy)
右部分if条件-yy
这部分确保 errorMsg
是 INACTIVE
if(xx & ((JSONArray)((JSONArray) ctx.item(Map.class).get("errorMsg")).get(0)).get(0).equals("INACTIVE"))
这是我用来测试的示例代码(我将 Jsonpath 2.1 及其依赖项作为外部 jar 导入到我的 eclipse 中)
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import net.minidev.json.JSONArray;
import com.jayway.jsonpath.Predicate;
import static com.jayway.jsonpath.JsonPath.parse;
public class JaywayJSON {
public static void main(String[] args) throws IOException {
String json = readFile("C:\test_Whosebug\jayway.json",
Charset.defaultCharset());
/*
* //Solution 1
*
* Filter responseFilter =
* Filter.filter(Criteria.where("errorMsg").is("INACTIVE"));
*
* Map<String, Object> inactiveFailedCompany =
* parse(json).read("$.payload[1].['Failed company(ies)'][1]",
* responseFilter);
*
* System.out.println("Company Object > " +
* inactiveFailedCompany.toString()); //output: Output > {id=COM002FILE,
* index=NA, errorMsg=[["INACTIVE"],["INVALID_LOCATION","INACTIVE"]]}
*
* System.out.println("Company ID > " +
* inactiveFailedCompany.get("id")); //output: COM002FILE
*/
// solution 2
Predicate inactiveCompaniesPredicate = new Predicate() {
@Override
public boolean apply(PredicateContext ctx) {
if (ctx.item(Map.class).containsKey("errorMsg")
&& ((JSONArray) ((JSONArray) ctx.item(Map.class).get(
"errorMsg")).get(0)).get(0).equals("INACTIVE")) {
return true;
} else {
return false;
}
}
};
List<Map<String, Object>> failedCompanies = parse(json).read(
"$.payload[1].['Failed company(ies)'][?]", List.class,
inactiveCompaniesPredicate);
for (Map<String, Object> object : failedCompanies) {
System.out.println(object.get("id"));
}
}
public static String readFile(String path, Charset encoding)
throws IOException {
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
}
我正在使用 Jayway JsonPath 2.1.0 使用 JsonPath 解析 JSON 字符串。
JSON结构如下:
{
"status": "",
"source": "",
"processedRecords": 1,
"totalRecords": 4,
"description": "1 company(ies) added/updated, and 2 company(ies) failed",
"payload": [{
"Added/updated company(ies)": [
"COM001FILE"
]
}, {
"Failed company(ies)": [{
"id": "COM003FILE",
"index": "NA",
"errorMsg": [
[
"INVALID_LOCATION"
]
]
}, {
"id": "COM002FILE",
"index": "NA",
"errorMsg": [
[
"INACTIVE"
],
[
"INVALID_LOCATION",
"INACTIVE"
]
]
}]
}]
}
现在的需求是获取errorMsg
包含INACTIVE
的id列表。为此,我使用了如下所示的过滤器。
Filter resposneFilter = Filter.filter(Criteria.where("errorMsg").is(
"INACTIVE"));
List<Map<String, Object>> respons = JsonPath.parse(response).read(
"$.payload[*]", resposneFilter);
但作为输出,我得到了有效载荷中的所有值。
是否可以得到预期的结果?
考虑到您提供的 JSON 并阅读了 Jayway JsonPath 的文档。我找到了两个可以帮助您解决问题的解决方案。
- 解决方案1可以直接访问errorMsg字段,但是当有多个公司时不适用,因为你必须手动循环
- 解决方案 2 允许构造特定于您的情况并且有些通用的自定义谓词。
解决方案 1 您的过滤器似乎是正确的,如下所示:
Filter responseFilter = Filter.filter(Criteria.where("errorMsg").is("INACTIVE"));
查看您的 JSON,有效负载可以被认为是起点,结构似乎是固定的 payload
数组的第二个值是失败的公司,这就是您感兴趣的因此,我会写 json 路径如下:
Map<String, Object> inactiveFailedCompany =
parse(json).read("$.payload[1].['Failed company(ies)'][1]", responseFilter);
如果您在上面注意到,我已经指定了 payload[1]
并且我假设这就是您的 JSON 的结构。我还指定了['Failed company(ies)'][1]
,那就是访问有INACTIVE
的公司。您显然可以将此解决方案与循环一起使用,以循环遍历 ['Failed company(ies)'][1]
的索引并按如下方式打印 ID:
System.out.println("Company Object > " + inactiveFailedCompany.toString());
//output: Output > {id=COM002FILE, index=NA, errorMsg=[["INACTIVE"],["INVALID_LOCATION","INACTIVE"]]}
System.out.println("Company ID > " + inactiveFailedCompany.get("id"));
//output: COM002FILE
看到上面的解决方案,我觉得不好,因为它不够好,所以我阅读了更多文档并遇到了Roll your own predicate因此解决方案2。
解决方案 2
正如文档中所解释的,我定制了谓词的 apply
方法以满足您的要求,解决方案如下:
Predicate inactiveCompaniesPredicate = new Predicate() {
@Override
public boolean apply(PredicateContext ctx) {
if(ctx.item(Map.class).containsKey("errorMsg") &&
((JSONArray)((JSONArray) ctx.item(Map.class).get("errorMsg")).get(0)).get(0).equals("INACTIVE")) {
return true;
} else {
return false;
}
}
};
现在使用上面的谓词如下:
List<Map<String, Object>> failedCompanies =
parse(json).read("$.payload[1].['Failed company(ies)'][?]", List.class, inactiveCompaniesPredicate);
然后循环遍历公司列表并打印失败公司的ID,如下所示:
for(Map<String, Object> object: failedCompanies) {
System.out.println(object.get("id"));
//output: COM002FILE
}
我想反思谓词中可怕的 if 条件,如下所示:
if 条件的左边部分 - xx
这部分过滤所有包含errorMsg字段的。
if(ctx.item(Map.class).containsKey("errorMsg") && yy)
右部分if条件-yy
这部分确保 errorMsg
是 INACTIVE
if(xx & ((JSONArray)((JSONArray) ctx.item(Map.class).get("errorMsg")).get(0)).get(0).equals("INACTIVE"))
这是我用来测试的示例代码(我将 Jsonpath 2.1 及其依赖项作为外部 jar 导入到我的 eclipse 中)
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import net.minidev.json.JSONArray;
import com.jayway.jsonpath.Predicate;
import static com.jayway.jsonpath.JsonPath.parse;
public class JaywayJSON {
public static void main(String[] args) throws IOException {
String json = readFile("C:\test_Whosebug\jayway.json",
Charset.defaultCharset());
/*
* //Solution 1
*
* Filter responseFilter =
* Filter.filter(Criteria.where("errorMsg").is("INACTIVE"));
*
* Map<String, Object> inactiveFailedCompany =
* parse(json).read("$.payload[1].['Failed company(ies)'][1]",
* responseFilter);
*
* System.out.println("Company Object > " +
* inactiveFailedCompany.toString()); //output: Output > {id=COM002FILE,
* index=NA, errorMsg=[["INACTIVE"],["INVALID_LOCATION","INACTIVE"]]}
*
* System.out.println("Company ID > " +
* inactiveFailedCompany.get("id")); //output: COM002FILE
*/
// solution 2
Predicate inactiveCompaniesPredicate = new Predicate() {
@Override
public boolean apply(PredicateContext ctx) {
if (ctx.item(Map.class).containsKey("errorMsg")
&& ((JSONArray) ((JSONArray) ctx.item(Map.class).get(
"errorMsg")).get(0)).get(0).equals("INACTIVE")) {
return true;
} else {
return false;
}
}
};
List<Map<String, Object>> failedCompanies = parse(json).read(
"$.payload[1].['Failed company(ies)'][?]", List.class,
inactiveCompaniesPredicate);
for (Map<String, Object> object : failedCompanies) {
System.out.println(object.get("id"));
}
}
public static String readFile(String path, Charset encoding)
throws IOException {
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
}