您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(guān)如何正確的使用 jsonpath,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
java項(xiàng)目demo:
注意: 其中他的max,min,avg,stddev函數(shù)只能類(lèi)似于如下處理:
//正確寫(xiě)法 但是感覺(jué)很雞肋 context.read("$.avg($.result.records[0].loan_type,$.result.records[1].loan_type,$.result.records[2].loan_type)");
不能傳入list 感覺(jué)比較雞肋,如果傳入list 他會(huì)報(bào)錯(cuò)(如下錯(cuò)誤寫(xiě)法):
//這樣會(huì)報(bào)錯(cuò) Object maxV = context.read("$.max($.result.records[*].loan_type)"); //這樣也會(huì)報(bào)錯(cuò) Object maxV = context.read("$.result.records[*].loan_type.max()"); //如果json文件中是這樣:"loan_type":"2",也會(huì)報(bào)錯(cuò),"loan_type":2 這樣才被認(rèn)為是數(shù)字
報(bào)錯(cuò)信息都一樣, 如下:
Exception in thread "main" com.jayway.jsonpath.JsonPathException: Aggregation function attempted to calculate value using empty array
public class JsonPathDemo { public static void main(String[] args) { String json = FileUtils.readFileByLines("demo.json"); ReadContext context = JsonPath.parse(json); //1 返回所有name List<String> names = context.read("$.result.records[*].name"); //["張三","李四","王五"] System.out.println(names); //2 返回所有數(shù)組的值 List<Map<String, String>> objs = context.read("$.result.records[*]"); //[{"name":"張三","pid":"500234199212121212","mobile":"18623456789","applied_at":"3","confirmed_at":"5","confirm_type":"overdue","loan_type":"1","test":"mytest","all":"2"},{"name":"李四","pid":"500234199299999999","mobile":"13098765432","applied_at":"1","confirmed_at":"","confirm_type":"overdue","loan_type":"3","all":"3"},{"name":"王五","pid":"50023415464654659","mobile":"1706454894","applied_at":"-1","confirmed_at":"","confirm_type":"overdue","loan_type":"3"}] System.out.println(objs); //3 返回第一個(gè)的name String name0 = context.read("$.result.records[0].name"); //張三 System.out.println(name0); //4 返回下標(biāo)為0 和 2 的數(shù)組值 List<String> name0and2 = context.read("$.result.records[0,2].name"); //["張三","王五"] System.out.println(name0and2); //5 返回下標(biāo)為0 到 下標(biāo)為1的 的數(shù)組值 這里[0:2] 表示包含0 但是 不包含2 List<String> name0to2 = context.read("$.result.records[0:2].name"); //["張三","李四"] System.out.println(name0to2); //6 返回?cái)?shù)組的最后兩個(gè)值 List<String> lastTwoName = context.read("$.result.records[-2:].name"); //["李四","王五"] System.out.println(lastTwoName); //7 返回下標(biāo)為1之后的所有數(shù)組值 包含下標(biāo)為1的 List<String> nameFromOne = context.read("$.result.records[1:].name"); //["李四","王五"] System.out.println(nameFromOne); //8 返回下標(biāo)為3之前的所有數(shù)組值 不包含下標(biāo)為3的 List<String> nameEndTwo = context.read("$.result.records[:3].name"); //["張三","李四","王五"] System.out.println(nameEndTwo); //9 返回applied_at大于等于2的值 List<Map<String, String>> records = context.read("$.result.records[?(@.applied_at >= '2')]"); //[{"name":"張三","pid":"500234199212121212","mobile":"18623456789","applied_at":"3","confirmed_at":"5","confirm_type":"overdue","loan_type":"1","test":"mytest","all":"2"}] System.out.println(records); //10 返回name等于李四的值 List<Map<String, String>> records0 = context.read("$.result.records[?(@.name == '李四')]"); //[{"name":"李四","pid":"500234199299999999","mobile":"13098765432","applied_at":"1","confirmed_at":"","confirm_type":"overdue","loan_type":"3"}] System.out.println(records0); //11 返回有test屬性的數(shù)組 List<Map<String, String>> records1 = context.read("$.result.records[?(@.test)]"); //[{"name":"張三","pid":"500234199212121212","mobile":"18623456789","applied_at":"3","confirmed_at":"5","confirm_type":"overdue","loan_type":"1","test":"mytest","all":"2"}] System.out.println(records1); //12 返回有test屬性的數(shù)組 List<String> list = context.read("$..all"); //["1","4","2","3"] System.out.println(list); //12 以當(dāng)前json的某個(gè)值為條件查詢(xún) 這里ok為1 取出records數(shù)組中applied_at等于1的數(shù)組 List<String> ok = context.read("$.result.records[?(@.applied_at == $['ok'])]"); //["1","4","2","3"] System.out.println(ok); //13 正則匹配 List<String> regexName = context.read("$.result.records[?(@.pid =~ /.*999/i)]"); //[{"name":"李四","pid":"500234199299999999","mobile":"13098765432","applied_at":"1","confirmed_at":"","confirm_type":"overdue","loan_type":"3","all":"3"}] System.out.println(regexName); //14 多條件 List<String> mobile = context.read("$.result.records[?(@.all == '2' || @.name == '李四' )].mobile"); //["18623456789","13098765432"] System.out.println(mobile); //14 查詢(xún)數(shù)組長(zhǎng)度 Integer length01 = context.read("$.result.records.length()"); //3 System.out.println(length01); //15 查詢(xún)list里面每個(gè)對(duì)象長(zhǎng)度 List<Integer> length02 = context.read("$.result.records[?(@.all == '2' || @.name == '李四' )].length()"); //[9,8] System.out.println(length02); //16 最大值 Object maxV = context.read("$.max($.result.records[0].loan_type,$.result.records[1].loan_type,$.result.records[2].loan_type)"); //3.0 System.out.println(maxV); //17 最小值 Object minV = context.read("$.min($.result.records[0].loan_type,$.result.records[1].loan_type,$.result.records[2].loan_type)"); //1.0 System.out.println(minV); //18 平均值 double avgV = context.read("$.avg($.result.records[0].loan_type,$.result.records[1].loan_type,$.result.records[2].loan_type)"); //2.3333333333333335 System.out.println(avgV); //19 標(biāo)準(zhǔn)差 double stddevV = context.read("$.stddev($.result.records[0].loan_type,$.result.records[1].loan_type,$.result.records[2].loan_type)"); //0.9428090415820636 System.out.println(stddevV); //20 讀取一個(gè)不存在的 String haha = context.read("$.result.haha"); //拋出異常 //Exception in thread "main" com.jayway.jsonpath.PathNotFoundException: No results for path: $['result']['haha'] //at com.jayway.jsonpath.internal.path.EvaluationContextImpl.getValue(EvaluationContextImpl.java:133) //at com.jayway.jsonpath.JsonPath.read(JsonPath.java:187) //at com.jayway.jsonpath.internal.JsonContext.read(JsonContext.java:102) //at com.jayway.jsonpath.internal.JsonContext.read(JsonContext.java:89) //at cn.lijie.jsonpath.JsonPathDemo.main(JsonPathDemo.java:58) //at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) //at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) //at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) //at java.lang.reflect.Method.invoke(Method.java:498) //at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) System.out.println(haha); } }
<dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <version>2.3.0</version> </dependency>
{ "action": "/interface.service/xxx/queryBlackUserData", "all": "1", "result": { "count": 2, "tenant_count": 2, "records": [ { "name": "張三", "pid": "500234199212121212", "mobile": "18623456789", "applied_at": "3", "confirmed_at": "5", "confirm_type": "overdue", "loan_type": 1, "test": "mytest", "all": "2" }, { "name": "李四", "pid": "500234199299999999", "mobile": "13098765432", "applied_at": "1", "confirmed_at": "", "confirm_type": "overdue", "loan_type": 3, "all": "3" }, { "name": "王五", "pid": "50023415464654659", "mobile": "1706454894", "applied_at": "-1", "confirmed_at": "", "confirm_type": "overdue", "loan_type": 3 } ], "all": "4" }, "code": 200, "subtime": "1480495123550", "status": "success", "ok": 3 }
public class FileUtils { /** * 以行為單位讀取文件,常用于讀面向行的格式化文件 */ public static String readFileByLines(String fileName) { File file = new File(fileName); BufferedReader reader = null; String str = ""; try { InputStream is = FileUtils.class.getClassLoader().getResourceAsStream(fileName); reader = new BufferedReader(new InputStreamReader(is)); String tempString = null; int line = 1; // 一次讀入一行,直到讀入null為文件結(jié)束 while ((tempString = reader.readLine()) != null) { // 顯示行號(hào) str += tempString; } reader.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { } } } return str; } }
補(bǔ)充:json接口測(cè)試的利器jsonpath
在測(cè)試REST接口的時(shí)候,經(jīng)常要解析JSON,那么可以使用開(kāi)源jsonpath進(jìn)行,其中看網(wǎng)上看到相關(guān)的說(shuō)法不錯(cuò)的使用場(chǎng)景為:
也稱(chēng)為關(guān)聯(lián)參數(shù)。在應(yīng)用業(yè)務(wù)接口中,完成一個(gè)業(yè)務(wù)功能時(shí),有時(shí)候一個(gè)接口可能不滿(mǎn)足業(yè)務(wù)的整個(gè)流程邏輯,需要多個(gè)接口配合使用,簡(jiǎn)單的案例如:B接口的成功調(diào)用依賴(lài)于A接口,需要在A接口的響應(yīng)數(shù)據(jù)(response)中拿到需要的字段,在調(diào)用B接口的時(shí)候,傳遞給B接口作為B接口請(qǐng)求參數(shù),拿到后續(xù)響應(yīng)的響應(yīng)數(shù)據(jù)。
接口關(guān)聯(lián)通常可以使用正則表達(dá)式去提取需要的數(shù)據(jù),但對(duì)于json這種簡(jiǎn)潔、清晰層次結(jié)構(gòu)、輕量級(jí)的數(shù)據(jù)交互格式,使用正則未免有點(diǎn)殺雞用牛刀的感覺(jué)(是的,因?yàn)槲也簧瞄L(zhǎng)寫(xiě)正則表達(dá)式),我們需要更加簡(jiǎn)單、直接的提取json數(shù)據(jù)的方式。
這里的數(shù)據(jù)驗(yàn)證指的是對(duì)響應(yīng)結(jié)果進(jìn)行數(shù)據(jù)的校驗(yàn)
接口自動(dòng)化測(cè)試中,對(duì)于簡(jiǎn)單的響應(yīng)結(jié)果(json),可以直接和期望結(jié)果進(jìn)行比對(duì),判斷是否完全相等即可。
如 json {"status":1,"msg":"登錄成功"}
尤其部分?jǐn)?shù)據(jù)存在不確定性、會(huì)根據(jù)實(shí)際情況變化的響應(yīng)結(jié)果,簡(jiǎn)單的判斷是否完全相等(斷言)通常會(huì)失敗。
如:
json {"status":1,"code":"10001","data":[{"id":1,"investId":"1","createTime":"2018-04-27 12:24:01","terms":"1","unfinishedInterest":"1.0","unfinishedPrincipal":"0","repaymentDate":"2018-05-27 12:24:01","actualRepaymentDate":null,"status":"0"},{"id":2,"investId":"1","createTime":"2018-04-27 12:24:01","terms":"2","unfinishedInterest":"1.0","unfinishedPrincipal":"0","repaymentDate":"2018-06-27 12:24:01","actualRepaymentDate":null,"status":"0"},{"id":3,"investId":"1","createTime":"2018-04-27 12:24:01","terms":"3","unfinishedInterest":"1.0","unfinishedPrincipal":"100.00","repaymentDate":"2018-07-27 12:24:01","actualRepaymentDate":null,"status":"0"}],"msg":"獲取信息成功"}
上面的json結(jié)構(gòu)嵌套了很多信息,完整的匹配幾乎不可能成功。比如其中的createTime信息,根據(jù)執(zhí)行接口測(cè)試用例的時(shí)間每次都不一樣。同時(shí)這個(gè)時(shí)間是響應(yīng)結(jié)果中較為次要的信息,在進(jìn)行接口自動(dòng)化測(cè)試時(shí),是可以選擇被忽略的。
能夠從json中提取出我們真正關(guān)注的信息(通常也被稱(chēng)為關(guān)鍵信息)。
如提取出status的值為1,data數(shù)組中每個(gè)對(duì)象的investId都為1,data中第三個(gè)對(duì)象的unfinishedPrincipal值為100.00,只要這三個(gè)關(guān)鍵信息校驗(yàn)通過(guò),我們就認(rèn)為響應(yīng)結(jié)果沒(méi)有問(wèn)題。
這里有個(gè)表格,說(shuō)明JSONPath語(yǔ)法元素和對(duì)應(yīng)XPath元素的對(duì)比。
XPath | JSONPath | Description |
/ | $ | 表示根元素 |
. | @ | 當(dāng)前元素 |
/ | . or [] | 子元素 |
.. | n/a | 父元素 |
// | .. | 遞歸下降,JSONPath是從E4X借鑒的。 |
* | * | 通配符,表示所有的元素 |
@ | n/a | 屬性訪(fǎng)問(wèn)字符 |
[] | [] | 子元素操作符 |
| | [,] | 連接操作符在XPath 結(jié)果合并其它結(jié)點(diǎn)集合。JSONP允許name或者數(shù)組索引。 |
n/a | [start:end:step] | 數(shù)組分割操作從ES4借鑒。 |
[] | ?() | 應(yīng)用過(guò)濾表示式 |
n/a | () | 腳本表達(dá)式,使用在腳本引擎下面。 |
() | n/a | Xpath分組 |
{ "store": { "book": [ { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }, { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ], "bicycle": { "color": "red", "price": 19.95 } } }
XPath | JSONPath | 結(jié)果 |
/store/book/author | $.store.book[*].author | 書(shū)點(diǎn)所有書(shū)的作者 |
//author | $..author | 所有的作者 |
/store/* | $.store.* | store的所有元素。所有的bookst和bicycle |
/store//price | $.store..price | store里面所有東西的price |
//book[3] | $..book[2] | 第三個(gè)書(shū) |
//book[last()] | $..book[(@.length-1)] | 最后一本書(shū) |
//book[position()<3] | $..book[0,1] $..book[:2] | 前面的兩本書(shū)。 |
//book[isbn] | $..book[?(@.isbn)] | 過(guò)濾出所有的包含isbn的書(shū)。 |
//book[price<10] | $..book[?(@.price<10)] | 過(guò)濾出價(jià)格低于10的書(shū)。 |
//* | $..* | 所有元素。 |
@RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc @ActiveProfiles("test") public class BookControllerTest { @Autowired private MockMvc mockMvc; @MockBean private BookRepository mockRepository; /* { "timestamp":"2019-03-05T09:34:13.280+0000", "status":400, "errors":["Author is not allowed.","Please provide a price","Please provide a author"] } */ //article : jsonpath in array @Test public void save_emptyAuthor_emptyPrice_400() throws Exception { String bookInJson = "{\"name\":\"ABC\"}"; mockMvc.perform(post("/books") .content(bookInJson) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.timestamp", is(notNullValue()))) .andExpect(jsonPath("$.status", is(400))) .andExpect(jsonPath("$.errors").isArray()) .andExpect(jsonPath("$.errors", hasSize(3))) .andExpect(jsonPath("$.errors", hasItem("Author is not allowed."))) .andExpect(jsonPath("$.errors", hasItem("Please provide a author"))) .andExpect(jsonPath("$.errors", hasItem("Please provide a price"))); verify(mockRepository, times(0)).save(any(Book.class)); } }
看完上述內(nèi)容,你們對(duì)如何正確的使用 jsonpath有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。