Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I am busy with a document where I need to add an Appendix with a list of names and short biographies (about a paragraph each).

I would be happier if I can do that as I describe the person in the relevant chapters save that to a macro and then add at the end. Similar to a Bibliography.

Is there a package that can do this or a way to build such macros?

share|improve this question
    
Answers to this question might be of use. –  Seamus Apr 8 '11 at 15:57
add comment

3 Answers 3

up vote 11 down vote accepted

I would take a slightly different approach than Seamus.

We first define a list to hold all the names. The list is to be delimited by commas:

\def\alist{}% {George, Martin, Seamus, Yiannis}

We then define helper macros to add a person to the list. At the same time we create a command on the fly to hold the Bio. For example typing \Mary will typeset the Bio for the person.

To print the Bios in the appendix we simply type,

\PrintBios

We also add a few helper functions to keep the list sorted, so that we can print them alphabetically. These are borrowed for the listings package (just a BubbleSort).

To loop through the list we use the @for from the LaTeX kernel.

Here is a minimal that includes all these. The Bios are just paragraphs from the lipsum package.

\documentclass[11pt]{book}
\usepackage{lstdoc,lipsum}
\begin{document}
\makeatletter
\def\alist{}

\let\sort\lst@BubbleSort 
\def\addtolist#1#2{
  \lst@lAddTo\alist{#2}
}

\long\gdef\addPerson#1#2{\addtolist\alist{#1,}}

\def\AddBio#1#2{%
\long\expandafter\gdef\csname#1\endcsname{\textbf{#1}: #2}
\addPerson{#1}{#2}
\sort\alist
}

\def\PrintBios{%
  \@for \i:=\alist\do{%
  \csname\i\endcsname}
}
%example
\AddBio{Yiannis}{\lipsum[2]}
\AddBio{Mary}{\lipsum[3]}
\AddBio{Ann}{\lipsum[1]}
% print the biographies
\PrintBios
\makeatother
\end{document}

I am not too sure how fast it will be for hundreds of Bios, but for about 100-200 the compiling time was imperceptible.

share|improve this answer
    
I'm late to the party, but I brought cake! :) Amazing answer, Yiannis! :) –  Paulo Cereda Mar 28 '13 at 1:12
add comment

Here's an example of using the newfile package to achieve this. It could obviously do with some tweaking. A lot of this is borrowed from answers to this question. Also thanks to Martin Scharrer for comments.

The idea is to write each author bio to a file and then read them all in at the end.

\documentclass{book}
\usepackage{newfile}
\usepackage{lipsum}
\newoutputstream{bios}
\openoutputfile{\jobname.bio}{bios}
\newcommand\styleauthor[1]{{\bfseries \begin{center}#1\end{center}}}
\newcommand\authorbio[2]{%
    \addtostream{bios}{%
      \unexpanded{%
        \styleauthor{#1}%
        \par
        #2
        \vspace{\baselineskip}}
    }
  }
\begin{document}
\chapter{Foo}
\authorbio{A. Author}{Here is a short bio on Albert Author

\lipsum[2]}

\chapter{Bar}

\authorbio{B. Buthor}{Here is a short bio on Brian Buthor

This allows newlines. Sweet.}

\appendix

\chapter{Author bios}
\closeoutputstream{bios}
\input{\jobname.bio}
\end{document}
share|improve this answer
    
This only works for single paragraphs... –  Seamus Apr 8 '11 at 16:14
    
@Seamus no it doesn't. You fixed it, remember? –  Seamus Apr 8 '11 at 16:25
    
@Seamus: Why shouldn't it work with more than one paragraph? It works fine in my tests. The only trouble I see if \par is redefined in a fragile way. Which can be fixed using: \newcommand\authorbio[2]{{\let\par\relax\addtostream{bios}{\noexpand\item[#1] #2}}} –  Martin Scharrer Apr 8 '11 at 16:27
    
@Martin Scharrer I hadn't actually thought it through. I was covering my back. It think the way the updated solution works should be even more robust and more easily customisable... –  Seamus Apr 8 '11 at 16:29
1  
@Seamus: Also i would recommend using \protect instead of \noexpand. It's much saver in writes. Here it might be ok, but e.g. \addtocontents writes the stuff first into the .aux file and then into the target file like .toc. Therefore you need more than one \noexpand. The \protect is then \noexpand\protect\noexpand :-) –  Martin Scharrer Apr 8 '11 at 16:34
show 11 more comments

Just for fun, here's Yiannis' answer reimplemented in LaTeX3. The idea is exactly the same: the \AddBio command saves the author name and bio to macros, and uses the sort argument to name them. The sort is also what the authors are sorted by.

This makes use of egreg's solution to how to sort strings in an l3 way. (the code has the answer linked in a comment).

\documentclass{article}
\usepackage{xparse,expl3,kantlipsum,l3sort}



\ExplSyntaxOn
\seq_new:N \l_authorlist_seq

% Sort, Author Name, Bio
\NewDocumentCommand{\AddBio}{mm+m}{
  \tl_new:c {l_#1_name_tl}
  \tl_gset:cn {l_#1_name_tl} {#2}
  \tl_new:c {l_#1_bio_tl} 
  \tl_gset:cn {l_#1_bio_tl} {#3}
  \seq_gput_right:Nn \l_authorlist_seq {#1}
}

% From egreg's answer: http://tex.stackexchange.com/a/52967/215

\prg_new_conditional:Npnn \string_compare:nnn #1 #2 #3 {TF}
  {
   \if_int_compare:w \pdftex_strcmp:D {#1}{#3} #2 \c_zero
    \prg_return_true:
   \else:
    \prg_return_false:
   \fi
  }

\NewDocumentCommand{\sortauthors}{ }{
  \seq_sort:Nn \l_authorlist_seq {
    \string_compare:nnnTF {##1} {>} {##2} {\sort_reversed:} {\sort_ordered:}
  }
}

\NewDocumentCommand{\PrintBio}{m}{
  \textbf{\tl_use:c {l_#1_name_tl}:~} \tl_use:c{l_#1_bio_tl}\par
}

\NewDocumentCommand{\PrintBios}{}{
  \sortauthors
  \seq_map_inline:Nn \l_authorlist_seq {\PrintBio{##1}}
}
\ExplSyntaxOff
\begin{document}

  \AddBio{foo}{Jethro Foo}{\kant[1-2]}
  \AddBio{bar}{Horatio Bar}{\kant[2-3]}
  \AddBio{kant}{Immanuel Kant}{\kant[5]}

\PrintBios
\end{document}

I'm sure some of the commands and so on don't live up to the macro naming conventions of LaTeX3, but it's a proof of concept...

share|improve this answer
    
I should have actually used l3prop rather than rely on token lists. I did it properly here about line 93. –  Seamus May 18 '13 at 12:18
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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