java - 使用 Jsonpath 获取列表

标签 java json 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"
                ]
            ]
        }]
    }]
}

现在的需求是获取一个id列表,其errorMsg包含INACTIVE。为此,我使用了如下所示的过滤器。

Filter resposneFilter = Filter.filter(Criteria.where("errorMsg").is(
            "INACTIVE"));
List<Map<String, Object>> respons = JsonPath.parse(response).read(
            "$.payload[*]", resposneFilter);

但作为输出,我得到了有效负载中的所有值。

是否可以得到预期的结果?

最佳答案

考虑到您提供的 JSON 并阅读 Jayway JsonPath 的文档。我找到了两个可以帮助您解决问题的解决方案。

  1. 解决方案1允许您直接访问errorMsg字段,但是当有多个公司时不适用,因为您必须手动循环
  2. 解决方案 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。

方案二

正如文档中所解释的,我定制了谓词的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
}

我想反射(reflection)一下谓词中可怕的 if 条件,如下所示:

if 条件的左边部分 - xx

这部分过滤所有包含 errorMsg 字段的。

if(ctx.item(Map.class).containsKey("errorMsg") && yy)

if 条件的右部分 - yy

这部分确保 errorMsgINACTIVE

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_stackoverflow\\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);
    }
}

关于java - 使用 Jsonpath 获取列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35269370/

相关文章:

unit-testing - JSON 路径没有值

java - 从 JSONPath 数组的不同对象中查询具有特定值的键

java - Selenium WebDriver get(url) 速度问题

javascript - 在 React 中映射本地 .json 数据

java - 使用线程每隔一分钟序列化一个 TreeMap

php - json_encode "not working"正确吗?

json - 当 jq select() 返回 false 时如何使用后备值

spring - 测试数组包含任意顺序的特定对象的jsonpath

java - LinUCB exploration-exploitation 算法不会随时间改善结果

java - 为新项目选择 'better' 或更熟悉的技术?