Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing and generating JSON

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?

like image 377
Pillsy Avatar asked Apr 13 '10 20:04

Pillsy


1 Answers

UPDATE: As noted in Pillsy's answer, JSON is a built-in format for Import and Export as of Mathematica 8: http://reference.wolfram.com/mathematica/ref/format/JSON.html. But, as discussed in the comments, the following seems to be a more robust solution as of Mathematica 10.4.1:

WARNING: This involves doing an eval (ToExpression) so don't use this to parse strings from untrusted sources.

First, 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. (Also need a few more substitutions for null, true, false, and scientific notation.)

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. (PS: Coming back to this later, I'm actually pretty pleased with the cleverness of that, and it seems to be perfectly robust. Magic strings FTW!)

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_String] := With[{tr = {"["     -> "(*_MAGIC__[__*){",
                                      "]"     -> "(*_MAGIC__]__*)}",
                                      ":"     -> "(*_MAGIC__:__*)->",
                                      "true"  -> "(*_MAGIC__t__*)True",
                                      "false" -> "(*_MAGIC__f__*)False",
                                      "null"  -> "(*_MAGIC__n__*)Null",
                                      "e"     -> "(*_MAGIC__e__*)*10^",
                                      "E"     -> "(*_MAGIC__E__*)*10^"}},
  eval@StringReplace[cat@FullForm@eval[StringReplace[json, tr]], Reverse/@tr]]

(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, as well as another utility function for displaying numbers in a JSON-appropriate way):

re = RegularExpression;
jnum[x_] := StringReplace[
  ToString@NumberForm[N@x, ExponentFunction->(Null&)], re@"\\.$"->""]

genJSON[a_ -> b_]  := genJSON[a] <> ":" <> genJSON[b]
genJSON[{x__Rule}] := "{" <> cat @@ Riffle[genJSON /@ {x}, ", "] <> "}"
genJSON[{x___}]    := "[" <> cat @@ Riffle[genJSON /@ {x}, ", "] <> "]"
genJSON[Null]      := "null"
genJSON[True]      := "true"
genJSON[False]     := "false"
genJSON[x_]        := jnum[x] /; NumberQ[x]
genJSON[x_]        := "\"" <> StringReplace[cat[x], "\""->"\\\""] <> "\""
like image 169
dreeves Avatar answered Oct 19 '22 12:10

dreeves