JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式, 构建于两种结构:
1. “名称/值”对的集合
{
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看上去还是相当简单的, 我们来测试下功能
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, 操作起来不太方便, 如果能够像下面这样操作, 生活是不是太美好了!!! 比如:
jsonObject.get("count").get("value").asInt
让我们来先创建JsonObject类
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)
}
}
这时候我们完成了无限级的get
jsonObject.getJsonObject("A").getJsonObject("B")...
当需要取叶子结点的值时
扫描二维码关注公众号,回复:
888439 查看本文章
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)
})
}
}
来看看测试吧
- 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的读取.