Tabularray: How to comment out some rows using \if condition inside a table stored in a macro

catchfileconditionalsmacrostablestabularray

The following gets me this error

! Incomplete \iffalse; all text was ignored after line
26.

So, how to make \if work inside the table stored in the macro \MyTable?

\newif\ifShowRow
\ShowRowfalse

\begin{filecontents*}[overwrite]{mytable.tex}
    1  &   2  \\
    3  &   4  \\
    \ifShowRow
    5  &   6  \\
    \fi
    7  &   8  \\
    9  &  10  \\
\end{filecontents*}

\documentclass{article}
\usepackage{catchfile, tabularray}
\UseTblrLibrary{siunitx}

\begin{document}
    
    \CatchFileDef{\MyTable}{mytable.tex}{}
    
    \begin{tblr}[ long, expand = \MyTable ]{ colspec = {X S} }
        One & {{{Two}}}  \\
        \MyTable
    \end{tblr}
    
\end{document}

Update

Adopting this answer, I couldn't manage to make the code below work


\newif\ifShowRow
\ShowRowfalse

\begin{filecontents*}[overwrite]{mytable.tex}
    1  &   2  \\
    % https://tex.stackexchange.com/a/58627/2288
    \ifthenelse{\boolean{ShowRow}}{ 3 & 4 \\ 5 & 6 \\ }{ 7 & 8 \\ 9 & 10 \\}
    9  &  10  \\
\end{filecontents*}

\documentclass{article}
\usepackage{catchfile, tabularray, xifthen}
\UseTblrLibrary{siunitx}

\begin{document}
    
    \CatchFileDef{\MyTable}{mytable.tex}{}
    
    \begin{tblr}[ long, expand = \MyTable ]{ colspec = {X S} }
        One & {{{Two}}}  \\
        \MyTable
    \end{tblr}
    
\end{document}

Best Answer

Environments coming from the package tabularray parse their "bodies" for the scaffold/the framework of the table. Seems the parsing-routines "expect" the tokens forming the scaffold/framework of the table to be present in the environment-body as is. Seems the parsing-routines "expect" not to need to obtain these tokens by having carried out in whatsoever way things that come from the "bodies" of these environments.

Expansion is one way/one concept of carrying out things in TeX.

In order to have a bit of expansion-support while that parsing is done, with recent releases of the tabularray-package the expand=...-key is provided, but that in turn implies that tokens provided as value of that key must be fully expandable.
But \ifthenelse is not fully expandable.
\ifthenelse is a macro which, beneath other things, yields tokens that are intended to trigger the performing of temporary assignments/to trigger the (re)defining of temporary macros/scratch-macros.
TeX does not carry out assignments in the stage of expansion but it does so in a later stage of its "digestive processes".
Using Donald E. Knuth's analogy of TeX being a beast with eyes and a digestive tract, expansion takes place in the gullet and assignments are carried out in the stomach, when expansion is already done.

With environments coming from the package tabularray a lot of parsing-work for detecting the scaffold/framework of the table is done by means of "internal" routines provided by the package. Tokens coming from the body of the environment and forming arguments of these internal routines do not get expanded for further examination. They are not carried out in whatsoever way. Unless they occur as value of the expand=...-key. Seems in this case triggering one step of expansion is the only way of "carrying out" which is possible. Performing assignments is not possible.

I used the phrase "one step of expansion" because usually in TeX's gullet expansion is a "process of regurgitation". I.e., if expanding an expandable token yields another expandable token now being the first token of the token-stream, that other expandable token will be expanded, too. Seems with the expand=...-key that regurgitation does not take place. You just get that other expandable token and that's it.

But you can easily establish "regurgitation":

As a trick you can trigger expansion of \romannumeral using expand = \romannumeral and (ab?)use \romannumeral-expansion for triggering a lot of expansion-work.

The gist of \romannumeral-expansion is:

\romannumeral gathers tokens until (either) having gathered a set of tokens that form a valid TeX-⟨number⟩-quantity (or seeing the need of raising an error-message). Expandable tokens are expanded while gathering.
In case the TeX-⟨number⟩-quantity does denote an integer which is positive, you get explicit character-tokens of category 12(other) that form the representation in lowercase roman numerals of the value currently represented by that TeX-⟨number⟩-quantity.
In case the TeX-⟨number⟩-quantity does denote an integer which is not positive, the tokens forming that TeX-⟨number⟩-quantity are silently discarded without whatsoever (disturbing error-)message and without TeX returning any tokens.

