Pandoc自定义Lua编写器使用RawBlock报all choices failed错误咨询
问题根本原因
pandoc的AST(抽象语法树)有严格的嵌套类型规则:
Math元素无论属于DisplayMath(块级展示公式)还是InlineMath(行内公式),本身都被归类为行内元素(Inline),默认嵌套在Para(段落)、Plain(纯文本块)这类块级元素的内容列表里。- 过滤器回调的返回值必须和处理节点的类型匹配:处理行内元素的回调,只能返回行内元素、行内元素列表,不能直接返回块级元素;处理块级元素的回调同理。
你原来的代码在Math这个行内元素的处理回调里直接返回RawBlock(块级元素),相当于往仅允许放行内元素的位置插入了块级节点,导致AST结构非法,pandoc遍历校验时找不到匹配的合法节点类型,就会抛出all choices failed的类型匹配错误。
你之前测试把RawBlock换成RawInline加换行能正常运行,本质是因为返回值类型回到了行内元素范畴,符合类型校验规则,但这种写法属于临时兼容:块级公式会被保留在原段落结构里,遇到公式前后存在其他文本的场景,很容易出现换行错乱、公式和正文粘连的问题。
正确实现方法
块级公式的正确处理逻辑是:先在块级节点层面识别「仅包含单个块级展示公式的段落」,把整个段落替换为RawBlock;剩余的行内公式、未单独成段的展示公式,再在行内层面用RawInline包裹,修正后的完整代码如下:
function Writer (doc, opts) local filter = { -- 块级处理:替换单独成段的块级公式 Para = function(elem) -- 判断当前段落是否只包含一个DisplayMath类型的数学元素 if #elem.content == 1 and elem.content[1].t == "Math" and elem.content[1].mathtype == "DisplayMath" then local math_content = elem.content[1].text -- 这里直接返回块级RawBlock,符合Para作为块级节点的返回类型要求 return pandoc.RawBlock('markdown', '$$\n' .. math_content .. '\n$$') end -- 不符合条件的段落不做修改 return nil end, -- 行内处理:处理所有行内场景的数学公式 Math = function(elem) local delimiter = "$$" return pandoc.RawInline('markdown', delimiter .. elem.text .. delimiter) end } return pandoc.write(doc:walk(filter), 'markdown', opts) end
使用修正后的代码执行原转换命令,既不会触发类型报错,也能保证单独成段的块级公式输出格式符合kramdown的解析规则,不会出现换行错乱问题。
内容的提问来源于stack exchange,提问作者asmaier
相关产品推荐
相关产品推荐

