2016-02-08 40 views
1

我正在使用Jayway JsonPath 2.1.0來使用JsonPath解析JSON字符串。使用Jsonpath獲取列表

的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" 
       ] 
      ] 
     }] 
    }] 
} 

現在的要求是讓IDS,其errorMsg包含INACTIVE的列表。要實現這一點,我正在使用如下所示的過濾器。

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

但作爲輸出,我得到的有效載荷的所有值。

是否有可能獲得預期的結果?

+1

errorMsg是一個數組數組,因此您應該驗證它是否包含包含文本的項目以及包含文本的項目「INACTIVE」 – andrucz

+0

errorMsg爲INACTIVE時,JSON的預期結果是什麼?它應該返回哪個json部分? – Raf

+0

@Raf它應該只返回Ids。 –

回答

3

考慮到您提供的JSON並閱讀了Jayway JsonPath的文檔。我發現了兩個解決方案可以幫助解決您的問題。

  1. 解決方案1,您可以直接訪問ERRORMSG領域,但不是applicbable當有一個以上的公司,你必須手動循環
  2. 方案2允許自定義謂詞是特定於您的情況下建設並且有點通用。

解決方案1 ​​ 您已經似乎是正確的,如下圖所示的過濾器:

Filter responseFilter = Filter.filter(Criteria.where("errorMsg").is("INACTIVE")); 

尋找到您的JSON,有效載荷可以被認爲是出發點和結構似乎被固定的第二個值​​陣列是失敗的公司,這就是你感興趣的,因此,我會寫如下的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); 

然後遍歷公司列表並打印f的ID ailed公司如下:

for(Map<String, Object> object: failedCompanies) { 
    System.out.println(object.get("id")); 
    //output: COM002FILE 
} 

我想反思嚇人如果斷言如下內部條件:

左如果條件的部分 - XX

這部分過濾所有那些包含errorMsg字段。如果條件的

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

右邊部分 - YY

這部分可以確保errorMsgINACTIVE

if(xx & ((JSONArray)((JSONArray) ctx.item(Map.class).get("errorMsg")).get(0)).get(0).equals("INACTIVE")) 

這裏是我用來測試示例代碼(我進口Jsonpath 2.1和它的依賴作爲外部罐子到我的日食)

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