2014-06-21 6 views
5

berücksichtigt die folgenden JSON von einem Anbieter bereitgestellt API:Wie durchqueren Sie JSON-Objektfelder mit JsPath?

import play.api.libs.json._ 
import play.api.libs.json.Reads._ 
import play.api.libs.functional.syntax._ 

val json = Json.parse(
    """ 
    |{ 
    | "returns": { 
    | "markets" : { 
    |  "ABC" : { 
    |  "label": "ABC", 
    |  "id":1 
    |  }, 
    |  "DEF" : { 
    |  "label": "DEF", 
    |  "id":2 
    |  } 
    | } 
    | } 
    |} 
    """.stripMargin) 

Wie eine Folge von Paaren „label“ und „ID“ Felder extrahieren. Von diesem Stück JSON das Ergebnis erwarte ich ist:

Seq((1,"ABC"),(2,"DEF")) 

ich mit der Konstruktion einer korrekten JsPath Extraktor ich scheitern, weil es beispielsweise ein einziges Spiel erwartet

Antwort

3

So würde ich diesen Parser aus schönen zusammensetzbaren Stücken bauen. Zunächst für einen Allzweck-Objekt-to-Array Transformator, den Schlüssel wegwirft: für ein Reads

val objToArray: Reads[JsArray] = 
    JsPath.json.pickBranch.map(obj => JsArray(obj.fields.map(_._2))) 

nun den Markt Objekte verarbeiten kann:

val marketReads: Reads[(Int, String)] = 
    ((__ \ 'id).read[Int] and (__ \ 'label).read[String]).tupled 

Und jetzt haben wir es alle zusammen binden:

val pairsReads: Reads[List[(Int, String)]] = 
    (__ \ 'returns \ 'markets).read(objToArray) andThen list(marketReads) 

Und schließlich:

scala> json.validate(pairsReads).foreach(println) 
List((1,ABC), (2,DEF)) 

Welches ist was du willst. Beachten Sie, dass ich die obigen Typen zur besseren Übersicht angegeben habe, aber das ist hier nicht notwendig - ich würde sie wahrscheinlich in echtem Code belassen, weil die Teile ziemlich klein und geradlinig sind.

+0

Genau das habe ich gesucht. Praktisch die erste Anweisung ist etwas, das ich nicht finden konnte. –

+0

Das 'objToArray' ist superclever. Vielen Dank! –

Verwandte Themen