Parsing JSON POST

32 views
Skip to first unread message

fbettag

unread,
Jul 14, 2009, 11:11:02 AM7/14/09
to Lift
Heyho,

any ideas how i can parse data that was posted as JSON?
For example:
{foo: [{bar: 'shiz'}, {bar: 'baz']}

best regards

Timothy Perrett

unread,
Jul 14, 2009, 12:38:57 PM7/14/09
to Lift
How about net.liftweb.util.JSONParser ?

There are also 3rd party JSON parser implementations written in scala
such as:

http://github.com/jonifreeman/literaljson/tree

Cheers, Tim

Jeppe Nejsum Madsen

unread,
Jul 14, 2009, 12:59:33 PM7/14/09
to lif...@googlegroups.com
fbettag <fr...@bett.ag> writes:

The above is not strictly JSON, but JSONParser.parse seems to handle
this as well:

scala> import net.liftweb.util._
import net.liftweb.util._

scala> JSONParser.parse("{foo: [{bar: 'shiz'}, {bar: 'baz']}")
res0: net.liftweb.util.Box[Any] = Full(Map(foo -> List(Map(bar -> shiz))))

/Jeppe

fbettag

unread,
Jul 15, 2009, 3:01:43 AM7/15/09
to Lift
I just noticed i forgot a } after 'baz' ;)

Thanks for your replies

fbettag

unread,
Jul 15, 2009, 4:01:35 AM7/15/09
to Lift
Ok, i found out that the POSTed JSON was in S.params("results").first,
which contains:

Full(Map(name -> New Content, language -> en, content -> , id -> ext-
record-1))

So i tried this:
for ((key, value) <- JSONParser.parse(S.params("results").first)) {
Log.error(key + " -> " + value)
}

But it doesn't go through the loop. I guess it has something to do
with the Full() around the Map.
I tried .elements on the returned Full() for an iterable, but it still
doesn't run through the loop.

Any ideas?

Jeppe Nejsum Madsen

unread,
Jul 15, 2009, 4:20:38 AM7/15/09
to lif...@googlegroups.com
On Wed, Jul 15, 2009 at 10:01 AM, fbettag<fr...@bett.ag> wrote:
>
> Ok, i found out that the POSTed JSON was in S.params("results").first,
> which contains:
>
> Full(Map(name -> New Content, language -> en, content -> , id -> ext-
> record-1))
>
> So i tried this:
>        for ((key, value) <- JSONParser.parse(S.params("results").first)) {
>                Log.error(key + " -> " + value)
>        }
>
> But it doesn't go through the loop. I guess it has something to do
> with the Full() around the Map.
> I tried .elements on the returned Full() for an iterable, but it still
> doesn't run through the loop.
>
> Any ideas?

If S.params("results") contain


Full(Map(name -> New Content, language -> en, content -> , id -> ext-
> record-1))

It seems like it's already parsed, in which case you could do

for (results <- S.params("results"); (key, value) <-results) {


Log.error(key + " -> " + value)
}

/Jeppe

fbettag

unread,
Jul 15, 2009, 4:51:29 AM7/15/09
to Lift
Args Sorry, the Full(Map(..)) gets returned by the JSON Parser.

for (res <- JSONParser.parse(S.params("results").first); (key, value)
<- res) {
Log.error(key + " -> " + value)
}

Anyhow it still doesn't run through the loop. This stuff is really
over-complicated.

marius d.

unread,
Jul 15, 2009, 5:22:01 AM7/15/09
to Lift
Try using for comprehensions

for (res <- JSONParser.parse(S.params("results").first);
(key, value) <- res) yield some_expression

Marius

fbettag

unread,
Jul 15, 2009, 5:27:16 AM7/15/09
to Lift
Any variation i try gives me:

(key, value) <- res
value filter is not a member of Any

fbettag

unread,
Jul 15, 2009, 7:06:36 AM7/15/09
to Lift
For future reference:

