Sashmark / Blog

Markdown table generator checklist: CSV rows to a table

Bobby Huang ·

Under Asking pandoc for a pipe table, the T1 and T4 command lines are quoted with lines from their output. The section Same rows through markitdown quotes the read-back counts logged for run T3. Reader steps for your own file are numbered in Count rows and cells before you share.

Key takeaways

  • Under The Doe test file, the log's copy of doe.csv appears without line numbers.
  • The section Asking pandoc for a pipe table quotes the T1 and T4 command lines.
  • See Pandoc's own table syntax for the T2 command and its output lines.
  • Read Same rows through markitdown for the T3 output and its read-back.
  • Numbered reader steps are listed in Count rows and cells before you share.

The question here: how do I turn spreadsheet rows into a Markdown table without losing values? Save the rows as a CSV file, run pandoc with its CSV reader, then render the result back and count rows and cells against the source. The count matters because T3 from the test log came back with rc=0 while a cell value changed in its read-back.

This markdown table generator checklist is a set of commands you type yourself, plus one count check. The results below come from one test log, written by one run of a test script on one computer. Pipe rows and alignment are spelled out in this guide to Markdown table syntax.

The Doe test file

The input is doe.csv: a header row and three data rows for Jane Doe, John Doe and Doe Holdings. The test log prints it with line numbers. Here it is with those numbers left off:

Name,Account,Amount,Note
Jane Doe,00123,"1,200.50",paid
John Doe,00456,,"a|b"
Doe Holdings,00789,300,"line one
line two"

Jane Doe's Account value, 00123, starts with two zeros. Her Amount, 1,200.50, holds a comma, and the file wraps it in double quotes. John Doe has an empty Amount cell and a Note of a|b with a literal pipe. The Doe Holdings Note runs over two lines of the file, line one and line two, inside one pair of quotes.

The read-back header in the test log counts the source as 4 rows, header included, and 12 data cells. The script also wrote doe.tsv, a copy split by tabs that keeps the header, Jane Doe and John Doe and leaves out the Doe Holdings row. Per that same header, the TSV copy has 3 rows and 8 data cells.

Asking pandoc for a pipe table

In the test log, T1 asked pandoc to read the CSV and write a pipe table:

pandoc -f csv -t gfm doe.csv -o out1.md

Run T1 in the test log closed on rc=0, and its stderr block is empty. The out1.md file T1 wrote, as the test log prints it, holds an HTML table, from <table> on line 1 to </table> on line 31. These are the lines for the Doe Holdings row in that logged T1 output:

<tr>
<td>Doe Holdings</td>
<td>00789</td>
<td>300</td>
<td>line one<br />
line two</td>
</tr>

For T1, the test log shows the two-line Note cell as one td holding a <br /> tag between line one and line two. The same logged T1 output has John Doe's pipe value as <td>a|b</td>. To read up on tags like these sitting inside a .md file, open this explainer on raw HTML in Markdown.

In the test log, T4 ran the same target on the TSV copy:

pandoc -f tsv -t gfm doe.tsv -o out4.md

T4's exit code in the test log is rc=0, and out4.md came out as a pipe table:

| Name     | Account | Amount   | Note |
|----------|---------|----------|------|
| Jane Doe | 00123   | 1,200.50 | paid |
| John Doe | 00456   |          | a\|b |

Looking at T4's out4.md in the test log, John Doe's pipe reads a\|b and his Amount cell holds no text. The doe.tsv input printed in the test log has no two-line cell, so T4 shows nothing about one.

Pandoc's own table syntax

In the test log, T2 kept the CSV reader and picked pandoc's own Markdown as the target:

pandoc -f csv -t markdown doe.csv -o out2.md

Run T2 in the test log finished with rc=0. Its out2.md, per that log, frames the table with lines of dashes:

  -----------------------------------------------
  Name           Account   Amount     Note
  -------------- --------- ---------- -----------
  Jane Doe       00123     1,200.50   paid

  John Doe       00456                a\|b

  Doe Holdings   00789     300        line one\
                                      line two
  -----------------------------------------------

Under T2, the test log shows John Doe's pipe as a\|b, a backslash placed before it. For more on backslashes like that one, read this page about escaping characters in Markdown. The logged T2 output keeps both lines of the Doe Holdings Note: line one\ ends line 8 of out2.md, and line two sits on line 9 under it.

In T2 of the test log, this table form is drawn with dashes and spaces. Multiline and grid table syntax, and how pandoc reads it, has its own page: multiline cells in Markdown tables.

Same rows through markitdown

In the test log, T3 handed doe.csv to markitdown, sending its output into out3.md:

markitdown doe.csv > out3.md

T3 exited rc=0 per the test log, leaving 0 stderr lines. Its out3.md, per the same log, is a pipe table:

| Name | Account | Amount | Note |
| --- | --- | --- | --- |
| Jane Doe | 00123 | 1,200.50 | paid |
| John Doe | 00456 |  | a|b |
| Doe Holdings | 00789 | 300 | line one
line two |

