datatool DTLgetvalue 使用 foreachitem

datatool DTLgetvalue 使用 foreachitem

以下代码应该从 mydata.csv 的第一行获取值,然后将值复制到新的空行。

我正在使用 foreachitem 将键传递给 DTLgetvalue 函数。它可以编译,但它不会从 itemlist 中获取每个键,而是似乎使用项目列表的最后一个键。我是否遗漏了有关如何将 listofitems 传递给 DTLfuction 的某些信息,或者 \tmp 变量是否未刷新?

\documentclass[a4paper,10pt]{article}

\usepackage{datatool}
\usepackage{listofitems}
\usepackage{tabularx}


\begin{filecontents*}{mydata.csv}
ColA,   ColB,     ColC
John,   Doe,      1
Eve,    Johansen, 2
Scott,  Great,    3
\end{filecontents*}

\DTLloaddb[keys={ColA,ColB,ColC}]{mydata}{mydata.csv}

\readlist\keylist{ColA,ColB,ColC} %%% making a list of header-keys

\newcommand{\addemptyrow}{%
    \DTLnewrow{mydata}%%%
    \foreachitem\key\in\keylist{%
        \DTLgetvalue{\tmp}{mydata}{1}{\dtlcolumnindex{mydata}{\key}}%
        \DTLnewdbentry{mydata}{\key}{\tmp}}
        }

\begin{document}
\DTLdisplaydb{mydata}

\addemptyrow{}

\DTLdisplaydb{mydata}

\end{document}

答案1

所以,我解决了。这是使用 expand 的问题。仍然没有完全理解 expand 的概念,但找到了一个类似的旧线程这里

因此,如果我在宏中添加 \dtlexpandnewvalue,上述操作即可奏效

\readlist\keylist{ColA,ColB,ColC}
\newcommand{\addemptyrow}{%
    \DTLnewrow{mydata}%%%
    \dtlexpandnewvalue
    \foreachitem\key\in\keylist{%
        \DTLgetvalue{\tmp}{mydata}{1}{\dtlcolumnindex{mydata}{\key}}%
        \DTLnewdbentry{mydata}{\key}{\tmp}}
        \dtlnoexpandnewvalue
        }

如果没有 \dtlexpandnewvalue,我只会看到 \tmp 的最后一个值(即“1”) 不在这里工作 使用 \dtleexpandnewvalue 解决了这个问题 在此处输入图片描述

答案2

问题是它\tmp没有得到扩展,因此您实际上是\tmp在每个单元格中添加。

有多种方法可以解决这个问题。这里我提出了一种基于 的另一种方法,xparse这种expl3方法也使列表循环的管理更加容易。

\begin{filecontents*}{\jobname.csv}
ColA,   ColB,     ColC
John,   Doe,      1
Eve,    Johansen, 2
Scott,  Great,    3
\end{filecontents*}

\documentclass[a4paper,10pt]{article}

\usepackage{datatool}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\makelist}{mm}
 {
  \clist_clear_new:c { l__sorenj_list_#1_clist }
  \clist_set:cn { l__sorenj_list_#1_clist } { #2 }
 }
\NewDocumentCommand{\maplist}{mm}
 {
  \cs_set_protected:Nn \__sorenj_list_map:n { #2 }
  \clist_map_function:cN { l__sorenj_list_#1_clist } \__sorenj_list_map:n
 }
\NewDocumentCommand{\xDTLnewdbentry}{mmm}
 {
  \exp_args:Nnno \DTLnewdbentry { #1 } { #2 } { #3 }
 }
\ExplSyntaxOff

\DTLloaddb[keys={ColA,ColB,ColC}]{mydata}{\jobname.csv}
\makelist{keylist}{ColA,ColB,ColC} %%% making a list of header-keys

\begin{document}

\DTLdisplaydb{mydata}

\DTLnewrow{mydata}

\maplist{keylist}{%
  \DTLgetvalue{\tmp}{mydata}{1}{\dtlcolumnindex{mydata}{#1}}%
  \xDTLnewdbentry{mydata}{#1}{\tmp}%
}

\DTLdisplaydb{mydata}

\end{document}

没有\key必要,你只需用 表示当前项目。注意,如果你将循环嵌入另一个宏的定义中,#1它应该变成。##1

的扩展\tmp是唯一需要关心的另一件事,它的工作是\exp_args:NnnV跳过第一个标记(在本例中为\DTLnewdbentry)和接下来的两个支撑组,以扩展下一个标记(即)的值\tmp

在此处输入图片描述

相关内容