The latter case is more interesting for our purposes:
You can (ab?)use \romannumeral for triggering TeX to do a lot of (macro-)expansion-work (="token-replacing"-work) and "exchanging-tokens-in-the-token-stream"-work/"flipping-tokens-around-in-the-token-stream"-work as long as it is ensured that after all this expansion- and exchanging-/flipping-work the very next token in the token-stream is a TeX-⟨number⟩-quantity denoting an integer whose value is not positive.

In the example below for providing the TeX-⟨number⟩-quantity denoting an integer whose value is not positive I use the token \stopexpansion, defined as \chardef\stopexpansion=`\^^00. \stopexpansion is a \chardef-token and in the context of gathering a TeX-⟨number⟩-quantity is assumed to denote the value "0" which is not positive. TeX's rules for gathering a TeX-⟨number⟩-quantity say that no optional trailing spaces or whatever will be discarded when the TeX-⟨number⟩-quantity in question is formed by a \chardef-token. Besides this \stopexpansion is also a control-word-token and therefore is not affected by things like \uppercase or \lowercase.

In the example below, for triggering expansion I actually use \romannumeral. But I use it as a token \startexpansion which via \let is made equal to \romannumeral.

Besides this with tables in general you need to ensure that things like & and \\ are nested in curly braces until the very last step of expansion is done, whereafter only those tokens remain that should actually form the framework/scaffold of the table.
Otherwise TeX's own mechanisms for parsing/detecting the framework/scaffold of a table might intercept expansion and take things for the content of a table-cell that actually should be removed by expansion.
You can do this, e.g., by passing things as brace-nested macro-arguments, e.g., for \@firstoftwo or \@secondoftwo.
(\@firstoftwo is a macro of the LaTeX 2ε-kernel which picks the first of two undelimited/brace-nested arguments.
\@secondoftwo is a macro of the LaTeX 2ε-kernel which picks the second of two undelimited/brace-nested arguments.)

\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
  \csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
\makeatother

\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue


\begin{filecontents*}[overwrite]{mytable.tex}
    1  &  2  \\
    \startexpansion
    \ExpandableConditionCheckTrueFalse{ShowRow}%
                                      {\stopexpansion 3 & 4 \\ 5 & 6 \\ }%
                                      {\stopexpansion 7 & 8 \\ 9 & 10 \\}%
    11  &  12  \\
\end{filecontents*}

\documentclass{article}
\usepackage{catchfile, tabularray}

\UseTblrLibrary{siunitx}

\begin{document}
    
    \CatchFileDef{\MyTable}{mytable.tex}{}

    \begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
        One & {{{Two}}}  \\
        \startexpansion\expandafter\stopexpansion\MyTable
    \end{tblr}
    
\end{document}

enter image description here



If you like you can place \stopexpansion into the definition-text of \ExpandableConditionCheckTrueFalse.

Then the syntax of \ExpandableConditionCheckTrueFalse in any case, also outside tabularray-environments, is
\startexpansion\ExpandableConditionCheckTrueFalse{<name of \if-switch without leading "if">}{<true code>}{<false code>}.

I.e., \ExpandableConditionCheckTrueFalse must always be preceded by \startexpansion (or by \romannumeral).

(By the way: I decided for ⟨name of \if-switch without leading "if"⟩ instead of providing the \if..-token directly because this way you won't have unbalanced \if..-tokens on toplevel of your code. Otherwise you would have to write things like

\ExpandableConditionCheckTrueFalse{\ifShowRow}{<true code>}{<false code>}%

Here \ifShowRow is not balanced by \fi which can cause trouble when embedded in surrounding \if..-\else-\fi-expressions because \if..-\else-\fi-nesting is independent from any kind of group-nesting, i.e., is independent from brace-group-nesting also.)

\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
  \csname if#1\endcsname
  \expandafter\expandafter\expandafter\stopexpansion\expandafter\@firstoftwo
  \else
  \expandafter\expandafter\expandafter\stopexpansion\expandafter\@secondoftwo
  \fi
}%
\makeatother

\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue


\begin{filecontents*}[overwrite]{mytable.tex}
    1  &  2  \\
    \startexpansion
    \ExpandableConditionCheckTrueFalse{ShowRow}%
                                      {3 & 4 \\ 5 & 6 \\ }%
                                      {7 & 8 \\ 9 & 10 \\}%
    11  &  12  \\
\end{filecontents*}

\documentclass{article}
\usepackage{catchfile, tabularray}

\UseTblrLibrary{siunitx}

\begin{document}
    
    \CatchFileDef{\MyTable}{mytable.tex}{}

    \begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
        One & {{{Two}}}  \\
        \startexpansion\expandafter\stopexpansion\MyTable
    \end{tblr}
    
\end{document}

I cannot recommend "hiding" \startexpansion within another macro.

Currently expand =... will be applied to one token only.

I.e., with \begin{tblr}[expand = \foo, expand = \bar ] the directive expand = \bar will override the directive expand = \foo and only expansion of \bar will be triggered while parsing the body of the environment.

When "hiding" \startexpansion within another macro, then you would need to apply expand=<that other macro-token wherein \startexpansion is hidden> which would

  • leave you with the top-level expansion of that macro not being expanded further and
  • annihilate a preceding expand=\startexpansion. I.e., you could not use \startexpansion any more for triggering expansion of other things. E.g., you would not have means for triggering the expansion of the macro defined via \CatchFileDef.

But I can give you a macro for better expansion-control and avoiding large chains of \expandafter:

%%----------------------------------------------------------------------
%% \startexpansion\Expandsteps{<number K>}<tokens>
%%  ->   <tokens> will be hit by \expandafter K times.
%%----------------------------------------------------------------------
\@ifdefinable\UD@innerdfork{\def\UD@innerdfork#1d#2#3dd{#2}}%
\newcommand*\UD@dfork[1]{%
  \UD@innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd%
}%
\newcommand*\Expandsteps[1]{%
  \expandafter\UD@innerExp\expandafter{\expandafter}%
  \romannumeral\number\number#1 000d%
}%
\newcommand*\UD@innerExp[2]{%
  \UD@dfork{#2}{#1\stopexpansion}{\UD@innerExp{#1#1\expandafter}}%
}%

Here is how it could be integrated into a MWE:

\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
  \csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
%%----------------------------------------------------------------------
%% \startexpansion\Expandsteps{<number K>}<tokens>
%%  ->   <tokens> will be hit by \expandafter K times.
%%----------------------------------------------------------------------
\@ifdefinable\UD@innerdfork{\def\UD@innerdfork#1d#2#3dd{#2}}%
\newcommand*\UD@dfork[1]{%
  \UD@innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd%
}%
\newcommand*\Expandsteps[1]{%
  \expandafter\UD@innerExp\expandafter{\expandafter}%
  \romannumeral\number\number#1 000d%
}%
\newcommand*\UD@innerExp[2]{%
  \UD@dfork{#2}{#1\stopexpansion}{\UD@innerExp{#1#1\expandafter}}%
}%
\makeatother

\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue


\begin{filecontents*}[overwrite]{mytable.tex}
    1  &  2  \\
    \startexpansion\Expandsteps{5}%
    % 5 expansion-steps are needed:
    %   1st step expands  `\ExpandableConditionCheckTrueFalse`.
    %   2nd step expands  `\csname if<foobar>\endcsname`. This yields a token `\if<foobar>`.
    %   3rd step expands the token `\if<foobar>`.
    %      In case condition is true this leads to removal of 
    %      the token `\if<foobar>`.
    %      In case condition is false this leads to removal of 
    %      the entire true-branch and `\else`.
    %   4th step:
    %      In case condition is true this expands `\expandafter` before 
    %      `\@firstoftwo` which in turn expands `\else` behind `\@firstoftwo` 
    %      which leads to removal of the entire `\else-branch and 
    %      the `\fi`.
    %      In case condition is false this expands `\expandafter` before 
    %      `\@secondoftwo` which in turn expands `\fi` behind `\@secondoftwo`
    %      which leads to removal of `\fi`.
    %   5th step:
    %      In case condition is true this expands the remaining `\@firstoftwo`.
    %      In case condition is false this expands the remaining `\@secondoftwo`.
    \ExpandableConditionCheckTrueFalse{ShowRow}%
                                      {3 & 4 \\ 5 & 6 \\ }%
                                      {7 & 8 \\ 9 & 10 \\}%
    11  &  12  \\
