Play Framework:如何按字母顺序对JSON排序

Play Framework:如何按字母顺序对JSON排序,json,scala,playframework,Json,Scala,Playframework,给定以下JSON { "z": 100, "b": 50, "q": 12 } 如何按字母顺序对键排序?非常简单,但(显然)我们需要确保有一个JsObject val js = Json.parse("""{ "z": 100, "b": 50, "q": 12 }""") val jsObject = js.as[JsObject] // Not actually safe, but bear with me 这些字段只是以Seq[(String,Js

给定以下JSON

{
   "z": 100,
   "b": 50,
   "q": 12
}
如何按字母顺序对键排序?

非常简单,但(显然)我们需要确保有一个
JsObject

val js = Json.parse("""{
   "z": 100,
   "b": 50,
   "q": 12
}""")

val jsObject = js.as[JsObject] // Not actually safe, but bear with me
这些字段只是以
Seq[(String,JsValue)]
的形式存储在名为
fields
的字段中

我们可以用相同的字段创建一个新的
JsObject
,除了排序

scala> JsObject(jsObject.fields.sortBy(_._1))
res6: play.api.libs.json.JsObject = {"b":50,"q":12,"z":100}
前面,我提到将
用作[JsObject]
是不安全的,因为如果我们的
JsValue
实际上是一个数组或字符串,它将抛出一个异常。处理
JsValue
的更安全的方法是在
JsObject
上进行模式匹配并对其排序,而不对任何其他类型执行任何操作。创建递归排序所有键的方法非常简单:

def sortJs(js: JsValue): JsValue = js match {
    case JsObject(fields) => JsObject(fields.sortBy(_._1).map { case (k, v) => (k, sortJs(v)) })
    case _ => js
}

val js = Json.parse("""{
   "z": 100,
   "b": {"k": 1, "j": 3, "i": 98},
   "q": 12
}""")

scala> sortJs(js)
res8: play.api.libs.json.JsValue = {"b":{"i":98,"j":3,"k":1},"q":12,"z":100}
这对我来说很有用(通过以下测试):

  • Scala版本:2.11.8
  • 播放json版本:2.6.10

Just FTR:这是我在接受答案时遇到的错误:

scala> def sortJs(js: JsValue): JsValue = js match {
     |     case JsObject(fields) => JsObject(fields.sortBy(_._1).map { case (k, v) => (k, sortJs(v)) })
     |     case _ => js
     | }
<console>:16: error: value sortBy is not a member of scala.collection.Map[String,play.api.libs.json.JsValue]
           case JsObject(fields) => JsObject(fields.sortBy(_._1).map { case (k, v) => (k, sortJs(v)) })
                                                    ^
<console>:16: error: type mismatch;
 found   : Any
 required: play.api.libs.json.JsValue
           case JsObject(fields) => JsObject(fields.sortBy(_._1).map { case (k, v) => (k, sortJs(v)) })
                                                                                                 ^
scala>def-sortJs(js:JsValue):JsValue=js-match{
|case-JsObject(fields)=>JsObject(fields.sortBy(u._1).map{case(k,v)=>(k,sortJs(v))})
|case=>js
| }
:16:错误:value sortBy不是scala.collection.Map[String,play.api.libs.json.JsValue]的成员
case-JsObject(fields)=>JsObject(fields.sortBy(u._1).map{case(k,v)=>(k,sortJs(v))})
^
:16:错误:类型不匹配;
发现:有吗
必需:play.api.libs.json.JsValue
case-JsObject(fields)=>JsObject(fields.sortBy(u._1).map{case(k,v)=>(k,sortJs(v))})
^

我遇到了与Yuchen在接受答案时遇到的相同问题。我就是这样让它工作的:

def sortJs(js: JsValue): JsValue = js match {
  case JsObject(fields) => JsObject(fields.toSeq.sortBy(_._1).map { case (key, value) => (key, sortJs(value.asInstanceOf[JsValue]))})
  case _ => js
}
上述版本不处理递归排序JsArray。这个版本可以处理这个问题

def sortJs(js: JsValue): JsValue = js match {
  case JsObject(fields) => JsObject(fields.toSeq.sortBy(_._1).map { case (key, value) => (key, sortJs(value.asInstanceOf[JsValue])) })
  case JsArray(array) => JsArray(array.map(e => sortJs(e)))
  case other => other
}
def sortJs(js: JsValue): JsValue = js match {
  case JsObject(fields) => JsObject(fields.toSeq.sortBy(_._1).map { case (key, value) => (key, sortJs(value.asInstanceOf[JsValue]))})
  case _ => js
}
def sortJs(js: JsValue): JsValue = js match {
  case JsObject(fields) => JsObject(fields.toSeq.sortBy(_._1).map { case (key, value) => (key, sortJs(value.asInstanceOf[JsValue])) })
  case JsArray(array) => JsArray(array.map(e => sortJs(e)))
  case other => other
}