如何在Pandoc的 Lua过滤器中把信息从块级元素传递到行内元素

编程语言 2026-07-08

我正在使用pandoc处理一个xhtml文件。该文件包含脚注,脚注在正文中以指向未在正文中的元素的链接来标记。

在AST中,脚注包含在紧随正文文本之后的BulletList中。

我正在转换为LaTeX,且希望正文中的链接被替换为LaTeX的脚注命令。

为了获取脚注的文本,我创建了一个函数,扫描BulletList,并创建一个Lua表,其中包含目标字符串和脚注文本字符串。BulletList函数执行时,这个Lua表已被创建。但不幸的是,由于过滤器函数的默认执行顺序,Link函数在BulletList函数之前执行,导致Lua表为空。

我读到可以在Pandoc Lua Filters中修改过滤器的执行顺序,但我还没搞清楚具体怎么实现。希望得到一些帮助。

这是我的lua过滤器:

 footnotes = {}

 function BulletList (elem)
   local note_count = 0
   local bList = elem.content
   local label
   print ("In BulletList")
   for k, v in ipairs(bList) do
     label = v[1].content[1].identifier
     local note_text
     for kk, vv in ipairs(v[3].content) do
     local this_text
       for kkk, vvv in ipairs(vv.content) do
          if vvv.tag == "Link" then
           this_text =  vvv.content
          else
           this_text = vvv
          end
          if note_text == nil then
             note_text = pandoc.Inlines(this_text)
          else
             if pandoc.utils.type(this_text) == "Inlines" then
               note_text =  note_text .. this_text
             else
               note_text:insert(this_text)
             end
          end
       end
     end
     note_count = note_count + 1
     footnotes[note_count] = {label, note_text}
     print (note_count, footnotes[note_count][1], footnotes[note_count][2])
   end
   return {} -- Swallow the BulletList
  end

function Link (elem)
  if FORMAT:match 'latex' then
    if elem.classes[1] == "study-note-ref" then
      local backRef = elem.identifier
      local word = elem.content[2]
      local targ = string.sub(elem.target,2)
      local note_content
      print ("in Link", #footnotes)
      for k, v in ipairs(footnotes) do
        if v[1] == targ then
          note_content = v[2]
        end
      end
      if not note_content then
        note_content = "footnote text not found"
      end
      local new_el = pandoc.Inlines({
        word ,
        pandoc.RawInline('latex', "\\footnote{\n") ,
        note_content ,
        pandoc.RawInline('latex', "\n}")
        })
      return new_el
    else
      return elem
    end
  end
end

function Pandoc(doc)
  doc = doc:walk {BulletList = BulletList}
  print (#footnotes)
  return doc:walk {}
end

这是我的AST:

[ Div 
    ( "" , [ "body-block" ] , [] )
    [ Div 
        ( "" , [ "verse" ] , [] )
        [ Para
            [ Str "Text"
            , Space
            , Str "with"
            , Space
            , Link
                ( "BACK_note3a" , [ "study-note-ref" ] , [] )
                [ Superscript [ Str "a" ] , Str "footnote" ]
                ( "#note3a" , "" )
            , Str "." 
            ]   
        ]   
    ]   
, BulletList
    [ [ Para
          [ Span
              ( "note3a" , [] , [] )
              [ Link
                  ( "" , [ "BACK" ] , [] )
                  [ Str "\9664" ]
                  ( "#BACK_note3a" , "" )
              ]   
          ]   
      , Div 
          ( "" , [ "label-group" ] , [] )
          [ Para
              [ Span ( "" , [ "label-verse" ] , [] ) [ Str "3" ]
              , Span ( "" , [ "label-marker" ] , [] ) [ Str "a" ]
              ]   
          ]   
      , Para
          [ Span
              ( "" , [] , [ ( "note-category" , "cross-ref" ) ] ) 
              [ Link
                  ( "" , [ "scripture-ref" ] , [] )
                  [ Str "Footnote" , Space , Str "text" ]
                  ( "ref-file.xhtml#p30" , "" )
              , Str "." 
              ]   
          ]   
      ]   
    ]   
]

解决方案

有多种方法可以修改过滤器的执行顺序。

通过 walking文档::walk 方法允许执行一个过滤器,因此在对 Pandoc 进行过滤时,提供了一种非常灵活的修改文档的方法:

function Pandoc (doc)
  doc = doc:walk{
    BulletList = function (bl)
      -- collect the notes here
    end
  }
  doc = doc:walk{
    Link = function (l)
      -- replace the footnote links
      -- (Could also use `pandoc.Note` instead of `pandoc.RawInline`)
    end,
  }

  return doc
end

另一种方法让过滤器返回多个“子过滤器”,它们按给定的顺序执行。我把这种方法视为已被弃用:

return {
  {
    BulletList = function (...)
      return nil
    end
  },
  {
    Link = function (link)
      return nil
    end
  },
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章