[Tex/LaTex] How to loop over the JSON object / list

jsonloopsluatex

I want to loop over section in the following JSON and print name the number of times it appears under section. How could I do this?

{
  "ID": "23",
  "section": [
      {
          "name": "A",
          "text": "This is the start of section",
          "subsection": [
            {
             name: "Sub section AA",
             text: " This is some text"
            },
            {
             name: "Sub section BB",
             text: " This is some text"
            }
          ]
      },
      {
          "name": "B", 
          "text": "This is the start of the section",
          "subsection": [
             {
               name: "Sub section EE",
               text: " This is some text"
             },
             {
               name: "Sub section DD",
               text: " This is some text"
            }
           ]
      }
  ]
}

Here is how I am reading and parsing the JSON:

\documentclass{report}
\usepackage{luacode}
% load json file
\begin{luacode}
    local json = require("json")
    local file = io.open("sample.json")
    tab = json.parse(file:read("*all"))
    file:close()
\end{luacode}

\begin{document}

The ID of the document is \directlua{tex.print(tab['ID'])}

Here is the list of all the sections:

\end{document}

json.lua file that parses the JSON (Taken from answer by Henri Menke):

    local lpeg = assert(require("lpeg"))
local C, Cf, Cg, Ct, P, R, S, V =
    lpeg.C, lpeg.Cf, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.R, lpeg.S, lpeg.V

-- number parsing
local digit    = R"09"
local dot      = P"."
local eE       = S"eE"
local sign     = S"+-"^-1
local mantissa = digit^1 * dot * digit^0 + dot * digit^1 + digit^1
local exponent = (eE * sign * digit^1)^-1
local real     = sign * mantissa * exponent / tonumber

-- optional whitespace
local ws = S" \t\n\r"^0

-- match a literal string surrounded by whitespace
local lit = function(str)
    return ws * P(str) * ws
end

-- match a literal string and synthesize an attribute
local attr = function(str,attr)
    return ws * P(str) / function() return attr end * ws
end

-- JSON grammar
local json = P{
    "object",

    value =
        V"null_value" +
        V"bool_value" +
        V"string_value" +
        V"real_value" +
        V"array" +
        V"object",

    null_value =
        attr("null", nil),

    bool_value =
        attr("true", true) + attr("false", false),

    string_value =
        ws * P'"' * C((P'\\"' + 1 - P'"')^0) * P'"' * ws,

    real_value =
        ws * real * ws,

    array =
        lit"[" * Ct((V"value" * lit","^-1)^0) * lit"]",

    member_pair =
        Cg(V"string_value" * lit":" * V"value") * lit","^-1,

    object =
        lit"{" * Cf(Ct"" * V"member_pair"^0, rawset) * lit"}"
}

return { parse = function(str) return assert(json:match(str)) end }

Update:

I am trying to add dynamic sections / sub-sections using the for loop. For example,

\section{ A }
  This is the A section
   \addcontentsline{toc}{section}{ Some Sub Section }
   \addcontentsline{toc}{section}{Another Sub Section}

\section{ B }
  This is the B section
\section{ C }
  This is the C section

Like sections and sub-sections, I will also dynamically generate tables from the JSON read.

Best Answer

You can just iterate over the returned Lua table:

enter image description here

\documentclass{report}
\usepackage{luacode}
% load json file
\begin{luacode}
    local json = require("json")
    local file = io.open("sample.json")
    tab = json.parse(file:read("*all"))
    file:close()
\end{luacode}

\begin{document}

The ID of the document is \directlua{tex.print(tab['ID'])}

Here is the list of all the sections:
\directlua{
for i,k in ipairs(tab["section"]) do
 if (i>1) then
     tex.sprint (", ")
 end
     tex.sprint (k.name)
end
}
\end{document}

enter image description here

The updated json was invalid, I assume this was intended:

{
    "ID": "23",
    "section": [
    {
            "name": "A",
            "text": "This is the start of section",
            "subsection": [
        {
            "name": "Sub section AA",
            "text": " This is some text"
        },
        {
            "name": "Sub section BB",
            "text": " This is some text"
        }
            ]
    },
      {
          "name": "B", 
          "text": "This is the start of the section",
          "subsection": [
              {
          "name": "Sub section EE",
          "text": " This is some text"
              },
              {
          "name": "Sub section DD",
                  "text": " This is some text"
              }
          ]
      }
    ]
}

So just change the Lua iterations to

\documentclass{report}
\usepackage{luacode}
% load json file
\begin{luacode}
    local json = require("json")
    local file = io.open("sample.json")
    tab = json.parse(file:read("*all"))
    file:close()
\end{luacode}

\begin{document}

The ID of the document is \directlua{tex.print(tab['ID'])}

\chapter{zzz}

\directlua{
for i,k in ipairs(tab["section"]) do
     tex.print ("\string\\section{" .. k.name .. "}")
     tex.print (k.text)
  for ii,kk in ipairs(k["subsection"]) do
     tex.print ("\string\\subsection{" .. kk.name .. "}")
     tex.print (kk.text)
end
end
}
\end{document}

A more complete version would need to escape any tex-special characters and guard against empty fields.

Related Question