, 5 min read

Converting Markdown to Springer Nature LaTeX Format

I created a blog post Tendler-like Formulas for Stiff ODEs which I wanted to get published in Springer "Numerical Algorithms".

Springer "Numerical Algorithms" first published starting in 1991. Its editor in chief is Claude Brezisnki.

Blog post 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)' => 16,
    'Shampine (1982)' => 17,
    'Skeel (1976)' => 18,
    'St\"adter et al (2021)' => 19,
    'Tendler (1973)' => 20,
    'Tendler/Bickart/Picel (1976)' => 21,
    'Tendler/Bickart/Picel (1978)' => 22,
    'Tischer (1983)' => 23,
    'Tischer/Sacks-Davis (1983)' => 24,
    'Tischer/Gupta (1985)' => 25,
    'Werner/Arndt (1986)' => 26,
);

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.

  1. The journal wants German Umlaute to be escaped with LaTeX codes
  2. HTML codes are converted to LaTeX codes
  3. Numbering of paragraphs and theorems is converted from PHP to fixed numbers.
  4. 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.

while (<>) {
    s/_Proof:_/\\begin{proof}/;
    s/&nbsp; &nbsp; &#9744;/\\end{proof}/;

    s/&deg;/\\textdegree{}/g;
    s/&ldquo;/``/g;
    s/&rdquo;/''/g;
    s/&ndash;/--/g;
    s/&mdash;/---/g;
    s/&nbsp;/~/g;
    s/&amp;/\\&/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;
    }

    #s/!\[\]\(\*<\?=\$rbase\?>\*\/img\/([-\w]+)\.jpg\)/\\includegraphics[scale=0.4]{$1}/;
    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\?>\. (Definition\.|Examples\.|Theorem:|Main theorem:|Notation\.)__/) {
    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

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.