尝试向 datatool 添加 select 命令时遇到 Runaway 错误

尝试向 datatool 添加 select 命令时遇到 Runaway 错误

与一个附带项目相关,我想向datatool包中添加类似 SQL 的 select 和 where。该\DTselect命令允许我指定列的列表和现有表名,并将仅包含所选列的新表放置在输出表中。最后,我想添加一个,\DTwhere它允许我选择一组行并输出到新命名的表中。但我被这个问题难住了\DTselect,希望得到一个或多个 LaTeX 向导的帮助。

以下示例显示了我计划如何使用各种语言字母名称的玩具“seq”表来设置表格。它将允许用户使用 向表中添加一行\addSeq,在 xkeyval 可选参数中给出字段值,在单个强制参数中给出“id”。

这是我的 MWE,或者更确切地说是 Mnon-WE。我遇到了失控参数错误,但我不知道为什么。

\documentclass{article}

\usepackage{datatool}
\usepackage{longtable}

\makeatletter

% Check whether db named in #1 exists.  If not, issue error message in #2.
\newcommand{\checkfordb}[2]{\DTLifdbempty{#1}{\errmessage{#2}}{\relax}}

% Add fields #2 to a database #1
% #1->dbname, #2-><field name list>
\newcommand{\addcolstodb}[2]{%
  \renewcommand*{\do}[1]{\DTLaddcolumn{#1}{##1}}%
  \dolistloop{#2}}

% Add #4 to table #1 if #3 is in list of fields #2. Used in \DTselect below.
% #1->dbname, #2-><fieldname>, #3-><select fields>, #4->item
\newcommand{\addtodbfield}[4]{%
  \xifinlist{#2}{#3}%
  {\DTLnewdbentry{#1}{#2}{#3}}%
  {}}

\DTLnewdb{seqs}
\DTLaddcolumn{seqs}{id}
\DTLaddcolumn{seqs}{roman}
\DTLaddcolumn{seqs}{greek}
\DTLaddcolumn{seqs}{hebrew}

\define@key{addSeq}{roman}{\DTLnewdbentry{seqs}{roman}{#1}}
\define@key{addSeq}{greek}{\DTLnewdbentry{seqs}{greek}{#1}}
\define@key{addSeq}{hebrew}{\DTLnewdbentry{seqs}{hebrew}{#1}}

\newcommand{\addSeq}[2][]{%
  \DTLnewrow{seqs}%
  \DTLnewdbentry{seqs}{id}{#2} %
  \setkeys{addSeq}{#1}}

\newcommand{\makeTable}[2][]{%
    \DTLdisplaylongdb[caption={Simple table #2},#1]{#2}}

% Here is where the trouble is:
\newcommand*{\DTselect}[3]{%
  \checkfordb{#1}{Table named #1 does not exist.}%
  \forcsvlist{\listadd\LDcols}{#2}%
  \DTLnewdb{#3}%
  \addcolstodb{#3}{\LDcols}
  \DTLforeach*{#1}{}{%
    \DTLforeachkeyinrow{\LDvalue}{%
      \addtodbfield{#3}{\dtlkey}{\LDcols}{\LDvalue}}}}

\makeatother

\begin{document}
% Set up a table
\addSeq[roman=A, greek=alpha, hebrew=aleph]{aaa}
\addSeq[roman=B, greek=beta, hebrew=beth]{bbb}
\addSeq[roman=D, greek=delta, hebrew=dalet]{ddd}
\addSeq[roman=G, greek=gamma, hebrew=gimel]{ggg}

% Print it
\makeTable{seqs}

\DTselect{seqs}{greek, hebrew}{foreign}
\makeTable{foreign}

\end{document}

当我运行它时,出现以下错误:

Runaway argument?
\q@nil \edef \dtl@dogetentry {\noexpand \dtlgetentryfromcurrentrow {\noexpand \ETC.
! File ended while scanning use of \@dtl@getrow.
<inserted text> 
                \par 
<*> mwe_select.tex
                  
! Emergency stop.
<*> mwe_select.tex

据我所知,没有\par找到任何 ,无论是明确的还是隐含的。我感觉 datatool 内部有些不对劲,但希望能有其他人来帮我看看。

答案1

您几乎已经成功了!仅剩几个问题:

  • \DTselect\addtodbfield\DTLnewdbentry旨在将条目添加到由 的\DTselect第 3 个参数表示的数据库中。但\DTLnewdbentry仅当由于 而数据库中有某些行可用时才可应用\DTLnewrow。在您的代码中,您不会调用\DTLnewrow将行添加到由 的第 3 个参数表示的数据库中\DTselect。应用\DTLnewdbentry 而不会\DTLnewrow导致您遇到的失控参数错误。
  • \addtodbfield需要\dtlexpandnewvalue。要添加的项目不是用 表示,#3而是用 表示#4
  • \checkfordb尽管有,你还是定义它\DTLifdbexists

我建议这样做:

\documentclass{article}

\usepackage{datatool}
\usepackage{longtable}

\makeatletter

% Add fields #2 to a database #1
% #1->dbname, #2-><field name list>
\newcommand{\addcolstodb}[2]{%
  \renewcommand*{\do}[1]{\DTLaddcolumn{#1}{##1}}%
  \dolistloop{#2}}

% Add #4 to table #1 if #3 is in list of fields #2. Used in \DTselect below.
% #1->dbname, #2-><fieldname>, #3-><select fields>, #4->item
\newif\ifCreateNewRow
\newcommand{\addtodbfield}[4]{%
  \xifinlist{#2}{#3}%
  {%
    \ifCreateNewRow\CreateNewRowfalse\DTLnewrow{#1}\fi
    {\dtlexpandnewvalue\DTLnewdbentry{#1}{#2}{#4}}%
  }%
  {}%
}

\DTLnewdb{seqs}
\DTLaddcolumn{seqs}{id}
\DTLaddcolumn{seqs}{roman}
\DTLaddcolumn{seqs}{greek}
\DTLaddcolumn{seqs}{hebrew}

\define@key{addSeq}{roman}{\DTLnewdbentry{seqs}{roman}{#1}}
\define@key{addSeq}{greek}{\DTLnewdbentry{seqs}{greek}{#1}}
\define@key{addSeq}{hebrew}{\DTLnewdbentry{seqs}{hebrew}{#1}}

\newcommand{\addSeq}[2][]{%
  \DTLnewrow{seqs}%
  \DTLnewdbentry{seqs}{id}{#2}%
  \setkeys{addSeq}{#1}}

\newcommand{\makeTable}[2][]{%
    \DTLdisplaylongdb[{caption={Simple table #2},#1}]{#2}}

% Here is where the trouble was:
\newcommand*{\DTselect}[3]{%
  \DTLifdbexists{#1}{%
    \forcsvlist{\listadd\LDcols}{#2}%
    \DTLnewdb{#3}%
    \addcolstodb{#3}{\LDcols}%
    \DTLforeach*{#1}{}{%
      % \addtodbfield checks an if switch for deciding whether 
      % creating a new row is necessary - this way empty rows
      % within the #3-database can be avoided:
      \CreateNewRowtrue
      \DTLforeachkeyinrow{\LDvalue}{%
        \addtodbfield{#3}{\dtlkey}{\LDcols}{\LDvalue}%
      }%
    }%
  }{%
    \errmessage{Table named #1 does not exist.}%
  }%
}%

\makeatother

\begin{document}
% Set up a table
\addSeq[roman=A, greek=alpha, hebrew=aleph]{aaa}
\addSeq[roman=B, greek=beta, hebrew=beth]{bbb}
\addSeq[roman=D, greek=delta, hebrew=dalet]{ddd}
\addSeq[roman=G, greek=gamma, hebrew=gimel]{ggg}

% Print it
\makeTable{seqs}

\DTselect{seqs}{greek, hebrew}{foreign}
\makeTable{foreign}

\end{document}

在此处输入图片描述

相关内容