与一个附带项目相关,我想向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}