2

It's my first time using argonauts and only have a small knowledge of lenses (enough to get by). I've spent a while trying to figure out the problem myself but getting nowhere.

I'm trying to build a lens to get a JsonArray (of Strings) from some JSON. I can get as far as the Object that has the Array but not sure what to do from there.

The JSON looks like:

json example

And my lens so far is this:

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

I'm not sure if that jArrayPL is correct either. What I would like to do is just retrieve the text from the Array.

So to wrap up, can anyone help me in finding out how to construct a lens that looks into hashtags and then for each element of the array look into the text, finally getting a values as a JsonArray.

Update:

With some help from Travis I have the following code compiling:

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))

Unfortunately, I get a runtime error: scalaz.Scalaz$.ToEitherOps(Ljava/lang/Object;)Lscalaz/syntax/EitherOps; starting at the line val \/-(json) = Parse.parse(rawJSON)

Thanks in advance!

2 Answers 2

3

Are you willing to use the Monocle lenses that Argonaut provides instead of the Scalaz lenses? If so, working with traversals is a lot nicer:

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)

And then:

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)"
    }
  ]
}

And so on. You could do something similar with Scalaz lenses but it would take more work.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for the answer @Travis. Can I clarify if this is pseudo code or if it should be runnable? The reason I'm asking is that I can't get it to run myself. Here's a pastebin of the error I'm getting back: pastebin.com/UbdXjd3F I'm using Monocle version 1.2.0, Scalaz version 7.0.6 and Argonaut version 6.0.4. Hopefully there's no dependency issue.
@FintahH It's a real REPL session, but with Argonaut 6.1, which uses a different Monocle version with a slightly different package arrangement. I'm not at a computer at the moment but can give the proper imports for 6.0.4 later.
@FintanH Oh, sorry, I was wrong—the Monocle lenses weren't available at all in 6.0.4.
Right! So I just updated to 6.1 because I saw the update while I was exploring the only part of the example I can't get working now is the each and index functions as they say they're not in that package.
Was able to compile but got a runtime error. Updated the post.
|
0

Well, if you only want to extract the fields:

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 )

..or better

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 )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.