Search code examples
markdownpandoc

Does pandoc support creation of markdown tables in its templates?


I am reading the pandoc manual nd if I am understanding this correctly, it supports usage of a template file and a YAML file that contains the variables to use in the templates. It also says that the YAML supports any arbitrary objects (even lists). However, I want to ask if its possible to render markdown tables in the template using the YAML data. The examples only show a simple key and value mapping.


Edit: I created a testable.md file that contains this

---
table:
  caption: Cities
  headers: [city, population]
  rows:
    - [Berlin, '3,748,148']
    - [Tokyo, '13,839,910']
---

$table$

**Random Text**

and used this command to use the filter provided by tarleb: pandoc -f markdown -t docx --lua-filter=yaml_table.lua -o target.docx testtable.md

However it seems that the output file still does not contain the table. Am I missing something?


Edit: I realized that the template file is specified differently from the input It worked properly when I made testtable.md to only contain the following:

---
table:
  caption: Cities
  headers: [city, population]
  rows:
    - [Berlin, '3,748,148']
    - [Tokyo, '13,839,910']
---

And created a template file called markdowntmpl.md containing the following

$table$

**Random Text**

Then I used the following command:

pandoc -f markdown -t markdown --template=markdowntemplate.md --lua-filter=yaml_table.lua -o target.md testtable.md

Output:

  city     population
  -------- ------------
  Berlin   3,748,148
  Tokyo    13,839,910

  : Cities

**Random Text**

Then I can proceed to creating a docx document out of it.


Solution

  • All elements representable in Markdown can also be put into metadata fields. The easiest way to insert complex elements is to use the newline-preserving YAML syntax for multiline strings. E.g.,

    ---
    table: |
      | city   | population |
      |--------|------------|
      | Berlin |  3,748,148 |
      | Tokyo  | 13,839,910 |
    ---
    

    This defines table as a metadata field containing a table.


    There is no "native" YAML way of defining a table, but you can roll your own with a pandoc Lua filter.

    Say one would like to define a table like this:

    ---
    table:
      caption: Cities
      headers: [city, population]
      rows:
        - [Berlin, '3,748,148']
        - [Tokyo, '13,839,910']
    ---
    

    Then it's possible to use the following filter to convert it into a pandoc table.

    local List = require 'pandoc.List'
    
    function repeated(item, times)
      local result = {}
      for i = 1, times do result[i] = item end
      return result
    end
    
    function to_table (tbl)
      if tbl.t ~= 'MetaMap' or not tbl.rows then
        return nil
      end
    
      -- Turn MetaInlines into blocks
      local to_blocks = function (x) return {pandoc.Plain(List:new(x))} end
    
      local headers = (List:new(tbl.headers)):map(to_blocks)
      local rows = List:new(tbl.rows):map(
        function (row) return List:new(row):map(to_blocks) end
      )
      local columns = #rows[1]
      local aligns = tbl.aligns or repeated(pandoc.AlignDefault, columns)
      local widths = tbl.widths or repeated(0, columns)
      return pandoc.Table(List:new(tbl.caption), aligns, widths, headers, rows)
    end
    
    function Meta (meta)
      for k, v in pairs(meta) do
          local success, result = pcall(to_table, v)
          if success and result then
            meta[k] = pandoc.MetaBlocks{result}
          end
      end
      return meta
    end