2

I want to have some condition of what to do if the key that was provided is not in the db. But \DTLfetch does return a value in case it had found one before. How can I catch all the 'x' in this example?

\documentclass{article}

\usepackage{datatool}

% csv file 1
\begin{filecontents*}{abbreviationss.csv}
    term, abbreviation
    Machine Learning, ML
    Artificial Neural Network, ANN
\end{filecontents*}

\DTLloaddb{abbreviations}{abbreviationss.csv}

\begin{document}

\begin{itemize}
    \item x : \DTLfetch{abbreviations}{term}{x}{abbreviation}
    \item Machine Learning : \DTLfetch{abbreviations}{term}{Machine Learning}{abbreviation}
    \item x : \DTLfetch{abbreviations}{term}{x}{abbreviation}
    \item Artificial Neural Network : \DTLfetch{abbreviations}{term}{Artificial Neural
    Network}{abbreviation}
    \item x : \DTLfetch{abbreviations}{term}{x}{abbreviation}
\end{itemize}

\end{document}

output:

enter image description here

2 Answers 2

1

I think the most easy approach is using \DTLgetvalueforkey (and evaluating/calling the macro defined by \DTLgetvalueforkey):

\documentclass{article}

\usepackage{datatool}

\begin{filecontents*}{abbreviationss.csv}
    "term", "abbreviation"
    Machine Learning, ML
    Artificial Neural Network, ANN
\end{filecontents*}

\DTLloaddb{abbreviations}{abbreviationss.csv}

