5

I encountered a very strange problem today.

I want to fill tables with automatic generated data. Hence, I designed a macro, which takes four arguments (one being optional). Arguments No. 1 and 4 are allowed to be empty, therefore I put an \ifx#1\@empty test into my code.

This is my macro in the first version:

\newcommand{\admin}[4][]{%
  #2&#3&
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \texttt{\@rzid}\fi&
  \def\@ldap{#1}\ifx\@ldap\@empty\relax
    yes
  \else
    & no
  \fi%
  \\%
}

I was very surprised to find, that LaTeX didn't compile. This was the result:

! Extra \fi.
\\admin ...ldap @empty \relax yes \else & no \fi
\\
! Incomplete \ifx; all text was ignored after line 51.
< inserted text>
\fi

After two hours fiddling, I found out, that the ampersand causes all the trouble. This macro works without LaTeX throwing an error:

\newcommand{\admin}[4][]{%
  #2&#3&
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \texttt{\@rzid}\fi&
  \def\@ldap{#1}\ifx\@ldap\@empty\relax
    yes
  \else 
    no
  \fi%
  \\%
}

The disadvantage is, that the word "No" is now standing in the wrong column. :-( My MWA (Minimal Work Around) is now as follows, but I'd like to know, what went wrong and how to avoid the additional if-clause I came up with.

\documentclass{article}

\makeatletter
%% This did not work due to the "&".  Removing the ampersand will get
%% the macro working, but than the word "No" from the ifclause will be
%% printed in the wrong column.
% \newcommand{\admin}[4][]{%
%   #2&#3&
%   \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \texttt{\@rzid}\fi&
%   \def\@ldap{#1}\ifx\@ldap\@empty\relax
%     yes
%   %% The error starts here.  Comment out the next two lines, and the
%   %% error vanishes.  Remove the ampersand & and its also gone!
%   \else
%     & no
%   %% This would work
%   % \else 
%   %   no
%   \fi%
%   \\%
% }

%% Now: this works, but you have to have an extra if-clause!
\newcommand{\admin}[4][]{%
  #2&#3&%
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \@rzid\fi&%
  \def\@ldap{#1}\ifx\@ldap\@empty\relax
    Yes
  \fi
  &
  \newcommand{\admin}[4][]{%
  #2&#3&%
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \@rzid\fi&%
  \def\@ldap{#1}\ifx\@ldap\@empty\relax
    Yes
  \fi
  &
  \ifx\@ldap\@empty\relax\else
    No
  \fi%
  \\%
\def\@ldap{#1}\ifx\@ldap\@empty\relax\else
    No
  \fi%
  \\%
}
\makeatother

\begin{document}
  \begin{tabular}{@{}lllcc@{}}
    \hline
    \multicolumn{2}{@{}c}{Anwender}
    & \multicolumn{1}{c}{RZ-ID}
    & \multicolumn{2}{c@{}}{LDAP} \\
    \multicolumn{1}{@{}c}{Vorname}
    & \multicolumn{1}{c}{Nachname}
    &
    & \multicolumn{1}{c}{Yes}
    & \multicolumn{1}{c@{}}{No} \\
    \hline
    \admin{First}{Lastname}{fl19}
    \admin{Some}{Othername}{so97}
    \admin[false]{Not}{Listed}{}
    \hline
  \end{tabular}
\end{document}

PS.: This is a minimal example. In my real document, the macro is way more elaborative, as I added a lot more info to the second-last and last column. Therefore, a suggestion, to use \multicolumn{2}{c}{Yes} or \multicolumn{2}{c}{NO}, spanning the last two columns to avoid the ampersand, is no option to me.

Jan
  • 5,293

2 Answers2

5

Note that in your actual MWA (I like that! :-D) you are getting

enter image description here

which probably isn't the intended result. The reason behind it is the same as the reason why your first solution fails: cells are groups, and your \def\@ldap is restricted to the fourth column. You should use \gdefinstead to have it working.

Personally I see no point in avoiding the double \if at all costs but this would be a possible way

\newcommand{\admin}[4][]{%
  #2&#3&%
  \def\@rzid{#4}\ifx\@rzid\@empty\relax ./. \else \@rzid\fi &
  \def\@ldap{#1}%
  \ifx\@ldap\@empty\relax % I prefer \if\relax\detokenize{#1}\relax
     \def\@tempa{\textcolor{green}{\ding{51}}&}%
  \else
     \def\@tempa{&\textcolor{red}{\ding{55}}}%
  \fi
  \@tempa
  \\
}

enter image description here

Basically, the \if just sets the definition of\@tempa, which is expanded only after the \if has been worked out.

campa
  • 31,130
4

Conditionals cannot straddle alignment cells, but you can remove the conditional before issuing &; the technique uses \@firstoftwo and \@secondoftwo. See Why the \expandafter\@firstoftwo idiom?

\documentclass{article}

\makeatletter

\newcommand{\admin}[4][]{%
  #2&#3&%
  \if\relax\detokenize{#4}\relax
    ./.%
  \else
    #4%
  \fi&%
  \if\relax\detokenize{#1}\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {Yes}{&No}%
  \\%
}
\makeatother

\begin{document}
  \begin{tabular}{@{}lllcc@{}}
    \hline
    \multicolumn{2}{@{}c}{Anwender}
    & \multicolumn{1}{c}{RZ-ID}
    & \multicolumn{2}{c@{}}{LDAP} \\
    \multicolumn{1}{@{}c}{Vorname}
    & \multicolumn{1}{c}{Nachname}
    &
    & \multicolumn{1}{c}{Yes}
    & \multicolumn{1}{c@{}}{No} \\
    \hline
    \admin{First}{Lastname}{fl19}
    \admin{Some}{Othername}{so97}
    \admin[false]{Not}{Listed}{}
    \hline
  \end{tabular}
\end{document}

I also removed the two auxiliary macros, preferring a different safe test for emptiness.

enter image description here

egreg
  • 1,121,712