, 6 min read
Converting Markdown to Springer Nature LaTeX Format
Original post is here eklausmeier.goip.de/blog/2026/01-18-converting-markdown-to-springer-nature-latex-format.
Blog posts on this very blog are created in Markdown with MathJax, i.e., LaTeX formulas, sprinkled in. The static site generator Simplified Saaze then converts this into HTML. Obviously, I didn't want to create two documents, i.e., one for the blog, and another for the journal. Also, the journal might reject the submission. In that case I would at least retain the blog post.
The solution is to use a small Perl script blog2springer to automatically convert the Markdown from the blog to the LaTeX required for the journal.
I had done the reverse thing here: Converting Journal Article from LaTeX to Markdown, i.e., take LaTeX as input and produce a blog post in Markdown format.
1. Perl script blog2springer
Here we run down the Perl script called blog2springer.
Bibliographic references in a blog post are done using [reftext](hyperlink), while the journal LaTeX format is still very oldstyle and uses numbers.
I use a hash to convert reftext to numbers.
#!/bin/perl -W
# Reformat Markdown with MathJax to Springer Nature LaTeX format
# Elmar Klausmeier, 31-Dec-2025
use strict;
my ($skip,$summary,$ref,$refcnt,$sec,$eq,$ineq,$cnt,$enum,$itemize) = (0,0,0,0,0,0,0,0,0,0);
my %L = (
'Akrivis/Katsoprinakis (2020)' => 1,
'Albrecht (1978)' => 2,
'Albrecht (1985)' => 3,
'Bickart/Picel (1973)' => 4,
'Butcher (2016)' => 5,
'Gaffney (1984)' => 6,
'Gohberg/Lancaster/Rodman (1978)' => 7,
'Gohberg/Lancaster/Rodman (2009)' => 8,
'Gupta (1985)' => 9,
'Hairer/Wanner/Nørsett (2008)' => 10,
'Hairer/Wanner (2010)' => 11,
'Mihelcic/Wingerath (1981)' => 12,
'Montenbruck/Gill (2000)' => 13,
'Norsett/Thomsen (1986)' => 14,
'Petzold (1983)' => 15,
'Rubin (1973)' => 99,
'Shampine (1982)' => 16,
'Skeel (1976)' => 17,
'St\"adter et al (2021)' => 18,
'Tendler (1973)' => 19,
'Tendler/Bickart/Picel (1976)' => 20,
'Tendler/Bickart/Picel (1978)' => 21,
'Tischer (1983)' => 22,
'Tischer/Sacks-Davis (1983)' => 23,
'Tischer/Gupta (1985)' => 24,
'Werner/Arndt (1986)' => 25,
);
Springer Nature preloads a number of LaTeX packages.
It seems that it has difficulties with \usepackage{algorithmicx}, although I didn't follow through this.
The script has some values hardcoded, which are specific to the article, like author, etc.
print << "EOF";
\\documentclass[pdflatex,sn-mathphys-num]{sn-jnl}% Math and Physical Sciences Numbered Reference Style
\\usepackage{graphicx}%
\\usepackage{multirow}%
\\usepackage{amsmath,amssymb,amsfonts}%
\\usepackage{amsthm}%
\\usepackage{mathdots}%
\\usepackage{mathrsfs}%
\\usepackage[title]{appendix}%
\\usepackage{xcolor}%
\\usepackage{textcomp}%
\\usepackage{manyfoot}%
\\usepackage{booktabs}%
\\usepackage{algorithm}%
\\usepackage{algpseudocode}%
\\usepackage{listings}%
\\theoremstyle{thmstylethree}%
\\newtheorem{definition}{Definition}%
\\raggedbottom
\\graphicspath{ {./} }
\\setcounter{MaxMatrixCols}{15}
\\renewcommand{\\thesection}{\\arabic{section}.}
\\newcommand{\\dcol}{\\operatorname*{col}}
\\newcommand{\\drow}{\\operatorname*{row}}
\\newcommand{\\diag}{\\operatorname*{diag}}
\\newcommand{\\bov}[2]{\\overline{\\mathbf #1}_{#2}} % boldface and overlined
\\newcommand{\\bopo}{\\bov P1}
\\newcommand{\\boro}{\\bov R1}
\\newcommand{\\bfR}{{\\mathbf{R}}}
\\newcommand{\\bovy}[1]{\\bov Y{\\!#1}}
\\newcommand{\\ovbf}[1]{\\overline{\\mathbf{#1}}}
\\author{\\fnm{Elmar} \\sur{Klausmeier}}
\\email{Elmar.Klausmeier\@gmail.com}
\\date{\\today}
\\begin{document}
\\keywords{cyclic linear multistep methods, matrix polynomials, stiff differential equations, convergence analysis, Widlund-wedge}
\\pacs[Mathematics Subject Classification]{65L04 65L06}
\\pacs[CR]{G.1.7}
EOF
The loop reads each line of the blog post and reformats it.
- The journal wants German Umlaute to be escaped with LaTeX codes
- HTML codes are converted to LaTeX codes
- Numbering of paragraphs and theorems is converted from PHP to fixed numbers.
- Enumerations are converted to the respective format in LaTeX
The Markdown contains some PHP code like so:
__<?=++$c?>.__ Consider the multistep method
That is converted using the $cnt variable.
For tables I entered them two times: once for Markdown, and once for LaTeX and used an if-statement:
<?php if ($c === 0) { ?>
\begin{table}[htbp]
\caption{Widlund-wedge angle for Tendler and Tischer formulas}
\begin{tabular}{@{}lllll|ll@{}}
\toprule
$p$ & $\ell$ & abs(root) & $\alpha$(Tendler) & $\delta$(Tendler) & $\alpha$(Tischer) & $\delta$(Tischer) \\
\midrule
. . .
\end{table}
<?php } else { ?>
$p$ | $\ell$ | abs(root) | $\alpha$(Tendler)| $\delta$(Tendler) | | $\alpha$(Tischer) | $\delta$(Tischer)
----|-----|-------------|----------------|-------------------|-|------------------|------------------
1 | 3 | 0 | 90° | 0 | | 90° | 0
. . .
<?php } ?>
The script is.
while (<>) {
s/_Proof:_/\\begin{proof}/;
s/ ☐/\\end{proof}/;
s/°/\\textdegree{}/g;
s/“/``/g;
s/”/''/g;
s/–/--/g;
s/—/---/g;
s/ /~/g;
s/&/\\&/g;
s/\\unicode\{x22F0\}/\\iddots/g;
s/Ä/\\"A/g;
s/Ö/\\"O/g;
s/Ü/\\"U/g;
s/ä/\\"a/g;
s/ö/\\"o/g;
s/ü/\\"u/g;
s/ß/\\ss{}/g;
if (/<\?php if \(false\) \{ \?>/) { $skip = 1; next; }
if (/<\?php \} \?>/) { $skip = 0; next; }
if (/<\?php if \(\$c === 0\) \{ \?>/) { $skip = 0; next; }
if (/<\?php \} else \{ \?>/) { $skip = 1; next; }
next if ($skip == 1);
next if (/<\?php \$c=0; \?>/);
print "\\title[$1]{$1}\n\n" if (/^title: "([^"]+)"/);
if (/^__Abstract.__/) { $summary = 1; print "\\abstract{"; next; }
if ($summary == 1) {
if (length($_) < 2) { $summary = 2; print "}\n\\maketitle\n\n"; next; }
print;
next;
}
next if ($summary != 2);
next if (/^\\def\\/);
if (/^## \d\. References<a id/) { $ref=1; print "\n\n\\begin{thebibliography}{90}\n\n"; next; }
if ($ref == 1) {
if ( $refcnt > 1 && length($_) < 2) { $ref = 0; print "\n\\end{thebibliography}\n\n"; next; }
s/\[([^\]]+?)\]\([^\)]+?\)/$1/g;
if (/^1\. /) {
s/^1\. //;
printf("\n\\bibitem{b%d}\n",++$refcnt);
}
}
if (/^## (\d)\. ([^<]+)<a id/) { $sec=1; print "\n\n\\section{$2}\\label{sec$1}\n\n"; next; }
next if ($sec != 1);
if (/^\$\$/) {
if ($eq % 2 == 0) { $ineq = 1; print "\\begin{align*}\n"; }
else { $ineq = 0; print "\\end{align*}\n"; }
++$eq;
next;
}
s/__(\d+)__/\\textbf{$1}/;
s/__(\w+ \w+ \w+:)__/\\textbf{$1}/;
s/__\((\d+)\)__/\\textbf{($1)}/;
s/`(\w+ \w+)`/\\texttt{$1}/g;
if ($ineq == 0) {
s/ _(\w+)_( |\+)/ \\emph{$1}$2/g;
s/ _(\w+ \w+)_( |\.)/ \\emph{$1}$2/g;
s/ _(\w+ \w+ \w+)_( |\.)/ \\emph{$1}$2/g;
}
if (/!\[\]\(\*<\?=\$rbase\?>\*\/img\/([-\w]+)\.jpg "([^"]+?)"\)/) {
print "\\begin{figure}[H]\n\\begin{center}\n\\includegraphics[scale=0.4]{$1}\n\\caption{$2}\n\\end{center}\\end{figure}\n";
next;
}
foreach my $l (keys %L) {
s/\[\Q$l\E\]\([^\)]*?\)/\[$L{$l}]/g;
}
s/\[([^\]]+?)\]\(\*<\?=\$rbase\?>[^\)]+?\)/$1/g;
s/\[([^\]]+?)\]\([^\)]+?\)/$1/g;
if (/__<\?=\+\+\$c\?>\.__/) { my $t = sprintf("\\textbf{%d.}",++$cnt); s/__<\?=\+\+\$c\?>\.__/${t}/; }
if (/__<\?=\+\+\$c\?>\. (\w+|['\w]+ \w+)(\.|:)__/) {
my $t = sprintf("\\textbf{%d. %s%s}",++$cnt,$1,$2);
s/__<\?=\+\+\$c\?>\. (\w+|['\w]+ \w+)(\.|:)__/${t}/;
}
if (/^1\. /) {
if ($enum == 0) { $enum = 1; print "\\begin{enumerate}\n"; }
s/^1\. /\\item /;
} elsif ($enum == 1 && length($_) < 2) { $enum = 0; print "\\end{enumerate}\n\n"; }
if (/^\* /) {
if ($itemize == 0) { $itemize = 1; print "\\begin{itemize}\n"; }
s/^\* /\\item /;
} elsif ($itemize == 1 && length($_) < 2) { $itemize = 0; print "\\end{itemize}\n\n"; }
print;
}
Finally we add the footer.
print "\\end{document}\n\n";
2. Usage
I downloaded the journal article template. That zip-file contains the following:
$ unzip -l "Download+the+journal+article+template+package+(December+2024+version).zip"
Archive: Download+the+journal+article+template+package+(December+2024+version).zip
Length Date Time Name
--------- ---------- ----- ----
0 2024-12-13 05:44 sn-article-template/
0 2024-12-13 05:01 sn-article-template/bst/
151345 2024-12-13 05:01 sn-article-template/bst/sn-apacite.bst
29828 2024-12-13 05:01 sn-article-template/bst/sn-aps.bst
35515 2024-12-13 05:19 sn-article-template/bst/sn-basic.bst
33968 2024-12-13 05:01 sn-article-template/bst/sn-chicago.bst
64023 2024-12-13 05:01 sn-article-template/bst/sn-mathphys-ay.bst
64164 2024-12-13 05:01 sn-article-template/bst/sn-mathphys-num.bst
39056 2024-12-13 05:01 sn-article-template/bst/sn-nature.bst
39951 2024-12-13 05:01 sn-article-template/bst/sn-vancouver-ay.bst
40758 2024-12-13 05:01 sn-article-template/bst/sn-vancouver-num.bst
2890 2024-12-13 05:01 sn-article-template/empty.eps
91593 2024-12-13 05:01 sn-article-template/fig.eps
421391 2024-12-13 05:20 sn-article-template/sn-article.pdf
34686 2024-12-13 05:45 sn-article-template/sn-article.tex
5123 2024-12-13 05:01 sn-article-template/sn-bibliography.bib
55857 2024-12-13 05:01 sn-article-template/sn-jnl.cls
418495 2024-12-13 05:01 sn-article-template/user-manual.pdf
--------- -------
1528643 18 files
For my article I only needed sn-jnl.cls.
I did not use BibTeX as the blog post points to external references via HTML links, while the journal just uses numbers for citations.
Converting the blog post goes like this:
blog2springer ~/php/sndsaaze/content/blog/2026/01-20-tendler-like-formulas-for-stiff-odes.md > tendler-like-formulas-for-stiff-odes.tex
Copy the three images:
cp -p /srv/http/img/BDFvsTendlervsTischer.jpg .
cp -p /srv/http/img/BDFvsTendlervsTischerRunge.jpg .
cp -p /srv/http/img/eTendler3-StabilityMountain.jpg .
Then compile with LaTeX:
pdflatex tendler-like-formulas-for-stiff-odes.tex
Then view the result:
mupdf tendler-like-formulas-for-stiff-odes.pdf
I use mupdf for viewing PDFs.
The final result is here: tendler-like-formulas-for-stiff-odes-submitted.pdf.