\newcommand{\getabbreviation}[1]{% 
    #1 : %
    \DTLgetvalueforkey{\scratchmacro}{abbreviation}{abbreviations}{term}{#1}%
    \scratchmacro
    %\scratchmacro will be \@dtlnovalue -> "Undefined Value" if #1 is not found.
    % Alternatively:
    % \DTLifnull{\scratchmacro}{Hey, this is undefined!}{\scratchmacro}%
}%

\begin{document}

\begin{itemize}
\item\getabbreviation{x}   
\item\getabbreviation{Machine Learning}
\item\getabbreviation{x}
\item\getabbreviation{Artificial Neural Network}
\item\getabbreviation{x}
\end{itemize}
    
\end{document}

enter image description here



Like the approach of Simon Dispa this is based on \DTLforeach*:

\documentclass{article}

\usepackage{datatool}

\begin{filecontents*}{abbreviationss.csv}
    "term", "abbreviation"
    Machine Learning, ML
    Artificial Neural Network, ANN
\end{filecontents*}

\DTLloaddb{abbreviations}{abbreviationss.csv}

\newif\ifnotfound
\global\notfoundtrue

\newcommand{\getabbreviation}[1]{% 
    #1 : %
    \global\notfoundtrue
    \DTLforeach*[{\equal{\term}{#1}}]{abbreviations}{\abbreviation=abbreviation, \term=term}%
                {\abbreviation\global\notfoundfalse\dtlbreak}%
    \ifnotfound Undefined Value\fi
}%

\begin{document}

\begin{itemize}
\item\getabbreviation{x}   
\item\getabbreviation{Machine Learning}
\item\getabbreviation{x}
\item\getabbreviation{Artificial Neural Network}
\item\getabbreviation{x}
\end{itemize}
    
\end{document}

enter image description here



If the real-life-scenario is not just about some itemize-thing but you really need to catch the situation of \DTLfetch not finding the ⟨column1 value⟩:

With your MWE you get a lot of ! Package datatool Error: No row found in database `abbreviations' for column ` 1' matching `x'.-errors on the terminal and in the .log-file.

Syntax of \DTLfetch is:

\DTLfetch{⟨db name⟩}%
         {⟨column1 name⟩}%
         {⟨column1 value⟩}%
         {⟨column2 name⟩}%

Section "6.11.1 Operating on Current Row" of the User Manual for datatool bundle version 2.32 says:

\dtlgetrowindex{⟨row cs⟩}{⟨db name⟩}{⟨col idx⟩}{⟨value⟩}
Similar to \DTLgetrowindex but doesn't produce an error if no match is found. You can test the result by using \ifx⟨row cs⟩\dtlnovalue.

So you can write a wrapper for \DTLfetch which applies

\dtlgetrowindex{⟨row cs⟩}%
               {⟨db name⟩}%
               {⟨col idx of column1⟩}%
               {⟨column1 value⟩}%

for defining ⟨row cs⟩ and then does:

\ifx⟨row cs⟩\dtlnovalue\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{%
  ⟨ tokens in case ⟨column1 name⟩ does not have a value ⟨column1 value⟩ ⟩%
}{%
  \DTLfetch{⟨db name⟩}{⟨column1 name⟩}{⟨column1 value⟩}{⟨column2 name⟩}%
}%

You need the index of column1/of ⟨col idx of column1⟩.

You can get that via \dtlcolumnindex{⟨db name⟩}{⟨column1 name⟩}

In order to have the arguments of \dtlgetrowindex—especially ⟨col idx of column1⟩=\dtlcolumnindex{⟨db name⟩}{⟨column1 name⟩}—expanded before carrying out \dtlgetrowindex, you can define a scratch-macro via \protected@edef where expansion of the command \dtlgetrowindex and expansion of the to-be-defined command ⟨row cs⟩ is prevented by prepending \noexpand, but the expansion of other arguments of \dtlgetrowindex is not prevented, and then call that scratch-macro:

\documentclass{article}

\usepackage{datatool}

%\DTLfetchifcolOneValueExists{<db name>}%
%                            {<column1 name>}%
%                            {<column1 value>}%
%                            {<column2 name>}%
%                            {<tokens in case <column1-value> does not exist>}%
%
%   Turn @ into a normal letter so that it can be used as part of the name of a control sequence:
\makeatletter
%   Test if the command \NewDocumentCommand is not available.
%   If so, use traditional \newcommand.  Otherwise use it.
\@ifundefined{NewDocumentCommand}%
{\newcommand\DTLfetchifcolOneValueExists[5]}%
{\NewDocumentCommand\DTLfetchifcolOneValueExists{mmmmm}}%
{%
  % open a local scope:
  \begingroup
  % define the scratch macro
  \protected@edef\@dtl@dogetrowforvalue{%
    \endgroup\noexpand\dtlgetrowindex{\noexpand\dtl@rowidx}{#1}{\dtlcolumnindex{#1}{#2}}{#3}%
  }%
  % Call the scratch-macro:
  \@dtl@dogetrowforvalue
  % Expansion of the scratch-macro yields:
  %   \endgroup %<-after processing \endgroup the local scope is closed and thus the scratch-macro is undefined.
  %   \dtlgetrowindex{\dtl@rowidx}{<expansion of #1>}{<expansion of \dtlcolumnindex{#1}{#2}>}{<expansion of #3>}%
  %   % After processing \dtlgetrowindex the macro \dtl@rowidx is defined.
  \ifx\dtl@rowidx\dtlnovalue\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {#5}{\DTLfetch{#1}{#2}{#3}{#4}}%
}%
\makeatother


% csv file 1
\begin{filecontents*}{abbreviationss.csv}
    term, abbreviation
    Machine Learning, ML
    Artificial Neural Network, ANN
\end{filecontents*}

\DTLloaddb{abbreviations}{abbreviationss.csv}

\begin{document}

\begin{itemize}
    \item x :
          \DTLfetchifcolOneValueExists{abbreviations}%
                                      {term}%
                                      {x}%
                                      {abbreviation}%
                                      {Column `term' doesn't have a value `x'}
    \item Machine Learning :
          \DTLfetchifcolOneValueExists{abbreviations}%
                                      {term}%
                                      {Machine Learning}%
                                      {abbreviation}%
                                      {Column `term' doesn't have a value `Machine Learning'}
    \item x : 
          \DTLfetchifcolOneValueExists{abbreviations}%
                                      {term}%
                                      {x}%
                                      {abbreviation}%
                                      {\DTLstringnull}
    \item Artificial Neural Network :
          \DTLfetchifcolOneValueExists{abbreviations}%
                                      {term}%
                                      {Artificial Neural Network}%
                                      {abbreviation}%
                                      {Column `term' doesn't have a value `Artificial Neural Network'}
    \item x :
          \DTLfetchifcolOneValueExists{abbreviations}%
                                      {term}%
                                      {x}%
                                      {abbreviation}%
                                      {\dtlnovalue}
\end{itemize}

\end{document}

enter image description here

If you wish to obtain some null-value instead of the phrase "Column `term' doesn't have a value `x' ", you can provide one of the tokens \DTLstringnull/\DTLnumbernull/\dtlnovalue instead. (\DTLstringnull yields NULL. \DTLnumbernull yields 0. \dtlnovalue yields Undefined Value. All three tokens can be used as first argument of \DTLifnull etc.)

2

The command \itemx will generate a new \item every time a term is found. Otherwise it does nothing.

Output:

A

\documentclass{article}

\usepackage{datatool}

\begin{filecontents*}{abbreviationss.csv}
    "term", "abbreviation"
    Machine Learning, ML
    Artificial Neural Network, ANN
\end{filecontents*}

\DTLloaddb{abbreviations}{abbreviationss.csv}

\begin{document}

\newcommand{\itemx}[1]{% added <<<<
    \DTLforeach*{abbreviations}{\abbreviation=abbreviation, \term=term}
    {\ifthenelse{\equal{\term}{#1}} 
    {\item \term:   \abbreviation } {}}
            }

\begin{itemize}
    \itemx{x}   
    \itemx{Machine Learning}
    \itemx{x}
    \itemx{Artificial Neural Network}
    \itemx{x}
\end{itemize}
    
\end{document}

Alternative (faster and warning)

Using \DTLassignfirstmatch and changing \PackageError into a \PackageWarning

x

\documentclass{article}

\usepackage{datatool}

    
\begin{filecontents*}{abbreviationss2.csv}
    "term", "abbreviation"
    Machine Learning, ML
    Artificial Neural Network, ANN
    Artificial Intelligence, AI
\end{filecontents*}

\DTLloaddb{abbreviations}{abbreviationss2.csv}

\newcommand{\term}{}
\newcommand{\abbreviation}{}

\makeatletter   
\renewcommand*{\dtl@assignfirstmatch}[4]{%
    \DTLifdbexists{#2}%
    {%
        {%
            \dtlgetrowindex{\dtl@asg@rowidx}{#2}{\dtlcolumnindex{#2}{#3}}{#1}%
            \ifx\dtl@asg@rowidx\dtlnovalue%
            \PackageWarning{datatool}{No match found for \string\DTLassignfirstmatch{#2}{#3}{#1}{#4}}{}%
            \else
            \dtlgetrow{#2}{\dtl@asg@rowidx}%
            \@dtl@assign{#4}{#2}%
            \fi
        }%
    }%
    {%
        \PackageError{datatool}{Data base `#2' doesn't exist}{}%
    }%
}

\makeatother

    \newcommand{\itemx}[1]{%
    \renewcommand{\term}{}%
    \renewcommand{\abbreviation}{}%
    \DTLassignfirstmatch{abbreviations}{term}{#1}{\term=term,\abbreviation=abbreviation}%
    \ifthenelse{\equal{\abbreviation}{}}{\item #1:~(\dtlnovalue)}{\item #1:~(\abbreviation)}%
}

\newcommand{\findx}[1]{%
    \renewcommand{\term}{}%
    \renewcommand{\abbreviation}{}%
    \DTLassignfirstmatch{abbreviations}{term}{#1}{\term=term,\abbreviation=abbreviation}%
    \ifthenelse{\equal{\abbreviation}{}}{~(\dtlnovalue)}{~(\abbreviation)}%
}

\begin{document}
    
    \DTLdisplaydb{abbreviations}
    \bigskip
    
    \begin{itemize}
        \itemx{x}   
        \itemx{Machine Learning}
        \itemx{x}
        \itemx{Artificial Neural Network}
        \itemx{x}
    \end{itemize}
    
    \bigskip
    
    
    Deep Learning\findx{Deep Learning} is a subset of Artificial Neural Network\findx{Artificial Neural Network},
    which in turn is a subset of Machine Learning\findx{Machine Learning} and
     Artificial Intelligence\findx{Artificial Intelligence}.    
    
\end{document}
1
  • If you don't provide tokens for the "else"-case you can use \DTLforeach*'s optional argument: \DTLforeach*[{\equal{\term}{#1}}]{abbreviations}{\abbreviation=abbreviation, \term=term}{\item#1 : \abbreviation} Aug 9, 2021 at 17:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.