繁体   English   中英

使用Scala解析JSON上的节点 -

[英]Parsing nodes on JSON with Scala -

我被要求解析一个JSON文件,以获取用户输入的超过指定速度的所有总线。

JSON文件可以在这里下载

就像这样:

{
"COLUMNS": [
    "DATAHORA",
    "ORDEM",
    "LINHA",
    "LATITUDE",
    "LONGITUDE",
    "VELOCIDADE"
],
"DATA": [
    [
        "04-16-2015 00:00:55",
        "B63099",
        "",
        -22.7931,
        -43.2943,
        0
    ],
    [
        "04-16-2015 00:01:02",
        "C44503",
        781,
        -22.853649,
        -43.37616,
        25
    ],
    [
        "04-16-2015 00:11:40",
        "B63067",
        "",
        -22.7925,
        -43.2945,
        0
    ],
]
}

问题是:我对scala很陌生,之前从未与json合作过(对我感到羞耻)。 我需要的是从DATA节点获取“Ordem”,“Linha”和“Velocidade”。

我创建了一个case类来封装所有数据,以便以后查找那些超过指定速度的数据。

case class Bus(ordem: String, linha: Int, velocidade: Int)

我这样做是将文件作为textFile和spliting来读取。 虽然这样,我需要预先知道文件的内容,以便在DATA节点之后转到行。

我想知道如何使用JSON解析器执行此操作。 我尝试了很多解决方案,但我无法适应我的问题,因为我需要从DATA节点中提取所有行而不是一个节点内的节点。

谁能帮我?

PS:对不起我的英语,不是母语人士。

首先,您需要了解不同的JSON数据类型。 JSON中的基本类型是数字,字符串,布尔值,数组和对象。 示例中返回的数据是一个具有两个键的对象: COLUMNSDATA COLUMNS键的值为字符串和数字的数组。 DATA键的值是字符串数组的数组。

您可以使用PlayJSON之类的库来处理此类数据:

val js = Json.parse(x).as[JsObject]
val keys = (js \ "COLUMNS").as[List[String]]
val values = (js \ "DATA").as[List[List[JsValue]]]

val busses = values.map(valueList => {
    val keyValues = (keys zip valueList).toMap 
    for {
      ordem <- keyValues("ORDEM").asOpt[String]
      linha <- keyValues("LINHA").asOpt[Int]
      velocidade <- keyValues("VELOCIDADE").asOpt[Int]
    } yield Bus(ordem, linha, velocidade)
})

请注意在将属性转换为预期类型时使用asOpt 如果可能,此运算符将键值转换为提供的类型(包含在Some ),否则返回None 因此,如果要提供默认值而不是忽略其他结果,则可以使用keyValues("LINHA").asOpt[Int].getOrElse(0)

您可以在其文档中阅读有关此处使用的Play JSON方法的更多信息,例如\\as ,以及asOpt

您可以使用Spark SQL来实现它。 在JSON数据集请参阅节在这里

实质上,使用spark API加载JSON并将其注册为临时表。 您可以从那里在表上运行SQL查询。

正如在@Ben Reich的回答中看到的那样,代码效果很好。 非常感谢你。

虽然,我的Json在“Linha”上有一些类型问题。 正如我在问题上的JSON示例中可以看到的那样,有“”和数字,例如781。

当尝试执行keyValues("LINHA").asOpt[Int].getOrElse(0) ,它产生了一个错误,指出value flatMap is not a member of Int 所以,我不得不改变一些事情:

case class BusContainer(ordem: String, linha: String, velocidade: Int)
val jsonString = fromFile("./project/rj_onibus_gps.json").getLines.mkString
val js = Json.parse(jsonString).as[JsObject]
val keys = (js \ "COLUMNS").as[List[String]]
val values = (js \ "DATA").as[List[List[JsValue]]]

val buses = values.map(valueList => {
  val keyValues = (keys zip valueList).toMap
  println(keyValues("ORDEM"),keyValues("LINHA"),keyValues("VELOCIDADE"))
  for {
    ordem <- keyValues("ORDEM").asOpt[String]
    linha <- keyValues("LINHA").asOpt[Int].orElse(keyValues("LINHA").asOpt[String])
    velocidade <- keyValues("VELOCIDADE").asOpt[Int]
  } yield BusContainer(ordem, linha.toString, velocidade)
})

谢谢您的帮助!

暂无
暂无

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

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