如何调整Pandoc Lua过滤器执行顺序,实现Block到Inline信息传递
解决Pandoc Lua过滤器执行顺序问题:先收集脚注再处理链接
核心思路
Pandoc默认按AST节点类型的固定顺序执行过滤器,Link节点会早于BulletList被处理。要打破这个顺序,最可靠的方式是在全局文档处理阶段先主动收集脚注信息,再处理正文里的链接节点,具体有两种落地方式:
- 利用
Pandoc全局入口函数,先遍历所有Block提取脚注数据 - 调用
pandoc.walk函数分两次遍历AST:第一次收集脚注,第二次替换链接
具体实现代码
基于你的需求调整后的完整Lua过滤器:
-- 全局存储脚注ID与内容的映射表 local footnotes = {} function Pandoc(doc) -- 第一步:遍历所有Block,提取脚注信息并移除原脚注列表 local cleaned_blocks = {} for _, block in ipairs(doc.blocks) do if block.t == 'BulletList' then -- 假设BulletList的每个item对应一个脚注,根据你的AST结构调整解析逻辑 for _, item in ipairs(block.content) do local note_id = nil local note_content = {} -- 遍历脚注项内的行内元素,分离ID和内容 for _, inline in ipairs(item[1].content) do if inline.t == 'Link' and inline.target:match('^#fn:') then note_id = inline.target:sub(4) -- 提取"fn:"后的ID部分 else table.insert(note_content, inline) end end if note_id then footnotes[note_id] = note_content end end -- 脚注列表处理后从文档中移除(若需保留可跳过此逻辑) else table.insert(cleaned_blocks, block) end end -- 第二步:遍历所有Link节点,替换为LaTeX脚注命令 local final_blocks = pandoc.walk_block(pandoc.Div(cleaned_blocks), { Link = function(link) local target = link.target -- 匹配正文中的脚注引用链接(格式为#fnref:xxx) if target:match('^#fnref:') then local note_id = target:sub(7) -- 提取"fnref:"后的ID if footnotes[note_id] then -- 将脚注内容转为字符串后包裹成LaTeX命令 return pandoc.RawInline('latex', string.format('\\footnote{%s}', pandoc.utils.stringify(footnotes[note_id]))) end end -- 非脚注链接原样返回 return link end }) -- 返回修改后的文档 return pandoc.Pandoc(final_blocks, doc.meta) end
关键细节说明
- 全局入口优先执行:
Pandoc函数是Pandoc过滤器的最高优先级入口,会在所有节点级过滤器(如单独的Link、BulletList函数)之前运行,确保脚注信息先被收集完毕。 - AST遍历逻辑适配:代码中的脚注解析逻辑需根据你的实际AST结构调整,比如脚注ID的提取规则、内容的组成元素等。
- LaTeX命令生成:用
RawInline包裹LaTeX脚注命令,确保Pandoc输出时直接保留该格式。
对应AST结构参考
你的XHTML转换后AST结构大致如下:
正文中的脚注引用Link节点:
Link { attr = {"", [], [("href", "#fnref:1")]}, content = [Str "1"], target = "#fnref:1", title = "" }正文末尾的脚注BulletList节点:
BulletList { content = { Plain { content = { Link { attr = {"fn:1", [], [("href", "#fnref:1")]}, content = [Str "1"], target = "#fnref:1", title = "" }, Space, Str "这是脚注的具体内容。" } } } }
内容的提问来源于stack exchange,提问作者Carl Sorensen
相关产品推荐
相关产品推荐

