1

I am quite frustrated about the following: Iam writing a document with requirements which have requirement IDs as a beginning of a line (I'm using these in an enumerate environment). I want to collect the requirements in a DATATOOL database and output the requirements at the end of the document in a table.

Whatever I tried, the following macro works fine in the sense that it adds a requirement line with proper requirement ID into the enumerate environment, but it odes NOT add output the requirement ID in the column "reqKey" when I display the table at the end - I have the suspicion that something with the variable access to "\@reqID" does not work.

Any help very much appreciated.

\DTLnewdb{reqs}
\DTLnewdbcolumn{reqs}{reqKey}
\DTLnewdbcolumn{reqs}{reqText}

...

\makeatletter
    \newcommand\req@nomen@count[1]{%
      \@ifundefined{c@#1}
        {% the counter doesn't exist
         \newcounter{#1}\setcounter{#1}{1}%
        }
        {% the counter exists
         \stepcounter{#1}%
        }%
    }
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % markers for requirements
    \newcommand{\req}[2][0]{%
        \req@nomen@count{#2}%
        \ifthenelse{\equal{#1}{0}}
        {REQ.#2.\padzeroes[3]{\decimalnum{\value{#2}}}}
        {REQ.#2.\padzeroes[3]{\decimalnum{\value{#2}}}.\padzeroes[2]{\decimalnum{#1}}}
    }
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \newcommand{\@reqID}{}
    \newcommand{\itemReq}[3][0]{
        \DTLnewrow{reqs}
        \ifthenelse{\equal{#1}{0}}
        {\renewcommand{\@reqID}{\req{#2}}}
        {\renewcommand{\@reqID}{\req{#1}{#2}}}
        \item[\textcolor{blue}{[\@reqID]}]#3%
        \DTLnewdbentry{reqs}{reqKey}{\@reqID}
        \DTLnewdbentry{reqs}{reqText}{#3}
        }
    \makeatother
...
\begin{document}
\begin{enumerate}
\itemReq{reqCategory}{Requirement text, can be lengthy}
\end{enumerate}
...
\DTLdisplaylongdb{reqs}
\end{document}

The output of this code looks like this: Output of code above


Edit as requested I want to share an minimal adjusted (according to esdd's solution) example:

\documentclass{article} 
\usepackage{enumitem}
\usepackage{fmtcount}
\usepackage{datatool}

\DTLnewdb{reqs}
\DTLaddcolumn{reqs}{reqKey}
\DTLaddcolumn{reqs}{reqText}

\makeatletter
% macro creating a new latex counter for every new entitiy name and requirement
\newcommand\req@nomen@count[1]{%
  \@ifundefined{c@#1}
    {% the counter doesn't exist
     \newcounter{#1}\setcounter{#1}{1}%
    }%
    {% the counter exists
     \stepcounter{#1}%
    }%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% markers for requirements
\newcommand{\req}[2][0]{%
        \ifthenelse{\equal{#1}{0}}
          {REQ.#2.\padzeroes[3]{\decimalnum{\value{#2}}}}
          {REQ.#2.\padzeroes[3]{\decimalnum{\value{#2}}}.\padzeroes[2]{\decimalnum{#1}}}%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand{\@reqID}{}

\newcommand{\itemReq}[3][0]{
    \req@nomen@count{#2}%
    \DTLnewrow{reqs}%
    \ifthenelse{\equal{#1}{0}}
          {\renewcommand{\@reqID}{\req{#2}}}
          {\renewcommand{\@reqID}{\req[#1]{#2}}}%
    \item[{[\@reqID]}]#3%
    \dtlexpandnewvalue%
    \DTLnewdbentry{reqs}{reqKey}{\@reqID}%
    \DTLnewdbentry{reqs}{reqText}{#3}%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
\begin{enumerate}
\itemReq{CategoryA}{Requirement category 1 text 1.}
\itemReq{CategoryA}{Requirement category 1 text 2.}
\itemReq{CategoryB}{Requirement category 1 text 1.}
\end{enumerate}
\DTLdisplaydb{reqs}
\end{document}

This code has another problem: the IDs in the table are always the ID with the highest counter in the text.

  • Welcome to TeX.SX! Can you please expand the code snippet that you have posted to a full minimal working example. A MWE should compile and be as small as possible to demonstrate your problem. it's much easier to help you if we have working code to start from. – Andrew Jun 19 '17 at 16:50
3

Update

\dtlexpandnewvalue seems to expand only once. So you have to use an additional argument for \req that takes \arabic{<countername>}.

With your changed example:

\documentclass{article} 
\usepackage{fmtcount}
\usepackage{datatool}

\DTLnewdb{reqs}
\DTLaddcolumn{reqs}{reqKey}
\DTLaddcolumn{reqs}{reqText}

\makeatletter
% macro creating a new latex counter for every new entitiy name and requirement
\newcommand\req@nomen@count[1]{%
  \@ifundefined{c@#1}
    {% the counter doesn't exist
     \newcounter{#1}\setcounter{#1}{1}%
    }%
    {% the counter exists
     \stepcounter{#1}%
    }%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% markers for requirements
\newcommand{\req}[3][0]{%
        \ifthenelse{\equal{#1}{0}}
          {REQ.#2.\padzeroes[3]{\decimalnum{#3}}}
          {REQ.#2.\padzeroes[3]{\decimalnum{#3}}.\padzeroes[2]{\decimalnum{#1}}}%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand{\@reqID}{}

\newcommand{\itemReq}[3][0]{%
    \req@nomen@count{#2}%
    \DTLnewrow{reqs}%
    \ifthenelse{\equal{#1}{0}}
          {\renewcommand{\@reqID}{\req{#2}{\arabic{#2}}}}
          {\renewcommand{\@reqID}{\req[#1]{#2}{\arabic{#2}}}}%
    \item[{[\@reqID]}]#3%
    \dtlexpandnewvalue%
    \DTLnewdbentry{reqs}{reqKey}{\@reqID}%
    \DTLnewdbentry{reqs}{reqText}{#3}%
}
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
\begin{enumerate}
\itemReq{CategoryA}{Requirement category 1 text 1.}
\itemReq{CategoryA}{Requirement category 1 text 2.}
\itemReq{CategoryB}{Requirement category 1 text 1.}
\end{enumerate}
\DTLdisplaydb{reqs}
\end{document}

Result:

enter image description here

But maybe you can avoid the nesting of commands:

\documentclass{article} 
\usepackage{fmtcount}
\usepackage{datatool}

\DTLnewdb{reqs}
\DTLaddcolumn{reqs}{reqKey}
\DTLaddcolumn{reqs}{reqText}

\makeatletter
\newcommand{\@reqID}{}
\newcommand{\itemReq}[3][0]{%
  \@ifundefined{c@#2}{\newcounter{#2}}{}%
  \stepcounter{#2}%
  \DTLnewrow{reqs}%
  \ifthenelse{\equal{#1}{0}}
    {\renewcommand{\@reqID}{REQ.#2.\padzeroes[3]{\decimalnum{\arabic{#2}}}}}
    {\renewcommand{\@reqID}{REQ.#2.\padzeroes[3]{\decimalnum{\arabic{#2}}}.\padzeroes[2]{\decimalnum{#1}}}}%
  \item[{[\@reqID]}]#3%
  \dtlexpandnewvalue%
  \DTLnewdbentry{reqs}{reqKey}{\@reqID}%
  \DTLnewdbentry{reqs}{reqText}{#3}%
}
\makeatother

\begin{document}
\begin{enumerate}
\itemReq{CategoryA}{Requirement category 1 text 1.}
\itemReq{CategoryA}{Requirement category 1 text 2.}
\itemReq{CategoryB}{Requirement category 1 text 1.}
\end{enumerate}
\DTLdisplaydb{reqs}
\end{document}

The result is the same as above.


Old answer

With the following code only the last values of the counters are used, when the database is printed.

datatool does not expand added values by default. When you display the table the original definition is valid. So all printed keys are empty.

To expand the values while added to database reqs use \dtlexpandnewvalue inside the definition of \@regID.

Additionally I think you do not want to step the counter in \req because \req is excecuted twice per \@regID: onces for printing as argument of \item and once for adding to the database.

And I have changed another row of the code, because \req takes an optional and an mandatory argument (not two mandantory arguments).

In the following example I also use package enumitem to define an own listenvironment reqDecsr.

\documentclass{article}
\usepackage{fmtcount}
\usepackage{xcolor}
\usepackage{longtable}
\usepackage{enumitem}
\newlist{reqDescr}{description}{1}
\setlist[reqDescr]{leftmargin=8em}

\usepackage{datatool}


\DTLnewdb{reqs}
\DTLaddcolumn{reqs}{reqKey}
\DTLaddcolumn{reqs}{reqText}

\makeatletter
    \newcommand\req@nomen@count[1]{%
      \@ifundefined{c@#1}
        {% the counter doesn't exist
         \newcounter{#1}\setcounter{#1}{1}%
        }
        {% the counter exists
         \stepcounter{#1}%
        }%
    }
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % markers for requirements
    \newcommand{\req}[2][0]{%
        %\req@nomen@count{#2}% <- remove it here
        \ifthenelse{\equal{#1}{0}}
          {REQ.#2.\padzeroes[3]{\decimalnum{\value{#2}}}}
          {REQ.#2.\padzeroes[3]{\decimalnum{\value{#2}}}.\padzeroes[2]{\decimalnum{#1}}}%
    }
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \newcommand{\@reqID}{}
    \newcommand{\itemReq}[3][0]{%
        \req@nomen@count{#2}% <- use it here
        \DTLnewrow{reqs}%
        \ifthenelse{\equal{#1}{0}}
          {\renewcommand{\@reqID}{\req{#2}}}
          {\renewcommand{\@reqID}{\req[#1]{#2}}}% <- changed
        \item[\textcolor{blue}{[\@reqID]}]#3%
        \dtlexpandnewvalue% <- added
        \DTLnewdbentry{reqs}{reqKey}{\@reqID}%
        \DTLnewdbentry{reqs}{reqText}{#3}%
        }
    \makeatother
\begin{document}
\begin{reqDescr}
\itemReq{reqCategory}{Requirement text, can be lengthy.}
\end{reqDescr}
...
\DTLdisplaylongdb{reqs}
\end{document}

Result:

enter image description here

If the entries are longer, then you can replace

\DTLdisplaylongdb{reqs}

by something like

\begin{longtable}{lp{.65\textwidth}}
  \textbf{reqKey}&\multicolumn{1}{l}{\textbf{reqText}}\\
  \endhead
  \DTLforeach*{reqs}{\Key=reqKey,\Text=reqText}{\DTLiffirstrow{}{\tabularnewline}\Key&\Text}
\end{longtable}

enter image description here

BTW: Please always provide a MWE. Then we do not have to guess which packages are needed to compile your code.

| improve this answer | |
  • Thanks esdd, your solution proposal almost solves my problem. I edited my initial question and provided a minimal working example including your fixes. Now the IDs appears in the db-output table but always with the ID with the highest number. Any ideas? – WolfiG Jun 20 '17 at 13:18
  • @WolfiG See my updated answer. – esdd Jun 20 '17 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.