2013-06-27 14 views
5

私はScalatraを使用していますが、この質問はScalaプログラミングで有効です。私はRuby on Railsの背景から来ています。単純なXML Builderやjsonbuilder(https://github.com/rails/jbuilder)などのテンプレートシステムを使用して、入れて、私はRESTfulなAPIの私のJSONまたはXML出力は次のようなテンプレートを作成することで、どうなるかを完全に制御を持っていた:JSONおよび/またはXMLテンプレートを使用したScala

Jbuilder.encode do |json| 
    json.content format_content(@message.content) 
    json.(@message, :created_at, :updated_at) 

    json.author do 
    json.name @message.creator.name.familiar 
    json.email_address @message.creator.email_address_with_name 
    json.url url_for(@message.creator, format: :json) 
    end 

    if current_user.admin? 
    json.visitors calculate_visitors(@message) 
    end 

    json.comments @message.comments, :content, :created_at 

    json.attachments @message.attachments do |attachment| 
    json.filename attachment.filename 
    json.url url_for(attachment) 
    end 
end 

ここでは理想的ですが、コントローラー+アクションに必要なロジックを持つ@messageオブジェクトをまとめています。それはif current_user.admin?のようなロジックを持つテンプレートに渡されますが、そうでない場合は何も含まれていません。

ScalaやScalatraで同様のことを行うのに使用できる同等のツールとは何ですか?私はserializerを知っているので、特定のモデルから生成されたJSONやXMLを上書きすることができますが、それはas_jsonまたはas_xmlをオーバーライドするRubyで同じことです(間違っていれば修正します)。しかし、テンプレートははるかに複雑で、複数のモデル、具体的なデータ構造、データの特定の順序付けなどがあります。これは必要な柔軟性です。 Scala/Scalatra環境でこのようなテンプレートを可能にするツールが存在していますか?

答えて

4

残念ながらXMLでこれを行うには本当に良いライブラリはありません(Anti-Xmlは見てみる価値がありますが)。しかし、そこにJSONのため、このようなライブラリがあり、それはあなたには、いくつかのパラダイムの違いを除いて、基本的には、RubyのJsBuilderでできることすべてを行うことができますプレイJSONでPlayJson です:

  1. Scalaは可能と多くの多くのように機能することを試みますライブラリは変更不可能なデータ構造で動作します。 Play jsonは例外ではありません。つまり、を変更することはできません。 jsonツリー全体の一部を再構築する必要があります。

  2. Scalaは静的型付けされた言語です。これは素晴らしいことですが、コンパイラはすべての型シグネチャを正しさをチェックします。ただし、型シグネチャを指定する必要があります。 - ケースクラスの定義と一致するようにScalaのマクロによって生成される

    import org.joda.time.DateTime 
    import org.joda.time.format.DateTimeFormat 
    
    case class Attachment(fileName: String, url: String) 
    case class Author(name: String, email: String, url: String) 
    case class Comment(content: String, created_at: DateTime) 
    case class Post(author: Author, content: String, attachments: List[Attachment], comments: List[Comment], created_at: DateTime, updated_at: DateTime) 
    
    object Main { 
    
        import play.api.libs.json._ 
        import play.api.libs.functional.syntax._ 
    
        val isAdmin = true 
    
        def calculateVisits(post: Post) = 35 
    
        implicit val jodaTimeWrites: Writes[DateTime] = new Writes[DateTime] { 
        def writes(c: DateTime): JsValue = { 
         Json.toJson(c.toString(DateTimeFormat.fullDateTime())) 
        } 
        } 
        implicit val attachmentFormat = Json.format[Attachment] 
    
        implicit val authorWrites: Writes[Author] = (
        (__ \ "name").write[String] and 
        (__ \ "email").write[String] and 
        (__ \ "url").write[String]) { unlift(Author.unapply) } 
    
        implicit val commentWrites: Writes[Comment] = (
        (__ \ "content").write[String] and 
        (__ \ "created_at").write[DateTime]) { unlift(Comment.unapply) } 
    
        implicit val postWrites: Writes[Post] = (
        (__ \ "content").write[String] and 
        (__ \ "created_at").write[DateTime] and 
        (__ \ "updated_at").write[DateTime] and 
        (__ \ "author").write[Author] and 
        (__ \ "visitors").write[Option[Int]] and 
        (__ \ "comments").write[List[Comment]] and 
        (__ \ "attachments").write[List[Attachment]]) { post: Post => 
         (
         post.content, 
         post.created_at, 
         post.updated_at, 
         post.author, 
         if (isAdmin) Some(calculateVisits(post)) else None, 
         post.comments, 
         post.attachments) 
        } 
    
        def main(args: Array[String]): Unit = { 
        val post = Post(
         Author("David H.", "[email protected]", "http://example.com/users/1-david.json"), 
         "<p>This is <i>serious</i> monkey business</p>", 
         List(
         Attachment("forecast.xls", "http://example.com/downloads/forecast.xls"), 
         Attachment("presentation.pdf", "http://example.com/downloads/presentation.pdf")), 
         List(
         Comment("Hello everyone!", new DateTime()), 
         Comment("To you my good sir!", new DateTime())), 
         new DateTime(), 
         new DateTime()) 
    
        Console println (Json prettyPrint (Json toJson post)) 
        } 
    
    } 
    

    お知らせattachmentFormat

ここではサンプルコードです。私のプロジェクトでは、1つのマニュアルを書いたことがありませんフォーマットオーバーライドコンパイラは私のためのすべてのフォーマットを生成します!しかし、私は必要があればすることができます。良い例はjodaTimeWritesです - デフォルトのjodaTimeFormatはマシン処理に適した長い値を生成しますが、私はそれを自分自身の暗黙的なフォーマットで上書きしてルビのサンプルとマッチさせました。代わりに、私はScalaののの33本のライン(ケースクラスなし)何とか、より複雑なマッピングを得たRubyコードの21行から今

{ 
    "content" : "<p>This is <i>serious</i> monkey business</p>", 
    "created_at" : "Friday, July 5, 2013 4:19:42 PM +03:00", 
    "updated_at" : "Friday, July 5, 2013 4:19:42 PM +03:00", 
    "author" : { 
    "name" : "David H.", 
    "email" : "[email protected]", 
    "url" : "http://example.com/users/1-david.json" 
    }, 
    "visitors" : 35, 
    "comments" : [ { 
    "content" : "Hello everyone!", 
    "created_at" : "Friday, July 5, 2013 4:19:42 PM +03:00" 
    }, { 
    "content" : "To you my good sir!", 
    "created_at" : "Friday, July 5, 2013 4:19:42 PM +03:00" 
    } ], 
    "attachments" : [ { 
    "fileName" : "forecast.xls", 
    "url" : "http://example.com/downloads/forecast.xls" 
    }, { 
    "fileName" : "presentation.pdf", 
    "url" : "http://example.com/downloads/presentation.pdf" 
    } ] 
} 

:上記

コードは、次の出力を生成します。なぜもっとタイプするのですか?今私は、Attachmentの代わりにCommentを渡すと私は確信しているので、私はコンパイラのエラーを取得するか、私の同僚が間違ってjoda.time.DateFormatをjava.util.DateFormatに変更すると、 。ここで

0

はScalaの組み込みのXMLリテラルと優れたargonaut.io JSONシリアライズライブラリを使用して答えのスケッチです:

// dependencies for use with scala 2.10.2: 
// "io.argonaut" %% "argonaut" % "6.0-RC3" 
// "org.scalaz" %% "scalaz-core" % "7.0.1" 

import scalaz._, Scalaz._ 
import argonaut._, Argonaut._ 

object ArgonautJsonExample extends App { 

    case class File(name: String, url: String = "http://my.dummy.url") 
    case class Message(name: String, isAdmin: Boolean, attachmentOpt: Option[File]) 
    val message = 
    new Message(
     "Erik", 
     true, 
     Some(File("strawberry.png")) 
    ) 

    val json: Json = 
    ("name" := message.name) ->: 
    ("filename" :=? message.attachmentOpt.map(_.name)) ->?: 
    ("url" :=? message.attachmentOpt.map(_.url)) ->?: 
    jEmptyObject 


    val myXml = 
    <myObject> 
     <author> 
     <name>{message.name}</name> 
     </author> 
     { 
     message.attachmentOpt map { file => 
      <attachment url={file.url}> 
      {file.name} 
      </attachment> 
     } getOrElse xml.NodeSeq.Empty 
     } 
    </myObject> 


    println("json = " + json) 
    println("") 
    println("xml = " + myXml) 

} 

この意志はあなたを与える:

json = {"url":"http://my.dummy.url","filename":"strawberry.png","name":"Erik"} 

xml = <myObject> 
    <author> 
    <name>Erik</name> 
    </author> 
    <attachment url="http://my.dummy.url"> 
     strawberry.png 
     </attachment> 
</myObject> 
関連する問題