2013-07-18 6 views
0

Я в процессе выбора хорошей библиотеки Scala JSON, и консенсус, похоже, заключается в том, что lift-json в настоящее время является лучшим выбором.Изменение объекта JSON с помощью lift-json

После игры с ним (версия 2.5.1) для заклинания я смог выполнить большую часть вещей, которые мне были нужны довольно легко, за исключением одного: изменение существующего JValue.

Говорят, что у меня есть следующий экземпляр JValue:

val john = ("id" -> 1) ~ 
      ("name" -> "Foo") ~ 
      ("nested" -> 
      ("id" -> 2) ~ 
      ("name" -> "Bar")) 

Я хотел бы изменить имя родительского элемента из Foo в foo. Я думал, что метод transform был путь:

john transform { 
    case JField("name", _) => JField("name", "foo") 
}) 

Но это меняет как родителя и вложенного элемента name полей в foo - которые, в ретроспективе, на самом деле не должно было быть сюрпризом.

Я просмотрел документацию и код и не смог найти способ выбрать конкретное поле с ключом name. Я что-то пропустил?

Другое решение (и это работает), как представляется, слияние двух JValue объектов, но это кажется немного многословным:

john merge JObject(JField("name", "foo") :: Nil) 

Есть встроенный, более читаемый способ достижения того же результата ? Я, вероятно, мог написать неявное преобразование от JField до JObject, но кажется странным, что lift-json еще не имеет такого механизма. Если бы мне пришлось делать ставки, это было бы на том, что я не нашел его, а не на нем.

EDIT: Я чувствую себя немного глупо Теперь

john transform { 
    case JField("name", "Foo") => JField("name", "foo") 
}) 

Не самое оптимальное решение в мире, но вполне читаемым и лаконичным.

ответ

0

Это некрасиво, как он использует изменяемую переменную и он также использует json4s (который использует подъемную-JSON под капотом), но это работает:

import org.json4s.JsonAST._ 
import org.json4s.native.JsonMethods._ 
import org.json4s.JsonDSL._ 

object JsonTesting { 
    def main(args: Array[String]) { 
    val john = ("id" -> 1) ~ 
      ("name" -> "Foo") ~ 
      ("nested" -> 
      ("id" -> 2) ~ 
      ("name" -> "Bar")) 

    var changed = false 
    val john2 = john transformField { 
     case JField("name", _) if !changed => 
     changed = true 
     JField("name", "foo") 
    } 
    } 
} 

Я не мог найти более чистый способ сказать он либо проходит только один уровень глубины, либо должен знать глубину для каждого проверяемого узла, поэтому я бы включил переключатель только на первом уровне глубины.

0

Используйте replace метод JValue так:

john.replace(List("name"), "foo")

Реализация этого «заменить» метод является катастрофой, а имя заменить предлагает (для меня) состояние модификация, которая не является правдой, но оно делает вещь

JObject(List((id,JInt(1)), (name,JString(foo)), (nested,JObject(List((id,JInt(2)), (name,JString(Bar)))))))

 Смежные вопросы

  • Нет связанных вопросов^_^