\end{filecontents*}

\documentclass{article}
\usepackage{catchfile, tabularray}

\UseTblrLibrary{siunitx}

\begin{document}
    
    \CatchFileDef{\MyTable}{mytable.tex}{}

    \begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
        One & {{{Two}}}  \\
        \startexpansion\expandafter\stopexpansion\MyTable
        %\startexpansion\Expandsteps{1}\MyTable
    \end{tblr}
    
\end{document}

If you wish, you can hardcode \Expandsteps into \ExpandableConditionCheckTrueFalse—if you do that, then, like with hardcoding \stopexpansion into \ExpandableConditionCheckTrueFalse, each instance of \ExpandableConditionCheckTrueFalse needs to be preceded by \startexpansion. So when it comes to nesting, a smaller amount of expansion-steps needs to be triggered as each \startexpansion itself will trigger some more, but the token \startexpansion needs to be provided more often:

\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
  \Expandsteps{4}%
      % 4 expansion-steps are needed:
      %   1st step expands  \csname if<foobar>\endcsname. This yields a token \if<foobar>.
      %   2nd step expands the token \if<foobar>.
      %   3rd step expands \expandafter before \@firstoftwo/\@secondoftwo.
      %   4th step expands \@firstoftwo/\@secondoftwo.
  \csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
