Манипуляции с lift-json — добавление в нужном месте

рассмотрим следующий json:

{
  "type":"A1",
  "system":{
    "path":"/example.org/FooBar",
    "lastModified":"2013-10-01T12:00:00Z"
  },
  "fields":{
    "foo1":["bar1"],
    "foo2":["bar2"],
    "foo3":["bar3"]
  }
}

теперь, используя lift-json, я хочу изменить этот json на:

{
  "type":"A1",
  "system":{
    "path":"/example.org/FooBar",
    "lastModified":"2013-10-01T12:00:00Z"
  },
  "fields":{
    "foo1":["bar1"],
    "foo2":["bar2"],
    "foo3":["bar3"]
  },
  "injected":{
    "bar1":"foo1",
    "bar2":"foo2"
  }
}

Итак, я попробовал следующее:

scala> val json = parse("""
     |{
     |  "type":"A1",
     |  "system":{
     |    "path":"/example.org/FooBar",
     |    "lastModified":"2013-10-01T12:00:00Z"
     |  },
     |  "fields":{
     |    "foo1":["bar1"],
     |    "foo2":["bar2"],
     |    "foo3":["bar3"]
     |  }
     |}""")

json: net.liftweb.json.JValue = JObject(List(JField(type,JString(A1)), JField(system,JObject(List(JField(path,JString(/example.org/FooBar)), JField(lastModified,JString(2013-10-01T12:00:00Z))))), JField(fields,JObject(List(JField(foo1,JArray(List(JString(bar1)))), JField(foo2,JArray(List(JString(bar2)))), JField(foo3,JArray(List(JString(bar3)))))))))

scala> json transform{case JObject(l) => JObject(l ::: List(JField("injected", ("bar1" -> "foo1") ~ ("bar2" -> "foo2"))))}
res0: net.liftweb.json.JsonAST.JValue = JObject(List(JField(type,JString(A1)), JField(system,JObject(List(JField(path,JString(/example.org/FooBar)), JField(lastModified,JString(2013-10-01T12:00:00Z)), JField(injected,JObject(List(JField(bar1,JString(foo1)), JField(bar2,JString(foo2)))))))), JField(fields,JObject(List(JField(foo1,JArray(List(JString(bar1)))), JField(foo2,JArray(List(JString(bar2)))), JField(foo3,JArray(List(JString(bar3)))), JField(injected,JObject(List(JField(bar1,JString(foo1)), JField(bar2,JString(foo2)))))))), JField(injected,JObject(List(JField(bar1,JString(foo1)), JField(bar2,JString(foo2)))))))

scala> Printer.pretty(render(res0))
res1: String = 
{
  "type":"A1",
  "system":{
    "path":"/example.org/FooBar",
    "lastModified":"2013-10-01T12:00:00Z",
    "injected":{
      "bar1":"foo1",
      "bar2":"foo2"
    }
  },
  "fields":{
    "foo1":["bar1"],
    "foo2":["bar2"],
    "foo3":["bar3"],
    "injected":{
      "bar1":"foo1",
      "bar2":"foo2"
    }
  },
  "injected":{
    "bar1":"foo1",
    "bar2":"foo2"
  }
}

и, как вы можете видеть, часть injected также была добавлена ​​в fields и system. я просто хотел добавить его один раз под корень.

Итак, что я делаю неправильно? и как я могу преобразовать json в нужную мне структуру?


person gilad hoch    schedule 01.10.2013    source источник


Ответы (2)


Проблема, с которой вы столкнулись, заключается в том, что частичная функция, определенная в преобразовании, сопоставляется на всех возможных уровнях в структуре json. Поскольку компоненты «система» и «поля» внешнего JObject сами по себе являются объектами JObject, они соответствуют частичной функции и также преобразуются.

Чтобы получить желаемый результат, вам нужно уточнить соответствие, например:

json transform {case JObject(fields) if (fields contains JField("type", "A1")) =>
   JObject(l ::: ...

используя некоторую уникальную информацию о самом внешнем объекте (здесь, что для его «типа» установлено значение «A1»).

Кроме того, у lift json есть возможность слияния, с которой я не имел дело, но которая может дать то, что вы хотите:

json merge JObject(JField("injected", ...) :: Nil)
person Shadowlands    schedule 01.10.2013
comment
Спасибо! слияние отлично сработало и дало мне именно то, что я хотел. - person gilad hoch; 01.10.2013

Если вам нужно добавить поле только в одном месте, transform не лучший инструмент — вместо этого вы можете просто использовать ~:

val newJson = json match {
  case obj: JObject =>
    obj ~ ("injected" -> ("bar1" -> "foo1") ~ ("bar2" -> "foo2"))
  case _ => throw new RuntimeException("Did not receive a JSON object!")
}

Если вы точно знаете, что всегда будете анализировать объект, вы можете привести json к JObject и избежать здесь сопоставления.

person Travis Brown    schedule 01.10.2013
comment
я не всегда использую parse, это было просто для демонстрации. - person gilad hoch; 01.10.2013