[Tex/LaTex] Write values to a file

external files

I'd like to write the contents of a macro to an external file. The code below

\documentclass{article}
\begin{document}
\newcommand\foo[3]{1: #1, 2: #2 and 3: #3}

\foo{foo}{bar}{baz}

\foo{See \ref{sec}}{\begin{description}
  \item[whatever] Hello
\end{description}}{Some text}

\section{A section}
\label{sec}

\end{document}

writes 1: foo, 2: bar and 3: baz and 1: See 1, 2: whatever Hello and 3: Some text into the PDF file. This should go to an external file, perhaps as XML or CSV or something else parsable. I only need the output (line breaks can be ignored) of the macro, not the source (\ref{...} for example)

I use LuaLaTeX, so I might just go ahead and parse the output nodes, but there might be a solution at the macro level?

Best Answer

Judging from the comments, you know this already but you can open a file with something like

\newwrite\myoutput
\immediate\openout\myoutput=\jobname.output

I have used the tex file name \jobname for the output file with an "output" extension. You can write to this file using

\write\myputout{stuff}

With your MWE, things go horribly wrong with expansion. To get around this in the past I have used an \unexpandedwrite macro that I found somewhere in TeXbook. Using this I can get your MWE to compile and produce the output:

1: foo
2: bar
 and 3: baz
1: See 1\hbox {}
2: \begin {description} \item [whatever] Hello \end {description}
 and 3: Some text

Depending on what you expect for #1, #2, and #3 you could of course use \write for some of them and \unexpandedwrite for others. This is what I have done below.

EDIT

@jfbu points out in the comments that there is now an \unexpanded macro so \unexpandedwrite is not needed anymore, so my MWe can be shortened to:

\documentclass{article}

\newwrite\myoutput
\immediate\openout\myoutput=\jobname.output

\newcommand\foo[3]{%
  \write\myoutput{1: #1}
  \write\myoutput{\unexpanded{2: #2}}
  \write\myoutput{ and 3: #3}
}

\begin{document}
  \foo{foo}{bar}{baz}

  \foo{See \ref{sec}}{\begin{description}
    \item[whatever] Hello
  \end{description}}{Some text}

  \section{A section}
  \label{sec}
\end{document}

Here is the original code:

\documentclass{article}

%% from the TeXbook
\def\\{\let\stoken= } \\
\long\def\unexpandedwrite#1#2{\def\finwrite{\write#1}%
  {\aftergroup\finwrite\aftergroup{\sanitize#2\endsanity}%
  }}
\def\sanitize{\futurelet\next\sanswitch}
\def\sanswitch{\ifx\next\endsanity
  \else\ifcat\noexpand\next\stoken\aftergroup\space\let\next=\eat
  \else\ifcat\noexpand\next\bgroup\aftergroup{\let\next=\eat
  \else\ifcat\noexpand\next\egroup\aftergroup}\let\next=\eat
  \else\let\next=\copytoken\fi\fi\fi\fi \next
}
\def\eat{\afterassignment\sanitize \let\next= }
\long\def\copytoken#1{%
  \ifcat\noexpand#1\relax\aftergroup\noexpand
  \else\ifcat\noexpand#1\noexpand~\aftergroup\noexpand\fi\fi
  \aftergroup#1\sanitize%
}
\def\endsanity\endsanity{}

\newwrite\myoutput
\immediate\openout\myoutput=\jobname.output

\newcommand\foo[3]{%
  \write\myoutput{1: #1}
  \unexpandedwrite\myoutput{2: #2}
  \write\myoutput{ and 3: #3}
}

\begin{document}
  \foo{foo}{bar}{baz}

  \foo{See \ref{sec}}{\begin{description}
    \item[whatever] Hello
  \end{description}}{Some text}

  \section{A section}
  \label{sec}
\end{document}