简体   繁体   English

如何解析邮递员收藏?

[英]how to parse postman-collection?

Goal :目标

I am trying to parse the postman_echo collection json and persist the result into a new json copy on disk, resulting the same file as the original one.我正在尝试解析 postman_echo 集合 json 并将结果保存到磁盘上的新 json 副本中,从而产生与原始文件相同的文件。

I prefer built-in data structure from the language, but using json library should be good too.我更喜欢该语言的内置数据结构,但使用 json 库也应该不错。 Not sure Antlr4 is a better way.不确定 Antlr4 是更好的方法。

follow-up question后续问题
is it possible to allow any valid nested json in the body of post request?是否可以在发布请求的正文中允许任何有效的嵌套 json?

update: https://github.com/chakpongchung/postman-parser In the end we come up with this satisfactory solution.更新: https://github.com/chakpongchung/postman-parser最后我们想出了这个令人满意的解决方案。

An alternative to what zoran mentioned is to create a case class if the structure is not too dynamic (with Play JSON).如果结构不太动态(使用 Play JSON),则 zoran 提到的替代方法是创建一个案例 class。 This would make it easier to compare the result.这将更容易比较结果。

case class MyObject(
  queryString: List[KeyValue],
  method: String,
  url: String,
  httpVersion: String
) ... and so on

object MyObject {
    implicit val format: Format[MyObject] = Json.format
}

case class KeyValue(name: String, value: String)

object KeyValue {
    implicit val format: Format[KeyValue] = Json.format
}

Then, you just need to do:然后,您只需要执行以下操作:

object JsonParser extends App {
  val postman_collections = "./scala_input.json"
  val jsonifiedString = scala.io.Source.fromFile(postman_collections).mkString

  val myJsonData = Try(Json.parse(jsonifiedString)).map(_.as[MyObject])

  myJsonData match {
    case Success(myValue) => // compare your case class here
    case Failure(err) => println("none")
  }
}

There are multiple problems in your parser and most of them are that you are trying to use default parser to handle Json object as string.您的解析器存在多个问题,其中大多数是您尝试使用默认解析器将 Json object 作为字符串处理。 For example, in Request you are handling header as Seq[String] when it's actually Seq of (key, value) pairs.例如,在 Request 中,您将 header 作为 Seq[String] 处理,而它实际上是(键,值)对的 Seq。 For this particular case, you should change it to something like this:对于这种特殊情况,您应该将其更改为以下内容:

case class Request(
                method: String,
                header: Seq[HeaderItem], // header: []
                url: Option[Url] = None,
                description: String = ""
              )
object Request {
   implicit val format: Format[Request] = Json.using[Json.WithDefaultValues].format

case class HeaderItem(key: String, value: String)

object HeaderItem {
   implicit val format: Format[HeaderItem] = Json.format
 }

You can convert header to Seq[String] if you want, but you will have to write custom Read for that.如果需要,您可以将 header 转换为 Seq[String] ,但您必须为此编写自定义读取。 In the above case you also have cases when description is missing, so you want to handle that with default values.在上述情况下,您也有缺少描述的情况,因此您希望使用默认值来处理。 You have such problems to handle in few other places as well, eg "response".您在其他几个地方也有这样的问题需要处理,例如“响应”。

Another problem that I've noticed is a way how you handle "type" property from Json string.我注意到的另一个问题是如何处理 Json 字符串中的“类型”属性。 Type is reserved keyword, and you can handle it by wrapping it in ``, eg类型是保留关键字,可以用`包裹来处理,例如

case class Script(
    `type`: String,
     exec: Seq[String]
)

I'm not sure if I understand your question well, but if you are trying to iterate over json string, you might try something like this:我不确定我是否很好地理解了您的问题,但是如果您尝试遍历 json 字符串,您可以尝试这样的操作:

  import play.api.libs.json.{JsObject, JsValue, Json}
  import scala.util.{Failure, Success, Try}


  object JsonParser extends App {
    val postman_coolections = "./resources/scala_input.json"
    val jsonifiedString = scala.io.Source.fromFile(postman_coolections).mkString

    val json: JsValue = Try(Json.parse(jsonifiedString)) match {
      case Success(js) => js
      case Failure(ex) => throw new Exception("Couldn't parse json", ex)
   }
 json.asInstanceOf[JsObject].fields.foreach{
   case (key: String, value: JsValue)=>
      println(s"Key:$key value:${value.toString}")
      writeFile(s"$key.json", Json.prettyPrint(value))
 }

//writing the whole postman input as a single file

writeFile("postmanInputFormatted.json", Json.prettyPrint(json))
writeFile("postmanInput.json", Json.stringify(json))

// To access individual property one option is to use this approach

val lookedValue = json \ "postData" \ "params" \ 1 \ "hello" \ "test"

lookedValue match {
  case JsDefined(value) => println(s"Test value is $value")
  case JsUndefined() => println("Didn't find test value")
}
// or
val lookedValueAlt = (json \ "postData" \ "params" \ 1 \ "hello" \ "test").getOrElse(throw SomeException)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM