# Ways to parse JSON in LaTeX?

I'm writing my recipes (food) in a small textfile in JSON. Are there any ways to parse this in LaTeX? I know, that are lots of templates dealing with recipes, but I want to have my own style, which can be change very fast e.g. my mother is not interested in stuff like calories :)

Here is one simple example:

{
"recipe": {
"title":"First recipe",
"source":"My first cookbook",
"carbs":"1 oz",
"fat":"1 oz",
"protein":"1 oz",
"cal":"100 kcal",
"ingredients": [
{"item":"Eggs"},
{"item":"Oil"},
{"item":"Nuts"}
],
"cooking": [
{"step":"Mix eggs and oil"},
]
}
}

• Can you make a small example? – egreg Jan 11 '15 at 11:26
• Are you aware of tex.blogoverflow.com/2012/10/… ? – DG' Jan 11 '15 at 11:35
• I'd added one example. – user3417078 Jan 11 '15 at 21:09
• In order to help the readers, it would be useful to know if all recipes must have entries for all these keywords, or if some may be missing from some recipes. – Steven B. Segletes Jan 11 '15 at 21:24
• @StevenB.Segletes JSON has an exceptionally simple grammar, see the railroad diagrams at json.org – David Carlisle Jan 11 '15 at 21:31

Although the question is about parsing JSON in LaTeX, since the OP wants to "have my own style, which can be change very fast", I'll give a ConTeXt solution for its simplicity.

ConTeXt already comes up with a parser for JSON. To use it, simply load

\usemodule[json]


Then, you can use the Lua function utilities.json.tolua to convert JSON string to Lua table and the Lua function utilities.json.tostring to convert a Lua table to a JSON string.

It is very simple to typeset Lua tables using ConTeXt Lua Document. Here is a complete example:

\usemodule[json]
\startluacode

userdata = userdata or {}
local json = utilities.json

userdata.show_recipe = function(recipe)

local lua_recipe  = json.tolua(recipe).recipe
local ingredients = lua_recipe.ingredients
local cooking     = lua_recipe.cooking

context.subject(lua_recipe.title)

local show_value = function(value)
context.NC() context(value)
context.EQ() context(lua_recipe[value])
context.NC() context.NR()
end

context.starttabulate()
show_value("source")
show_value("carbs")
show_value("protein")
show_value("cal")
context.stoptabulate()

context.subsubject("Ingredients")
context.startitemize{"packed, intro"}
for i = 1,#ingredients do
context.startitem()
context(ingredients[i].item)
context.stopitem()
end
context.stopitemize()

context.subsubject("Cooking")
context.startitemize{"packed, intro"}
for i = 1,#cooking do
context.startitem()
context(cooking[i].step)
context.stopitem()
end
context.stopitemize()

end
\stopluacode


Now you can simply define a TeX macro to pass its argument to the Lua function.

% Note that I use the braces around #1 to make the input
% syntax slightly simpler
\define[1]\Recipe
{\ctxlua{userdata.show_recipe([==[{#1}]==])}}


Let's add some minimal styling to format the section heads. As with all ConTeXt documents, you can change the format by using appropriate \setup... command.

\setuphead[subject][style=\bfb]


Finally, the main document

\starttext

\Recipe
{
"recipe": {
"title":"First recipe",
"source":"My first cookbook",
"carbs":"1 oz",
"fat":"1 oz",
"protein":"1 oz",
"cal":"100 kcal",
"ingredients": [
{"item":"Eggs"},
{"item":"Oil"},
{"item":"Nuts"}
],
"cooking": [
{"step":"Mix eggs and oil"},
]
}
}

\stoptext


which gives

Try this:

\documentclass{scrbook}
\usepackage{luacode}

\begin{filecontents*}{test.json}
{
"recipe": {
"title":"First recipe",
"source":"My first cookbook",
"carbs":"1 oz",
"fat":"1 oz",
"protein":"1 oz",
"cal":"100 kcal",
"ingredients": [
{"item":"Eggs"},
{"item":"Oil"},
{"item":"Nuts"}
],
"cooking": [
{"step":"Mix eggs and oil"},
]
}
}
\end{filecontents*}

\begin{document}

\begin{luacode}
--  We use the lualibs built-in modules
--  this loads all the modules including a json converter
--

local M = M or {}

require("lualibs.lua")

-- @json file
function getjsonfile (file)
local f, s
f = io.open(file, 'r')
f.close()
return s
end

local s =  utilities.json.tolua(getjsonfile('test.json'))

local rep, write = string.rep, tex.print

function M.inspect (tab, offset)
local openbracket, closebracket, par = "\\{", "\\mbox{..}\\}", "\\par"

offset = offset or ""
for k, v in pairs (tab) do
local newoffset = offset .. "\\mbox{~~}"
if type(v) == "table" then
write(offset .. k .. " = " .. openbracket .. par)
M.inspect(v, newoffset)
write(offset .. closebracket .. par)
else
if k~="data" then write(offset..k.." =  ".. tostring(v), "\\par")
else
write(offset.."k = char data ")
end
end
end
end

tex.print(M.inspect(s))
\end{luacode}

\end{document}


It should give you this:

The formatting is done using an inspect method that uses an \mbox{~~} to space the brackets out.

• Does the lualibs module load the same JSON parser that is included as util-jsn.lua in the ConTeXt distribution? – Aditya Jan 12 '15 at 1:53
• @Aditya It is very simialr github.com/phi-gamma/lualibs. They are based on the ConTeXt ones. – Yiannis Lazarides Jan 12 '15 at 4:39
• @Aditya It’s the same code, just not updated as frequently. – Philipp Gesang Jan 15 '15 at 6:21

As always, I missed David's comment, so my idea is not 100% original. :) As David said in the chatroom, he subliminally gave me a hint, which proves his powers are beyond comprehension, and that ducks aren't noted for their powers of comprehension normally. :)

Attention: Although my answer works, please favour Yiannis' answer since it uses a module from the standard lualibs available in LuaTeX.

I'll provide a naive answer using LuaTeX just to get things working as quickly as possible. :)

First things first: get this simple JSON encoder/decoder written in pure Lua from Jeffrey Friedl's site. The file is self-contained and it's named JSON.lua. Save to your working directory.

Jeffrey's code is released under a Creative Commons Attribution 3.0 Unported License.

At the very same level, save your JSON file as, say, recipes.json:

{
"recipe": {
"title":"First recipe",
"source":"My first cookbook",
"carbs":"1 oz",
"fat":"1 oz",
"protein":"1 oz",
"cal":"100 kcal",
"ingredients": [
{"item":"Eggs"},
{"item":"Oil"},
{"item":"Nuts"}
],
"cooking": [
{"step":"Mix eggs and oil"},
]
}
}


At last, but not least, our TeX file (e.g, recipes.tex):

\documentclass{article}

\usepackage{luacode}

\begin{document}

\begin{luacode}
local handler = io.open(file, "rb")
handler:close()
return content
end
tex.print(table['recipe']['title'])
\end{luacode}

\end{document}


\$ lualatex recipes.tex

Enjoy! :)
• @YiannisLazarides: it is? Oh my, I'm a silly duck! :) Let me try here and I will update the answer. Thanks, Yiannis! :) – Paulo Cereda Jan 11 '15 at 21:59
• @Yiannis: You were absolutely right, there is a JSON parser in LuaLibs! :) Sadly, I cannot load it (according to the documentation, it's in the "extended set"), even after trying a couple of settings. Do you know how we could use it? – Paulo Cereda Jan 11 '15 at 22:10