2

I want to load data from a file and use it in a figure caption. Found this code (that I've modified slightly to demonstrate it's limitations) which does exactly what I want it to do when it works, for example in the math environment. But it doesn't work at all in a figure caption or section title. Is there anyway to resolve this issue?

    \documentclass{article}
    \usepackage{datatool, filecontents}
    \DTLsetseparator{ = }

    \begin{filecontents*}{mydata.dat}
    foo = 10
    bar = 20
    \end{filecontents*}

    \begin{document}
    \DTLloaddb[noheader, keys={thekey,thevalue}]{mydata}{mydata.dat}
    \newcommand{\mycommand}[1]{\DTLfetch{mydata}{thekey}{#1}{thevalue}}

    %This works
    The first value \mycommand{foo} and the second value $\mycommand{bar}$.

    %This doesn't
    \section{\mycommand{foo}}

    %Nor this
    \begin{figure}
        \caption{And some parameter has the value \mycommand{foo}}
    \end{figure}
    \end{document}
David Carlisle
  • 757,742

2 Answers2

4

The command as defined is fragile, so you need to use \protect\mycommand when used in moving arguments such as \section or \caption.

David Carlisle
  • 757,742
1

A readarray/listofitems approach would work nicely.

\documentclass{article}
\usepackage{readarray}

\begin{filecontents*}{mydata.dat}
foo = 10
bar = 20
\end{filecontents*}

\newcommand\mycommand[1]{\csname keydata#1\endcsname}
\begin{document}
\readarraysepchar{;}
\readdef{mydata.dat}\mydata
\setsepchar{;/=}
\ignoreemptyitems
\readlist*\myrecords{\mydata}
\foreachitem\z\in\myrecords[]{%
  \expandafter\xdef\csname keydata\myrecords[\zcnt,1]\endcsname{%
    \myrecords[\zcnt,2]}%
}
%This works
The first value \mycommand{foo} and the second value $\mycommand{bar}$.
%This doesn't
\section{\mycommand{foo}}
%Nor this
\begin{figure}
\caption{And some parameter has the value \mycommand{foo}}
\end{figure}
\end{document}

enter image description here

And if you need to preserve the key data unexpanded, a little extra effort gives this:

\documentclass{article}
\usepackage{readarray}
\usepackage[T1]{fontenc}
\begin{filecontents*}{mydata.dat}
foo = 10
bar = 20
foomac = \today
\end{filecontents*}

\newcommand\mycommand[1]{\csname keydata#1\endcsname}
\begin{document}
\readarraysepchar{;}
\readdef{mydata.dat}\mydata
\setsepchar{;/=}
\ignoreemptyitems
\readlist*\myrecords{\mydata}
\foreachitem\z\in\myrecords[]{%
  \expandafter\def\csname keydata\myrecords[\zcnt,1]\expandafter\expandafter
  \expandafter\endcsname\expandafter\expandafter\expandafter{%
  \myrecords[\zcnt,2]}%
}
%This works
The first value \mycommand{foo} and the second value $\mycommand{bar}$.

Key value3 is not pre-expanded: 
\detokenize\expandafter{\keydatafoomac}.
%This doesn't
\section{\mycommand{foo}}
%Nor this
\begin{figure}
\caption{And some parameter has the value \mycommand{foo}}
\end{figure}
\end{document}

enter image description here