# Collect contents of lists at beginning of document

I would like to create a custom list environment that collects the contents of these lists and places it at the beginning of the document.

\begin{objectives}
\item See no evil.
\end{objectives}

lots of stuff 1

\begin{objectives}
\item Hear no evil.
\end{objectives}

lots of stuff 2

\begin{objectives}
\item Speak no evil.
\end{objectives}

lots of stuff 3


I would like the objectives environment to be defined so that the commands above have the same effect as

\begin{enumerate}
\item See no evil.
\item Hear no evil.
\item Speak no evil.
\end{enumerate}

lots of stuff 1

lots of stuff 2

lots of stuff 3


(The reason I can't just move the objectives to the start of the document manually is that my content is spread across multiple files that will be combined a la carte.) I know I can use the collect package to obtain the list at the end of the document by defining

\usepackage{collect}
\definecollection{ob}
\newenvironment{objective}{%
\collect{ob}{}{}}{\endcollect}

..earlier content..

\begin{enumerate}
\includecollection{ob}
\end{enumerate}


It seems that a solution would need to depend on \immediate\write\tempfile{} to create a temporary file to store the contents. However, each of my attempts to create a temporary file will only succeed if I place the list at the end.

I know it is possible to collect content to be placed at the beginning of a document because a table of contents or a list of figures does just that. I haven't been able to make heads or tails of the code in the todonotes package or tocloft package.

Could you please point me in the right direction?

You can use the built in mechanism for the table of contents:

\documentclass{article}
\usepackage{environ}

\usepackage{lipsum} % just for the example

\makeatletter
\newcommand{\printobjectives}{%
\section*{Objectives}
\begin{enumerate}
\def\@noitemerr{\@latex@warning{Empty objective list}}%
\@starttoc{obj}
\end{enumerate}
}
\newcommand{\l@obj}[2]{#1}
\makeatother

\NewEnviron{objectives}
{%
\noexpand\unexpanded{\unexpanded\expandafter{\BODY}}%
}%
}

\begin{document}

\printobjectives

\section{Main}

\begin{objectives}
\item See no evil.
\end{objectives}

\lipsum[2]

\begin{objectives}
\item Hear no evil.
\end{objectives}

\lipsum[3]

\begin{objectives}
\item Speak no evil.
\end{objectives}

\lipsum[4]

\end{document}


If you load hyperref, but don't require hyperlinks for the objective list, do

\let\originalcontentsline\contentsline
\usepackage{hyperref}


(the first line is to save the original meaning of \contentsline) and change the code between \makeatletter and \makeatother into

\makeatletter
\newcommand{\printobjectives}{%
\section*{Objectives}
\begin{enumerate}
\let\contentsline\originalcontentsline
\def\@noitemerr{\@latex@warning{Empty objective list}}%
\@starttoc{obj}
\end{enumerate}
}
\newcommand{\l@obj}[3]{#1}
\makeatother

• The hyperref package turns the items in the objective list into clickable links. Any ideas on how to make the hyperref package ignore the objective environment? – Serge Jun 15 '14 at 4:56
• @Serge I added the corrections for the new situation – egreg Jun 15 '14 at 8:31
• It's amazing that two little lines could fix the problem. You saved me a whole week of work with your answer and subsequent edit. It will take me a lot of studying to figure out exactly what your code does. You are a wizard. – Serge Jun 15 '14 at 18:30
• I have copied the code exactly as is, but when I add the package hyperref to the preamble and rerun, the list collected in Objectives becomes a single line So rather than print Objectives 1. See no evil. 2. Hear no evil. 3. Speak no evil. it prints Objectives See no evil. Hear no evil. Speak no evil. The addition of that package is the only change I made. Any ideas? – Mahoma Sep 5 '16 at 5:27
• I'm trying to keep the hyperlinks It works if I use the fix detailed above but I lose the hyperlinks – Mahoma Sep 5 '16 at 5:46