Skip to content

markdown

Appunti su Pandoc: stili personalizzati per Word

Brevi appunti pratici sull'integrazione tra Markdown, Pandoc e Microsoft Word tramite file di stile personalizzati.

Documenti Word

Generare un documento con gli stili di riferimento:

pandoc -o custom-reference.docx --print-default-data-file reference.docx

Si possono quindi modificare gli stili all'interno del file "custom-reference" con le normali modalità di Microsoft Word.

Introdurre nuovi stili:

<div custom-style="Super big">My super big text</div>
Normal text. <span custom-style="Highlighted text">This is highlighted</span>

(devono essere esistenti nel file custom-reference.docx)

Si può quindi compilare il documento con:

pandoc documento.md -o documento.docx --reference-doc=custom-reference.docx

Per quanto riguarda le tabelle non è purtroppo possibile modificare lo stile standard. Si può però effettuare un passaggio con python:

import docx
document = docx.Document('/tmp/xxx.docx')
for table in document.tables:
    table.style = document.styles['custom_style']
document.save("target.docx")

Dynamic Markdown

Markdown è un sistema di markup che può essere utilizzato per aggiungere elementi di formattazione a dei normali file di testo. È molto apprezzato dagli sviluppatori, e non a caso è il sistema di riferimento per GitHub oppure per StackOverflow ma può essere utilizzato per qualsiasi tipo di documento, compresi report, libri, manuali, testi, etc.

Uno strumento indispensabile per lavorare, tra le altre cose, su documenti markdown è pandoc che viene definito come il coltellino svizzero per i documenti di testo. Può essere infatti utilizzato per convertire documenti markdown in documenti Word, Open Office, LaTeX, PDF, etc.

Ad esempio:

pandoc test.md -s -o test.odt

oppure:

pandoc test.md -s -o test.pdf

(necessario aver installato pdflatex, come ad es. portable MikTex, e configurato il PATH in maniera adeguata).

È possibile inoltre applicare dei template di alta qualità, come il template Eisvogel

pandoc test.md -s -o test.pdf --template eisvogel

Markdown Dinamico

Ho pensato che sarebbe estremamente comodo poter disporre di un documento markdown "dinamico". Ad esempio, per inserire delle tabelle in un documento Markdown posso utilizzare il plugin MarkDown per Adminer che ho scritto qualche tempo fa, in modo molto semplice e con i risultati spesso migliori di un copia-incolla da Excel su documento Word!

