Как разобрать список или массив json в scala для игровой платформы 2.2

Я пишу несколько тестовых примеров RESTful API, и у меня мало опыта работы с scala playframwork.

Вот пример моего JSON.

  [ {
   "size" : "5082",
   "date-created" : "Wed Nov 19 17:10:39 CST 2014",
   "id" : "546d236fb84e894eefd8f769",
   "content-type" : "image/png",
   "filename" : "chrome-on-windows.PNG"
 }, {
   "size" : "15684",
   "date-created" : "Mon Jan 12 17:28:02 CST 2015",
   "id" : "54b4588266b3d11b1c1e9db6",
   "content-type" : "image/png",
   "filename" : "logos_ncsa.png"
 }, {
   "size" : "1267871",
   "date-created" : "Mon Jan 12 17:28:03 CST 2015",
   "id" : "54b4588366b3d11b1c1e9dba",
   "content-type" : "image/jpg",
   "filename" : "morrowplots.jpg"
 } ]

Как видите, у меня есть список / массив элементов JSON. Я хочу получить идентификатор файла morrowplots.jpg и сохранить его в переменной, которая будет использоваться для успешных вызовов API.

Итак, я установил свой код, чтобы он выглядел следующим образом. Переменная результата в приведенном ниже коде - это строка JSON, которую вы видите выше.

  case class FileName(size: String, datecreated: String, id: String,    contenttype: String, filename: String)

  implicit val fileReads: Reads[FileName] = (
  (__ \\ "size").read[String] and
  (__ \\ "datecreated").read[String] and
  (__ \\ "id").read[String] and
  (__ \\ "content-type").read[String] and
  (__ \\ "filename").read[String]
  )(FileName.apply _)

  val json: JsValue = Json.parse(contentAsString(result))

  val nameResult: JsResult[FileName] = json.validate[FileName](fileReads)
  info("Right after validate")
    nameResult match {
      case s: JsSuccess[FileName] => {
        val testfile: FileName = s.get
        // Do something with testfile
        info("Success")
      }
      case e: JsError => {
        info("Error")
        info("Errors: " + JsError.toFlatJson(e).toString())
      }
    }

Это дает мне следующую ошибку.

[info] + Ошибки: {"obj size": [{"msg": "error.path.result.multiple", "args": []}], "obj filename": [ {"msg": "error.path.resul t.multiple", "args": []}], "obj id": [{"msg": "error.path.result.multiple", " args ": []}]," obj content-type ": [{" msg ":" error.path .result.multiple "," args ": []}]," obj * datecreated ": [{"msg": "error.path.missing", "args": []}]}

Итак, как мне исправить эту проблему со списком / массивом и как выполнить поиск по имени файла, чтобы получить идентификатор?

Заранее спасибо.


person Eugene Roeder    schedule 20.01.2015    source источник


Ответы (2)


Я не эксперт по игре, так что это может быть не идиоматично, но должно решить вашу проблему. Во-первых, ваш json date-created по сравнению с вашим scala, ожидающим datecreated. Во-вторых, вы должны использовать только одну косую черту для своего Reads. Затем вам нужно запустить validate против List[FileName].

Что касается поиска по имени файла, теперь вы можете извлечь список из JsSuccess и запустить filter против него.

Окончательный код будет выглядеть примерно так

case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)

  implicit val fileReads: Reads[FileName] = (
  (__ \ "size").read[String] and
  (__ \ "date-created").read[String] and
  (__ \ "id").read[String] and
  (__ \ "content-type").read[String] and
  (__ \ "filename").read[String]
  )(FileName)

  val json: JsValue = Json.parse(contentAsString(result))

  val nameResult = json.validate[List[FileName]]

  val list = nameResult match {
      case JsSuccess(list : List[FileName], _) => list
      case e: JsError => {
        info("Errors: " + JsError.toFlatJson(e).toString())
        List()
      }
    }

  list filter(_.filename contains "morrow")
person Justin Pihony    schedule 21.01.2015

Во-первых, вы можете решить использовать встроенные утилиты json, а не выполнять синтаксический анализ вручную.

  case class FileName(size: String, datecreated: String, id: String,    contenttype: String, filename: String)
  object FileName {
    implicit val formatFileName = Json.format[FileName]
  }

Здесь у вас есть все, что вам нужно для синтаксического анализа базового объекта json. Компилятор будет использовать макрос (IIRC) для генерации кода, эквивалентного тому, который вы написали вручную. Поскольку у вас нет экзотических проверок в ваших полях, ручное написание классов Reads и Writes не требуется.

Тогда вы можете прочитать это так:

    def readString(str: String) = {
      val jsr: JsResult[Seq[FileName]] = Json.parse(str).validate[Seq[FileName]]
      jsr.fold(
        error => {
          ???
        },
        success => {
          ???
        }
      )
    }

jsr - это JsResult. Это может быть либо JsSuccess, либо JsError.

Также обратите внимание на полный тип. Поскольку у вас есть массив в качестве ввода, вы должны поместить свой вывод в коллекцию, например, Seq.

Вы можете сбросить свой JsResult. fold ожидает двух функций. Один для случая ошибки, он имеет тип Seq [(JsPath, Seq [ValidationError])] => X, где X - тип возвращаемого значения вашей функции. Он показывает вам все проблемы, из-за которых ваш json не удалось преобразовать в Seq [FileName].

Другой - на случай успеха. Он имеет тип Seq [FileName] => X с тем же X, что и раньше.

Теперь вы можете решить, что добавить в эти две функции.

Как указал Джастин, вы тоже можете написать это со спичкой. Это может быть проще, даже если оно менее функционально:

    def readString(str: String) = {
      val jsr: JsResult[Seq[FileName]] = Json.parse(str).validate[Seq[FileName]]
      jsr match {
        case JsResult(seq) => ???
        case e: JsError => ???
      }
    } 
person Agemen    schedule 21.01.2015