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.

3

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

  • 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 Aug 22 '19 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 Aug 22 '19 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 Aug 22 '19 at 10:10

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.