Tuttavia sarebbe meglio ancora poter pescare i dati direttamente dal database di origine (così come da un CSV, XLSX, o quant'altro).

Un sistema che potrebbe funzionare è Jinga2 ovvero uno dei più utilizzati framework per template di Python. Questo sistema però, per precisa scelta architetturale, non prevede la possibilità di mescolare codice di programmazione con condice markup. Avendo vissuto in prima persona gli anni '90 dello scorso millennio, dove il codice HTML si mischiava al codice di programmazione senza capire bene il limiti di dove finiva uno ed iniziava l'altro, posso dire che tale scelta è perfettamente condivisibile. Tuttavia, pur essendo una opzione sempre valida, non è quello che stavo cercando!

Linguaggi di scripting?

Si potrebbe usare un Makefile con qualche script bash, magari integrato con dei sistemi che generano output in formato markdown come il mio perl-Sql-Textify.

Oppure PHP che, nel bene e nel male, permette di inserire del codice all'interno di un documento e può quindi essere utilizzato per rendere un documento Markdown dinamico.

Oppure ancora il buon vecchio HTML::Mason, che mi ha dato grandi soddisfazioni all'inizio del millennio permettendo di integrare codice HTML con il linguaggio perl. Purtoppo né HTML::Mason né Mason2 sono attivamente sviluppati da anni, anche se proprio nel momento in cui ho iniziato a scrivere questo post (ovvero il giorno 11 febbraio 2023 - scrivo molto lentamente!) è stato pubblicato HTML::Mason versione 1.60 che contiene un piccolo bugfix. Non ci sono poi aggiornamenti successivi.

Script Python?

Ho pensato di risolvere il problema con dei piccoli script Python. Un documento Markdown sarà composto come segue, con del codice Python inserito all'interno del documento:

---
title: "Report Dinamico"
author: [Federico Thiella]
date: 2023-09-11
subject: "Report Dinamico"
keywords: [codice, python, esempio]
lang: "it"
table-use-row-colors: True
book: True
...
^ import mktools as mk
^ c={'host':'myhost.mshome.net', 'database':'mydatabase', 'user':'myuser', 'password':'mypassword'}
# Report Dinamico creato con Markdown

^ q=mk.query_db("select * from sezioni", c)
^ for r in q['rows']:

## Titolo: <& r[2] &>

<& r[3] &>

Inserisci una tabella:

^   w=mk.query_db("""
^      select
^        col1,
^        col2,
^        col3
^      from
^        progetti
^      where
^        progetto_id={}
^      order by
^        col1, col2, col3
^      """.format(str(r[0])), c)
^   w['head'][1]['name']='Colonna 1'
^   w['head'][1]['align']='right'
^   w['head'][2]['name']='Colonna 2'
^   w['head'][2]['align']='right'
^   w['head'][3]['name']='Colonna 3'
^   w['head'][3]['align']='left'
^   mk.markdown_table(w['head'], w['rows'])
^^
\pagebreak
  1. questo codice Markdown dinamico verra compilato dallo script pp.py in uno script puro python, che può essere eseguito e che genererà in output il codice Markdown statico finale, pronto da poter essere utilizzato e/o convertito in altri formati;
  2. la libreria mktools.py contiene delle funzioni utili per eseguire velocemente delle operazioni su database:
  3. mk.query_db esegue una query e restituisce intestazione w['head'] e righe w['rows'];
  4. mk.markdown_table che converte la tabella descritta da intestazione e righe in formato markdown.

La compilazione del documento avviene in questo modo:

python pp.py -i documento.md | python | pandoc -o documento.pdf --template eisvogel.latex -s

(lo script dinamico e la libreria di utilities saranno pubblicate e descritte su GitHub quanto prima. Non si tratta di un sistema "professionale" ).

Mako Templates

Un'ultima opzione può essere il sistema Mako Templates, la cui filosofia "Don't reinvent the wheel...your templates can handle it!" contrasta con il mio paragrafo precedente. Lo approfondirò appena mi sara possibile!

SQL Markdown Builder

I like text editors, especially Sublime Text. And I like to work at the command line (on Linux, on Mac... but even on Windows 10 it has become very nice).

So it's pretty normal that everything I write is in Markdown syntax!

Since I work every day with SQL, and every day I have to prepare quick reports, extract some data, share some tables, share some rows... I needed a tool to run a SQL query against a database that returns a table in Markdown format!

This way I can easily copy & paste to a new mail, and format it nicely and professionally with markdown-here, quickly and without becoming crazy.

So I quickly wrote this tool and I called SQL Markdown Builder because it can easily be integrated with Sublime Text, even if it is not a native plugin.

Yes I know this is a little off topic from Mason and Sentosa, but this tool is written in Perl and... I included it in Sentosa anyway! So let's start!

Getting Started

Make sure you have installed perl, File::Slurp, Getopt::Long, DBI, and the DBD libraries for your database:

cpanm File::Slurp
cpanm Getopt::Long
cpanm DBI
cpanm DBD::SQLite
cpanm DBD::Pg
cpanm DBD::mysql
...

Run a query

Once everything is installed, you can write a single query, or more queries separated by a ; in a .SQL text file:

drop table if exists gardens;

create table gardens (
    id integer primary key,
    name varchar(100),
    city varchar(100)
);

insert into gardens (name, city) values
('Gardens By The Bay', 'Singapore'), ('Hyde Park', 'London'),
('Central Park', 'New York'), ('Villa Borghese', 'Rome'),
('Princes Street Gardens','Edinburgh');

select * from gardens;

and you can run your query file at the command line:

perl sqlbuild.pl -c dbi:SQLite:dbname=test.sqlite3 -s query.sql

the connection string is in the DBI format, this example is for SQLite so we don't need to specify a username or a password.

SQL Markdown Builder will execute every single query in sequence against the specified database. If the query is an INSERT or an UPDATE query, it will return '0 rows', otherwise it will return the results in Markdown format (nicely aligned):

0 rows
0 rows
0 rows

id | name                   | city
---|------------------------|----------
1  | Gardens By The Bay     | Singapore
2  | Hyde Park              | London
3  | Central Park           | New York
4  | Villa Borghese         | Rome
5  | Princes Street Gardens | Edinburgh

If some columns become too big, you can specify the maximum size of a column with -mw parameter (or use -h to see all parameters).

Instead of using the command line, you can also specify all connection strings, usernames, passwords inside the .SQL file itself:

/*
  conn="dbi:SQLite:dbname=test.sqlite3"
  username=""
  password=""
*/

This is very handy but not too secure (other users might peek inside your files, and also updating a password might become complicated).

Integration with Sublime Text

This is for Windows, but Linux and OSX will be very similar.

Just get the provided file Sql-mk-build.sublime-build, update the working_dir:

{
    "cmd": ["perl", "sqlbuild.pl", "-s", "$file" ],
    "working_dir": "c:\\GitHub\\Sql-mk-builder\\"
    "selector": "*.sql"
}

and move it to the build directoy:

C:\Users\YOURUSERNAMEHERE\AppData\Roaming\Sublime Text 3\Packages\User

then you can edit your .SQL files with Sublime Text, and see the results using CTRL+B.

Happy SQL & Markdown!