Scala徒手實現JSON Parser

JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式, 構建於兩種結構:

1. 「名稱/值」對的集合json

{
    key-name : key-value
}
- key-name: 類型只能是string
- key-value: 類型多是number, string, boo, null, object, array

2. 值的有序列表, 在大多數狀況下能夠理解爲數組(Array)數組

[object, object, ...]

用scala實現上面JSON的定義

class JsonParser extends JavaTokenParsers {

  def jNum: Parser[Double] = floatingPointNumber ^^ (_.toDouble)

  def jStr: Parser[String] = stringLiteral ^^ (s => s.substring(1, s.length() - 1))

  def jBool: Parser[Boolean] = "(true|false)".r ^^ (_.toBoolean)

  def jNull: Parser[Null] = "null".r ^^ (t => null)

  def term = jsonArray | jsonObject | jNum | jBool | jNull | jStr

  def jsonArray: Parser[List[Any]] = "[" ~> rep(term <~ ",?".r) <~ "]" ^^ (l => l)

  def jsonObject: Parser[Map[String,Any]] = "{" ~> rep(
    (
      jStr ~ ":" ~ jNum |
        jStr ~ ":" ~ jBool |
        jStr ~ ":" ~ jNull |
        jStr ~ ":" ~ jsonObject |
        jStr ~ ":" ~ jsonArray |
        jStr ~ ":" ~ jStr
      ) <~ ",?".r
  ) <~ "}" ^^ {
    os =>
      var map = Map[String,Any]()
      os.foreach(o =>
        o match {
          case k ~ ":" ~ v => map = map ++ Map(k->v)
        })
      map
  }
}

這個 parser看上去仍是至關簡單的, 咱們來測試下功能app

val json =
      """{
        | "key":"yardville",
        | "doc_count":2,
        | "avg_age":{
        |   "value":37.0
        |   },
        | "count":{
        |   "value":2
        |   }
        |}
      """.stripMargin

    val jsonObject = JsonParser.parse(JsonParser.jsonObject,json)
    val result = jsonObject.get("key")
    println(result)

執行結果以下:工具

result is: yardville測試

繼續改進

從上面看來, 若是我對JSON對象訪問路徑是:count/value, 或者層次比較深, 如:A/B/C/D/E, 操做起來不太方便, 若是可以像下面這樣操做, 生活是否是太美好了!!! 好比:this

jsonObject.get("count").get("value").asIntscala

讓咱們來先建立JsonObject類rest

class JsonObject(value:Any) {

  def isJsonObject = {
    this.value.isInstanceOf[Map[String,Any]]
  }
  def asJsonObject = {
    if(isJsonObject) {
      this.value.asInstanceOf[Map[String,Any]]
    } else {
      throw new ClassCastException(s"it is not json object")
    }
  }
  def getJsonObject(key:String) = {
    new JsonObject(this.asJsonObject.get(key).get)
  }

  def get(key:String) = {
    new JsonElement(this.asJsonObject.get(key).get)
  }
}

這時候咱們完成了無限級的getcode

jsonObject.getJsonObject("A").getJsonObject("B")...對象

當須要取葉子結點的值時

jsonObject.getJsonObject("A").getJsonObject("B").get("C").asString

咱們來看看JsonElement的實現

class JsonElement(value:Any) {

  def isObject = {
    this.value.isInstanceOf[Object]
  }
  def asObject = {
    if(isObject) {
      this.value.asInstanceOf[Object]
    } else {
      null
    }
  }

  def asString = {
    if(asObject!=null)
      asObject.toString
    else {
      ""
    }
  }

 def isDoubel = {
    this.value.isInstanceOf[Double]
  }
  def asDouble = {
    if(isDoubel) {
      this.value.asInstanceOf[Double]
    } else {
      0d
    }
  }

  def isBoolean = {
    this.value.isInstanceOf[Boolean]
  }
  def asBoolean = {
    if(isBoolean) {
      this.value.asInstanceOf[Boolean]
    } else {
      false
    }
  }
}

咱們還須要一個入口類 JsonMapper

class JsonMapper (text:String) {

  def getJsonObject(key:String) = {
    val result = JsonParser.parseAll(JsonParser.jsonObject,text)
    val eleMap = result.get

    new JsonObject(eleMap.get(key).get)
  }

  def getJsonArray(text:String) = {
    JsonParser.parseAll(JsonParser.jsonArray,text).get.map(l=>{
      new JsonObject(l)
    })
  }
}

來看看測試吧

  1. json-object-test
val dataMapping: String = """
          {  "temp": {
                "properties": {
                    "temp": {
                      "type": "string",
                      "store": true
                    }
                }
             }
          }"""
    val mapper = new JsonMapper(dataMapping)
    val jsonObject = mapper.getJsonObject("temp")
    val temp = jsonObject.getJsonObject("properties").getJsonObject("temp")
    val type_string = temp.get("type").asString
    val store = temp.get("store").asObject
    println(s"type:$type_string")
    println(s"store:$store")

結果以下:

type:string

store:true

  • json-array-test
val dataMappping =
      """[
        | {"key":"yardville","doc_count":2,"avg_age":{"value":37.0},"count":{"value":2}},
        | {"key":"camino","doc_count":1,"avg_age":{"value":37.0},"count":{"value":1}},
        | {"key":"delshire","doc_count":1,"avg_age":{"value":36.0},"count":{"value":1}},
        | {"key":"forestburg","doc_count":1,"avg_age":{"value":37.0},"count":{"value":1}},
        | {"key":"foscoe","doc_count":1,"avg_age":{"value":31.0},"count":{"value":1}}
        |]
      """.stripMargin

    val mapper = new JsonMapper(dataMappping)
    val array = mapper.getJsonArray(dataMappping)
    val first = array(0)
    val key = first.get("key").asString
    val age_value = first.getJsonObject("avg_age").get("value").asObject
    val count_value = first.getJsonObject("count").get("value").asDouble.toInt
    println(s"key: $key")
    println(s"age avg: $age_value")
    println(s"count: $count_value")

結果以下:

key: yardville

age avg: 37.0

count: 2

到些爲止, 咱們沒有依賴任何JSON序列化工具, 完成的JSON string的讀取.

相關文章
相關標籤/搜索