Question
What would be the best way to reference previously defined environment content later on in a tex file? Specifically content that can include other latex commands and not just text?
Related: Labeling a text and referencing it later (Text only)
The Goal
Create a separate page for just the exam solutions.
Implementation
To accomplish this I created a new environment sol that wrapped the solution environment native to the exam docclass. This wrapper then created a label for the solutions body content which I would use later on to reference.
The sol environment:
\makeatletter
\NewEnviron{sol}{%
\def\@currentlabel{\BODY}\label{solt:\thequestion}%
\begin{solution}%
\protect\BODY
\end{solution}%
}
\makeatother
I would then define my questions and their solutions:
\begin{questions}
\begin{question}
Test Question
\begin{sol}
Test Solution
\includegraphics[width=3cm,height=3cm,keepaspectratio]{image.png}
\end{sol}
\end{question}
\end{questions}
And finally print the solutions using a custom command that would look through each question, and find its labelled solution:
\newcommand\printsolutions{%
\begin{multicols*}{2}
\xintFor* ##1 in {\xintSeq{1}{\thequestion}} \do {%
\def\x{##1}
\noindent
\x) ~\ref{solt:\x}\\
\\
}
\end{multicols*}
}
All together, there are four files:
- index.tex which holds the configuration and the includes
- questions.tex which holds the questions
- solutions.tex which holds the solutions
- index-solutions.tex which is used to compile the solutions only into a pdf
index.tex
\documentclass[addpoints,12pt]{exam}
\usepackage{amsmath}
\usepackage{graphicx}
\usepackage{array}
\usepackage{blindtext}
\usepackage{xintexpr}
\usepackage{pgffor}
\usepackage{environ}
\usepackage{multicol}
\makeatletter
\NewEnviron{sol}{%
\def\@currentlabel{\BODY}\label{solt:\thequestion}%
\begin{solution}%
\protect\BODY
\end{solution}%
}
\makeatother
\newcommand\printsolutions{%
\begin{multicols*}{2}
\xintFor* ##1 in {\xintSeq{1}{\thequestion}} \do {%
\def\x{##1}
\noindent
\x) ~\ref{solt:\x}\\
\\
}
\end{multicols*}
}
\begin{document}
\include{questions}
\include{solutions}
\end{document}
questions.tex
\begin{questions}
\begin{question}
Test Question
\begin{sol}
Test Solution
\protect\includegraphics[width=3cm,height=3cm,keepaspectratio]{image.png}
\end{sol}
\end{question}
\begin{questions}
solutions.tex
\section*{\centering Solutions}
\printsolutions
index-solutions.tex
\includeonly{solutions}
\input{index}
The Problem
This approach worked for 90% of the cases but would fail when the \BODY argument contains elements such as the \includegraphics command. If I protect the \includegraphics command, it works perfectly. I'm guessing because it doesn't expand the includegraphics command immediately.
Since I can't always know what will be the contents of the \BODY, I cant manually go through and set the \protect on troublesome commands such as the \includegraphics. Is there a better way to get around this?


\labelto do that. – David Carlisle Apr 11 '20 at 20:11\csname...\endcsname) and simply use the macros in the end to access the saved contents. Now, I believe you mostly need to give a short and clear description of the expected input syntax and output. – frougon Apr 11 '20 at 23:17