2013-07-11 23 views
11

Tôi đã hai JsValue tạo ra từ lớp trường hợp, ví dụ: Sách và Sổ chi tiếtLàm thế nào để hợp nhất một JsValue để JsObject mực phẳng

val bookJson = Json.tojson(Book) 
val bookDetailJson = Json.tojson(BookDetail) 

và định dạng sẽ là:

//Book 
{ 
    id: 1, 
    name: "A Brief History of Time" 
} 

//BookDetail 
{ 
    bookId: 1, 
    author: "Steven Hawking", 
    publicationDate: 1988, 
    pages: 256 
} 

Làm thế nào tôi có thể hợp nhất chúng với một Json duy nhất trong khung công tác 2.10? ví dụ:

//Book with detail 
{ 
    id: 1, 
    name: "A Brief History of Time", 
    bookId: 1, 
    author: "Steven Hawking", 
    publicationDate: 1988, 
    pages: 256 
} 

Tôi đã cố gắng chuyển đổi và thất bại trong việc lặp qua JsValue thứ hai:

val mapDetail = (__).json.update(
        __.read[JsObject].map { o => 
        o.deepMerge(JsObject(Seq(("detail", bookDetailJson)))) 
       }) 

bookJson.validate(mapDetail).get 

Nó sẽ trở thành một bậc xuống, mà tôi không thực sự muốn.

//Book with detail 
{ 
    id: 1, 
    name: "A Brief History of Time", 
    detail: { 
      bookId: 1, 
      author: "Steven Hawking", 
      publicationDate: 1988, 
      pages: 256 
      } 
} 

Vui lòng cho tôi biết nếu bất kỳ mẹo nào có thể cung cấp cho phép biến đổi Json này. Cảm ơn nhiều!

+0

Có vẻ như lớp 'JsObject' hỗ trợ phương thức' ++ 'để kết hợp hai' JsObject '. Bạn đã thử đưa chúng vào 'JsObject' (nếu chúng không phải kiểu đó) và sau đó sử dụng' ++'? – cmbaxter

+0

Đó là nỗ lực của tôi mà đã cho tôi kết quả tương tự. Thật vậy, tôi nghĩ deepMerge sẽ cho tôi một câu trả lời tốt hơn. – Joyfulvillage

+0

Vấn đề thực sự là khi tôi chuyển đổi một JsValue để JsObject, tôi chỉ có thể sử dụng JsObject (Seq (("chi tiết", detailsJson))) đó sẽ tạo ra điều này: chi tiết: { bookId: 1, tác giả: " Steven Hawking ", publicationDate: 1988, pages: 256 } – Joyfulvillage

Trả lời

13

Phát có rất nhiều tính năng mới cho JSON ngay bây giờ. Đây sẽ là một giới thiệu tuyệt vời cho các đặc tính Format[A] (xem Scala Json Inception) mà bạn có thể bao gồm ngầm như tôi sẽ hiển thị, hoặc rõ ràng với các phương pháp yêu cầu một ẩn Format[A]/Reads[A]/Writes[A].

Tạo một lớp hợp để đại diện cho đối tượng JSON của bạn,

case class Book(id: Int, name: String) 
case class BookDetail(id: Int, author: String, publicationDate: Int, pages: Int) 

Tạo đối tượng đồng có chứa ngầm Format[A] để Format/Reads/Writes sẽ tự động được trong phạm vi khi bạn cần chúng.

object Book { 
    implicit val fmt: Format[Book] = Json.format[Book] 
} 

object BookDetail { 
    implicit val fmt: Format[BookDetail] = Json.format[BookDetail] 
} 

Bây giờ bạn có thể làm một cái gì đó như thế này,

val bookJson = Json.toJson(Book(1, "A Brief History Of Time")) 
val bookDetailJson = Json.toJson(BookDetail(1, "Steven Hawking", 1988, 256)) 
bookJson.as[JsObject].deepMerge(bookDetailJson.as[JsObject]) 

Và bạn sẽ có một đối tượng như thế này,

{ 
    id: 1, 
    name: "A Brief History Of Time", 
    author: "Steven Hawking", 
    publicationDate: 1988, 
    pages: 256 
} 

Tôi đã thử điều này trong REPL nhưng nó không công việc, trong một ứng dụng Play nó chỉ tốt mặc dù. Cũng trong một kịch bản sản xuất, chúng tôi có thể sử dụng asOpt[T] thay cho as[T].

Dưới đây là một ví dụ về lý do tại sao asOpt[T] có thể phù hợp hơn, giả sử thay vì một đối tượng JSON hợp lệ cho cuốn sách bạn nhận được,

val bookJson = Json.toJson("not a book") 

Bạn sẽ kết thúc với một

[JsResultException: JsResultException(errors:List((,List(ValidationError(validate.error.expected.jsobject,WrappedArray())))))] 

Nhưng giả sử thay vào đó bạn thay đổi phương thức của mình để sử dụng asOpt[T],

bookJson.asOpt[JsObject].getOrElse(Json.obj()).deepMerge(bookDetailJson.asOpt[JsObject].getOrElse(Json.obj())) 

Bây giờ bạn sẽ kết thúc với ít nhất một đối tượng JSON một phần,

{ 
    id: 1, 
    author: "Steven Hawking", 
    publicationDate: 1988, 
    pages: 256 
} 

Vì vậy, tùy thuộc vào cách bạn muốn xử lý JSON được định dạng không đúng, bạn có thể chọn một trong hai tùy chọn.

+1

1 Cảm ơn soo nhiều deepMerge là chính xác những gì tôi đang tìm kiếm nhưng api Scala là quá lớn mà nó dễ dàng bỏ qua! – toidiu

1

JsObject là loại phụ của JsValue.

JsValue có thể đơn giản được chuyển đổi sang sử dụng JsObject như hoặc asOpt phương pháp từ JsValue. Ví dụ:

val someJsValue = .... 
val asObject:JsObject = someJsValue.as[JsObject] 
val asObjectMaybe:Option[JsObject] = v.asOpt[JsObject] 

Trong trường hợp của JsArray bạn không thể sử dụng trên mã. Nếu bạn sử dụng phát và phân tích cú pháp JSON bằng mảng, thì Json.toJson (...) sẽ tạo ra JsValue thực sự là JsArray. Bạn cần chuyển đổi JsArray như sau:

val someJsValueButArray = .... 
val asJsArray:JsArray = Json.toJson(someJsValueButArray).as[JsArray] 
val asSeqOfJsObjects:Seq[JsObject] = asJsArray.value.map(_.as[JsObject]) 
Các vấn đề liên quan