Gatling : 获取 JSON 数组中第一个对象的第一个元素
Gatling : get the first element of the first object in a JSON Array
我有这个 JSON 对象 :
{"isCompany":false,"accommodations":[{"id":"00000000031000000067","isChecked":false,"name":"5 JULI 2017","addressLine1":"STRAAT 10 ","addressLine2":"1000 New York","nightsDeclared":0,"schoolNightsDeclared":0,"schoolNightsAttached":0,"taxableNights":0.0,"totalPayment":0.0,"isInProgress":false,"isLate":false,"isPayed":"false","deadline":"2021-12-31","initialAmount":0.0,"remainingAmount":0.0},{"id":"00000000031000006362","isChecked":false,"name":"BELLEVIE","addressLine1":"STRAAT 10 ","addressLine2":"1000 New York","nightsDeclared":0,"schoolNightsDeclared":0,"schoolNightsAttached":0,"taxableNights":0.0,"totalPayment":0.0,"isInProgress":false,"isLate":false,"isPayed":"false","deadline":"2021-12-31","initialAmount":0.0,"remainingAmount":0.0}]}
如果美化,渲染这个:
{
"isCompany": false,
"accommodations": [
{
"id": "00000000031000000067",
"isChecked": false,
"name": "5 JULI 2017",
"addressLine1": "STRAAT 10 ",
"addressLine2": "1000 New York",
"nightsDeclared": 0,
"schoolNightsDeclared": 0,
"schoolNightsAttached": 0,
"taxableNights": 0.0,
"totalPayment": 0.0,
"isInProgress": false,
"isLate": false,
"isPayed": "false",
"deadline": "2021-12-31",
"initialAmount": 0.0,
"remainingAmount": 0.0
},
{
"id": "00000000031000006362",
"isChecked": false,
"name": "BELLEVIE",
"addressLine1": "STRAAT 10 ",
"addressLine2": "1000 New York",
"nightsDeclared": 0,
"schoolNightsDeclared": 0,
"schoolNightsAttached": 0,
"taxableNights": 0.0,
"totalPayment": 0.0,
"isInProgress": false,
"isLate": false,
"isPayed": "false",
"deadline": "2021-12-31",
"initialAmount": 0.0,
"remainingAmount": 0.0
}
]
}
我已经从 HTML 内部的 div 中获得了这个完整的 JSON 数组,方法如下:
.check(css("section.ht-declarations-tab-content-container>div#DATA--DECL-DATA").saveAs("jsonObj"))
然后渲染结果我写了这个:
.exec { session => println("json = " + session("jsonObj").as[String]); session }.exitHereIfFailed
然而,如前所述,我得到了完整的 JSON 数组。
如何只获取第一个对象的第一个ID元素?所以基本上:00000000031000000067
我会用 Jackson 做那份工作:
private static final ObjectMapper MAPPER = new ObjectMapper();
public static String getFirstId(String json) throws JsonProcessingException {
return MAPPER.readTree(json).get("accommodations").get(0).get("id").asText();
}
那么你可以这样做:
System.out.println(getFirstId(json));
输出:
00000000031000000067
如果你想将 de JSON
打印成一棵树,你可以这样做:
public static String toTree(String json) throws JsonProcessingException {
return MAPPER.readTree(json).toPrettyString();
}
那么你可以这样做:
System.out.println(toTree(json));
输出:
{
"isCompany" : false,
"accommodations" : [ {
"id" : "00000000031000000067",
"isChecked" : false,
"name" : "5 JULI 2017",
"addressLine1" : "STRAAT 10 ",
"addressLine2" : "1000 New York",
"nightsDeclared" : 0,
"schoolNightsDeclared" : 0,
"schoolNightsAttached" : 0,
"taxableNights" : 0.0,
"totalPayment" : 0.0,
"isInProgress" : false,
"isLate" : false,
"isPayed" : "false",
"deadline" : "2021-12-31",
"initialAmount" : 0.0,
"remainingAmount" : 0.0
}, {
"id" : "00000000031000006362",
"isChecked" : false,
"name" : "BELLEVIE",
"addressLine1" : "STRAAT 10 ",
"addressLine2" : "1000 New York",
"nightsDeclared" : 0,
"schoolNightsDeclared" : 0,
"schoolNightsAttached" : 0,
"taxableNights" : 0.0,
"totalPayment" : 0.0,
"isInProgress" : false,
"isLate" : false,
"isPayed" : "false",
"deadline" : "2021-12-31",
"initialAmount" : 0.0,
"remainingAmount" : 0.0
} ]
}
如果您的 JSON 嵌入在 HTML 中,您有 2 种可能性:
- 像您目前所做的那样使用
css
检查从 HTML 中提取 JSON,然后使用 transform
解析 JSON 并提取所需的值,例如使用其他答案中建议的 Jackson
- 使用
regex
一次性提取想要的值,例如check(regex(""""accommodations":\[\{"id":"(.*?)""""))
这可以通过几个步骤完成。
- 一开始只需要提取json并更改响应体。
- 然后您可以使用简单的
jsonPath
并使用 json
更改 - 使用 transformResponse
提取 json 字符串并删除断行并设置为新的响应正文
http("...")
.get("...")
.transformResponse { (response, _) =>
val json = response.body.string match {
case s"""<div id="DATA--DECL-DATA">${json}</div>""" => json.replaceAll("\n", "")
}
response.copy(body = new StringResponseBody(json, response.body.charset))
}
.check(jsonPath("$...").find.saveAs("..."))
我建议使用 circe 来解析 JsonString,有两种方法可以做到这一点:
- 要求您将以下包添加到您的 sbt 构建中:
val core = "io.circe" %% "circe-core" % circeVersion
val generic = "io.circe" %% "circe-generic" % circeVersion
val parser = "io.circe" %% "circe-parser" % circeVersion
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full),
此方法使用大小写 类 和字段提取来获取您想要的对象。 Case 类 可以专门定义您想要的字段或将整个 json 对象表示为文档。此解决方案为您提供了很大的灵活性,但需要大量样板
// SOLUTION 1:
import io.circe.parser.decode
import io.circe.generic.JsonCodec
/**
* First Build two case classes to represent
* the JSON object that you will be parsing to
*/
@JsonCodec
case class Accommodation(id: String)
@JsonCodec
case class Response(isCompany: Boolean, accommodations: List[Accommodation]) {
def getFirstAccomodationID: Option[String] = {
this.accommodations.headOption match {
case Some(accommodation) => Some(accommodation.id)
case _ => None
}
}
}
/* In order to actually pull the data */
val response: Either[io.circe.Error,Response] = decode[Response](jsonString)
println(response.right.get.getFirstAccomodationID)
- 需要您添加以下包
val core = "io.circe" %% "circe-core" % circeVersion
val generic = "io.circe" %% "circe-generic" % circeVersion
val parser = "io.circe" %% "circe-parser" % circeVersion
val optics = "io.circe" %% "circe-optics" % circeVersion
此解决方案使用 json 解析和遍历来获取所需的确切字段,并允许您准确指定所需的字段。
对于阅读代码的人来说,此解决方案也更紧凑且更易于推理。
// SOLUTION 2:
import io.circe._,
import io.circe.parser._
/* First convert the String into a JSON object */
val json: Json = parse(jsonString).getOrElse(Json.Null)
import io.circe.optics.JsonPath._
/* Use Circe Optics to define the json path you wish to traverse */
val _getFirstAccomodationID = root.accommodations.each.id.string
/* Finally, fetch the actual String value */
val firstId: Option[String] = _getFirstAccomodationID.getAll(json).headOption
println(firstId)
我有这个 JSON 对象 :
{"isCompany":false,"accommodations":[{"id":"00000000031000000067","isChecked":false,"name":"5 JULI 2017","addressLine1":"STRAAT 10 ","addressLine2":"1000 New York","nightsDeclared":0,"schoolNightsDeclared":0,"schoolNightsAttached":0,"taxableNights":0.0,"totalPayment":0.0,"isInProgress":false,"isLate":false,"isPayed":"false","deadline":"2021-12-31","initialAmount":0.0,"remainingAmount":0.0},{"id":"00000000031000006362","isChecked":false,"name":"BELLEVIE","addressLine1":"STRAAT 10 ","addressLine2":"1000 New York","nightsDeclared":0,"schoolNightsDeclared":0,"schoolNightsAttached":0,"taxableNights":0.0,"totalPayment":0.0,"isInProgress":false,"isLate":false,"isPayed":"false","deadline":"2021-12-31","initialAmount":0.0,"remainingAmount":0.0}]}
如果美化,渲染这个:
{
"isCompany": false,
"accommodations": [
{
"id": "00000000031000000067",
"isChecked": false,
"name": "5 JULI 2017",
"addressLine1": "STRAAT 10 ",
"addressLine2": "1000 New York",
"nightsDeclared": 0,
"schoolNightsDeclared": 0,
"schoolNightsAttached": 0,
"taxableNights": 0.0,
"totalPayment": 0.0,
"isInProgress": false,
"isLate": false,
"isPayed": "false",
"deadline": "2021-12-31",
"initialAmount": 0.0,
"remainingAmount": 0.0
},
{
"id": "00000000031000006362",
"isChecked": false,
"name": "BELLEVIE",
"addressLine1": "STRAAT 10 ",
"addressLine2": "1000 New York",
"nightsDeclared": 0,
"schoolNightsDeclared": 0,
"schoolNightsAttached": 0,
"taxableNights": 0.0,
"totalPayment": 0.0,
"isInProgress": false,
"isLate": false,
"isPayed": "false",
"deadline": "2021-12-31",
"initialAmount": 0.0,
"remainingAmount": 0.0
}
]
}
我已经从 HTML 内部的 div 中获得了这个完整的 JSON 数组,方法如下:
.check(css("section.ht-declarations-tab-content-container>div#DATA--DECL-DATA").saveAs("jsonObj"))
然后渲染结果我写了这个:
.exec { session => println("json = " + session("jsonObj").as[String]); session }.exitHereIfFailed
然而,如前所述,我得到了完整的 JSON 数组。
如何只获取第一个对象的第一个ID元素?所以基本上:00000000031000000067
我会用 Jackson 做那份工作:
private static final ObjectMapper MAPPER = new ObjectMapper();
public static String getFirstId(String json) throws JsonProcessingException {
return MAPPER.readTree(json).get("accommodations").get(0).get("id").asText();
}
那么你可以这样做:
System.out.println(getFirstId(json));
输出:
00000000031000000067
如果你想将 de JSON
打印成一棵树,你可以这样做:
public static String toTree(String json) throws JsonProcessingException {
return MAPPER.readTree(json).toPrettyString();
}
那么你可以这样做:
System.out.println(toTree(json));
输出:
{
"isCompany" : false,
"accommodations" : [ {
"id" : "00000000031000000067",
"isChecked" : false,
"name" : "5 JULI 2017",
"addressLine1" : "STRAAT 10 ",
"addressLine2" : "1000 New York",
"nightsDeclared" : 0,
"schoolNightsDeclared" : 0,
"schoolNightsAttached" : 0,
"taxableNights" : 0.0,
"totalPayment" : 0.0,
"isInProgress" : false,
"isLate" : false,
"isPayed" : "false",
"deadline" : "2021-12-31",
"initialAmount" : 0.0,
"remainingAmount" : 0.0
}, {
"id" : "00000000031000006362",
"isChecked" : false,
"name" : "BELLEVIE",
"addressLine1" : "STRAAT 10 ",
"addressLine2" : "1000 New York",
"nightsDeclared" : 0,
"schoolNightsDeclared" : 0,
"schoolNightsAttached" : 0,
"taxableNights" : 0.0,
"totalPayment" : 0.0,
"isInProgress" : false,
"isLate" : false,
"isPayed" : "false",
"deadline" : "2021-12-31",
"initialAmount" : 0.0,
"remainingAmount" : 0.0
} ]
}
如果您的 JSON 嵌入在 HTML 中,您有 2 种可能性:
- 像您目前所做的那样使用
css
检查从 HTML 中提取 JSON,然后使用transform
解析 JSON 并提取所需的值,例如使用其他答案中建议的 Jackson - 使用
regex
一次性提取想要的值,例如check(regex(""""accommodations":\[\{"id":"(.*?)""""))
这可以通过几个步骤完成。
- 一开始只需要提取json并更改响应体。
- 然后您可以使用简单的
jsonPath
并使用 json
更改 - 使用 transformResponse
提取 json 字符串并删除断行并设置为新的响应正文
http("...")
.get("...")
.transformResponse { (response, _) =>
val json = response.body.string match {
case s"""<div id="DATA--DECL-DATA">${json}</div>""" => json.replaceAll("\n", "")
}
response.copy(body = new StringResponseBody(json, response.body.charset))
}
.check(jsonPath("$...").find.saveAs("..."))
我建议使用 circe 来解析 JsonString,有两种方法可以做到这一点:
- 要求您将以下包添加到您的 sbt 构建中:
val core = "io.circe" %% "circe-core" % circeVersion
val generic = "io.circe" %% "circe-generic" % circeVersion
val parser = "io.circe" %% "circe-parser" % circeVersion
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full),
此方法使用大小写 类 和字段提取来获取您想要的对象。 Case 类 可以专门定义您想要的字段或将整个 json 对象表示为文档。此解决方案为您提供了很大的灵活性,但需要大量样板
// SOLUTION 1:
import io.circe.parser.decode
import io.circe.generic.JsonCodec
/**
* First Build two case classes to represent
* the JSON object that you will be parsing to
*/
@JsonCodec
case class Accommodation(id: String)
@JsonCodec
case class Response(isCompany: Boolean, accommodations: List[Accommodation]) {
def getFirstAccomodationID: Option[String] = {
this.accommodations.headOption match {
case Some(accommodation) => Some(accommodation.id)
case _ => None
}
}
}
/* In order to actually pull the data */
val response: Either[io.circe.Error,Response] = decode[Response](jsonString)
println(response.right.get.getFirstAccomodationID)
- 需要您添加以下包
val core = "io.circe" %% "circe-core" % circeVersion
val generic = "io.circe" %% "circe-generic" % circeVersion
val parser = "io.circe" %% "circe-parser" % circeVersion
val optics = "io.circe" %% "circe-optics" % circeVersion
此解决方案使用 json 解析和遍历来获取所需的确切字段,并允许您准确指定所需的字段。
对于阅读代码的人来说,此解决方案也更紧凑且更易于推理。
// SOLUTION 2:
import io.circe._,
import io.circe.parser._
/* First convert the String into a JSON object */
val json: Json = parse(jsonString).getOrElse(Json.Null)
import io.circe.optics.JsonPath._
/* Use Circe Optics to define the json path you wish to traverse */
val _getFirstAccomodationID = root.accommodations.each.id.string
/* Finally, fetch the actual String value */
val firstId: Option[String] = _getFirstAccomodationID.getAll(json).headOption
println(firstId)