# How to redefine commands and environments, and make them acceptable for \write

My general problem is the following. I want to "convert" many .tex files into some other format (xml-like). I don't want to modify the tex files, I can only build a documentclass. The texfiles are organized in blocs ( i will call them content-blocs), through commands and environment, for example, roughly:

\begin{document}
\content{blablabla}
\titre{joli titre}
\explanation{i muss explain that...}
\begin{definition}
here some nice text
\end{definition}
....
\end{document}


My present method, is to capture the content of the commands or environments and use \write to write them in a file:

\newwrite\tempfile
\immediate\openout\tempfile="test.xml"


For example (the following is defined in the documentclass used by the tex file):

\newcommand{\content}[1]{
\immediate\write\tempfile{<content>}
\immediate\write\tempfile{\content}
\immediate\write\tempfile{</content>}
}


The complication comes from the fact, that the commands and environments in \content may contain more than text, e.g other macros. For example :

\content{
some blablabla  \textbf{important} etc etc
}

\begin{definition}
consider the following points :
\begin{quote}
quote quote quote
\end{quote}
and so on, and so on...
\end{definition}


In this form, this gives a compilation error, because \write can't write this into the file. On the other hand, I know the exhaustive list of commands/environments that can appear in the "content-blocs". I though about capturing them, through a redefinition. For example :

