2

I have a csv file with tags and (page) nrs, as follows:

tag,nr
t1,1
t2,5
t3,9

The nr-column refers to page numbers in a pdf file. Each page has a corresponding tag. Given a tag, I want to show the corresponding page in a figure in my latex document.

With datatools I can load the csv file, and fetch the page nr of a given tag. For example, for tag t2 I get page nr 5.

But now when I feed that page nr as the page=... argument to includegraphics, I get the error message

"! Missing number, treated as zero."`

What extra step should I take to convert the latex 5 string into a page nr that includegraphics can handle?

Here's a simplified version (using counters instead of includegraphics) that triggers the problem:

\documentclass{article}
\usepackage{datatool}

\begin{document}

\DTLloaddb{tags}{prestags.csv} \newcommand{\pagenr}{\DTLfetch{tags}{tag}{t2}{nr}}

\newcounter{snr} \addtocounter{snr}{\pagenr}

\end{document}

% Output:

! Missing number, treated as zero. <to be read again> \let l.10 \addtocounter{snr}{\pagenr}

What should I do to fix this?

  • 1
    AFAIK you need to use \DTLgetvalue to define \pagenr. (Sorry, cannot test currently). – cabohah Jan 05 '24 at 15:14
  • 1
    The problem is that \DTLfetch is not expandable. You can use the technique here: retrieving substring of `\DTLfetch` to overcome this. – Alan Munn Jan 05 '24 at 15:45
  • Thanks!! I now got it to work with DTLgetvalue in combination with DTLgetlocation. The dtlcurrentvalue trick to handle non-expandable results seems nice too. Please feel free to turn your suggestions into answers that I can upvote / accept (I can also do this if that's what you prefer). – avandeursen Jan 05 '24 at 15:51

4 Answers4

1

The problem is that the \DTLfetch macro isn't expandable. You can use the technique described here:

to overcome this. Here's a worked out example:

\documentclass{article}
\begin{filecontents}{\jobname.csv}
tag,nr
t1,1
t2,5
t3,9
\end{filecontents}
\usepackage{datatool}
\newcommand{\getvar}[1]{\DTLfetchsave{\myvar}{tags}{tag}{#1}{nr}}
\newcommand{\DTLfetchsave}[5]{%
  \edtlgetrowforvalue{#2}{\dtlcolumnindex{#2}{#3}}{#4}%
  \dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{#2}{#5}}%
  \let#1\dtlcurrentvalue
}
\newcounter{snr}
\begin{document}

\DTLloaddb{tags}{prestags.csv}

\setcounter{snr}{3} The counter value is \thesnr

\getvar{t2} \addtocounter{snr}{\myvar} The counter value is: \thesnr

\end{document}

output of code

Alan Munn
  • 218,180
1

Here, I use the readarray package to digest the csv file and a listofitems read to place the data into an list. The macro \getvar is expandable.

\begin{filecontents*}[overwrite]{prestags.csv}
tag,nr
t1,1
t2,5
t3,9
\end{filecontents*}
\documentclass{article}
\usepackage{readarray,graphicx}
\begin{document}
\readarraysepchar{\\}
\readdef{prestags.csv}\mycsvdata
\setsepchar{\\/,}
\readlist*{\mycsvlist}{\mycsvdata}
\foreachitem\z\in\mycsvlist[]{%
  \expandafter\gdef\csname mytag\mycsvlist[\zcnt,1]\expandafter
    \endcsname\expandafter{\expandafter
    \mycsvlist\expandafter[\zcnt,2]}%
}
\newcommand\getvar[1]{\csname mytag#1\endcsname}

The t2 tag corresonds with page \getvar{t2}

\includegraphics[page=\getvar{t3},scale=.6]{readarray.pdf} \end{document}

enter image description here

1

If you don't mind defining a scratch-macro globally, you can probably use \DTLassignfirstmatch:

When compiling the following example, you get two error messages.

This is on purpose so you can see what happens in case of attempting to retrieve non-existing values.

\begin{filecontents*}{prestags.csv}
tag,nr
t1,1
t2,5
t3,9
\end{filecontents*}

\makeatletter \newcommand\MyStuffDTLfetchsavePackageError[7]{% \PackageError{#1}{#7}{% In order to retrieve from database #2\MessageBreak the value of the key #5 in the first row\MessageBreak where the key #3 has value #4,\MessageBreak database #2 must exist and have keys\MessageBreak #3 and #5 and a row where the key #3\MessageBreak has the value #4.% }% \global\let#6=\dtlnovalue }% \DeclareRobustCommand{\MyStuffDTLfetchsave}[5]{% %#1 = macro to store as result %#2 = data base name %#3 = key 1 %#4 = value of key 1 %#5 = key 2 @bsphack \DTLifdbexists{#2}{% \DTLifhaskey{#2}{#3}{% \DTLifhaskey{#2}{#5}{% \global\let#1=\dtlnovalue \DTLassignfirstmatch{#2}{#3}{#4}{#1=#5}% \ifx#1\dtlnovalue\expandafter@firstofone\else\expandafter@gobble\fi {% \MyStuffDTLfetchsavePackageError{My Stuff}{#2}{#3}{#4}{#5}{#1}% {In data base #2' no row's key#3' holds the value #4'}% }% }{% \MyStuffDTLfetchsavePackageError{My Stuff}{#2}{#3}{#4}{#5}{#1}% {There is no key#5' in data base #2'}% }% }{% \MyStuffDTLfetchsavePackageError{My Stuff}{#2}{#3}{#4}{#5}{#1}% {There is no key#3' in data base #2'}% }% }{% \MyStuffDTLfetchsavePackageError{My Stuff}{#2}{#3}{#4}{#5}{#1}% {Data base#2' doesn't exist}% }% @esphack }% \makeatother

\documentclass{article} \usepackage{datatool}

\newcounter{snr}

\begin{document}

\DTLloaddb{tags}{prestags.csv}

\setcounter{snr}{3}% \noindent The counter value is: \thesnr

\MyStuffDTLfetchsave{\scratchy}{tags}{tag}{t1}{nr}% \ifx\scratchy\dtlnovalue \noindent The value of the key nr in the row where the key tag has the value t1 could not be retrieved.

\noindent Calculations where this value would have been used were not performed. \else \noindent The value of the key nr in the row where the key tag has the value t1 is: \scratchy

\addtocounter{snr}{\scratchy}% \noindent After adding that value to the counter, the counter value is: \thesnr \fi

\MyStuffDTLfetchsave{\scratchy}{tags}{tag}{t2}{nr}% \ifx\scratchy\dtlnovalue \noindent The value of the key nr in the row where the key tag has the value t2 could not be retrieved.

\noindent Calculations where this value would have been used were not performed. \else \noindent The value of the key nr in the row where the key tag has the value t2 is: \scratchy

\addtocounter{snr}{\scratchy}% \noindent After adding that value to the counter, the counter value is: \thesnr \fi

\MyStuffDTLfetchsave{\scratchy}{tags}{tag}{t3}{nr}% \ifx\scratchy\dtlnovalue \noindent The value of the key nr in the row where the key tag has the value t3 could not be retrieved.

\noindent Calculations where this value would have been used were not performed. \else \noindent The value of the key nr in the row where the key tag has the value t3 is: \scratchy

\addtocounter{snr}{\scratchy}% \noindent After adding that value to the counter, the counter value is: \thesnr \fi

\MyStuffDTLfetchsave{\scratchy}{tags}{tag}{t4}{nr}% \ifx\scratchy\dtlnovalue \noindent The value of the key nr in the row where the key tag has the value t4 could not be retrieved.

\noindent Calculations where this value would have been used were not performed. \else \noindent The value of the key nr in the row where the key tag has the value t4 is: \scratchy

\addtocounter{snr}{\scratchy}% \noindent After adding that value to the counter, the counter value is: \thesnr \fi

\end{document}

enter image description here

Ulrich Diez
  • 28,770
0

As suggested by @cabohah, the DTLfetch line in the question can be replaced by the following two lines:

\DTLgetlocation{\rownr}{\colnr}{tags}{t2}
\DTLgetvalue{\pagenr}{tags}{\rownr}{\dtlcolumnindex{tags}{nr}}

Since this was a simple change, this is what I ended up using.