2012-08-09 12 views
11

Mój problem polega na tym, że otrzymuję tekst JSON od say, twitter. Następnie chcę przekonwertować ten tekst na natywny obiekt w scala. Czy istnieje standardowa metoda, aby to zrobić? Używam również grać 2Jak przekonwertować JSON na typ w Scala

Oto co mam

import scala.io.Source.{fromInputStream} 
import java.net._ 

val url = new URL("https://api.twitter.com/1/trends/1.json") 
val content = fromInputStream(url.openStream).getLines.mkString("\n") 
val json = Json.parse(content) 
val a = (json \ "trends") 
Ok(a(0)) 

Chcę uzyskać wszystkie nazwy trendy z JSON

+1

możliwe duplikat [Jak można skonstruować i przetwarza ciąg JSON Scala/skok] (http://stackoverflow.com/questions/927983/how-can-i-construct-and-pars-a-json-string-in-scala-lift) –

+0

jest także Jerkson i kilka innych mniej znanych bibliotek –

+1

@ om-nom-nom: Nie sądzę, że to liczy się jako duplikat - inne pytanie dotyczy właśnie Lift, a nie Play (i tak jest dość starożytny). –

Odpowiedz

4

ja osobiście wolę lift-json, ale jest to dość łatwe do zrobienia tego z Play's JSON library:

import play.api.libs.json._ 
import scala.io.Source 

case class Trend(name: String, url: String) 

implicit object TrendReads extends Reads[Trend] { 
    def reads(json: JsValue) = Trend(
    (json \ "name").as[String], 
    (json \ "url").as[String] 
) 
} 

val url = new java.net.URL("https://api.twitter.com/1/trends/1.json") 
val content = Source.fromInputStream(url.openStream).getLines.mkString("\n") 
val trends = Json.parse(content) match { 
    case JsArray(Seq(t)) => Some((t \ "trends").as[Seq[Trend]]) 
    case _ => None 
} 

Teraz ten produkuje następujące:

scala> trends.foreach(_.foreach(println)) 
Trend(#TrueFactsAboutMe,http://twitter.com/search/?q=%23TrueFactsAboutMe) 
Trend(#200mFinal,http://twitter.com/search/?q=%23200mFinal) 
Trend(Jamaica 1,2,3,http://twitter.com/search/?q=%22Jamaica%201,2,3%22) 
Trend(#DontComeToMyHouse,http://twitter.com/search/?q=%23DontComeToMyHouse) 
Trend(Lauren Cheney,http://twitter.com/search/?q=%22Lauren%20Cheney%22) 
Trend(Silver & Bronze,http://twitter.com/search/?q=%22Silver%20&%20Bronze%22) 
Trend(Jammer Martina,http://twitter.com/search/?q=%22Jammer%20Martina%22) 
Trend(Japan 2-0,http://twitter.com/search/?q=%22Japan%202-0%22) 
Trend(Prata e Bronze,http://twitter.com/search/?q=%22Prata%20e%20Bronze%22) 
Trend(Final 200m,http://twitter.com/search/?q=%22Final%20200m%22) 

Więc tak, wygląda na właściwy.

3

Proponuję użyć Jackson JSON processor. Działa zarówno w Javie, jak iw Scali. Wystarczy dodać adnotacje do swoich klas, które opisują, w jaki sposób chcesz mapować dane JSON do swoich obiektów natywnych.

Przykład:

import scala.reflect.BeanProperty 
import org.codehaus.jackson.map.ObjectMapper; 
import org.codehaus.jackson.annotate._ 

class User { 
    @BeanProperty var gender: String = null 
    @BeanProperty var verified: Boolean = false 
    @BeanProperty var userImage: Array[Byte] = null 
    @BeanProperty var name: Name = null 
} 

case class Name { 
    @BeanProperty var first: String = null; 
    @BeanProperty var last: String = null; 
} 

object Json { 
    def main(argv: Array[String]) { 
    val input = """{ 
    "name" : { "first" : "Joe", "last" : "Sixpack" }, 
    "verified" : false, 
    "userImage" : "Rm9vYmFyIQ==" 
}"""; 

    val mapper = new ObjectMapper(); // can reuse, share globally 
    val user: User = mapper.readValue(input, classOf[User]); 

    print(user.name.first); 
    } 
} 

To rozwiązanie ma niewielki kłopot, że trzeba opisywać każde pole z @BeanProperty, ale nie wiem, prostszy sposób.


Uwaga: O ile wiem, Jackson nie używa javax.bean.Introspector, próbuje znaleźć pobierające/ustawiające badając metody sama. Jeśli tak, wszystko byłoby łatwiejsze, możliwe byłoby napisać po prostu

@scala.reflect.BeanInfo 
case class Name { 
    var first: String; 
    var last: String; 
} 
3

Wystarczy popatrzeć na Lift-Json. Jest to część platformy internetowej Lift, ale może być używana jako samodzielna biblioteka. Może analizować json w klasach przypadków (i ich kolekcjach, np. Listach i mapach) i nie wymaga dodawania adnotacji. Obsługuje także renderowanie klas jako json oraz łączenie i wysyłanie zapytań do json.

Oto przykład wzięty z ich strony internetowej:

import net.liftweb.json._ 
implicit val formats = DefaultFormats // Brings in default date formats etc. 

case class Child(name: String, age: Int, 
       birthdate: Option[java.util.Date]) 
case class Address(street: String, city: String) 
case class Person(name: String, address: Address, 
       children: List[Child]) 
val json = parse(""" 
     { "name": "joe", 
      "address": { 
      "street": "Bulevard", 
      "city": "Helsinki" 
      }, 
      "children": [ 
      { 
       "name": "Mary", 
       "age": 5 
       "birthdate": "2004-09-04T18:06:22Z" 
      }, 
      { 
       "name": "Mazy", 
       "age": 3 
      } 
      ] 
     } 
     """) 

json.extract[Person] 
/* Person = Person(joe, Address(Bulevard,Helsinki), 
        List(Child(Mary,5,Some(Sat Sep 04 18:06:22 EEST 2004)), 
         Child(Mazy,3,None))) 
*/ 
Powiązane problemy