\renewcommand{\textbf}[1]{<bold>#1</bold>}


works, the command \content will produces in the file "test.xml" a line

some blablabla  <bold>important</bold> etc etc


Problem 1: This strategy does not work for environments. My attempt

\renewenvironment{quote}{<quote>}{</quote>}


fails miserably.

Problem 2: I would need this in particular for the itemize environment (instead of quote). I know that redefining \item may yield some problems

Problem 3: In the content-blocks, I have sometimes commands with optional arguments, eg :

\content{bla bla \com[opt]{AAA} bla bla}


Here again, it fails, because commands with optional arguments are not fully expandable. As workaround, i can redefine the command \com with \DeclareExpandableDocumentCommand from the package xparse.

\DeclareExpandableDocumentCommand\expandCom{ o m} {<com : #1>#2</com>}


It seems to solve my problem for commands with optional arguments, but I would need the same for environments with optional arguments.

Problem 4: I need to treat the content of the content-blocs, in order to extract information. For this i use in particular \edef, and i need that the macros (\com, \texbf, and so on...) expand correctly in a edef. But i guess that it is exactely the same problem like with \write. For both \edef and \write one needs fully expandable macros inside, isn't it ?

EDIT1 Concerning Bruno's question. I think that David's solution is somehow secure, because it does not redefine the existing commands/environments, but it rather creates new ones (\mwx\begin, etc...).

Nevertheless, following Bruno's suggestion, i try to simply redefine the command \begin and \end for the environments i need (quote and definition, in this example). My attempt fails nevertheless. It might be because of \ifthenelse, but on the other hand, i never feel comfortable with \ifx :

\documentclass{article}
\usepackage{ifthen}

\let\originalbegin\begin
\let\originalend\end
\def\begin#1{%
\ifthenelse{\equal{#1}{quote}}{<quote:special def for quote>}{
\ifthenelse{\equal{#1}{definition}}{<DEF: another definition>}{\originalbegin{#1}
}
}
}
\def\end#1{%
\ifthenelse{\equal{#1}{quote}}{</quote>}{
\ifthenelse{\equal{#1}{definition}}{</DEF>}{\originalend{#1}
}
}
}
\newwrite\tempfile
\immediate\openout\tempfile="nico.xml"
\begin{document}

\def\content{
some blablabla  etc etc
\begin{definition}
consider the following points :
\begin{quote}
quote quote quote
\end{quote}
and so on, and so on...
\end{definition}
}
\immediate\write\tempfile{\content}%
\immediate\closeout\tempfile
\end{document}

-
Two thoughts. First, might you be better off with a script (perhaps python) than a TeX solution? Second, you might get more useful help if you provided a MWE with input TeX file and a handbuilt file showing the output you wanted. –  Ethan Bolker Jun 22 '12 at 15:50
do you want anything to expand or do you just want something that is like (or is) the filecontents environment that just writes its content verbatim? –  David Carlisle Jun 22 '12 at 16:06
You might be interested in this question: tex.stackexchange.com/q/19538/86 –  Loop Space Jun 22 '12 at 18:04

Something like this perhaps (plain TeX writing to the terminal, but could be adapted)

\long\def\mywrite{%
\begingroup
\obeyspaces\mywritey}

\long\def\mywritey#1{%
\immediate\write20{\mywritex#1\endmywritex}%
\endgroup}

\long\def\mywritex#1{%
\expandafter\ifx\csname mwx\string#1\endcsname\relax
\string#1%
\expandafter\mywritex
\else
\csname mwx\string#1\expandafter\endcsname
\fi}

\newlinechar=^^J
\long\def\mywritedef#1{\expandafter\def\csname mwx\string#1\endcsname}
\mywritedef\endmywritex{}
\mywritedef\par{^^J<p/>^^J\mywritex}
\mywritedef\begin#1{<\mywritex{#1}\endmywritex>\mywritex}
\mywritedef\end#1{</\mywritex{#1}\endmywritex>\mywritex}
\mywritedef\textbf#1{<bold>\mywritex#1\endmywritex</bold>\mywritex}

\mywritedef{definition}{DEF\mywritex}

\mywrite{

some blablabla  \textbf{important} etc etc

\begin{definition}
consider the following points :
\begin{quote}
quote quote quote
\end{quote}
and so on, and so on...
\end{definition}

}

\bye


It writes out:

\$ tex write.tex
This is TeX, Version 3.1415926 (TeX Live 2011/Cygwin)
(./write.tex

<p/>
some blablabla  <bold>important</bold> etc etc
<p/>
<DEF>   consider the following points :   <quote>      quote quote quote   </qu
ote>   and so on, and so on...</DEF>
<p/>

<p/>

)
No pages of output.

-
Your solution is very interesting (one can always learn a lot from your solutions...) but i think it is not suitable for my situation : i need to consider commands with optional arguments, and different number of arguments. On the other hand, i don't want these commands/environments to have the same effect. Some will write something like <bold>...</bold>, but some should do other things. This is why i would prefer to redefine them separately. For the moment, my solution works except for environments (i need in particular itemize) –  nicolas roy Jun 22 '12 at 21:01
commands with different numbers of arguments are easily handled by the above just use the usual \def rather than \newcommand syntax #1#2#3 etc. optional atrguments are trickier you need an expandable test for [] but that is not so hard. I made all environments do the same thing but again it would be easy for \begin and end to look up the name and do environment specific code. But I'll let it lie for now. Ping me here or in mail if you want this pushed further. –  David Carlisle Jun 22 '12 at 22:44
Why not simply change the definition of \begin and \end (and other commands) rather than parsing the argument of \mywrite one token at a time? –  Bruno Le Floch Jun 23 '12 at 6:54
You have to use expandable commands \ifthenelse` is just about the least expandable command there is. It does any number of internal assignments and tests. –  David Carlisle Jun 25 '12 at 10:45
It is possible to make this more and more involved while retaining the expansion-only nature, but is it wise? It is probably far easier to just write out more or less any well formed xml (eg not distinguishing different environments other than writing out the environment name as in my answer) and then using xml tools such as XSLT to re-arange the result. You coudl also use latexml or tex4ht to do this first stage of converting the tex input. –  David Carlisle Jun 25 '12 at 10:47

Pandoc can translate TeX into html. Presumably with a little work, you could use something like this to do the translation for you? I really think this would be a better solution that trying to have TeX write the files for you.

-