1

I would like to implement the following processsing for each row of my data, which is read with datatool:

if ( (\No = 5 and \B=11111) OR (\No = 5 and \B=22222) ):
  \inserpageA
else if ( (\No = 5) AND (\B not 11111) AND (\B not 22222) ): 
  \inserpageB
else: 
  \No \hspace{1cm} \B  \hspace{5cm} \A

My code:

\RequirePackage{filecontents}
\begin{filecontents*}{test.csv}
Acol, Bcol, NoCol
Ax,Bxxxx,1
Ay,By,3
A1,B22,2
A2,B44,4
A3,11111,5
Ax,B,1
Ay,By,3
A1,B22,2
A2,B44,4
A3,22222,5
Ax,Bxxxx,1
Ay,By,3
A1,B22,2
A2,B44,4
A3,33333,5
\end{filecontents*}

\documentclass{article}
\usepackage{datatool}
\DTLloaddb{mydata}{test.csv}
\newcommand{\inserpageA}[2]{%
\subsubsection*{AAA}
\newpage
}
\newcommand{\inserpageB}[2]{%
\subsubsection*{BBB}
\newpage
}
\begin{document}

\DTLforeach*{mydata}{\A=Acol, \B=Bcol, \No=NoCol}%
{%
 \No \hspace{1cm} \B  \hspace{3cm}  \A

}%

\end{document}

Please show how to implement the above rule. Thank you.

1 Answer 1

5

There are several ways to do that. I propose two solutions, one using xifthen, the other using expl3. It would also be doable with ifthen and functions from datatool.

Note that for tests on \B, I used string comparison because the contents is not always a number, contrary to \No. I replaced one 2222 with 22222 in your logical expression (looks like a mistake in your question?).

I implemented the logical tests as you wrote them, but they could be simplified (the \No = 5 test could be factored out).

Using xifthen

\RequirePackage{filecontents}
\begin{filecontents*}{test.csv}
Acol, Bcol, NoCol
Ax,Bxxxx,1
Ay,By,3
A1,B22,2
A2,B44,4
A3,11111,5
Ax,B,1
Ay,By,3
A1,B22,2
A2,B44,4
A3,22222,5
Ax,Bxxxx,1
Ay,By,3
A1,B22,2
A2,B44,4
A3,33333,5
\end{filecontents*}

\documentclass{article}
\usepackage{xifthen}
\usepackage{datatool}
\DTLloaddb{mydata}{test.csv}

\newcommand{\inserpageA}{%
  \subsubsection*{AAA}
  \newpage
}
\newcommand{\inserpageB}{%
  \subsubsection*{BBB}
  \newpage
}

\begin{document}

\DTLforeach*{mydata}{\A=Acol, \B=Bcol, \No=NoCol}%
{%
  \ifthenelse{\(\cnttest{\No}{=}{5}\AND \equal{\B}{11111}\)\OR
              \(\cnttest{\No}{=}{5}\AND \equal{\B}{22222}\)}%
    {\inserpageA}%
    {\ifthenelse{\cnttest{\No}{=}{5}\AND
                 \NOT\equal{\B}{11111}\AND
                 \NOT\equal{\B}{22222}}%
       {\inserpageB}%
       {\No\hspace{1cm}\B \hspace{5cm}\A\par}%
    }%
}%

\end{document}

Using expl3

Maybe you'll find the expl3 way more readable. Contrary to xifthen, boolean expressions for l3prg (the expl3 module for these things) use standard precedence rules for && and || (logical AND and logical OR, respectively), which is nice.

Note that spaces are ignored between \ExplSyntaxOn and \ExplSyntaxOff. If you need a space there, use ~ or \space. ~ may be ignored as usual after a control word, for instance the ~ in \B ~ is ignored, but \B \space will insert a space token when \space is expanded (it is a macro expanding to an explicit space token).

\RequirePackage{filecontents}
\begin{filecontents*}{test.csv}
Acol, Bcol, NoCol
Ax,Bxxxx,1
Ay,By,3
A1,B22,2
A2,B44,4
A3,11111,5
Ax,B,1
Ay,By,3
A1,B22,2
A2,B44,4
A3,22222,5
Ax,Bxxxx,1
Ay,By,3
A1,B22,2
A2,B44,4
A3,33333,5
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}
\usepackage{datatool}
\DTLloaddb{mydata}{test.csv}

\ExplSyntaxOn

\NewDocumentCommand \lfortiProcessOneRow { }
  {
    \bool_if:nTF
      { % The parentheses below are not necessary, because && has higher
        % priority than || in expl3 (l3prg) boolean expressions.
        ( \int_compare_p:nNn { \No } = { 5 } && \str_if_eq_p:Vn \B {11111} ) ||
        ( \int_compare_p:nNn { \No } = { 5 } && \str_if_eq_p:Vn \B {22222} )
      }
      { \inserpageA }
      {
        \bool_if:nTF
          { \int_compare_p:nNn { \No } = { 5 } &&
            ! \str_if_eq_p:Vn \B {11111}       &&
            ! \str_if_eq_p:Vn \B {22222}
          }
          { \inserpageB }
          { \No \hspace{1cm} \B \hspace{5cm} \A \par }
      }
  }

\ExplSyntaxOff

\newcommand{\inserpageA}{%
  \subsubsection*{AAA}
  \newpage
}
\newcommand{\inserpageB}{%
  \subsubsection*{BBB}
  \newpage
}

\begin{document}

\DTLforeach*{mydata}{\A=Acol, \B=Bcol, \No=NoCol}{\lfortiProcessOneRow}

\end{document}

Output of both examples

Output

3
  • super. Thank so much. I tested add "\ifthenelse{(\cnttest{\No}{=}{1})}% {\inserpageA} before \ifthenelse{(\cnttest{\No}{=}{5}\AND \equal{\B}{11111})\OR (\cnttest{\No}{=}{5}\AND \equal{\B}{22222})}%" ..but don't work. How can i add more condition: If \No = 1, insert page A. Thanks
    – latexforti
    Commented Aug 22, 2019 at 7:46
  • 1
    You are missing a braced group for the “else” part. Look at the xifthen manual page 2. The syntax is \ifthenelse{〈test expression〉}{〈true code〉}{〈false code〉}. Also, you don't need the parentheses here (( and )) but when you use them in an xifthen test, they must be preceded by a backslash, as in \( or \).
    – frougon
    Commented Aug 22, 2019 at 7:49
  • 1
    I added an expl3-based solution, you may find it easier to work with. Look for Boolean expressions in interface3.pdf for documentation on l3prg (expl3) boolean expressions.
    – frougon
    Commented Aug 22, 2019 at 10:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .