在Pandoc Lua扩展中将Span转为BulletList,适配PDF与HTML
解决跨格式的链接列表生成问题
核心思路
问题根源是你试图在内联元素处理流程里生成块级列表,这违反了Pandoc的文档模型规则(块元素不能嵌套在内联元素中)。正确的处理逻辑是:
- 在内联元素阶段捕获目标链接并存入全局表
- 在块元素阶段找到标记为
Sources的块,将其替换为标准的列表块(BulletList/OrderedList),让Pandoc自动适配HTML、PDF等输出格式
完整Lua扩展代码
-- 全局表存储捕获到的链接,结构:{ {text = "链接文本", url = "链接地址"}, ... } local captured_links = {} -- 处理内联元素:捕获特定样式的Span并转为Link function Inline(inline) if inline.t == "Span" then local style = inline.classes[1] -- 匹配Word转换后的自定义样式(空格通常转成连字符,需根据实际转换结果调整) if style == "Link-to-Artifact" or style == "Hyperlink" then local link_text = pandoc.utils.stringify(inline.content) local link_url = "" -- 提取链接地址:优先从Span内的Link元素取,再从属性取 for _, elem in ipairs(inline.content) do if elem.t == "Link" then link_url = elem.target break end end if link_url == "" then link_url = inline.attributes.href or "" end -- 有效链接存入全局表 if link_url ~= "" then table.insert(captured_links, {text = link_text, url = link_url}) end -- 返回转换后的Link元素替换原Span return pandoc.Link(inline.content, link_url) end end return inline end -- 处理块元素:替换Sources样式的块为列表 function Block(block) -- 匹配带有Sources自定义样式的段落块 if block.t == "Para" and block.classes[1] == "Sources" then local list_items = {} -- 把每个链接转为列表项(Para块包裹Link元素) for _, link in ipairs(captured_links) do local link_elem = pandoc.Link(pandoc.Str(link.text), link.url) table.insert(list_items, {pandoc.Para{link_elem}}) end -- 生成无序列表(要有序列表就换成pandoc.OrderedList(list_items)) local sources_list = pandoc.BulletList(list_items) -- 清空全局表,避免后续重复生成 captured_links = {} -- 返回列表块替换原Sources块 return sources_list end return block end -- 注册过滤器 return { {Inline = Inline}, {Block = Block} }
关键说明
- 样式匹配调整:Word自定义样式转Markdown时,空格一般会转为连字符(比如
Link to Artifact→Link-to-Artifact),你需要对照实际转换后的Markdown内容调整style的判断值。 - 链接地址提取:如果Word超链接转换后,Span内部直接包含
Link元素,代码已处理这种情况;如果链接地址存在于Span的属性中,调整inline.attributes.href的对应键名即可。 - 跨格式适配:生成的
BulletList/OrderedList是Pandoc原生块元素,会自动被转换为HTML的<ul>/<ol>或PDF的对应列表格式,无需依赖RawHTML。 - 块替换逻辑:直接将
Sources样式的段落块替换为列表块,完全符合Pandoc的文档模型,不会出现块/内联嵌套的问题。
内容的提问来源于stack exchange,提问作者dmonder
相关产品推荐
相关产品推荐

