4

I am trying to create a more complicated template but created this short example to document what I really want to do.

I want to create a form letter where the user will not see any complicated stuff which could be confusing. For this I want to hide all the datatool stuff

\documentclass{scrlttr2}
\usepackage{datatool}

\newcommand{\myDatabase}[1]{
    \DTLloaddb{test}{#1}%
}

%This is not working:
%\AtBeginDocument{
%   \DTLloaddb{test}{test.csv}%
%   \DTLforeach{test}{\name=Name, \age=Age}{%
%   \begin{letter}
%}
%
%\AtEndDocument{
%       \end{letter}}
%}

\myDatabase{test.csv}

\begin{document}
    \DTLforeach{test}{\name=Name, \age=Age}{% I want to remove this!
    \begin{letter}% I want to remove this!
        Dear Mr. \name
    \end{letter}}% I want to remove this!
\end{document}

My database test.csv looks just like this:

Name, Age
Alfred, 42
Brian, 23
Conrad, 66

My main problem is that splitting the \DTLForeach to appear at the beginning and conclude at the end of the document doesn't work. I tried already \bgroup and \egroup instead of using the bracket but this didn't change anything.

4
  • I know in my example somehow the first letter of "Dear" disappeares. Hints on this are welcome as well.
    – baghira
    Jul 19, 2018 at 16:58
  • I think if your users cannot tolerate any code at all in the document - not even something like \begin{myletter} ... \end{myletter}, then you should probably not be expecting them to use LaTeX. What happens when they want to include quotation marks or emphasise something? Don't force LaTeX on them if the whole idea of mark-up is alien. That's cruel and unusual typesetting in my book.
    – cfr
    Jul 20, 2018 at 0:49
  • The problem is not \begin{letter} and \end{letter}. It is the \DTLForeach. This is just a simple example. What i am doing is much more complicated. Since the user won't have to change the loop it is not necessary to see it.
    – baghira
    Jul 20, 2018 at 8:06
  • That's why I said myletter and not letter.
    – cfr
    Jul 20, 2018 at 23:52

1 Answer 1

5

First of all, the letter environment requires an argument, namely the address. This is probably the reason why the word Dear or parts of it disappear.

Regarding how to hide the machinery for generating the letters, here is a solution with several elements:

  • The definitions can be hidden by putting them into a style file or even a new document class (see below).

  • To use the contents of an environment (its body) as argument of another command, use \NewEnviron from the package environ. Applied to your example:

    \documentclass{scrlttr2}
    \usepackage{datatool}
    \usepackage{environ}
    \NewEnviron{Letters}[1]{%
      \DTLloaddb{test}{#1}%
      \DTLforeach{test}{\name=Name, \age=Age}{%
        \begin{letter}{\name}
        \BODY
        \end{letter}%
      }%
    }
    \begin{document}
    \begin{Letters}{test.csv}
      \opening{Dear Mr.~\name}
    \end{Letters}
    \end{document}
    
  • Finally, in order to hide \begin{documentclass} and \end{documentclass}, you have to use \aftergroup and a trick to make \BODY available after the Letters environment.

Here is the reduced input file:

\documentclass{myletters}
\begin{Letters}{test.csv}
  \opening{Dear Mr.~\name}
\end{Letters}

Put the following code into the file myletters.cls.

\ProvidesClass{myletters}[2018/07/20 My special letter class V0.42]
\LoadClass[a4paper,12pt]{scrlttr2}
% Define here any special class options
% \DeclareOption{...}{...}
% Pass all others to the underlying class
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrlttr2}}
\ProcessOptions\relax

\RequirePackage{datatool}
\newcommand\MakeLetters{%
  \begin{document}
    \DTLforeach{test}{\name=Name, \age=Age}{% 
      \begin{letter}{\name}
      \ContentsOfLetter
      \end{letter}%
    }%
  \end{document}%
}

\RequirePackage{environ}
\NewEnviron{Letters}[1]{%
  \DTLloaddb{test}{#1}%
  \expandafter\gdef\expandafter\ContentsOfLetter\expandafter{\BODY}%
  \aftergroup\MakeLetters
}

Here is the output of both versions:

enter image description here

enter image description here

enter image description here

6
  • There is an environment version of \DTLforeach (DTLenvforeach or DTLenvforeach*) which could be used instead. Jul 20, 2018 at 11:48
  • @NicolaTalbot Thanks for the suggestion. The environment works fine when used directly in the document, but in a \newenvironment command (with \begin{DTL...} in the begin-part and \end{DTL...} in the end-part) I get the error that the environments are closed in the wrong order. Using \DTLenvforeach and \endDTLenvforeach also doesn't help. The problem reminds me of the one that I solve by making \BODY global and using \aftergroup.
    – gernot
    Jul 20, 2018 at 12:14
  • Okay. I'll look into that. Thanks for the feedback. Jul 21, 2018 at 12:35
  • I tried to put the Environment into \AtBeginDocument, or. \AtEndDocument and got the Error "\begin{DTLenvforeach} on input line 18 ended by \end{document}.
    – baghira
    Jul 26, 2018 at 7:17
  • @baghira You can try \DTLenvforeach instead of \begin{DTLenvforeach} and \endDTLenvforeach instead of \end{DTLenvforeach}. If this doesn't work either, use the environ package as I have proposed in my solution.
    – gernot
    Jul 26, 2018 at 8:14

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.