%%----------------------------------------------------------------------
%% \startexpansion\Expandsteps{<number K>}<tokens>
%%  ->   <tokens> will be hit by \expandafter K times.
%%----------------------------------------------------------------------
\@ifdefinable\UD@innerdfork{\def\UD@innerdfork#1d#2#3dd{#2}}%
\newcommand*\UD@dfork[1]{%
  \UD@innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd%
}%
\newcommand*\Expandsteps[1]{%
  \expandafter\UD@innerExp\expandafter{\expandafter}%
  \romannumeral\number\number#1 000d%
}%
\newcommand*\UD@innerExp[2]{%
  \UD@dfork{#2}{#1\stopexpansion}{\UD@innerExp{#1#1\expandafter}}%
}%
\makeatother

\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue


\begin{filecontents*}[overwrite]{mytable.tex}
    1  &  2  \\
    \startexpansion % \startexpansion triggers expansion until finding \stopexpansion.
                    % So \startexpansion triggers expansion of \ExpandableConditionCheckTrueFalse
                    % which in turn internally uses `\Expandsteps` which in turn after the amount
                    % of expansion-steps needed delivers \stopexpansion.
    \ExpandableConditionCheckTrueFalse{ShowRow}%
                                      {3 & 4 \\ 5 & 6 \\ }%
                                      {7 & 8 \\ 9 & 10 \\}%
    11  &  12  \\
\end{filecontents*}

\documentclass{article}
\usepackage{catchfile, tabularray}

\UseTblrLibrary{siunitx}

\newif\iffoo\footrue
\newif\ifbar\bartrue

\begin{document}
    
    \CatchFileDef{\MyTable}{mytable.tex}{}

    \begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
       \startexpansion\Expandsteps{2}% <- Just some example of controlling expansion when nesting \ExpandableConditionCheckTrueFalse:
       \startexpansion\ExpandableConditionCheckTrueFalse{foo}{%
                                                \startexpansion
                                                \ExpandableConditionCheckTrueFalse{bar}{One footrue/bartrue & {{{Two footrue/bartrue}}}}%
                                                                                       {One footrue/barfalse & {{{Two footrue/barfalse}}}}%
                                              }%
                                              {%
                                                \startexpansion
                                                \ExpandableConditionCheckTrueFalse{bar}{One foofalse/bartrue & {{{Two foofalse/bartrue}}}}%
                                                                                       {One foofalse/barfalse & {{{Two foofalse/barfalse}}}}%
                                              }%
        \\
        \startexpansion\Expandsteps{1}\MyTable
    \end{tblr}
    
\end{document}

If you don't hardcode \Expandsteps or \stopexpansion into \ExpandableConditionCheckTrueFalse you need to specify more expansion-steps but you don't need \startexpansion so often:

\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
  \csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
%%----------------------------------------------------------------------
%% \startexpansion\Expandsteps{<number K>}<tokens>
%%  ->   <tokens> will be hit by \expandafter K times.
%%----------------------------------------------------------------------
\@ifdefinable\UD@innerdfork{\def\UD@innerdfork#1d#2#3dd{#2}}%
\newcommand*\UD@dfork[1]{%
  \UD@innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd%
}%
\newcommand*\Expandsteps[1]{%
  \expandafter\UD@innerExp\expandafter{\expandafter}%
  \romannumeral\number\number#1 000d%
}%
\newcommand*\UD@innerExp[2]{%
  \UD@dfork{#2}{#1\stopexpansion}{\UD@innerExp{#1#1\expandafter}}%
}%
\makeatother

\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue


\begin{filecontents*}[overwrite]{mytable.tex}
    1  &  2  \\
    \startexpansion % \startexpansion triggers expansion until finding \stopexpansion.
    \ExpandableConditionCheckTrueFalse{ShowRow}%
                                      {\stopexpansion 3 & 4 \\ 5 & 6 \\ }%
                                      {\stopexpansion 7 & 8 \\ 9 & 10 \\}%
    11  &  12  \\
\end{filecontents*}

\documentclass{article}
\usepackage{catchfile, tabularray}

\UseTblrLibrary{siunitx}

\newif\iffoo\footrue
\newif\ifbar\bartrue

\begin{document}
    
    \CatchFileDef{\MyTable}{mytable.tex}{}

    \begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
       \startexpansion\Expandsteps{10}% <- Just some example of controlling expansion when nesting \ExpandableConditionCheckTrueFalse:
       \ExpandableConditionCheckTrueFalse{foo}{%
                                                \ExpandableConditionCheckTrueFalse{bar}{One footrue/bartrue & {{{Two footrue/bartrue}}}}%
                                                                                       {One footrue/barfalse & {{{Two footrue/barfalse}}}}%
                                              }%
                                              {%
                                                \ExpandableConditionCheckTrueFalse{bar}{One foofalse/bartrue & {{{Two foofalse/bartrue}}}}%
                                                                                       {One foofalse/barfalse & {{{Two foofalse/barfalse}}}}%
                                              }%
        \\
        \startexpansion\Expandsteps{1}\MyTable
    \end{tblr}
    
\end{document}

If you don't want to keep track of the amount of expansion-steps just don't hardcode things and instead place \stopexpansion as first token of each final branch:

\makeatletter
\@ifdefinable\startexpansion{\let\startexpansion=\romannumeral}%
\@ifdefinable\stopexpansion{\chardef\stopexpansion=`\^^00}%
\newcommand\ExpandableConditionCheckTrueFalse[1]{%
  \csname if#1\endcsname\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%

\makeatother

\newif\ifShowRow
\ShowRowfalse
%\ShowRowtrue


\begin{filecontents*}[overwrite]{mytable.tex}
    1  &  2  \\
    \startexpansion % \startexpansion triggers expansion until finding \stopexpansion.
    \ExpandableConditionCheckTrueFalse{ShowRow}%
                                      {\stopexpansion 3 & 4 \\ 5 & 6 \\ }%
                                      {\stopexpansion 7 & 8 \\ 9 & 10 \\}%
    11  &  12  \\
\end{filecontents*}

\documentclass{article}
\usepackage{catchfile, tabularray}

\UseTblrLibrary{siunitx}

\newif\iffoo\footrue
\newif\ifbar\bartrue

\begin{document}
    
    \CatchFileDef{\MyTable}{mytable.tex}{}

    \begin{tblr}[ long, expand = \startexpansion ]{ colspec = {X S} }
       \startexpansion
       \ExpandableConditionCheckTrueFalse{foo}{%
                                                \ExpandableConditionCheckTrueFalse{bar}{\stopexpansion One footrue/bartrue & {{{Two footrue/bartrue}}}}%
                                                                                       {\stopexpansion One footrue/barfalse & {{{Two footrue/barfalse}}}}%
                                              }%
                                              {%
                                                \ExpandableConditionCheckTrueFalse{bar}{\stopexpansion One foofalse/bartrue & {{{Two foofalse/bartrue}}}}%
                                                                                       {\stopexpansion One foofalse/barfalse & {{{Two foofalse/barfalse}}}}%
                                              }%
        \\
        \startexpansion\expandafter\stopexpansion\MyTable
    \end{tblr}
    
\end{document}