views:

280

answers:

2

Mathematica's list of built-in formats is pretty extensive; however, JSON is not on that list. Is there an existing solution for generating and parsing JSON in Mathematica, or are we going to have to roll our own solution?

+3  A: 

This guy has a clever example of parsing JSON code in Mathmatica

Jweede
I think that's just pulling the numbers out a JSON expression though, right?
dreeves
yep. That's the great thing about JSON, so easy to parse.
Jweede
Yeah, I love JSON. By "just pulling the numbers out [of] a JSON expr" I meant as opposed to fully parsing it, into an isomorphic nested Mathematica expression. My answer attempts to do that.
dreeves
very true, this is why I voted your answer up. :)
Jweede
+4  A: 

Great question! A really quick-and-dirty partial solution to JSON parsing would be this:

ToExpression[StringReplace[json, {"["->"{", "]"->"}", ":"->"->"}]]

Ie, just replace square brackets with curly braces and colons with arrows and then eval it. All that remains is to not do those substitutions inside of strings.

There's probably a more elegant solution to the not-within-strings problem, but the first thing to come to mind is to do substitutions like "{"->"(*MAGICSTRING*){" and then, after the eval (when comments outside of strings will have disappeared), reverse those substitutions.

That's slightly easier said than done but the following JSON parser seems to work:

cat = StringJoin@@(ToString/@{##})&;          (* Like sprintf/strout in C/C++. *)
eval = ToExpression;            (* Mathematica function names are too verbose! *)

parseJSON[json_] := eval@StringReplace[cat@FullForm@eval[StringReplace[json, 
  {"[" -> "(*MAGIC[*){", 
   "]" -> "(*MAGIC]*)}", 
   ":" -> "(*MAGIC:*)->"}]], 
  {"(*MAGIC[*){" -> "[", 
   "(*MAGIC]*)}" -> "]", 
   "(*MAGIC:*)->" -> ":"}]

(cat and eval are convenience functions. Simply cat = ToString would work in this case but I like this more general version that concatenates all its arguments into a string.).

Finally, here's a function to generate JSON (which does need the more general cat):

genJSON[x_String] := "\"" <> cat[x] <> "\""
genJSON[x_] := cat[x] /; NumberQ[x]
genJSON[a_ -> b_] := genJSON[a] <> ":" <> genJSON[b]
genJSON[{x__Rule}] := "{" <> cat @@ Riffle[genJSON /@ {x}, ", "] <> "}"
genJSON[{x___}] := "[" <> cat @@ Riffle[genJSON /@ {x}, ", "] <> "]"
genJSON[x_] := cat[x]
dreeves
@Pillsy, let us know if this works for you or if you find any bugs or make improvements. Your answers have been incredibly helpful to me so I was eager to repay the favor!
dreeves