Pandoc Lua 过滤器:对不显示 table 中的所有键

Pandoc Lua Filters: pairs does not show all keys in table

从Pandoc 2.0版本开始,就有了写Lua Filters的能力。但是,在 Pandoc 2.0 中,我发现在元素 table 上使用 Lua 的 pairs 不会显示 table.

中的所有键

这里有一个最小的例子来说明这一点。在 filter.lua 我有:

function Para(elem)
  io.stderr:write("A: " .. type(elem) .. "\n")
  for k, v in pairs(elem) do
    io.stderr:write("B: " .. k .. "\n")
  end
  io.stderr:write("C: " .. elem["t"] .. "\n")
  io.stderr:write("D: " .. tostring(elem["c"]) .. "\n")
  -- Return elem unchanged
  return nil
end

现在从命令行,我 运行:

echo "Hello." | pandoc -f markdown -t native --lua-filter filter.lua

这会产生输出:

A: table
B: c
C: Para
D: table: 0x53adb40
[Para [Str "Hello."]]

我可以将 -t native 更改为 -t json,以便最后一行变为:

{"blocks":[{"t":"Para","c":[{"t":"Str","c":"Hello."}]}],"pandoc-api-version":[1,17,2],"meta":{}}

所以从 (B) 处的输出来看,c 似乎是 elem 中唯一的键,但从 (C) 处可以清楚地看出 t 也是一个密钥,因为我可以访问它以获取 Para。这里发生了什么,为什么 t 键在 pairs 完成的循环中隐藏了?

t值隐藏在元素的metatable中:pandoc不是为每个元素分配一个t值,而是为每个元素设置一个metatable .这样做的原因是为了在可用性和性能之间找到平衡。

将数字 table 索引返回 Haskell 比访问字符串索引值要快得多。然而,用户应该能够以直接面向对象的方式使用元素,通过可读的字符串属性访问元素组件。这就是我们为每个元素分配 metatables 的原因。 metatable 包含有关元素类型的信息(例如,Plain 与 Para 等)并定义访问器(例如,content 是 Plain 和 Para 元素中索引 0 的别名)。

因此可以通过调用 elem.t 获取元素 elem 的类型,但元素本身没有该键,metatable 有。这就是为什么在使用 pairs 遍历元素时 t 不显示的原因。可以使用 getmetatable 函数接收 metatable.

您可能会喜欢以下获取访问者名称的方法(未记录且可能会更改)。

for k, _ in pairs(getmetatable(elem).getters) do
    print k
end

或者,lua 过滤器文档中关于 "Module pandoc" 的部分列出了每种元素类型的访问器。