【问题标题】:Parsing a file having content as Json format in Scala在Scala中解析内容为Json格式的文件
【发布时间】:2019-11-29 08:53:36
【问题描述】:

我想解析一个内容为 json 格式的文件。 我想从文件中提取一些属性(名称、DataType、Nullable)来动态创建一些列名。 我已经浏览了一些示例,但其中大多数都使用案例类,但我的问题是每次收到文件时可能有不同的内容。

我尝试使用 ujson 库来解析文件,但我无法理解如何正确使用它。

object JsonTest {
  def main(args: Array[String]): Unit = {

    val source = scala.io.Source.fromFile("C:\\Users\\ktngme\\Desktop\\ass\\file.txt")
    println(source)
    val input = try source.mkString finally source.close()
    println(input)

    val data = ujson.read(input)
    data("name") = data("name").str.reverse
    val updated = data.render()
  }
}

文件示例的内容:

{
"Organization": {
"project": {
"name": "POC 4PL",
"description": "Implementation of orderbook"
},
"Entities": [
{
"name": "Shipments",
"Type": "Fact",
"Attributes": [
{
"name": "Shipment_Details",
"DataType": "StringType",
"Nullable": "true"
},
{
"name": "Shipment_ID",
"DataType": "StringType",
"Nullable": "true"
},
{
"name": "View_Cost",
"DataType": "StringType",
"Nullable": "true"
}
],
"ADLS_Location": "/mnt/mns/adls/raw/poc/orderbook/"
}
]
}
}

预期输出:

StructType(
Array(StructField("Shipment_Details",StringType,true),
StructField("Shipment_ID",DateType,true),   
StructField("View_Cost",DateType,true))) 

StructType 需要以编程方式添加到预期的输出中。

【问题讨论】:

    标签: json scala parsing circe ujson


    【解决方案1】:

    尝试使用 Playframework 的 Json 工具 - https://www.playframework.com/documentation/2.7.x/ScalaJson

    这是您问题的解决方案- \ 将您的 json 放在文本文件中

        val fil_path = "C:\\TestData\\Config\\Conf.txt"
        val conf_source = scala.io.Source.fromFile(fil_path)
        lazy val json_str = try conf_source.mkString finally conf_source.close()
        val conf_json: JsValue = Json.parse(json_str)
        val all_entities: JsArray = (conf_json \ "Organization" \ "Entities").get.asInstanceOf[JsArray]
        val shipments: JsValue = all_entities.value.filter(e => e.\("name").as[String] == "Shipments").head
        val shipments_attributes: IndexedSeq[JsValue] = shipments.\("Attributes").get.asInstanceOf[JsArray].value
        val shipments_schema: StructType = StructType(shipments_attributes.map(a => Tuple3(a.\("name").as[String], a.\("DataType").as[String], a.\("Nullable").as[String]))
          .map(x => StructField(x._1, StrtoDatatype(x._2), x._3.toBoolean)))
        shipments_schema.fields.foreach(println)
    

    输出是 -

    StructField(Shipment_Details,StringType,true)
    StructField(Shipment_ID,StringType,true)
    StructField(View_Cost,StringType,true)
    

    【讨论】:

    • 非常感谢@ValaravausBlack ?
    【解决方案2】:

    这取决于你是否希望它是完全动态的,这里有一些选项:

    如果你只想阅读一个字段,你可以这样做:

    import upickle.default._
    
    val source = scala.io.Source.fromFile("C:\\Users\\ktngme\\Desktop\\ass\\file.txt")
    val input = try source.mkString finally source.close()
    val json = ujson.read(input)
    
    println(json("Organization")("project")("name")) 
    

    输出将是:"POC 4PL"

    如果您只希望属性与类型一起使用,您可以这样做:

    import upickle.default.{macroRW, ReadWriter => RW}
    import upickle.default._
    
    val source = scala.io.Source.fromFile("C:\\Users\\ktngme\\Desktop\\ass\\file.txt")
    val input = try source.mkString finally source.close()
    val json = ujson.read(input)
    val entitiesArray = json("Organization")("Entities")(0)("Attributes")
    println(read[Seq[StructField]](entitiesArray))
    
    case class StructField(name: String, DataType: String, Nullable: String)
    object StructField{
      implicit val rw: RW[StructField] = macroRW
    }
    

    输出将是:List(StructField(Shipment_Details,StringType,true), StructField(Shipment_ID,StringType,true), StructField(View_Cost,StringType,true))

    另一种选择是使用不同的库来进行类映射。如果您使用 Google Protobuf StructJsonFormat 它可以是 2-liner:

    import com.google.protobuf.Struct
    import com.google.protobuf.util.JsonFormat
    
    val source = scala.io.Source.fromFile("C:\\Users\\ktngme\\Desktop\\ass\\file.txt")
    val input = try source.mkString finally source.close()
    
    JsonFormat.parser().merge(input, builder)
    println(builder.build())
    

    输出将是:fields { key: "Organization" value { struct_value { fields { key: "project" value { struct_value { fields { key: "name" value { string_value: "POC 4PL" } } fields { key: "description" value { string_value: "Implementation of orderbook" } } } } } fields { key: "Entities" value { list_value { values { struct_value { fields { key: "name" value { string_value: "Shipments" } }...

    【讨论】:

    • 嘿@Boaz 我不了解 Google Protobuf。如果我使用第一个解决方案,那么我可以动态提取属性吗?如何传递输入文件路径。你能分享一个完整的例子吗?感谢您的支持。
    • @Stark 我添加了完整的示例和 Google 库的链接。
    • 在执行上述程序时,我得到空指针异常:(与您分享异常消息。
    • ujson.AstTransformer$class.transformObject(AstTransformer.scala:15) 的线程“main”java.lang.NullPointerException 的异常在 ujson.Value$.transformObject(Value.scala:86) 在 ujson .Value$.transform(Value.scala:152) at ujson.Value$.transform(Value.scala:86) at ujson.AstTransformer$$anonfun$transformArray$1.apply(AstTransformer.scala:11) at ujson.AstTransformer$ $anonfun$transformArray$1.apply(AstTransformer.scala:11) at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
    • 在 scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48) 在 ujson.AstTransformer$class.transformArray(AstTransformer.scala:11) 在 ujson.Value$.transformArray(Value. scala:86) at ujson.Value$.transform(Value.scala:151) at ujson.Value$class.transform(Value.scala:75) at ujson.Arr.transform(Value.scala:211) at upickle.Api $class.read(Api.scala:32) at upickle.default$.read(Api.scala:102) at StructField$.delayedEndpoint$StructField$1(StructField.scala:18) at StructField$delayedInit$body.apply(StructField .scala:10)
    猜你喜欢
    • 2019-05-20
    • 2016-10-17
    • 2020-10-13
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多