2017-02-10 9 views
1

JSON мне нужна помощь, чтобы разобрать строку JSON в классе, используя лестницу playJsonScala - преобразовать строку в Json с помощью Play

Я написал форматчик, но я не знаю, как обращаться с вложенными массивами.

Где Документ Case класс

case class Document(content: String, score: Double, size: Int, path:String) 

и форматировщик

implicit val similarHashFormatter: Format[SimilarHash] = (
    ((__ \ "hits" \ "hits" \\ "fields")(0) \ "content_hash")(0).format[String] and 
    (__ \ "hits" \ "hits" \\ "_score").format[Double] and 
    ((__ \ "hits" \ "hits" \\ "fields")(0) \ "ast_size")(0).format[Int] and 
    ((__ \ "hits" \ "hits" \\ "fields")(0) \ "path")(0).format[String] 
) (SimilarHash.apply, unlift(SimilarHash.unapply)) 

Это мой источник JSON

{ 
    "hits": { 
    "hits": [ 
     { 
     "score": 1.5204661, 
     "fields": { 
      "size": [ 
      557645 
      ], 
      "path": [ 
      "/user/ubuntu/app 
      ], 
      "content": [ 
      "images" 
      ] 
     } 
     }, 
     {   
     "score": 1.5199462, 
     "fields": { 
      "size": [ 
      556835 
      ], 
      "path": [ 
      "/user/ubuntu/app 
      ], 
      "content": [ 
      "documents" 
      ] 
     } 
     } 
    ] 
    } 
} 

Любая идея?

+0

, что делает ваш взгляд определения класса SCALA как? в большинстве случаев проще всего использовать макрос Json.format для вашего класса case для обработки более сложных моделей. – josephpconley

+0

@josephpconley Я просто добавил класс Case Document, какой-нибудь пример использования макроса Json.format? –

ответ

0

я понял, решение, основанное на комментарий Лету, но не создавая несколько операций чтения.

implicit val docReader: Reads[Document] = (
     (__ \ "fields" \ "content")(0).read[String] and 
     (__ \ "_score").read[Double] and 
     ((__ \ "fields") \ "size")(0).read[Int] and 
     ((__ \ "fields") \ "path")(0).read[String] 
    ) (Document.apply _) 


    implicit val docsReader: Reads[Documents] = (
     (__ \ "hits" \ "max_score").read[Double] and 
     (__ \ "hits" \ "hits").read[Seq[Document]] 
    ) (Documents.apply _) 

... и, наконец,

val response = Json.parse(inputStream).asOpt[Documents] 
1

Вы можете сделать это путем создания пользовательских Reads отдельно для каждого поля следующим образом:

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

    case class Document(content: String, score: Double, size: Int, path:String) 

    val jsonString = """{ 
         "hits": { 
          "hits": [ 
           { 
            "score": 1.5204661, 
            "fields": { 
             "size": [ 
              557645 
             ], 
             "path": [ 
              "/user/ubuntu/app" 
             ], 
             "content": [ 
              "images" 
             ] 
            } 
           }, 
           { 
            "score": 1.5199462, 
            "fields": { 
             "size": [ 
              556835 
             ], 
             "path": [ 
              "/user/ubuntu/app" 
             ], 
             "content": [ 
              "documents" 
             ] 
            } 
           } 
          ] 
         } 
        }""" 

    val playJson = Json.parse(jsonString) 

    val contentReads = new Reads[String] { 
    override def reads(json: JsValue): JsResult[String] = json \ "hits" match { 
     case JsDefined(o: JsObject) => 
     o \ "hits" match { 
      case JsDefined(arr: JsArray) => 
      arr.value.head \ "fields" match { 
       case JsDefined(fieldObj: JsObject) => 
       fieldObj \ "content" match { 
        case JsDefined(contentArr: JsArray) => 
        JsSuccess(Json.stringify(contentArr.value.head)) 
        case _ => JsError("""Can't read hits \ hits \ fields \ content""") 
       } 
       case _ => JsError("""Can't read hits \ hits \ fields""") 
       case _ => JsError("""Can't read hits \ hits""") 
      } 
      case _ => JsError("Can't read hits") 
     } 
    } 
    } 

    val sizeReads = new Reads[Int] { 
    override def reads(json: JsValue): JsResult[Int] = json \ "hits" match { 
     case JsDefined(o: JsObject) => 
     o \ "hits" match { 
      case JsDefined(arr: JsArray) => 
      arr.value.head \ "fields" match { 
       case JsDefined(fieldObj: JsObject) => 
       fieldObj \ "size" match { 
        case JsDefined(contentArr: JsArray) => 
        JsSuccess(Json.stringify(contentArr.value.head).toInt) 
        case _ => JsError("""Can't read hits \ hits \ fields \ size""") 
       } 
       case _ => JsError("""Can't read hits \ hits \ fields""") 
      } 
      case _ => JsError("""Can't read hits \ hits""") 
     } 
     case _ => JsError("Can't read hits") 
    } 
    } 

    val scoreReads = new Reads[Double] { 
    override def reads(json: JsValue): JsResult[Double] = json \ "hits" match { 
     case JsDefined(o: JsObject) => 
     o \ "hits" match { 
      case JsDefined(arr: JsArray) => 
      arr.value.head \ "score" match { 
       case JsDefined(score: JsValue) => 
       JsSuccess(Json.stringify(score).toDouble) 
       case _ => JsError("""Can't read hits \ hits \ score""") 
      } 
      case _ => JsError("""Can't read hits \ hits""") 
     } 
     case _ => JsError("Can't read hits") 
    } 
    } 

    val pathReads = new Reads[String] { 
    override def reads(json: JsValue): JsResult[String] = json \ "hits" match { 
     case JsDefined(o: JsObject) => 
     o \ "hits" match { 
      case JsDefined(arr: JsArray) => 
      arr.value.head \ "fields" match { 
       case JsDefined(fieldObj: JsObject) => 
       fieldObj \ "path" match { 
        case JsDefined(contentArr: JsArray) => 
        JsSuccess(Json.stringify(contentArr.value.head)) 
        case _ => JsError("""Can't read hits \ hits \ fields \ path""") 
       } 
       case _ => JsError("""Can't read hits \ hits \ fields""") 
      } 
      case _ => JsError("""Can't read hits \ hits""") 
     } 
     case _ => JsError("Can't read hits") 
    } 
    } 

    implicit val documentReads: Reads[Document] = (
    contentReads and 
    scoreReads and 
    sizeReads and 
    pathReads 
)(Document.apply _) 

    val document = playJson.validate[Document].get 
//result: Document("images",1.5204661,557645,"/user/ubuntu/app")