JSONParser.parse(S.params("results").first) match {
case Full(res: Map[String, String]) => {
try { obj.name(res("name")) } catch { case e => }
try { obj.content(res("content")) } catch { case e => }
try { obj.language(res("language")) } catch { case e => }

try {
obj.save
OkResponse()
} catch {
case e => Log.error("Could not save content", e);
InternalServerErrorResponse()
}
}
case _ => BadResponse()

Jeppe Nejsum Madsen

unread,
Jul 15, 2009, 8:00:15 AM7/15/09
to lif...@googlegroups.com
On Wed, Jul 15, 2009 at 11:27 AM, fbettag<fr...@bett.ag> wrote:
>
> Any variation i try gives me:
>
> (key, value) <- res
> value filter is not a member of Any

Ahh yes, JSONParser.parse returns Box[Any] since the result can be
either a list or a map. Still, you can do it like this

for (res <- S.params("results"); json <- JSONParser.parse(res)) json match {
case m: Map[_,_] => for((k,v) <- m) k match {
case "foo" => println("Found foo %s".format(v))
case y => println("Something else: %s".format(y))
}
case x => println("Didn't parse a map: %s".format(x))
}

/Jeppe

David Pollak

unread,
Jul 16, 2009, 4:10:20 PM7/16/09
to lif...@googlegroups.com
You can use:

Box.asA[Map[String, _]](in) which will return Full(in) if in is a Map[String, _] or Empty if it's not.  This helps in for comprehensions.
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

Jeppe Nejsum Madsen

unread,
Jul 17, 2009, 2:59:02 AM7/17/09
to lif...@googlegroups.com
David Pollak <feeder.of...@gmail.com> writes:

> You can use:
> Box.asA[Map[String, _]](in) which will return Full(in) if in is a
> Map[String, _] or Empty if it's not. This helps in for comprehensions.

Ah, didn't know that. Very nice!

/Jeppe

fbettag

unread,
Jul 24, 2009, 11:57:01 PM7/24/09
to Lift
Still one problem when parsing:

results: {"name":"New Content","language":"en","content":"","layout":
22}

java.lang.NumberFormatException: For input string: "22.0"
at java.lang.NumberFormatException.forInputString
(NumberFormatException.java:48)
at java.lang.Long.parseLong(Long.java:412)
at java.lang.Long.parseLong(Long.java:461)
at scala.runtime.RichString.toLong(RichString.scala:214)



def addOrUpdateContent(inContentid: String): LiftResponse = {
val obj = Content.find(By(Content.id, inContentid.toLong)) openOr
new Content

JSONParser.parse(S.params("results").first) match {
case Full(res: Map[String, String]) => {
try {
obj.name(res.getOrElse("name", obj.name).toString)
.content(res.getOrElse("content", obj.content).toString)
.language(res.getOrElse("language", obj.language).toString)
.layout(res.getOrElse("layout", obj.layout).toString.toLong)
.content(res.getOrElse("content", obj.content).toString)
.save
JsonResponse(JsObj("result" -> obj.asJs))
} catch {
case e => {
Log.error("Could not save content", e)
InternalServerErrorResponse()
}
}
}
case _ => BadResponse()
}
}

any ideas? the POST content is right, the parsing is b0rkst
somewhere :s

On 17 Jul., 08:59, Jeppe Nejsum Madsen <je...@ingolfs.dk> wrote:

David Pollak

unread,
Jul 29, 2009, 8:05:33 PM7/29/09
to lif...@googlegroups.com

The issue is that you're converting a Number (which is probably a Double) into a String and then parsing it as a Long and the Long parser is getting confused by the "." in the toString'ed Double.

I'd suggest writing a bit of code that uses Box'es/Option's and implicits to help you unpack the object in a type-safe manner.  There are already some examples in this thread.  If you need more examples or more concrete code, please let us know.
 


On 17 Jul., 08:59, Jeppe Nejsum Madsen <je...@ingolfs.dk> wrote:
> David Pollak <feeder.of.the.be...@gmail.com> writes:
> > You can use:
> > Box.asA[Map[String, _]](in) which will return Full(in) if in is a
> > Map[String, _] or Empty if it's not.  This helps in for comprehensions.
>
> Ah, didn't know that. Very nice!
>
> /Jeppe

Reply all
Reply to author
Forward
0 new messages