\DTLdeletedb(来自 datatool 包)在 \foreach 中无效

\DTLdeletedb(来自 datatool 包)在 \foreach 中无效

这个问题引出了包中的一个新功能:
datatool

\DTLgdeletedb在 (v2.13) 及更高版本中可用。


我正在尝试使用\foreach循环来迭代几个项目。每次迭代的步骤\ExtractData 如下:

  1. 将数据加载到mydb
  2. 提取适当的数据。
  3. 删除mydb

这在 之外工作得很好\foreach。但如果在 中使用\foreach,则似乎数据库未被删除,并且任何后续尝试创建具有相同名称的新数据库都会失败,并显示以下内容:

datatool错误:数据库“myDB”已存在。

笔记:

  • 下面的 MWE 示例表明,数据库访问在 之外\foreach和 在 之内都可以正常工作。第一的在 内调用\foreach
  • 发生故障仅有的\ExtractData如果在 中的 use 之后尝试使用\foreach。因此取消注释任何注释块都将显示失败。
  • 在有人问我为什么关闭并重新打开同一个数据库之前,在我的实际使用中,打开的数据文件对于每个成员都是不同的\foreach。只是数据库的名称相同。我想我每次都可以创建一个新名字,但我真的很想知道实际的问题是什么。

参考:

代码:

\documentclass{article}

\usepackage{filecontents}
\begin{filecontents*}{foo.dat}
    Smith, John, 1977-05-04
    Doe,   Jane, 1980-05-04
\end{filecontents*}

\usepackage{xstring}
\usepackage{pgffor}
\usepackage{datatool}

\newcommand{\ExtractData}[3]{% #1=file name #2=row, #3=col
    \DTLloaddb[noheader,keys={LastName, FirstName, DOB}]{myDB}{#1}%
    \IfEq{\DTLrowcount{myDB}}{0}{%
        \def\Value{NO VALUE}
    }{%
        \DTLgetvalue{\Value}{myDB}{#2}{#3}%
    }%
    \DTLdeletedb{myDB}%
    \Value%
}

\begin{document}
\section{Works}
\ExtractData{foo.dat}{1}{2}
\ExtractData{foo.dat}{1}{1}

\section{Works in foreach (one element)}
\foreach \x in {2}{
    \ExtractData{foo.dat}{1}{\x}
}

\section{Does NOT work subsequent to foreach (one element)}

%\ExtractData{foo.dat}{1}{1}

%\foreach \x in {1}{
%   \ExtractData{foo.dat}{1}{\x}
%}

\section{Does NOT works in foreach (more than one element)}
%\foreach \x in {2,1}{
%   \ExtractData{foo.dat}{1}{\x}\par\noindent
%}
\end{document}

答案1

\foreach在组内工作,因此数据库的删除只是本地的。定义一个“全局”删除命令\DTLgdeletedb并使用它。

\makeatletter
\newcommand*{\DTLgdeletedb}[1]{%
  \DTLifdbexists{#1}%
  {%
    \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#1}\do
    {%
      \global\expandafter\let\csname dtl@ci@#1@\@dtl@key\endcsname\undefined
    }%
    \global\expandafter\let\csname dtldb@#1\endcsname\undefined
    \global\expandafter\let\csname dtlkeys@#1\endcsname\undefined
    \global\expandafter\let\csname dtlrows@#1\endcsname\undefined
    \global\expandafter\let\csname dtlcols@#1\endcsname\undefined
  }%
  {%
    \PackageError{Can't delete database `#1':
       database doesn't exist}{}{}%
  }%
}
\makeatother

它与命令相同\DTLdeletedb,但带有\global前缀。我担心大量使用这种方法会污染保存堆栈;请注意。

答案2

我无法回答这个问题,但我想说的是循环\@for运行良好:

\documentclass{article}

\usepackage{filecontents}
\begin{filecontents*}{foo.dat}
    Smith, John, 1977-05-04
    Doe,   Jane, 1980-05-04
\end{filecontents*}

\usepackage{xstring}
\usepackage{pgffor}
\usepackage{datatool}

\newcommand{\ExtractData}[3]{% #1=file name #2=row, #3=col
    \DTLloaddb[noheader,keys={LastName, FirstName, DOB}]{myDB}{#1}%
    \IfEq{\DTLrowcount{myDB}}{0}{%
        \def\Value{NO VALUE}
    }{%
        \DTLgetvalue{\Value}{myDB}{#2}{#3}%
    }%
    \DTLdeletedb{myDB}%
    \Value%
}
\makeatletter
\let\myloop\@for
\makeatother
\begin{document}
\section{Works}
\ExtractData{foo.dat}{1}{2}
\ExtractData{foo.dat}{1}{1}

\section{Works in foreach (one element)}

\myloop\xx:={2}\do{%
  \ExtractData{foo.dat}{1}{\xx}%
  }

\section{Does NOT work subsequent to foreach (one element)}

\ExtractData{foo.dat}{1}{1}

\myloop\xx:={1}\do{%
   \ExtractData{foo.dat}{1}{\xx}%
}

\section{Does NOT works in foreach (more than one element)}
\myloop\xx:={2,1}\do{%
   \ExtractData{foo.dat}{1}{\xx}\par\noindent%
}
\end{document}

相关内容