Purpose
I teach English to middle and high school students at Tetsuryokukai, a preparatory school, and I create my lecture materials using \( \mathrm{\TeX} \). In the senior year lectures, we primarily work with past entrance exam questions from the University of Tokyo and provide explanations for them. During this process, I needed to build a database of exam questions using \( \mathrm{\TeX} \). The reason is that the questions used in class are not fixed each year — they are regularly replaced. If we simply list each question's explanation in a single \( \mathrm{\TeX} \) file, that file must be modified every time a question is swapped out. Furthermore, even if editing just one file were sufficient it would still be manageable, but as detailed in the next section "Database Contents," it is operationally unavoidable that information about a single question exists across multiple files. Specifically, the information for a single question is scattered across five files: (1) the question booklet, (2) the answer booklet, (3) the explanation booklet, (4) the answer sheet, and (5) the commentary. Having to update the information in all these files every time a question is revised is error-prone, and trying to prevent errors saps the motivation to revise questions at all, leading to situations like "I really want to replace this question, but it's too much trouble, so let's keep it this year." If we can dynamically change the content through a \( \mathrm{\TeX} \)-based database, we can save the non-essential time spent rewriting files and instead spend time on the content itself, leading to improved quality of teaching materials.
For an article with a similar intent, see this article by y_minoda for reference.
Database Contents
Regarding what to register in the database: each record consists of eight fields — question, answer, answer sheet, point allocation, grading criteria, target answer time, explanation, and commentary. A brief description of each:
- Question & Answer: The original exam question text and the corresponding model answer.
- Answer Sheet: Since the University of Tokyo's English entrance exam includes various formats such as word-count-specified questions and symbol-based questions, unlike math's blank answer sheets or science's lined-only answer sheets, each answer sheet must be individually created for each question.
- Point Allocation & Grading Criteria: The point allocation and grading criteria for each sub-question.
- Target Answer Time: The target answer time to be included in the explanation booklet.
- Explanation: The explanation materials used in post-exercise lectures.
- Commentary: A document distributed the following week containing grading impressions from scoring student answer sheets and frequently occurring mistakes.
Centralizing Question Usage Information
First, we centralize the information about which questions are used. That is, rather than doing \input{UTokyo-2000-1A}... in QuestionBooklet.tex and again \input{UTokyo-2000-1A}... in ExplanationBooklet.tex, we create a listing of which questions are used in each class session in a single file (here called QuestionConfig.sty). We specify the questions to use in comma-separated order.
%\ConfigureQuestions{week}{Question1,Question2,...}
\ConfigureQuestions{01}{UTokyo-2000-1A,UTokyo-2001-1B,...}
\ConfigureQuestions{02}{UTokyo-1986-1A,UTokyo-1999-1B,UTokyo-1973-2A,UTokyo-2004-2B,UTokyo-2010-3,UTokyo-2012-5}%
...
QuestionConfig.sty is defined as follows.
As preparation, we define \e@namedef, the fully-expanded version of \@namedef, as follows.
\def\e@namedef#1{\expandafter\edef\csname#1\endcsname}
%Replaces \def with \edef in the definition of \@namedef from latex.ltx
%\def\@namedef#1{\expandafter\def\csname #1\endcsname
\newcounter{SessionQuestionCount}%
\def\ConfigureQuestions#1#2{%
\setcounter{SessionQuestionCount}{0}%
\expandafter\@for\expandafter\list\expandafter:\expandafter=#2\do{%
\stepcounter{SessionQuestionCount}%
\e@namedef{Session#1Question\arabic{SessionQuestionCount}}{\list}%
\global\e@namedef{Session#1QuestionCount}{\arabic{SessionQuestionCount}}%
}%
}%
When creating the question booklet, answer booklet, explanation booklet, etc., we reference this file, and when revising the materials, only this single file needs to be changed.
Creating the Database
The database itself follows a directory tree structure like the following.
├UTokyo/
├1970/
├UTokyo-1970-1A.tex
├UTokyo-1970-1B.tex
├UTokyo-1970-2A.tex
├UTokyo-1970-2B.tex
├UTokyo-1970-3.tex
├UTokyo-1970-4A.tex
├UTokyo-1970-4B.tex
├UTokyo-1970-5.tex
...
├2023/
├UTokyo-2023-1A.tex
├UTokyo-2023-1B.tex
├UTokyo-2023-2A.tex
├UTokyo-2023-2B.tex
├UTokyo-2023-3.tex
├UTokyo-2023-4A.tex
├UTokyo-2023-4B.tex
├UTokyo-2023-5.tex
├KeioMedicine/
...
├2023/
├KeioMedicine-2023-1.tex
├KeioMedicine-2023-2.tex
├KeioMedicine-2023-3.tex
├KeioMedicine-2023-4.tex
Furthermore, each of these files contains the eight fields described above. For example, the file UTokyo-2023-1A.tex looks like this:
\RegisterQuestion{hoge}
\RegisterAnswer{huga}
\RegisterPoints{hige}
\RegisterGradingCriteria{hogehoge}
\RegisterTargetTime{12 min}
\RegisterAnswerSheet{piyo}
\RegisterExplanation{puyo}
\RegisterCommentary{piyora}
Each command is defined as follows.
\long\def\RegisterQuestion#1{\long\@namedef{\currfilebase-Question}{#1}}
\long\def\RegisterAnswer#1{\long\@namedef{\currfilebase-Answer}{#1}}
\long\def\RegisterPoints#1{\long\@namedef{\currfilebase-Points}{#1}}
\long\def\RegisterTargetTime#1{\long\@namedef{\currfilebase-TargetTime}{#1}}
\long\def\RegisterAnswerSheet#1{\long\@namedef{\currfilebase-AnswerSheet}{#1}}
\long\def\RegisterExplanation#1{\long\@namedef{\currfilebase-Explanation}{#1}}
\long\def\RegisterCommentary#1{\long\@namedef{\currfilebase-Commentary}{#1}}
\long\def\RegisterGradingCriteria#1{\long\@namedef{\currfilebase-GradingCriteria}{#1}}
We load the currfile package and retrieve the child file's filename via \currfilebase. Using \jobname would return the master file's filename instead.
Querying the Database
The file that queries the database — for example, the file that generates the question booklet — looks like this. In practice, the database resides in a separate directory from this file, but for simplicity, we assume the database is directly under the master file.
\begin{document}
\LoadSources %Load the database for this week's questions here
%\UseQuestion{section number}{sequential question number for this session}{processing after loading the question}
\UseQuestion{1}{1}{\newpage}%
\UseQuestion{1}{2}{}%
\UseQuestion{2}{3}{\newpage}%
\UseQuestion{3}{4}{\newpage}%
\UseQuestion{3}{5}{}%
\end{document}
Since loading the entire massive database would increase compilation time, the \LoadSources command loads only the database entries needed for that session. The definition of \LoadSources is as follows. We define a counter with \newcounter{Week}, and in the master file, we set the week number that the file should load.
\def\ParseSource#1{%
\@ParseSource#1\@nil
}
\def\@ParseSource#1-#2-#3\@nil{%
\input{./#1/#2/#1-#2-#3.tex}
}
\newcounter{Week}
\def\LoadSources{%Load all TeX sources for this week, defining question/answer/explanation info as @namedef{Session01Question1-Question} etc.
\fornext[1]{\@nameuse{Session\ifnum\c@Week<10 0\fi\the\c@Week QuestionCount}}{%
\expandafter\expandafter\expandafter\ParseSource\expandafter\expandafter\expandafter{\csname Session\ifnum\c@Week<10 0\fi\the\c@Week Question\arabic{k}\endcsname}
}
}
Next, regarding the definition of \UseQuestion: for example, in Session 1, we use the five questions registered in QuestionConfig.sty — UTokyo-2000-1A, UTokyo-2001-1B, UTokyo-2002-3, UTokyo-2022-4A, and UTokyo-2023-4B — but we want UTokyo-2000-1A and UTokyo-2000-1B to be grouped under the same main question, just as in the actual entrance exam. We also want to allow fine adjustments such as including \newpage between Question 1 and Question 2. For brevity, we assume there are three main questions.
\def\SectionOneContent{\noindent Question 1\par}
\def\SectionTwoContent{\noindent Question 2\par}
\def\SectionThreeContent{\noindent Question 3\par}
\long\def\UseQuestion#1#2#3{%
\if#11\relax
\appto\SectionOneContent{%
\csname\csname Session\ifnum\c@Week<10 0\fi\the\c@Week Question#2\endcsname-Question\endcsname%
#3%
}%
\fi
\if#12\relax
\appto\SectionTwoContent{%
\csname\csname Session\ifnum\c@Week<10 0\fi\the\c@Week Question#2\endcsname-Question\endcsname%
#3%
}%
\fi
\if#13\relax
\appto\SectionThreeContent{%
\csname\csname Session\ifnum\c@Week<10 0\fi\the\c@Week Question#2\endcsname-Question\endcsname%
#3%
}%
\fi
}
By using \appto, we append content after the \SectionXContent commands. Note that using \appto requires loading etoolbox.sty.
Conclusion
By building a database with \( \mathrm{\TeX} \) and dynamically constructing \( \mathrm{\TeX} \) source (token lists) in memory while loading only the necessary files based on content, we can reduce the effort required for material revision. By minimizing this non-essential time, we can spend more time refining the content of the materials themselves and more time interacting with students.