在 LaTeX 中解析 JSON 的方法?

在 LaTeX 中解析 JSON 的方法?

我正在用 JSON 在一个小型文本文件中编写我的食谱(食物)。有没有办法在 LaTeX 中解析它?我知道有很多处理食谱的模板,但我想有自己的风格,可以快速改变,例如我妈妈对卡路里之类的东西不感兴趣 :)

以下是一个简单的例子:

{
"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"},
        {"step":"Add nuts"}
    ]
}
}

答案1

虽然问题是关于在 LaTeX 中解析 JSON,但由于 OP 想要“有自己的风格,而且变化很快”,我将提供一个 ConTeXt 解决方案,以简化操作。

ConTeXt 已经提供了 JSON 解析器。要使用它,只需加载

\usemodule[json]

然后,您可以使用 Lua 函数utilities.json.tolua 将 JSON 字符串转换为 Lua 表,并使用 Lua 函数utilities.json.tostring将 Lua 表转换为 JSON 字符串。

使用以下方式排版 Lua 表非常简单:ConTeXt Lua 文档.以下是完整示例:

\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

现在您可以简单地定义一个 TeX 宏来将其参数传递给 Lua 函数。

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

让我们添加一些最小样式来格式化节头。与所有 ConTeXt 文档一样,您可以使用适当的命令更改格式\setup...

\setuphead[subject][style=\bfb]
\setuphead[subsubject][style=\bfa]

最后,主要文件

\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"},
              {"step":"Add nuts"}
          ]
      }
    } 

\stoptext

这使

在此处输入图片描述

答案2

尝试这个:

\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"},
        {"step":"Add nuts"}
    ]
}
}
\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')
        s = f:read('*a')
        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}

它应该给你这个:

在此处输入图片描述

格式化是使用检查方法完成的,该方法使用一个\mbox{~~}来隔开括号。

答案3

和往常一样,我错过了大卫的评论,所以我的想法并非 100% 原创。:)正如大卫在聊天室中所说,他潜意识地给了我一个暗示,这证明他的力量超出了理解范围,而鸭子通常并不以理解能力而闻名。:)

警告 注意力:lualibs虽然我的答案有效,但请青睐 Yiannis 的答案,因为它使用了LuaTeX 中可用的标准模块。

我将使用 LuaTeX 提供一个幼稚的答案,只是为了让事情尽快发挥作用。:)

首先要做的事情:得到这个用纯 Lua 编写的简单 JSON 编码器/解码器来自 Jeffrey Friedl 的网站。该文件是独立的,名为JSON.lua。保存到您的工作目录。

Jeffrey 的代码是根据 Creative Commons Attribution 3.0 Unported License 发布的。

在同一级别,将 JSON 文件保存为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"},
            {"step":"Add nuts"}
        ]
    }
}

最后,但并非最不重要的是我们的 TeX 文件(例如recipes.tex):

\documentclass{article}

\usepackage{luacode}

\begin{document}

\begin{luacode}
function read(file)
    local handler = io.open(file, "rb")
    local content = handler:read("*all")
    handler:close()
    return content
end
JSON = (loadfile "JSON.lua")()
local table = JSON:decode(read("recipes.json"))
tex.print(table['recipe']['title'])
\end{luacode}

\end{document}

使用以下方式运行文件

$ lualatex recipes.tex

结果:

食谱

享受!:)

答案4

以下是与 TeX Live 2020 (LuaHBTeX 1.12.0) 兼容的最新示例。第一个示例受到 Paulo cerreda 的回答的启发,但不依赖于外部工具。如果test.json您的 tex 文档旁边有一个包含 OP 配方的文件,那么

% !TEX encoding = UTF-8
% !TEX program = Lualatex

\documentclass{scrbook}
\usepackage{luacode}
\begin{document}
\begin{luacode}
require("lualibs.lua")
local f = io.open('test.json', 'r')
local s = f:read('*a')
f:close()
tab =  utilities.json.tolua(s)
\end{luacode} 
\luadirect{tex.sprint(tab['recipe']['title'])}
\end{document}

将排版为“First recipe”。请注意,这tab是一个全局 Lua 变量,稍后可以访问。

第二个例子来自 Yiannis Lazarides 的回答,它已被修复和简化以帮助 Lua 初学者,但给出相同的输出。

% !TEX encoding = UTF-8
% !TEX program = Lualatex
\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"},
        {"step":"Add nuts"}
    ]
}
}
\end{filecontents*}
\begin{document}
\begin{luacode}
local f = io.open('test.json', 'r')
local s = f:read('*a')
f:close()
require("lualibs.lua")
local tab =  utilities.json.tolua(s)
local openbracket = "\\{"
local closebracket = "\\mbox{..}\\}"
local par = "\\par"
local prettyprint
prettyprint = function (tab, prefix)
  for k, v in pairs (tab) do
    local newprefix = prefix .. "\\mbox{~~}"
    if type(v) == "table" then
      tex.print(prefix .. k .. " = " .. openbracket .. par)
      prettyprint(v, newprefix)
      tex.print(prefix .. closebracket .. par)
    elseif k == "data" then
      tex.print(prefix.."k = char data ")
    else
      tex.print(prefix..k.." =  ".. tostring(v), "\\par") 
    end
  end
end
prettyprint(tab, '')
\end{luacode} 
\end{document}

注意f.close(): Yiannis 的回答有错误。

相关内容