1

I have asked a question at How to delete a command in the \BODY macro of environment defined by \NewEnviron about the problem when I try to convert my ex environment to the multi environment of moodle package.

I have tried to solve my problem since last weekend, and now, I have solved almost everything. It works fine and give output .pdf file and .xml file correct result.

However, it takes errors with display math mode $$...$$ and \[...\] and \begin{center}...\end{center} environment.

Here is my code

\documentclass[12pt,a4paper]{article}
\usepackage[tikz]{moodle}
\usepackage{ifthen}
\usepackage{etoolbox}
\usepackage{environ}
\usepackage{xstring}
\usepackage{amsmath,amssymb,yhmath,mathrsfs,fontawesome}
\usepackage{fancyhdr,enumerate,tkz-euclide,tikz-3dplot,tikz,tkz-tab}
\moodleregisternewcommands

\makeatletter
\newcounter{c@ex}%
\setcounter{c@ex}{0}
\newcounter{ans@wer}%
\newcounter{correct@answer}%
\newcommand{\True}{}%
\newcommand\exname{MC}
%% Define the command to hide the text body of the environment.
\newlength{\trashlength}%
\def\hide@text#1{%
    \settowidth{\trashlength}{#1}
}
%% Define the command to find the correct answer.
\def\begin@ans{\@ifnextchar\True
{\setcounter{correct@answer}{\theans@wer}}{\stepcounter{ans@wer}}%
}
\environbodyname\@body
\htmlregister\@body
\htmlregister\final@result
\htmlregister\ans@one
\htmlregister\ans@two
\htmlregister\ans@three
\htmlregister\ans@four
\htmlregister\feed@back
\htmlregister\envbody
\newcommand{\choice}[4]{
    \gdef\ans@one{#1}
    \gdef\ans@two{#2}
    \gdef\ans@three{#3}
    \gdef\ans@four{#4}
    \gdef\del@choice{\choice
    {#1}
    {#2}
    {#3}
    {#4}
    }%
}%
\newcommand{\loigiai}[1]{
    \gdef\feed@back{#1}
    \gdef\del@feedback{\loigiai{#1}}
}%
\NewEnviron{ex}{%
}%
\AtEndEnvironment{ex}{%
    \stepcounter{c@ex}
    \hide@text{\@body}
%% Delete the macro \choice and \loigiai in the body of environment
    \hide@text{
        \global\let\@result\@body
        \expandarg
        \StrDel{\@result}{\del@choice}[\re@sult]
        \StrDel{\re@sult}{\del@feedback}[\re@@sult]
        \global\let\final@result\re@@sult
    }
%   \let\envbody\noexpand{\funal@result}
%% Finding the correct answer
\setcounter{ans@wer}{1}
\hide@text{\expandafter\begin@ans\ans@one}
\hide@text{\expandafter\begin@ans\ans@two}
\hide@text{\expandafter\begin@ans\ans@three}
\hide@text{\expandafter\begin@ans\ans@four}
%% Write the data in `milti' environment
\def\ex@name{\exname\thec@ex}
\ifnum\the\value{correct@answer}=1%
    \begin{multi}[numbering=ABCD,penalty=0,feedback={\feed@back}]{\ex@name}         
            \final@result
            \item* \ans@one%
            \item \ans@two%
            \item \ans@three%
            \item \ans@four%
    \end{multi}
\else
\ifnum\the\value{correct@answer}=2%
    \begin{multi}[numbering=ABCD,penalty=0,feedback={\feed@back}]{\exname\thec@ex}
            \final@result
            \item \ans@one%
            \item* \ans@two%
            \item \ans@three%
            \item \ans@four%
    \end{multi}
\else
\ifnum\the\value{correct@answer}=3
    \begin{multi}[numbering=ABCD,penalty=0,feedback={\feed@back}]{\exname\thec@ex}
            \final@result
            \item \ans@one%
            \item \ans@two%
            \item* \ans@three%
            \item \ans@four%
    \end{multi}
\else
\ifnum\the\value{correct@answer}=4
    \begin{multi}[numbering=ABCD,penalty=0,feedback={\feed@back}]{\exname\thec@ex}
            \final@result
            \item \ans@one%
            \item \ans@two%
            \item \ans@three%
            \item* \ans@four%   
    \end{multi}
\else
\relax
\fi
\fi
\fi
\fi
}%
\makeatother

\begin{document}
\begin{quiz}{My first test}
\begin{ex}
This is my question. $\dfrac{a}{b}$

\choice
{\True Answer one}
{Answer two}
{Answer three}
{Answer four}
\loigiai{This is a detail answer.}
\end{ex}
\end{quiz}
\end{document}

I don't know where is wrong, when I use display math mode in the body of my question I get errors (of course it is used right syntax)

! Missing $ inserted.
<inserted text>
$

In addition, when I use \begin{center}...\end{center} I get the error

! LaTeX Error: Something's wrong--perhaps a missing \item.

Please help me to fix them!

3
  • So, avoid \[..\] (and $$...$$) and instead use $...$. Use \centering instead of center environment. Thus, \centering $...$ will give a centered equation. Commented Sep 2, 2023 at 14:58
  • 1
    %% Define the command to hide the text body of the environment. that is not what \hide@text does, it typesets a space, and sets a length register, and gives errors on vertical material like a paragraph or display math. why do you need to measure the width???? Commented Sep 3, 2023 at 9:20
  • 1
    using c@ex as a counter name is not exactly wrong but rather confusing as latex uses c@ as a prefix for count registers, so \newcounter{ex} allocates \c@ex and \newcounter{c@ex} allocates \c@c@ex Commented Sep 3, 2023 at 9:26

3 Answers 3

4

You could simplify your example to

\documentclass{article}

\begin{document}

\mbox{$ \times $}

\mbox{$$ \times $$}

\mbox{\begin{center} x \end{center}}

\end{document}

Where you get no error from $ but $$ produces

! Missing $ inserted.
<inserted text> 
                $
l.7 \mbox{$$ \times $$}
                       
?

because in an hbox $$ is like $ $ and makes an empty math list so \times is not in math mode, it is in the text between two empty math lists.

and center produces

! LaTeX Error: Something's wrong--perhaps a missing \item.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              
                                                  
l.9 \mbox{\begin{center} x \end{center}}
                                        
? 

as you can not have a vertical display construct in a horizontal box.


So you definitely do not want

%% Define the command to hide the text body of the environment.
\newlength{\trashlength}%
\def\hide@text#1{%
    \settowidth{\trashlength}{#1}
}

which acts like \mbox and is the cause of the errors, you probably do not want \StrDel either. You do not say anywhere what you want this code to do, and I can not guess, so this answer is restricted to explaining why you get errors, I can't suggest alternative code.

6
  • as my question before tex.stackexchange.com/questions/694632/…, I have available data of the structure of ex environment. I want to convert them to the structure of multi environment of the moodle package. In the code you mentioned above I want to call the \@body to execute command \choice and \loigiai but I don't want to show the content of it. After that, I use \StrDel to delete \choice and \loigiai from \@body since I don't want to show them in the .xml file.
    – phchon
    Commented Sep 4, 2023 at 7:06
  • as your pointed out, It make errors because I call \@body in \hide@text like \mbox. How can I call and execute the macro \@body but to not show it output?
    – phchon
    Commented Sep 4, 2023 at 7:42
  • @phchon you could use \setbox\@tempboxa\vbox{{\@body}} with vbox and two brace groups but I doubt you need this at all. Commented Sep 4, 2023 at 7:56
  • @phchon why don't you simply give the commands suitable definitions for moodle, I can't see any reason for \StrDel or discarding boxes, but you haven't anywhere mentioned in the question the xml format being written. leaving people to reverse engineer the requirement by running the output. Commented Sep 4, 2023 at 8:03
  • With \vbox, the display math mode works fine, but it also makes error with \begin{center}...\end{center} environment.
    – phchon
    Commented Sep 4, 2023 at 8:04
1

As I noted in a comment, avoid \[..\] (and $$...$$) in this context and instead use $...$. Use \centering instead of the center environment. Thus, \centering $...$ will give a centered equation (you can use braces, {\centering $...$\par}, if you need to limit the scope of the centering).

You may or may not desire to add \displaystyle to the beginning of the equation material, if you wish to further emulate the display-style appearance otherwise provided by \[...\].

\documentclass[12pt,a4paper]{article}
\usepackage[tikz]{moodle}
\usepackage{ifthen}
\usepackage{etoolbox}
\usepackage{environ}
\usepackage{xstring}
\usepackage{amsmath,amssymb,yhmath,mathrsfs,fontawesome}
\usepackage{fancyhdr,enumerate,tkz-euclide,tikz-3dplot,tikz,tkz-tab}
\moodleregisternewcommands

\makeatletter
\newcounter{c@ex}%
\setcounter{c@ex}{0}
\newcounter{ans@wer}%
\newcounter{correct@answer}%
\newcommand{\True}{}%
\newcommand\exname{MC}
%% Define the command to hide the text body of the environment.
\newlength{\trashlength}%
\def\hide@text#1{%
    \settowidth{\trashlength}{#1}
}
%% Define the command to find the correct answer.
\def\begin@ans{\@ifnextchar\True
{\setcounter{correct@answer}{\theans@wer}}{\stepcounter{ans@wer}}%
}
\environbodyname\@body
\htmlregister\@body
\htmlregister\final@result
\htmlregister\ans@one
\htmlregister\ans@two
\htmlregister\ans@three
\htmlregister\ans@four
\htmlregister\feed@back
\htmlregister\envbody
\newcommand{\choice}[4]{
    \gdef\ans@one{#1}
    \gdef\ans@two{#2}
    \gdef\ans@three{#3}
    \gdef\ans@four{#4}
    \gdef\del@choice{\choice
    {#1}
    {#2}
    {#3}
    {#4}
    }%
}%
\newcommand{\loigiai}[1]{
    \gdef\feed@back{#1}
    \gdef\del@feedback{\loigiai{#1}}
}%
\NewEnviron{ex}{%
}%
\AtEndEnvironment{ex}{%
    \stepcounter{c@ex}
    \hide@text{\@body}
%% Delete the macro \choice and \loigiai in the body of environment
    \hide@text{
        \global\let\@result\@body
        \expandarg
        \StrDel{\@result}{\del@choice}[\re@sult]
        \StrDel{\re@sult}{\del@feedback}[\re@@sult]
        \global\let\final@result\re@@sult
    }
%   \let\envbody\noexpand{\funal@result}
%% Finding the correct answer
\setcounter{ans@wer}{1}
\hide@text{\expandafter\begin@ans\ans@one}
\hide@text{\expandafter\begin@ans\ans@two}
\hide@text{\expandafter\begin@ans\ans@three}
\hide@text{\expandafter\begin@ans\ans@four}
%% Write the data in `milti' environment
\def\ex@name{\exname\thec@ex}
\ifnum\the\value{correct@answer}=1%
    \begin{multi}[numbering=ABCD,penalty=0,feedback={\feed@back}]{\ex@name}         
            \final@result
            \item* \ans@one%
            \item \ans@two%
            \item \ans@three%
            \item \ans@four%
    \end{multi}
\else
\ifnum\the\value{correct@answer}=2%
    \begin{multi}[numbering=ABCD,penalty=0,feedback={\feed@back}]{\exname\thec@ex}
            \final@result
            \item \ans@one%
            \item* \ans@two%
            \item \ans@three%
            \item \ans@four%
    \end{multi}
\else
\ifnum\the\value{correct@answer}=3
    \begin{multi}[numbering=ABCD,penalty=0,feedback={\feed@back}]{\exname\thec@ex}
            \final@result
            \item \ans@one%
            \item \ans@two%
            \item* \ans@three%
            \item \ans@four%
    \end{multi}
\else
\ifnum\the\value{correct@answer}=4
    \begin{multi}[numbering=ABCD,penalty=0,feedback={\feed@back}]{\exname\thec@ex}
            \final@result
            \item \ans@one%
            \item \ans@two%
            \item \ans@three%
            \item* \ans@four%   
    \end{multi}
\else
\relax
\fi
\fi
\fi
\fi
}%
\makeatother

\begin{document}
\begin{quiz}{My first test}
\begin{ex}
\centering This is my question. $\dfrac{a}{b}$

 $\dfrac{c}{d}$
\choice
{\True Answer one}
{Answer two}
{Answer three}
{Answer four}
\loigiai{This is a detail answer.}
\end{ex}
\end{quiz}
\end{document}

enter image description here

1
  • I know we can use $...$ and \centering instead of $$...$$ or \[...\] but the moodle package only provides output the center environment in .xml file for uploading in moodle website. Therefore, we need to fix the problems and use center environment and display math mode.
    – phchon
    Commented Sep 2, 2023 at 16:06
1

Actually, all you need to do is to transform your input structure to the input structure that moodle expects. Here I am assuming that your input data always have the structure

\begin{ex}
  Question text
  \choice{...}{...}{...}{...}
  \loigiai{...}
\end{ex}

(in particular, the \choice always appears after "Question Text", and \loigiai always appears last, and every question has a \loigiai command (the feedback isn't optional).)

In this case, if you define ex using a \NewEnviron, you can parse \BODY with a delimited macro of the form

\long\def\@transformBody#1\choice#2#3#4#5\loigiai#6{...}

in which #1 becomes the question text, #2...#5 are the choices, and #6 is the feedback. One can try to just perform a suitable transformation and stuff things into \begin{multi}...\end{multi}, but since the latter is also built from a \NewEnviron, we can also cut-out the middleman and just copy the definition of multi with the appropriate things thrown in.

There is however one last problem: your original format marks the correct answer with \True and moodle uses *. Here I make another assumption: you always put \True at the beginning of the answer. Basically, I want to be able to expand \True to become * without impacting the rest of the choice text; this is easy to do for the first token in a list.

Remark: there may be other considerations I haven't thought off, but at least for basic test cases the following works. Some explanations are included in-line

\documentclass{article}
\usepackage[tikz]{moodle}
\usepackage{amsmath}
\usepackage{ifthen}
\usepackage{etoolbox}
\usepackage{environ}

\newcommand\True{*} %% Makes \True expand to *

\makeatletter
%%%%
\long\def\@transformBody#1\choice#2#3#4#5\loigiai#6{%
        %% The purpose of the next four lines are to expand the first token
        %% of the answer choices, so that \True -> *
        \ExpandArgs{Nf}\def\my@choice@A{#2}
        \ExpandArgs{Nf}\def\my@choice@B{#3}
        \ExpandArgs{Nf}\def\my@choice@C{#4}
        \ExpandArgs{Nf}\def\my@choice@D{#5}
        %% The next command creates the processed body text to pass on for
        %% processing by Moodle's internal commands. The complicated 
        %% string of \expandafter's are all because of the \True -> * replacement
        \long\edef\ex@NewBody{\unexpanded{#1}
                \noexpand\item\expandafter\unexpanded\expandafter{\my@choice@A}
                \noexpand\item\expandafter\unexpanded\expandafter{\my@choice@B}
                \noexpand\item\expandafter\unexpanded\expandafter{\my@choice@C}
                \noexpand\item\expandafter\unexpanded\expandafter{\my@choice@D}}%
        %% This stashes the feedback somewhere
        \def\ex@feedback{#6}%
}
\newcounter{mymulti}
\NewEnviron{ex}{%
        \refstepcounter{mymulti}
        \expandafter\@transformBody\BODY   %Process the \BODY
    \bgroup
      \setkeys{moodle}{numbering=ABCD,penalty=0,feedback={\ex@feedback},questionname={MC\themymulti}}% Sets most of the Moodle parameters for the MC question
      \global\advance\moodle@totalmarks by \csname moodle@default grade\endcsname pt
      \expandafter\gatheritems\xa{\ex@NewBody}% Feed the Moodle Processor the transformed body text
      %% everything below is copied straight from the definition of the 
      %% multi environment in moodle.sty
      \let\moodle@questionheader=\gatheredheader
      %First, the LaTeX processing
      \item \moodle@begin@samepage \textbf{\moodle@questionname}
      \ifmoodle@handout
        \moodle@makelatextag@qtype{multi}
      \else
        \moodle@latex@writetags
        \par
        \noindent
        \moodle@makelatextag@qtype{multi}%
        \moodle@makelatextag@value{default grade}{marked out of}
        \moodle@makelatextag@value{penalty}{penalty}%
      \fi
      \moodle@makelatextag@multi\par
      \noindent
      \moodle@questionheader
      \edef\moodle@generalfeedback{\expandonce\moodle@feedback}
      \csname moodle@multi@latexprocessing\endcsname
      \moodle@end@samepage
      %Now, writing information to XML
      \@moodle@ifgeneratexml{%
        \xa\questiontext\xa{\moodle@questionheader}% Save the question text.
        \csname writemultiquestion\endcsname
        \bgroup
          \gdef\moodle@answers@xml{}%
          \setkeys{moodle}{feedback={}}%
          \xa\loopthroughitemswithcommand\xa{\csname savemultianswer\endcsname}%
          \passvalueaftergroup{\moodle@answers@xml}%
        \egroup
        \moodle@writeanswers%
        \moodle@writetags%
        \writetomoodle{</question>}%
      }{}%
    \egroup
}%

%%%%






\makeatother

\moodleregisternewcommands


\begin{document}
\begin{quiz}{A}
\begin{ex}
This is my question. $\dfrac{a}{b}$

\choice
{\True Answer one}
{$15$ Answer two}
{Answer three}
{Answer four}
\loigiai{This is a detail answer.}
\end{ex}
\end{quiz}
\end{document}
4
  • Thanks for your answer. This is a new idea for me thinking carefully about my problem!
    – phchon
    Commented Sep 5, 2023 at 3:38
  • I have read the moodle.sty file but I cannot find the counter to count the number of questions in a quiz. Do you know which is the counter? Please, let me know the counter!
    – phchon
    Commented Sep 6, 2023 at 9:55
  • It is just an enumerate. (More precisely, \begin{quiz} ends by [essentially] opening up a \begin{enumerate}. And each question (e.g. \begin{multi}) writes a \item as the first thing it does. So the numbering is controlled by enumi if I am not mistaken. Commented Sep 8, 2023 at 3:22
  • Thanks you are right!
    – phchon
    Commented Sep 8, 2023 at 14:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .