【问题标题】:Gatling : get the first element of the first object in a JSON ArrayGatling :获取 JSON 数组中第一个对象的第一个元素
【发布时间】:2022-01-19 20:46:30
【问题描述】:

我有这个 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

【问题讨论】:

    标签: html scala gatling


    【解决方案1】:

    我会使用 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
      } ]
    }
    

    【讨论】:

      【解决方案2】:

      如果您的 JSON 嵌入在 HTML 中,您有两种可能性:

      1. 使用css 检查,就像您迄今为止所做的那样从 HTML 中提取 JSON,然后使用 transform 解析 JSON 并提取所需的值,例如使用 Jackson,如其他答案中所建议的那样李>
      2. 使用regex一次性提取所需值,例如check(regex(""""accommodations":\[\{"id":"(.*?)""""))

      【讨论】:

      • 我检查了第二个选项并且它正在工作,请您提供一个适用于 scala 的第一个选项的详细示例吗?
      • 有什么用?首先,您可以从 Scala 调用 Java 代码。然后 Gatling 从 3.7 开始就有了 Java DSL。如果您不了解或不愿意学习 Scala,则不必使用它。
      • 好的,谢谢,我会根据其他答案为第一个选项寻找 Java 解决方案。感谢您的快速回答。
      【解决方案3】:

      这可以通过几个步骤完成。

      1. 一开始只需要提取 json 并更改响应正文。
      2. 然后您可以使用简单的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("..."))
      

      【讨论】:

        【解决方案4】:

        我建议使用 circe 来解析 JsonString,有两种方法可以做到这一点:

        1. 要求您将以下软件包添加到您的 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)
        
        1. 需要您添加以下包
        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)
        

        【讨论】:

        • 针对 Scala 用户的好答案。但是,从 3.7 开始,Gatling 还提供了 Java DSL。作为 Gatling 的作者,我强烈建议对学习 Scala 没有任何兴趣的新手使用 Java DSL 并坚持使用 Java 库。
        • 非常酷!让我想起了 Jenkins,用户无需深入了解该语言即可了解如何构建管道。不完全了解 Gatling 的 DSL 的功能。也非常感谢您花时间查看我的答案以及您使用 Gatling 所做的所有开源工作!很高兴认识你:)
        猜你喜欢
        • 1970-01-01
        • 2014-03-25
        • 2010-12-27
        • 2021-09-19
        • 1970-01-01
        • 2019-11-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多