I didn't look at Charles's code because I wanted to see how difficult it would be to implement a generic sorting macro that was expandable. It turns out that it's more or less straight-forward to do in a continuation-passing style.
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
% #1 - comparator
% #2 - token list to sort
\newcommand\sort[2]{%
\ifstrempty{#2}
{}% else
{%
\sort@begin#1{}#2\sort@s\sort@begin
}%
}
% helpers
\def\sort@s{\sort@s}
\def\ifsort@s#1{%
\ifx\sort@s#1%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - rest of the list
\def\sort@begin#1#2#3#4\sort@begin{%
\ifsort@s{#4}
{%
\sortend{#3}%
\sort#1{#2}%
}% else
{%
\sort@go#1{#2}{#3}#4\sort@go
}%
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - smallest token so far
% #4 - token under consideration
% #5 - rest of the list
\def\sort@go#1#2#3#4#5\sort@go{%
#1{#3}{#4}{\sort@output#1{#2}{#5}}%
}
% #1 - comparator
% #2 - tokens processed so far
% #3 - rest of the list
% #4 - smaller of the two tokens
% #5 - larger of the two tokens
\def\sort@output#1#2#3#4#5{%
\ifsort@s{#3}
{%
\sortoutput{#4}%
\sort#1{#2{#5}}%
}% else
{%
\sort@begin#1{#2{#5}}{#4}#3\sort@begin
}%
}
\def\sort@numlt#1#2#3{%
\ifnumcomp{#1}<{#2}
{#3{#1}{#2}}% else
{#3{#2}{#1}}%
}
\def\sort@numgt#1#2#3{%
\ifnumcomp{#1}>{#2}
{#3{#1}{#2}}% else
{#3{#2}{#1}}%
}
\def\sort@alpha#1#2#3{%
\ifnumcomp{\pdfstrcmp{#1}{#2}}<{0}
{#3{#1}{#2}}% else
{#3{#2}{#1}}%
}
\newcommand*\sortnumlt{\sort\sort@numlt}
\newcommand*\sortnumgt{\sort\sort@numgt}
\newcommand*\sortalpha{\sort\sort@alpha}
\makeatother
% Change these to change out the sort outputs.
\newcommand*\sortoutput[1]{#1, }
\newcommand*\sortend[1]{#1.}
\begin{document}
\sortnumgt{87632147{55}9{8/2}}
\sortalpha{{Goodbye}{Cruel}{World}}
\renewcommand*\sortoutput[1]{#1}
\renewcommand*\sortend[1]{#1}
\edef\temp{\sortnumlt{87632147{55}9}}
\texttt{\meaning\temp}
\end{document}
I hope the code is readable. I tried to document the arguments to each function. In particular, the first argument to \sort
is a comparator control sequence that must take three arguments. The first two are the two elements of the following list to compare and the third is the continuation. Basically, the comparator should expand to either #3{#1}{#2}
or #3{#2}{#1}
depending on #1
being "less than" #2
.
I've implemented three such comparators. The first two compare lists of numbers whereas the third does alphanumeric string comparison using \pdfstrcmp
. Since the number comparisons use \ifnumcomp
from etoolbox
, you can use arbitrary arithmetic expressions for the elements, hence {8/2}
in the list.
Finally, to show that this is expandable (at least it is whenever the comparator, \sortoutput
, and \sortend
are), \temp
is defined using \edef
and its meaning is typeset to ensure that it has been set to the appropriate value: macro:->12346778955
.
Note that it would also be straight-forward to thread \sortoutput
and \sortend
through all of these macros so that multiple \sorts
could be used in the same expansion. I just didn't think about adding those until I had written all of the rest of the code (more or less).
Note further that this is selection sort and thus would take Θ(n2) time, even in the best case. However, this being TeX and it having to construct the token lists for each argument each time, I think this implementation is actually Θ(n3) time. So don't try it on large lists.
Holene,
I have done something similar in the past. For example, I once organised a scientific meeting. There was a website, where the attendees could register themselves by filling a given HTML form. The inserted data was stored in a database (on the first try, a simple text file, later on a SQL-Database).
The HTML page with the registration form did some checks, to ensure, the given data was plausible. Afterwards, the data was stored in the database and a registration letter was typeset by LaTeX, using the inserted data from the HTML form, and the final PostScript-file was sent automatically to an printer nearby.
Later on, after the registration was complete, I used the contents of the database to create a list of attendees (sorted either alphabetically or by ZIP-Code). To do so, I created some LaTeX-macros, which helped me, to get everything in a neat, representive layout. Biggest advantage is, that the script, you use to extract the data from your database, does not need to know anything about the final layout ...
I also used the same database entries, to create name badges for the attendees. There was another LaTeX-macro, which was able to detect, if it was a normal attendee, a speaker or a local organisation member (or even all three of them) :-).
All those scripts were coded in PHP; they did all the work to display the HTML page, as well as to communicate with the SQL-database as well as to generate the temporary LaTeX-documents and to call LaTeX to produce the PS files.
Today, I am using the export of our students learning platform (if you are curious: stud.IP), to generate attendees lists for my courses. This list is exported by the system as a CSV list. I wrote an bash script, which reads the csv list, utilizes SED and AWK, to delete the first 3 lines, filter the interesting informations for me and to output the result as a complete LaTeX file, ready to be compiled by pdfLaTeX. This time, I even though about writing a class of my own. In the end, I ended up in writing again a style file, which takes three package options. By means of this options, I am able, to manipulate the layout of one identical LaTeX command, to generate three completely different outputs. An attendee list, a big name plate to be placed in front of the student and last but not least, a certificate to be handed out after having successful finished the course.
What I wanted to make clear is, that you are absolute correct, to try to use LaTeX in order to produce automatically generated PDF files. To me, that makes absolute sense.
It only depends on your working environment, the tools you have at hand and the tools you can master. Unfortunately, you didn't tell any specific hints about those three things. Therefore my answer is
- Yes there is. Indeed, there is quite sure more than one language, you can use. It only depends on: which platform do you use, which language is available (bash, SED, AWK, Perl, PHP, Lisp, C, C++, C#, ...) and which language are you skilled and trained in.
- I wouldn't incorporate LaTeX into your language. Instead, I would argue, to ask your script, program, programing language to place a system call to do the dirty LaTeX job. For example: if you are programing in an ordinary shell (e.g. Bash, sh, csh, ... on Linux and MacOS computers, maybe Powershell or even Bash on newer Windows systems) you just can can say
pdflatex jan2016-report.tex
and it will produce the corresponding PDF output for you.
What you should do: you should examine carefully, what kind of data you can extract from your database. Try to build the extraction routine in that way, that all the output from the database (the CSV file you mentioned) is formatted exactly the same way, regardless if you are building a monthly or a quarterly report. Than you should try to split the relevant data into minor portions, that can be easily handled by LaTeX-Macros (which can hold up to nine arguments). Try to code some macros of your own, presenting some helpful LaTeX-commands and environments. The only thing you still have to do, is to code your reporting script, that it adds those LaTeX macros and environments into the result, the database query gave you.
Have fun
Jan
Best Answer
I don' know if this would be enough, but for your example it's enough (it requires eTeX)