# How to automatically create a book of abstracts of a scientific conference?

I'd like to prepare a book of abstracts of a scientific conference. I expect to receive about 650 articles. Suppose the articles are all the same document class and all have the following structure (feel free to change its structure):

\documentclass{article}
\usepackage{lipsum}% just for this example
\newcommand{\university}[1]{\\ \itshape #1}
\title{Title of the first article}
\author{Author 1 \university{Foo University}}
\date{}

\begin{document}
\maketitle
\begin{abstract}
\lipsum[1]
\end{abstract}
\section{Introduction}
Here goes some text ...
\end{document}


I want to extract the title, author, university, and the abstract of articles and put each two of them on the same page in my "Book of Abstracts" as follows:

Due to the large number of articles I want to automatically do this. Is there a package or template to do this?
Please keep in mind that I've searched this site very well and I didn't find an automatic way.

## Edit

Please assume that "Call for Papers" will be about next month, so we can still change the source code above if it helps find a better solution.

• My guess is that using some Perl script (or whatever language you prefer) for extracting the relevant information is the best strategy. – egreg Jan 24 '15 at 13:49
• I think, the combine package could help you. It allows you to have separate documents while being able to combine them into one as well. – Uwe Ziegenhagen Jan 24 '15 at 14:05
• @ChristianHupfer: Each article is in a separate folder on my Windows machine. As for your second question, No, I don't. – Sisabe Jan 24 '15 at 14:06
• @Sisabe You can surely extract the information when LaTeXing each file. Then you have to collect all the produced files. A script would be much more efficient. – egreg Jan 24 '15 at 14:12
• for better typography. It does not have much to do with your issue though. – pluton Jan 24 '15 at 21:30

This is just the solution proposed by wipet in mode batch. All you need is to put this .bat in the same directory of articles and run it (clic twice) you'll get abstract.tex and abstract.pdf test with 651 .tex files

@echo off

set path=C:/texlive/2014/bin/win32;%path%

(
echo \documentclass{article}
echo \usepackage{lipsum}
echo \newcommand{\university}[1]{\cr \itshape #1}
echo.
echo \def\onlyabstracts{%
echo    \long\def\documentclass##1##2\title##3##4\begin##5{\title{##3}##4}
echo    \def\title##1{\vskip5ex{\centering\LARGE##1\par}}
echo    \let\author=\authorX \let\and=\andX
echo    \def\date##1{}
echo    \let\maketitle=\relax
echo    \let\abstractX=\abstract
echo    \def\abstract{\abstractX \aftergroup\endinput}
echo }
echo \def\authorX#1{\medskip{\leftskip=0pt plus1fill \rightskip=\leftskip \lineskip=8pt
echo    \noindent\andA#1\crcr\egroup\egroup\par}}
echo \def\andA{\vtop\bgroup\baselineskip=14pt\halign\bgroup\hfil\large##\unskip\hfil\cr}
echo \def\andX{\crcr\egroup\egroup\hskip3em plus1em\andA}
echo.
echo \begin{document}
echo \onlyabstracts
) > abstract.tet
for %%a in (*.tex) do echo \input %%a  >> abstract.tet
echo \end{document} >> abstract.tet
ren abstract.tet abstract.tex
pdflatex abstract.tex

for %%a in (*.tet, *.aux, *.log, *.lof, *.lot, *.toc, *.idx, *.ilg, *.ind, *sync*, *.out, *.bbl, *.blg, *.thm) do del %%a

• Thank you very much. your solution is great. Just a simple question: suppose each article (with its figures, etc) is inside a folder. The folder names are the same as the name of the article inside them. Is there a way to modify your code to search for articles in this situation, too? – Sisabe Feb 7 '15 at 17:19
• yes i'll try to do it – touhami Feb 7 '15 at 17:28
• replace for %%a in (.tex) do echo \input %%a >> abstract.tet by for /f "tokens=" %%i in ('dir /a:d /b *') do echo \input{%%i/%%i} >> abstract.tet – touhami Feb 7 '15 at 17:56
• or by for /d %%a in (*) do echo \input{%%a/%%a} >> abstract.tet – touhami Feb 7 '15 at 18:03
• 1. Where should I put the .bat file? 2. There is no need to change the last line of your code in the new scenario? – Sisabe Feb 7 '15 at 18:16

You can try this:

\documentclass{article}
\usepackage{lipsum}% just for this example
\newcommand{\university}[1]{\cr \itshape #1}

\def\onlyabstracts{%
\long\def\documentclass##1##2\title##3##4\begin##5{\title{##3}##4}
\def\title##1{\vskip5ex{\centering\LARGE##1\par}}
\let\author=\authorX \let\and=\andX
\def\date##1{}
\let\maketitle=\relax
\let\abstractX=\abstract
\def\abstract{\abstractX \aftergroup\endinput}
}
\def\authorX#1{\medskip{\leftskip=0pt plus1fill \rightskip=\leftskip \lineskip=8pt
\noindent\andA#1\crcr\egroup\egroup\par}}
\def\andA{\vtop\bgroup\baselineskip=14pt\halign\bgroup\hfil\large##\unskip\hfil\cr}
\def\andX{\crcr\egroup\egroup\hskip3em plus1em\andA}

\begin{document}
\onlyabstracts
\input article1
\input article2
\input article3
...
\input article169
\end{document}


If you don't want to write 169times the \input article<number> you can use \loop. For example:

\newcount\tmpnum
\loop \advance\tmpnum by1 \input article\the\tmpnum\relax \ifnum\tmpnum<169 \repeat

• typing \input article650 might be tedious for 650 files and @Sisabe is renaming the files with article***.tex is required or while submission itself by each author it would take the article***.tex name – texenthusiast Jan 28 '15 at 2:08
• @wipet: Thakns for your solution but there is a problem: If one of the articles has more than one author (\author{First author \university{Foo University} \and Second author \university{Bar University}}), it throws errors. How to fix this? – Sisabe Jan 28 '15 at 13:50
• @Sisabe OK, I've added the \and feature to the code. The problem is that I don't know LaTeX, so I cannot foresee all LaTeX syntax peculiarities. – wipet Jan 28 '15 at 15:53

I've written a short pythontex solution:

\documentclass{article}
\usepackage{lipsum}
\usepackage{pythontex}

\newcommand{\university}[1]{{\centering\itshape\large #1\par}\vskip5ex}
\newcommand{\abstitle}[1]{{\centering\LARGE #1\par}\vskip3ex}
\newcommand{\absauthor}[1]{{\centering\large #1\par}}
\newcommand{\absname}{{\centering\bfseries\abstractname\par}\vskip1ex}

\begin{document}

\begin{pycode}
from __future__ import print_function
import os

os.chdir("..") #delete this for standalone script

content = open("content.tex", "w+")
path = os.getcwd() + "/abstracts" #directory for abstract tex files

for file in os.listdir(path):
if file.endswith(".tex"):
with open(path + "/" + file) as input_data:
for line in input_data:
if "\\title{" in line:
line = line.replace("\\title{","\\abstitle{")
print(line, file=content)
if "\\author{" in line:
line = line.replace("\\author{","\\absauthor{")
print(line, file=content)
if "\\university{" in line:
print(line, file=content)
print("\\absname\n", file=content)
if line.strip() == "\\begin{abstract}":
break
for line in input_data:
if line.strip() == "\\end{abstract}":
break
print(line, file=content)
\end{pycode}
\IfFileExists{content.tex}{
\input{content.tex}
}{Test}
\end{document}


Place all .tex-files in folder abstracts (or simply change the path) and run:

pdflatex filename.tex
pythontex filename.tex
pdflatex filename.tex


You really have to pay attention to the indents. The following commands can't be nested:

\title{...}
\author{...}
\university{...}


Otherwise, they appear twice.

You can customize everything in LaTeX or add some additional stuff with the python print-function.

• Doesn't the name of the articles matter? – Sisabe Jan 27 '15 at 13:04
• No, every file xyz.tex in the folder is being processed. – SLx64 Jan 27 '15 at 13:07

I was threatened in the chatroom for writing an answer, so here it is. :)

Personally, I think there cannot be an automatic solution in the sense of working without a minimal effort on complying with a couple of rules. That said, I decided to take the scripting path and provide a very simple yet powerful solution to this question.

First things first: I admit a paper containing at least something along these lines:

\title{How to eat rice}
\author{Foo Bar and Baz Fooz}
...
\begin{abstract}
Here lies my awesome text.
\end{abstract}


I could use regular expressions in order to extract these fields, but I decided to implement my own finite state machine with a few tricks under the sleeve: a very simple counting mechanism in order to detect a straightforward syntactic nesting and avoid premature symbol extraction. Of course, the script is hardcoded, but that's the price when you want things that work. :)

Without further ado, here's the Python script. Hopefully the Python enthusiasts won't kill me for being excessively verbose, but that's just the way I like to code. :) In case you are lost, these are FSM's. Of course, the solution is trivial, but I wouldn't even think of expanding the idea of using them beyond this simple case study, since TeX is not even context free. But that's another story.

from Cheetah.Template import Template
import glob, sys, getopt

def getTitle(text):
output = ""
state = 0
counter = 0
for symbol in text:
if state == 0:
if symbol == '\\':
state = 1
elif state == 1:
if symbol == 't':
state = 2
else:
state = 0
elif state == 2:
if symbol == 'i':
state = 3
else:
state = 0
elif state == 3:
if symbol == 't':
state = 4
else:
state = 0
elif state == 4:
if symbol == 'l':
state = 5
else:
state = 0
elif state == 5:
if symbol == 'e':
state = 6
else:
state = 0
elif state == 6:
if symbol == '{':
counter = counter + 1
state = 7
elif symbol not in [ ' ', '\n', '\t', '\r' ]:
state = 0
elif state == 7:
output = output + symbol
if symbol == '{':
counter = counter + 1
elif symbol == '\\':
state = 8
elif symbol == '}':
counter = counter - 1
if counter == 0:
return output[:-1]
elif state == 8:
output = output + symbol
state = 7

def getAuthor(text):
output = ""
state = 0
counter = 0
for symbol in text:
if state == 0:
if symbol == '\\':
state = 1
elif state == 1:
if symbol == 'a':
state = 2
else:
state = 0
elif state == 2:
if symbol == 'u':
state = 3
else:
state = 0
elif state == 3:
if symbol == 't':
state = 4
else:
state = 0
elif state == 4:
if symbol == 'h':
state = 5
else:
state = 0
elif state == 5:
if symbol == 'o':
state = 6
else:
state = 0
elif state == 6:
if symbol == 'r':
state = 7
else:
state = 0
elif state == 7:
if symbol == '{':
counter = counter + 1
state = 8
elif symbol not in [ ' ', '\n', '\t', '\r' ]:
state = 0
elif state == 8:
output = output + symbol
if symbol == '{':
counter = counter + 1
elif symbol == '\\':
state = 9
elif symbol == '}':
counter = counter - 1
if counter == 0:
return output[:-1]
elif state == 9:
output = output + symbol
state = 8

def getAbstract(text):
output = ""
state = 0
counter = 0
for symbol in text:
if state == 0:
if symbol == '\\':
state = 1
elif state == 1:
if symbol == 'b':
state = 2
else:
state = 0
elif state == 2:
if symbol == 'e':
state = 3
else:
state = 0
elif state == 3:
if symbol == 'g':
state = 4
else:
state = 0
elif state == 4:
if symbol == 'i':
state = 5
else:
state = 0
elif state == 5:
if symbol == 'n':
state = 6
else:
state = 0
elif state == 6:
if symbol == '{':
counter = counter + 1
state = 7
elif symbol not in [ ' ', '\n', '\t', '\r' ]:
state = 0
elif state == 7:
if symbol == 'a':
state = 8
else:
state = 0
elif state == 8:
if symbol == 'b':
state = 9
else:
state = 0
elif state == 9:
if symbol == 's':
state = 10
else:
state = 0
elif state == 10:
if symbol == 't':
state = 11
else:
state = 0
elif state == 11:
if symbol == 'r':
state = 12
else:
state = 0
elif state == 12:
if symbol == 'a':
state = 13
else:
state = 0
elif state == 13:
if symbol == 'c':
state = 14
else:
state = 0
elif state == 14:
if symbol == 't':
state = 15
else:
state = 0
elif state == 15:
if symbol == '}':
counter = 0
state = 16
else:
state = 0
elif state == 16:
output = output + symbol
if symbol == '{':
counter = counter + 1
elif symbol == '\\':
state = 17
elif symbol == '}':
counter = counter - 1
elif state == 17:
output = output + symbol
if symbol == 'e':
state = 18
else:
state = 16
elif state == 18:
output = output + symbol
if symbol == 'n':
state = 19
else:
state = 16
elif state == 19:
output = output + symbol
if symbol == 'd':
state = 20
else:
state = 16
elif state == 20:
output = output + symbol
if symbol == '{':
counter = counter + 1
state = 21
elif symbol not in [ ' ', '\n', '\t', '\r' ]:
state = 16
else:
elif state == 21:
output = output + symbol
if symbol == 'a':
state = 22
else:
state = 16
elif state == 22:
output = output + symbol
if symbol == 'b':
state = 23
else:
state = 16
elif state == 23:
output = output + symbol
if symbol == 's':
state = 24
else:
state = 16
elif state == 24:
output = output + symbol
if symbol == 't':
state = 25
else:
state = 16
elif state == 25:
output = output + symbol
if symbol == 'r':
state = 26
else:
state = 16
elif state == 26:
output = output + symbol
if symbol == 'a':
state = 27
else:
state = 16
elif state == 27:
output = output + symbol
if symbol == 'c':
state = 28
else:
state = 16
elif state == 28:
output = output + symbol
if symbol == 't':
state = 29
else:
state = 16
elif state == 29:
output = output + symbol
if symbol == '}':
counter = counter - 1
if counter == 0:
else:
state = 16
else:
state = 16

def getArticles(path):
elements = glob.glob(path)
articles = []
for element in elements:
with open(element, 'r') as handler:
article = {}
article['title'] = getTitle(content)
article['author'] = getAuthor(content)
article['abstract'] = getAbstract(content).strip()
articles.append(article)
return articles

def generateTemplate(articles, template, output):
with open(template, 'r') as handler:
merge = Template(source=content, searchList=[ { 'data': articles } ])
with open(output, 'w') as handler:
handler.write(str(merge))

def main(arguments):
options, _ = getopt.getopt(arguments, 'p:t:o:', ['path=', 'template=', 'output='])
if len(options) == 3:
for flag, value in options:
if flag in ('-p', '--path'):
path = value
if flag in ('-t', '--template'):
template = value
if flag in ('-o', '--output'):
output = value
articles = getArticles(path)
generateTemplate(articles, template, output)

main(sys.argv[1:])


Now let's say I have two papers as follows, following the very same structure:

article1.tex

\documentclass{article}

\newcommand{\university}[1]{{(\itshape#1)}}

\title{Title of the first article}
\author{Author 1 \university{Foo University} and Author 2 \university{Potato U}}
\date{}

\begin{document}

\maketitle

\begin{abstract}
This is a lovely abstract for paper 1. How do you like my text?
\end{abstract}

\section{Introduction}

Here goes some text of article 1.

\end{document}


article2.tex

\documentclass{article}

\newcommand{\university}[1]{{(\itshape#1)}}

\title{Title of the second article}
\author{Author 1 \university{Disney University}, Author 2 \university{Duck Academy} and Author 3 \university{University of Nowhere}}

\begin{document}

\maketitle

\begin{abstract}
This is a lovely abstract for paper 2. How do you like my text?
\end{abstract}

\section{Introduction}

Here goes some text of article 2.

\end{document}


Output of both, as one would expect. :)

article1.pdf

article2.tex

Now let's use the script. First of all, we need to create a template using the Cheetah language description. Simply put, we will use a for loop where we iterate through all dictionaries in the data array. Note that $ is used as a placeholder and not as math mode, as we are used in TeX. Don't worry with them, they'll be gone once we merge everything. :) Since we are dealing with a dictionary, we access values from its keys, so $article['title'] will return the title of that article. :) Here's our template:

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\newcommand{\university}[1]{{(\itshape#1)}}

\begin{document}

\begin{tabular}{p{.33\linewidth}p{.33\linewidth}p{.33\linewidth}}
\hline
Title & Authors & Abstract\\
\hline
#for $article in$data
$article['title'] &$article['author'] & $article['abstract']\\ #end for \hline \end{tabular} \end{document}  We can run the Python script providing the following parameters: • --path/-p <full path + file patterns>: the script will read all files in the provided path matching the file pattern. For example, /home/paulo/papers/*.tex will extract info from all .tex files in the papers folder under my home directory. • --template/-t <full template path>: the template to be populated with data extracted from files in the previous option. For example, /home/paulo/template.tex. • --output/-o <full output path>: the output file with all data merged into the template. For example, /home/paulo/abstracts.tex. Let's run: $ python code.py --path /home/paulo/papers/.tex --template /home/paulo/template.tex --output abstracts.tex


And that's it. This is the generated file:

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\newcommand{\university}[1]{{(\itshape#1)}}

\begin{document}

\begin{tabular}{p{.33\linewidth}p{.33\linewidth}p{.33\linewidth}}
\hline
Title & Authors & Abstract\\
\hline
Title of the first article & Author 1 \university{Foo University} and Author 2 \university{Potato U} & This is a lovely abstract for paper 1. How do you like my text?\\
Title of the second article & Author 1 \university{Disney University}, Author 2 \university{Duck Academy} and Author 3 \university{University of Nowhere} & This is a lovely abstract for paper 2. How do you like my text?\\
\hline
\end{tabular}

\end{document}


And this is the output:

Hope it helps. :)

• How to use your solution on my Windows machine? – Sisabe Jan 28 '15 at 13:54
• @Sisabe: Windows installer for Python and libraries might be a good start. :) – Paulo Cereda Jan 28 '15 at 15:44
• You were threatened for writing it? Dyna drueni! – cfr Jan 31 '15 at 4:30

My solution - is to use pdfpages package.

Main idea is:

1) creation of separate abstracts by scheme .tex to pdf (without headers and footers). TeX code of the abstract should write information about article (title, author or some other) into the .dat file. For more detail look here

2) Create .tex-combine, which will collect the abstracts in book of abstracts with pdfpages package, add a headers and footers to the pdf pages and create table of contents (using created before .dat-file). For more detail look here.

Code for inserting pdf pages:

%------------Macro for insertinf PDF---------------------
\newcommand\papertitle{}% initialize
\newcommand\paperauthors{}% initialize

\newcommand{\insertpaper}[1]%
{% #1 is the file name (without extension)
\clearpage
\renewcommand\papertitle{}% reinitialize
\renewcommand\paperauthors{}% reinitialize
\input{#1.dat}%
\phantomsection
\chapterprecistoc{\paperauthors}
}

\makeatletter
\newcommand{\thispaperauthor}[2]{%
\ifx#2\finishauthors
% no more authors
\else
\expandafter\thispaperauthor % reinsert the swallowed token
\fi
}
\makeatother

\def\InsertNumArticles#1#2{%
\edef\fold{#2}
\newcount\i
\i1
\newcount\f
\f#1
\loop \ifnum\i<\the\f \insertpaper{\fold/paper\the\i/paper\the\i} \advance\i by1 \repeat
}


Using this macro in .tex -combine:

\part*{Name of section 1}

\InsertNumArticles{2}{1Plenar}
% here 2 -- is a number of the abstracts
% 1Plenar -- folder, which is contain pdf and dat files, source of abstract .tex, .aux and so on.

\part{Name of section 2}

\InsertNumArticles{3}{Astrophysics}

\part{Name of section 3}

\InsertNumArticles{3}{Geo science}

• Wouldn't this include the total titlepage too? – user31729 Jan 24 '15 at 18:55
• @Christian Hupfer Ttltepage you can create in a .tex-combine – sergiokapone Jan 24 '15 at 18:57
• I meant the titlepages of the included articles (selecting at least the first page!) – user31729 Jan 24 '15 at 19:01
• @sergiokapone: Thanks for your answer, but could you please tell me how to use your code? I'm completely new in latex. Also, please see my edit above if it help you. – Sisabe Jan 24 '15 at 22:02
• pdfpages won't help you, because it requires PDF, not TeX-files. So please take the advice of egreg: find somebody who writes a short script for you which copies title, author, abstract of each of the 600 files into a single, new TeX-file. If necessary, you can make a redefinition of title and whatever to adapt the content. – Keks Dose Jan 27 '15 at 9:57

Around year 2000, I actually faced a similar challenge: I had to create an annual consortium report from individually supplied papers. I wrote my own class to do this but it was essentially based on the "combine" package as mentioned by Uwe Ziegenhagen in a comment above (as it is an actual solution, it deserves more than a comment). I don't know whether the package is still maintained nowadays but it certainly did the job at the time. Although I have left the consortium in 2004, my work is still used today. An example of a consortium report can be found here. You can easily identify the individual papers. The combine package does not just combine abstracts, it can combine entire papers. But you can simply create an own little class that takes care of the abstracts only if necessary. I suggest you read the documentation and have a go. If you need any help, let me know. Creation of the master tex file (that in your case includes all the individual 650 papers/abstracts) can be automated with a little script.

this .bat does the job

@echo off

set path=%~dp0/../../mtTex/miktex/bin;%path%

for  %%a in (*.tex) do  (
pdflatex "\AtBeginDocument{\let\mt\abstract\let\mmt\endabstract\renewenvironment{abstract}{\mt}{\mmt\newpage}}\input{%%a}")
for  %%a in (*.pdf) do  echo \includepdf[pages=1]{%%a} >>mtt.ext
echo \end{document} >> mtt.ext
pdflatex mtt.ext


where mtt.ext is

\documentclass{article}
\usepackage{pdfpages}
\begin{document}


all in one .bat

@echo off

set path=%~dp0/../../mtTex/miktex/bin;%path%

for  %%a in (*.tex) do  (
pdflatex "\AtBeginDocument{\let\mt\abstract\let\mmt\endabstract\renewenvironment{abstract}{\thispagestyle{empty}\mt}{\mmt\stop}}\input{%%a}")
echo \documentclass{article} >> mtt.tex
echo \usepackage{pdfpages} >> mtt.tex
echo \begin{document} >> mtt.tex
for  %%a in (*.pdf) do  echo \includepdf[pages=1]{%%a} >> mtt.tex
echo \end{document} >> mtt.tex
pdflatex mtt.tex
ren mtt.pdf mtt.mtp
for %%a in (mtt.tex, *.pdf, *.aux, *.log, *.lof, *.lot, *.toc, *.idx, *.ilg, *.ind, *sync*, *.out, *.bbl, *.blg, *.thm) do del %%a
ren mtt.mtp mtt.pdf
del mtt.mtp


it make 1min37s for 181 files:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}
\usepackage[frenchb]{babel}
\usepackage{lipsum}
\title{Les document}
\author{Moi meme}
\date{\today}
\begin{document}
\maketitle
\begin{abstract}
\lipsum[1]
\end{abstract}
\lipsum[1-10]
\end{document}

• How to use your code? Can you explain the usage? – Sisabe Feb 2 '15 at 20:50
• All .tex files in same directory and the .bat file= a text file with ext .bat, than you cite correctly the path = place where pdflatex.exe (for me: ../../mtTex/...) and then clic the .bat twice – touhami Feb 2 '15 at 21:03
• I'm using Windows 7 and TeX Live 2014. So what should I enter in the set path line of your answer? In my Windows path I have C:\texlive\2014\bin\win32. – Sisabe Feb 3 '15 at 7:26
• set path=C:/texlive/2014/bin/win32;%path% But there is a probleme with 650 files I'll try fix it. – touhami Feb 3 '15 at 19:21
• When I click on the .bat file twice, a command prompt window appears and several files in the current directory are created but when the window is closed, all those files are disappeared! – Sisabe Feb 3 '15 at 21:18

I recently had to face the same challenge in order to organize a physics workshop. A set of python tool has been developed to compile directly the booklet from a database provided by a google webform to collect the abstract information. The source code is available in github: https://github.com/olivier-klein/booklet