In out3.md as the test log prints it for T3, a|b keeps its pipe with no backslash. In that logged T3 output, the Doe Holdings Note cell is split across two lines of the file, and line two | sits on line 6 by itself.

The script then rendered out3.md back to HTML with pandoc and counted the tr and td tags. The T3 read-back line in the test log reads:

back3 rc=0 tr=5 td=16

So per the test log, the T3 read-back has 5 rows and 16 data cells, against 4 rows and 12 data cells in doe.csv. Two values changed in that logged T3 read-back. In the test log, John Doe's Note cell came back as <td>a</td>, and no cell in the T3 read-back holds the b from a|b. The same logged read-back shows the Doe Holdings Note cell as just line one, with line two as the first cell of a fifth row:

<tr>
<td>line two</td>
<td></td>
<td></td>
<td></td>
</tr>

Count rows and cells before you share

Your own output can get this same read-back. The script ran this line for T1:

pandoc -f gfm -t html out1.md -o back1.html
  1. Keep the source CSV or TSV file as it is, so you have something to count against.
  2. Run your conversion and save the result as a .md file.
  3. If your output is a pipe table or an HTML table, as out1.md, out3.md and out4.md were in the test log, render it back to HTML with pandoc, using the line above with your own file names. No read-back of out2.md from T2 appears in the test log.
  4. Count the tr tags and the td tags in the HTML file.
  5. Count the source: rows with the header included, then data rows times columns for the data cells. Compare the two sets of numbers.
  6. Look up by eye any value with a pipe, any empty cell, any value with leading zeros and any cell that runs over two lines.
  7. If a count or a value differs, fix the table by hand, or pick an output whose counts and values both match the source.

The test log prints three read-back lines:

back1 rc=0 tr=4 td=12
back3 rc=0 tr=5 td=16
back4 rc=0 tr=3 td=8

In the test log, back1 came to 4 rows and 12 data cells, the same as doe.csv. The logged back4 counts for T4, 3 rows and 8 data cells, match the TSV copy. The back3 counts are the T3 ones quoted under Same rows through markitdown.

The test log also has a value checks line for the four outputs. Each number counts the lines of that file holding the value:

out1.md 00123=1 1,200.50=1 escaped-pipe=0 raw-pipe-cell=0 line-one=1 line-two=1 html-table=1
out2.md 00123=1 1,200.50=1 escaped-pipe=1 raw-pipe-cell=0 line-one=1 line-two=1 html-table=0
out3.md 00123=1 1,200.50=1 escaped-pipe=0 raw-pipe-cell=1 line-one=1 line-two=1 html-table=0
out4.md 00123=1 1,200.50=1 escaped-pipe=1 raw-pipe-cell=0 line-one=0 line-two=0 html-table=0

So in the test log, 00123 and 1,200.50 turned up on 1 line of out1.md, out2.md, out3.md and out4.md. The test log's value lookup on the T3 file out3.md found both, while the T3 read-back still came to 5 rows. That is why the steps above ask for both checks.

To skip the command line, the free CSV to Markdown table tool builds the pipe table in your browser and shows its row and data cell counts, and the file stays on your computer.

When the input file is missing

In the test log, T5 gave pandoc nofile.csv, a file name missing from the test folder. The T5 header in the test log names this command:

pandoc -f csv -t gfm nofile.csv

Pandoc exited rc=1 in T5 of this test log. Among the T5 stderr lines in the test log is this one:

nofile.csv: withBinaryFile: does not exist (No such file or directory)

In the test log, T6 ran markitdown against nofile.csv as well:

markitdown nofile.csv

That T6 run also exited rc=1, per the test log. Its final stderr line, per the test log:

FileNotFoundError: [Errno 2] No such file or directory: 'nofile.csv'

When you see either line, check the spelling of the file name and the folder you ran the command from. Look at the return code before you count any tags.

Where Sashmark fits

After the rows land in a .md file, later fixes happen in that file. Sashmark, a .md viewer and editor meant for desktop computers, remains in development and hasn't had any release. If the plan holds, it would display that file as a tidy page, let you correct a typo right there, and save only the corrected words back using the Round-Trip approach it is planned around. Changes View, a further planned part, would point out which lines an agent touched since your last look, whether the file lives in a repo or somewhere else. No AI is planned inside the app.

See the planned features, the help pages and the roadmap for where each part stands.

sashmark.com

Questions

Where did the b in a|b go?
Check the T3 read-back lines quoted in Same rows through markitdown.
Can a cell keep two lines of text?
The section Pandoc's own table syntax shows the T2 output for the two-line Note cell.
Which error lines came back for a missing file?
Under When the input file is missing, the T5 and T6 error lines are quoted.
Did the zeros at the start of 00123 stay?
Look at the value checks line quoted in Count rows and cells before you share.

What Sashmark plans for v1: Features · Roadmap

View as Markdown