json lenses and arrays

173 views
Skip to first unread message

Richard Bowker

unread,
Feb 16, 2015, 6:54:30 PM2/16/15
to spray...@googlegroups.com
Is it possible to use json lenses to iterate through an array? As far as I understand * matches all elements and element(n) matches a specific element, but I'm not sure how they are supposed to be used when I don't know how many elements there are? For example if I want to iterate through an array and modify each element individually, is that possible?

Cheers

Rich

Age Mooij

unread,
Feb 17, 2015, 5:15:02 AM2/17/15
to spray...@googlegroups.com
Yes, that is what the * selector does. Something like this:

_.update('items / * / 'product / 'availableStock ! set[Int](defaultAvailableStock))

will set the the specified value to the "availableStock" field on the "product” associated with each individual item in the "items" array.

Does that answer your question?
Age
> --
> You received this message because you are subscribed to the Google Groups "spray.io User List" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to spray-user+...@googlegroups.com.
> Visit this group at http://groups.google.com/group/spray-user.
> To view this discussion on the web visit https://groups.google.com/d/msgid/spray-user/d87c2bac-14c5-40a6-8963-0a32e5b0d174%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Richard Bowker

unread,
Feb 17, 2015, 5:27:37 AM2/17/15
to spray...@googlegroups.com
that would set them all to the same defaultAvailableStock ?

what if I wanted to set each one of those values to something different?
and can i extract a list or sequence of the original int values?

cheers

Johannes Rudolph

unread,
Feb 17, 2015, 5:45:38 AM2/17/15
to spray...@googlegroups.com
Hi Richard,

On Tue, Feb 17, 2015 at 11:27 AM, Richard Bowker
<mechajoh...@googlemail.com> wrote:
> that would set them all to the same defaultAvailableStock ?

Yes.

> what if I wanted to set each one of those values to something different?

You can use `modify` instead of `set` to map the values from the
former to the new value.

> and can i extract a list or sequence of the original int values?

Of course :)

val stockValues = 'items / * / 'product / 'availableStock
val allOriginalValues = jsValue.extract[Int](stockValues)
val modified = jsValue.update(stockValues ! modify[Int](_ - 1))

HTH
--
Johannes

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net

Richard Bowker

unread,
Feb 17, 2015, 6:36:17 AM2/17/15
to spray...@googlegroups.com
thank you!

Richard Bowker

unread,
Feb 17, 2015, 10:32:00 AM2/17/15
to spray...@googlegroups.com
is there a way to iterate through a Lens[Seq] ?


On Tuesday, February 17, 2015 at 10:45:38 AM UTC, Johannes Rudolph wrote:

Richard Bowker

unread,
Feb 17, 2015, 10:39:56 AM2/17/15
to spray...@googlegroups.com
i'm asking this because i have the following use case.

i create a Lens[Seq] that matches a number of strings in an array. i need to then perform some work that manipulates each one of these strings, and then replace them in the original positions.

now i can find no mechanism to update each of the lenses with the result of the data. The update method only returns the original string so i cannot correlate that with the result i need to replace them. if i could somenow iterate and zip wit the results i could.

is there a way, or an alternate approach to achieving this?

Johannes Rudolph

unread,
Feb 17, 2015, 12:49:50 PM2/17/15
to spray...@googlegroups.com
Hi Richard,

On Tue, Feb 17, 2015 at 4:39 PM, Richard Bowker
<mechajoh...@googlemail.com> wrote:
> i need to
> then perform some work that manipulates each one of these strings, and then
> replace them in the original positions.

Have you tried `modify`? It seems to do what you are asking for if
every string can be transformed on its own.

> now i can find no mechanism to update each of the lenses with the result of
> the data. The update method only returns the original string so i cannot
> correlate that with the result i need to replace them. if i could somenow
> iterate and zip wit the results i could.

I don't really understand the details of the problem here :) Could you
post an example of input and output json that illustrates the task?

Richard Bowker

unread,
Feb 17, 2015, 12:51:37 PM2/17/15
to spray...@googlegroups.com
yeah, let me try to create a sanitized example to illustrate the task, that should make it easier to describe :)

Richard Bowker

unread,
Feb 17, 2015, 1:39:20 PM2/17/15
to spray...@googlegroups.com
effectively the string alone is not enough to specify the modification, its position in the array also matters, but the only context i get within the modify method is the original string itself, so i'm not sure i can achieve this with this method


On Tuesday, February 17, 2015 at 5:49:50 PM UTC, Johannes Rudolph wrote:

Johannes Rudolph

unread,
Feb 17, 2015, 1:45:14 PM2/17/15
to spray...@googlegroups.com
On Tue, Feb 17, 2015 at 7:39 PM, Richard Bowker
<mechajoh...@googlemail.com> wrote:
> effectively the string alone is not enough to specify the modification, its
> position in the array also matters, but the only context i get within the
> modify method is the original string itself, so i'm not sure i can achieve
> this with this method

This may then be a problem, because a `Lens[Seq]` may not only
represent a simple single json array but may aggregate elements from
several branches (e.g. if you have several `*` in the expression). So,
there's is no clear notion of how to specify the position inside the
whole tree. But I may misunderstand your case so a concrete example
would probably help the most.

Richard Bowker

unread,
Feb 25, 2015, 8:38:01 AM2/25/15
to spray...@googlegroups.com
Hi Johannes, here is some code to illustrate the task i was trying to achieve:

so i provide a list of lenses along with an identifier that is metadata for the "processing function" 

I extract all of the strings that the lenses refer to and gather them into a list, process them (which returns back the processed strings as a list) and then want to replace the results back in the matching places i got them from.

now if there was a way to "iterate" through a Lens[Seq] i could just apply them in the order i have them, rather than this non ideal side effecting hack.

is it possible to do this?

cheers

Rich

  def processLenses(sourceJson: String, metadata: List[(Lens[Seq], String)], processingFunction: List[(String, String)] => Future[String])(implicit ec: ExecutionContext): Future[String] = {
    val jsonAst = sourceJson.parseJson
    val tokenData = metadata.flatMap { case (lens, policy) => jsonAst.extract[String](lens) map { (_, policy)} }

    processingFunction(tokenData).map { results =>
      val mutableStack = mutable.Stack() ++ results

      val sinkJson = metadata.foldLeft(jsonAst) { case (newJsonTree, (lens, result)) =>
        newJsonTree.update(lens ! modify[String](_ => mutableStack.pop)).asJsObject
      }

      sinkJson.prettyPrint
    }
  } 
Reply all
Reply to author
Forward
0 new messages