使用Argonaut Lenses从JSON数组JSON对象中提取值

时间:2016-01-15 17:31:43

标签: scala scalaz lenses argonaut

这是我第一次使用argonauts而且只有很少的镜头知识(足以让你过去)。我花了一段时间试图自己解决问题,但无处可去。

我正在尝试构建一个镜头来从一些JSON获取JsonArray(字符串)。我可以获得具有数组的对象,但不知道该怎么做。

JSON看起来像:

json example

到目前为止我的镜头是这样的:

val hashtagsView = twitterEntitiesView >=> jsonObjectPL("hashtags") >=> jArrayPL

我不确定jArrayPL是否正确。我想做的只是从数组中检索文本。

总而言之,任何人都可以帮助我找到如何构建一个查看主题标签的镜头,然后对于数组中的每个元素查看文本,最后得到一个JsonArray的值。 / p>

更新

在Travis的帮助下,我有以下代码编译:

import argonaut._, Argonaut._
import monocle.std.list._, monocle.function.Each.each, monocle.function.Index.index
import scalaz._, Scalaz._

val \/-(json) = Parse.parse(rawJSON)
val lens = jObjectPrism
          .composeOptional(index("hashtags"))
          .composePrism(jArrayPrism)
          .composeTraversal(each[List[Json], Json])
          .composePrism(jObjectPrism)
          .composeOptional(index("text"))
          .composePrism(jStringPrism)

println(lens.getAll(json))

不幸的是,我从行scalaz.Scalaz$.ToEitherOps(Ljava/lang/Object;)Lscalaz/syntax/EitherOps;

开始收到运行时错误:val \/-(json) = Parse.parse(rawJSON)

提前致谢!

2 个答案:

答案 0 :(得分:3)

您是否愿意使用Argonaut提供的Monocle镜头代替Scalaz镜头?如果是这样,使用遍历可以更好:

import argonaut._, Argonaut._
import monocle.function.{ each, index }, monocle.std.list._
import scalaz._, Scalaz._

val doc = """{
  "hashtags": [
    { "indices": [0, 3], "text": "foo" },
    { "indices": [3, 6], "text": "bar" }
  ]
}"""

val \/-(json) = Parse.parse(doc)

val lens = jObjectPrism
  .composeOptional(index("hashtags"))
  .composePrism(jArrayPrism)
  .composeTraversal(each[List[Json], Json])
  .composePrism(jObjectPrism)
  .composeOptional(index("text"))
  .composePrism(jStringPrism)

然后:

scala> lens.getAll(json)
res0: List[argonaut.Argonaut.JsonString] = List(foo, bar)

scala> lens.modify(_ + " (new)")(json).spaces2
res1: String =
{
  "hashtags" : [
    {
      "indices" : [
        0,
        3
      ],
      "text" : "foo (new)"
    },
    {
      "indices" : [
        3,
        6
      ],
      "text" : "bar (new)"
    }
  ]
}

等等。你可以用Scalaz镜头做类似的事情,但需要做更多的工作。

答案 1 :(得分:0)

好吧,如果您只想提取字段:

import argonaut._, Argonaut._
import scalaz._, Scalaz._

val doc = """{
  "hashtags": [
    { "indices": [0, 3], "text": "foo" },
    { "indices": [3, 6], "text": "bar" }
  ]
}"""

val \/-(json) = Parse.parse(doc)
val lense = jObjectPL
val hashtags = (lense >=> jsonObjectPL("hashtags") >=> jArrayPL).get(json)

hashtags.get.foreach(i => (lense >=> jsonObjectPL("indices") ).get(i).get.println )
hashtags.get.foreach(i => (lense >=> jsonObjectPL("text") ).get(i).get.println )

..或更好

val ind = ((v:Json) =>(lense >=> jsonObjectPL("indices") ).get(v).get)
val text = ((v:Json) =>(lense >=> jsonObjectPL("text") ).get(v).get)

hashtags.get.foreach(i => (ind(i), text(i)).println )