使用 `ifthenelse` 将两个相关函数合并为一个

使用 `ifthenelse` 将两个相关函数合并为一个

这个问题基于 Peter Grill 的回答“包括主表的行的表”。

该函数PrintDTLTable在 Peter 的原始答案中。我想要一个可以遍历所有行的版本,因此我将其稍微修改为PrintDTLTableDefault,它没有行 ID 参数。和 都PrintDTLTablePrintDTLTableDefault预期工作。

我认为将它们组合成一个函数更有意义,所以我尝试使用,ifthenelse结果得到了 PrintDTLTableCombined。这给出了错误

ERROR: Argument of \isempty has an extra }.

我没有看到任何明显的语法或使用错误。与 LaTeX 一样,错误可能与错误消息完全无关。我不需要使用ifthenelse;其他东西也可以。

\documentclass{article}
\usepackage{array}
\usepackage{multirow}
\usepackage{datatool}
\usepackage{longtable}
\usepackage{filecontents}
\usepackage{xifthen}
\newcommand{\colhead}[1]{\multicolumn{1}{>{\bfseries}l}{#1}}
\newcounter{tabenum}\setcounter{tabenum}{0}
\newcommand{\nextnuml}[1]{\refstepcounter{tabenum}\thetabenum.\label{#1}}

\begin{filecontents*}{foo.dat}
  Hammer001,   Hammer,    1 ,  0 , 1 , 10 , 1 , \multirow{2}{2in}{light (add some words here to wrap around)}\\
  Hammer002,   Hammer,    2 ,  0 , 1 , 10 , 1 , heavy
  Hammer003,   Hammer,    3 ,  0 , 1 , 10 , 1 , really heavy
  Longsword001,Longsword, 1 , -1 , 2 , 75 , 2 , one-handed
  Longsword002,Longsword, 2 , -1 , 2 , 75 , 2 , two-handed
  Longsword003,Longsword, 3 , -1 , 2 , 75 , 2 , three-handed
\end{filecontents*}

\newcommand{\PrintDTLTable}[2]{%
  % #1 = database to search
  % #2 = list of rowIDs
  \begin{tabular}{c c c c c c c p{3.0cm}}
    & \colhead{Label} & \colhead{Cost} & \colhead{Weight} & \colhead{PropA} & \colhead{PropB} & \colhead{PropC} & \colhead{Description}\\\hline
    \DTLforeach[\DTLisSubString{#2}{\RowID}]{#1}{%
      \RowID=RowID,%
      \Label=Label,%
      \Cost=Cost,%
      \Weight=Weight,%
      \PropA=PropA,%
      \PropB=PropB,%
      \PropC=PropC,%
      \Description=Description%
    }{%
      \nextnuml{\RowID} & \Label &\Cost & \Weight & \PropA & \PropB & \PropC & \Description \\
    }%
  \end{tabular}
}%

\newcommand{\PrintDTLTableDefault}[1]{%
  % #1 = database to search
  \begin{longtable}{c c c c c c c p{3.0cm}}
    & \colhead{Label} & \colhead{Cost} & \colhead{Weight} & \colhead{PropA} & \colhead{PropB} & \colhead{PropC} & \colhead{Description}\\\hline
    \DTLforeach[\boolean{true}]
    {#1}{%
      \RowID=RowID,%
      \Label=Label,%
      \Cost=Cost,%
      \Weight=Weight,%
      \PropA=PropA,%
      \PropB=PropB,%
      \PropC=PropC,%
      \Description=Description%
    }{%
      \nextnuml{\RowID} & \Label &\Cost & \Weight & \PropA & \PropB & \PropC & \Description \\
    }%
  \end{longtable}
}%

\newcommand{\PrintDTLTableCombined}[2][]{%
 % #1 = list of rowIDs
 % #2 = database to search
  \begin{longtable}{c c c c c c c p{3.0cm}}
    & \colhead{Label} & \colhead{Cost} & \colhead{Weight} & \colhead{PropA} & \colhead{PropB} & \colhead{PropC} & \colhead{Description}\\\hline
    \DTLforeach
    [\ifthenelse{\isempty{#1}}{\boolean{true}}{\DTLisSubString{#1}{\RowID}}]
    {#2}{%
      \RowID=RowID,%
      \Label=Label,%
      \Cost=Cost,%
      \Weight=Weight,%
      \PropA=PropA,%
      \PropB=PropB,%
      \PropC=PropC,%
      \Description=Description%
    }{%
      \nextnuml{\RowID} & \Label &\Cost & \Weight & \PropA & \PropB & \PropC & \Description \\
    }%
  \end{longtable}
}%

\begin{document}
% \DTLsetseparator{&}% Define separator of the data
\DTLloaddb[noheader,keys={RowID,Label,Cost,Weight,PropA,PropB,PropC,Description}]{myDB}{foo.dat}

%\PrintDTLTable{myDB}{Hammer001,Hammer003,Longsword003}
%\PrintDTLTableDefault{myDB}
\PrintDTLTableCombined{myDB}

This is a reference to ~\ref{Hammer003}.

\end{document}

更新:@Werner 的宏对我有用。但是,我仍然想知道是什么导致我的尝试失败;也许这会很有启发。LaTeX 对初学者来说很令人沮丧,部分原因是对于非专家来说,它经常似乎无法调试。

答案1

当你使用以下命令执行“检查空参数”时,它会起作用

% http://tex.stackexchange.com/q/308/5764
\makeatletter
\def\ifemptyarg#1{%
  \if\relax\detokenize{#1}\relax % H. Oberdiek
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}
\makeatother

而不是xifthen \ifthenelse

\newcommand{\PrintDTLTableCombined}[2][]{%
 % #1 = list of rowIDs
 % #2 = database to search
  \begin{longtable}{c c c c c c c p{3.0cm}}
    & \colhead{Label} & \colhead{Cost} & \colhead{Weight} & \colhead{PropA} & \colhead{PropB} & \colhead{PropC} & \colhead{Description}\\\hline

    \DTLforeach
    [\ifemptyarg{#1}{\boolean{true}}{\DTLisSubString{#1}{\RowID}}]
    {#2}{%
      \RowID=RowID,%
      \Label=Label,%
      \Cost=Cost,%
      \Weight=Weight,%
      \PropA=PropA,%
      \PropB=PropB,%
      \PropC=PropC,%
      \Description=Description%
    }{%
      \nextnuml{\RowID} & \Label &\Cost & \Weight & \PropA & \PropB & \PropC & \Description \\
    }%
  \end{longtable}
}%

检查空参数有时会有问题,因为某些用途可能需要赋值,这是不允许的。


分析为什么你的方法不起作用是因为datatool评估条件。内部\DTLforeach[#1]{#2}{#3}{#4}是一个测试

\ifthenelse{#1}{<true>}{<false>}

datatool 用户指南支持这一点(部分5.4 迭代数据库,第 50 页):

\DTLforeach[<condition>]{<db name>}{<assign list>}{<text>}

可选参数<condition>是 允许的形式的条件\ifthenelse。这包括包提供的命令ifthen (例如\not\and\or),以及 2.2 节中描述的命令。 的默认<condition>值为\boolean{true}

因此,实际上您要实现的是一个嵌套条件,类似于

\ifthenelse{\ifthenelse{<condition>}{<trueA>}{<falseA>}}{<trueB>}{<falseB>}

重现该问题的最小示例如下

\documentclass{article}
\usepackage{xifthen}% http://ctan.org/pkg/xifthen
\begin{document}
\ifthenelse{\ifthenelse{\boolean{true}}{\boolean{true}}{\boolean{false}}}{A}{B}
\end{document}

虽然上面的内容(逻辑上)应该输出A为(因为嵌套条件应该输出\boolean{true},其求值为真,应该输出A),但您会收到错误

! Argument of \boolean has an extra }.
<inserted text> 
                \par 
l.4 ...an{true}}{\boolean{true}}{\boolean{false}}}
                                                  {A}{B}

除了使用不同的方法得出条件结果外,没有其他方法可以解决这个问题,因为您使用条件来决定是否打印行。​​也就是说,您无法在 之外评估条件\DTLforeach

相关内容