summaryrefslogtreecommitdiff
path: root/tex/context/base/mkii/xtag-ini.mkii
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkii/xtag-ini.mkii')
-rw-r--r--tex/context/base/mkii/xtag-ini.mkii3026
1 files changed, 3026 insertions, 0 deletions
diff --git a/tex/context/base/mkii/xtag-ini.mkii b/tex/context/base/mkii/xtag-ini.mkii
new file mode 100644
index 000000000..ce3cbacd0
--- /dev/null
+++ b/tex/context/base/mkii/xtag-ini.mkii
@@ -0,0 +1,3026 @@
+%D \module
+%D [ file=xtag-ini,
+%D version=2000.12.20,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt XML Macros / Initialization}
+
+%D Beware: don't rely on \longempty things, since this may
+%D change!
+
+\ifdefined\keeputfcharacters \else \let\keeputfcharacters\relax \fi % for mkiv
+\ifdefined\utfunicodetracer \else \newconstant\utfunicodetracer \fi % for mkiv
+
+%D \macros
+%D {defineinputmode,setinputmode}
+%D
+%D For old times sake we still support:
+
+\unexpanded\def\defineinputmode[#1]{\expandafter\newtoks\csname every#1inputmode\endcsname}
+\unexpanded\def\setinputmode [#1]{\the\executeifdefined{every#1inputmode}\emptytoks}
+
+\defineinputmode [TEX]
+\defineinputmode [XML]
+
+\setinputmode [TEX]
+
+%D Finally we make sure that the compound handler keeps doingits job.
+
+\ifx\normalcompound\undefined \let\normalcompound=| \fi
+
+\appendtoks \catcode`|=\activecatcode \let|\normalcompound \to \everyTEXinputmode
+\appendtoks \catcode`|=\lettercatcode \to \everyXMLinputmode
+
+%D This module is highly optimized for speed, which sometimes
+%D leads to rather unreadable code. Sorry for this.
+
+\bgroup \obeylines
+
+\gdef\startXMLdefinitions% keep %
+ {\bgroup\obeylines\dostartXMLdefinitions}
+
+\gdef\dostartXMLdefinitions #1
+ {\egroup\doifsomething{#1}{\writestatus{XML}{loading #1 support}}}
+
+\global\let\stopXMLdefinitions\relax
+
+\egroup
+
+% todo: XMLfullsave == also attributes
+% csnames
+% XMLelse -> elseXML
+
+%D Remark: some hard coded character things will be replaced
+%D by named glyphs as soon as the upgraded encoding modules
+%D are released. At that moment, unicode support will be
+%D provided in accordance with the normal support in \CONTEXT.
+
+%D Like it or not, this module deals with angle bracketed
+%D input. Processing \XML\ alike input in \CONTEXT\ has been
+%D possible since 1995, and till 2000 several methods ran in
+%D parallel. These were implemented in modules like the semi
+%D public \type {m-sgml}.
+%D
+%D There is not one optimal solution for processing \XML\ data.
+%D The oldest method was based on a very simple preprocessor
+%D written in \MODULA\ and later \PERL: \type {<command>} was
+%D converted into \type {\begSGML[command]} and optional
+%D parameters were passed.
+%D
+%D A second method uses a \PERL\ or \XSL\ transformation
+%D script that produces \CONTEXT\ commands. This method is
+%D much slower, mainly because the whole document is read into
+%D memory and a document tree is to be build. The advantage is
+%D that processing of the resulting document is fast.
+%D
+%D The third method uses a basic parser written in the \TEX\
+%D language, and apart from a few pitfalls, this method is
+%D clean and efficient, but not always robust. Because errors
+%D in the input are not catched on forehand, processing in
+%D \TEX\ may fail due to errors. But, given that a document
+%D can be validated on forehand, this is no big problem.
+%D
+%D Each method has its advantage, but especially the third
+%D method puts some demands on \CONTEXT, since no interference
+%D between the parser and the core commands may occur. What
+%D method is used, depends on the situation.
+%D
+%D All three methods introduce some problems in interfacing to
+%D core \CONTEXT\ functionality. This is due to the fact that
+%D sometimes we want to typeset content directly, while in
+%D other cases we just want to pick up data for later usage,
+%D either or not using delimited arguments. And, when moving
+%D data around, there is always the expansion problem to deal
+%D with.
+%D
+%D As can be expected, we have to map begin and end tags onto
+%D \CONTEXT's start- and stopcommands. This is the easy part.
+%D When we have to pass the content of an element to a macro
+%D as argument, we need to do a delimited grab. Such mappings
+%D are not that hard to implement and were part of \type
+%D {m-sgml.tex} already. New in this core module is nested
+%D grabbing. Also new here is the support for namespaces and
+%D extensive attribute handling. On the other hand, recursive
+%D traceback of attributes is no longer supported. Because
+%D this feature was not really used, we can hereby safely we
+%D declare the \type {m-sgml.tex} module obsolete.
+%D
+%D In order to be able to incorporate \XML\ style definitions
+%D into basic \TEX\ styles, we will provide some basic
+%D functionality in the core itself. Some of the functionality
+%D can be set up with this general command. We use a token
+%D list register to handle post||setup actions. This permits
+%D us to extend this command.
+
+\unprotect
+
+\newtoks\aftersetupXMLprocessing
+
+\def\setupXMLprocessing
+ {\dosingleargument\dosetupXMLprocessing}
+
+\def\dosetupXMLprocessing[#1]%
+ {\getparameters[\??xp][#1]\the\aftersetupXMLprocessing}
+
+\def\XMLprocessingparameter#1%
+ {\csname\??xp#1\endcsname}
+
+\protect
+
+%D Formally an \XML\ file starts with an unique sequence
+%D \type {<?xml}, but in most of the unilities that come with
+%D \CONTEXT\ we will be more tolerant, and gobble preceding
+%D spaces.
+
+\def\XMLbanner#1{\string<\string ?xml version='1.0' #1\string ?\string>}
+
+%D We will be dealing with elements, which means that we have
+%D to take care of \type {<this>} and \type {</that>}, but
+%D also with \type {<such/>} and \type {<so />}. In some cases
+%D the upper and lowercase alternatives need to be dealt with,
+%D although this is not realy needed since XML is case
+%D sensitive.
+%D
+%D We also have to handle entities, like \type {&you;} and
+%D \type {&me;}. These are quite easy to deal with and need to
+%D be hooked into the encoding and abbreviation mechanisms.
+%D
+%D And then there are the parameters to be taken care of. Here
+%D we meet \type {key="value"} but also \type {key='eulav'}
+%D and even the spacy \typ {key = "value"}.
+%D
+%D Since we have to handlers for each element and entity, we
+%D will create a few namespaces. Special care has to be
+%D given to preformated code.
+%D
+%D There are two namespace mechanisms in place: one for
+%D \TEX, and one for \XML. The later mechanism permits
+%D remapping and ignoring.
+
+\unprotect
+
+\def \@@XML {XML:}
+\edef\@@XMLentity {\@@XML ent} % &crap;
+\edef\@@XMLelement {\@@XML ele} % <this> </this> <that/>
+\edef\@@XMLvariable {\@@XML var} % key="val"
+\edef\@@XMLvalue {\@@XML val} % key="val"
+\edef\@@XMLpars {\@@XML par} %
+\edef\@@XMLdata {\@@XML dat} % mem buffer
+\edef\@@XMLcode {\@@XML cod} % named mem buffers
+\edef\@@XMLinstruction {\@@XML ins} % <?
+\edef\@@XMLmap {\@@XML map} % mapping on context attr
+\edef\@@XMLlist {\@@XML lst} %
+\edef\@@XMLnamespace {\@@XML nam} % namespace:element
+\edef\@@XMLurlspace {\@@XML url} %
+\edef\@@XMLescape {\@@XML esc} % <!
+\edef\@@XMLdepth {\@@XML dep} % used to track nesting
+\edef\@@XMLdopth {\@@XML dop} % used to track nesting
+\edef\@@XMLsave {\@@XML sav} % namespace for saved elements
+
+\iffalse % slightly faster
+
+\edef\@@XML {*}
+\edef\@@XMLentity {\@@XML a} % &crap;
+\edef\@@XMLelement {\@@XML b} % <this> </this> <that/>
+\edef\@@XMLvariable {\@@XML c} % key="val"
+\edef\@@XMLvalue {\@@XML d} % key="val"
+\edef\@@XMLpars {\@@XML e} %
+\edef\@@XMLdata {\@@XML f} % mem buffer
+\edef\@@XMLcode {\@@XML g} % named mem buffers
+\edef\@@XMLinstruction {\@@XML h} % <?
+\edef\@@XMLmap {\@@XML i} % mapping on context attr
+\edef\@@XMLlist {\@@XML j} %
+\edef\@@XMLnamespace {\@@XML k} % namespace:element
+\edef\@@XMLurlspace {\@@XML l} %
+\edef\@@XMLescape {\@@XML m} % <!
+\edef\@@XMLdepth {\@@XML n} % used to track nesting
+\edef\@@XMLdopth {\@@XML o} % used to track nesting
+\edef\@@XMLsave {\@@XML p} % namespace for saved elements
+
+\fi
+
+\let\normal@@XMLelement\@@XMLelement % we may overload this one later inside a group
+
+\newtoks\XMLtoks
+\newtoks\XMLresetlist
+
+\newif\ifignoreXMLspaces
+\newif\iffixedXMLfont
+\newif\iftraceXMLelements
+\newif\ifprocessingXML
+
+\newcount\XMLlevel % scratchcounter
+\newcount\XMLdepth % used here
+
+\newtoks\everyenableXML
+
+%D We will implement the parser by making a few characters
+%D active. For that reason we also have to save their
+%D original meaning.
+
+%D \macros
+%D {enableXML}
+%D
+%D The macro \type {\enableXML} will be used to turn on the
+%D parser. This means that after that, \TEX\ commands starting
+%D with a backslash will not longer be read as such. There is
+%D a way around this, but for convenience \TEXEXEC\ will take
+%D care of processing raw \XML\ files in a transparant way.
+
+% cmr -- best for tui and such
+%
+% \chardef\XMLtokensreduction\zerocount
+%
+% lmr -- best but problematic for tui file:
+
+\chardef\XMLtokensreduction\plustwo
+
+% \def\alwaysreduceXMLtokens {\XMLtokensreduction\plusone}
+% \def\permanentreduceXMLtokens{\XMLtokensreduction\plustwo}
+
+% part of this should move to a low level module
+
+% we predefine some macros, just to satisfy the dep parser
+
+\let\enableXMLexpansion \relax
+\let\disableXMLexpansion \relax
+\let\enableXML \relax
+\let\activateXMLescapetokens\relax
+\let\entitleXMLescapetokens \relax
+\let\reduceXMLescapetokens \relax
+\let\ignoreXMLescapetokens \relax
+\let\enableXMLelements \relax
+\let\disableXMLelements \relax
+
+% \bgroup
+% \catcode`\*=\commentcatcode
+% \catcode`\.=\escapecatcode
+% .catcode`.B=.begingroupcatcode
+% .catcode`.E=.endgroupcatcode
+% .catcode`.P=.parametercatcode
+%
+% .catcode`.&=.activecatcode
+% .catcode`.<=.activecatcode
+%
+% .catcode`.#=.activecatcode
+% .catcode`.$=.activecatcode
+% .catcode`.%=.activecatcode
+% .catcode`.\=.activecatcode
+% .catcode`.^=.activecatcode
+% .catcode`._=.activecatcode
+% .catcode`.{=.activecatcode
+% .catcode`.}=.activecatcode
+% .catcode`.|=.activecatcode
+% .catcode`.~=.activecatcode
+%
+% .gdef.enableXMLexpansion
+% B.def<B.doXMLelementE.let&=.doXMLentityE
+%
+% .gdef.disableXMLexpansion
+% B.unexpanded.def<B.doXMLelementE.let&=.doXMLentityE
+%
+% * internally the # becomes two #'s (before expanding, during
+% * the parsing stage) which is why we let the first # gobble
+% * the second one
+% *
+% * since this only takes place when reading arguments, as in
+% * \startXMLdata ... cum, suis, we can take place of it
+% * there; this is needed because reading from file goes wrong
+% * (eating up argument)
+%
+% .unexpanded.gdef.enableXML
+% B.catcode`.!=.othercatcode
+% .catcode`.?=.othercatcode
+% .catcode`.:=.othercatcode * active in french
+% .catcode`.;=.othercatcode * active in french
+% .catcode`.&=.activecatcode
+% .catcode`.<=.activecatcode
+% .catcode`.>=.othercatcode
+% .catcode`."=.othercatcode
+% .catcode`./=.othercatcode
+% .catcode`.'=.othercatcode
+% .catcode`.~=.othercatcode
+% .catcode`.#=.othercatcode
+% .let &=.doXMLentity
+% .unexpanded.def<B.doXMLelementE*
+% .ifcase.XMLtokensreduction
+% .entitleXMLescapetokens
+% .or
+% .reduceXMLescapetokens
+% .else
+% .ignoreXMLescapetokens
+% .fi
+% .processingXMLtrue
+% .the.everyenableXML
+% E
+%
+% .gdef.activateXMLescapetokens
+% B.catcode`.$=.activecatcode
+% .catcode`.%=.activecatcode
+% .catcode`.\=.activecatcode
+% .catcode`.^=.activecatcode
+% .catcode`._=.activecatcode
+% .catcode`.{=.activecatcode
+% .catcode`.}=.activecatcode
+% .catcode`.|=.activecatcode
+% E
+%
+% .xdef.entitleXMLescapetokens
+% B.noexpand.activateXMLescapetokens
+% .noexpand.def.noexpand#B.noexpand&.string#035;E*
+% .noexpand.def.noexpand$B.noexpand&.string#036;E*
+% .noexpand.def.noexpand%B.noexpand&.string#037;E*
+% .noexpand.def.noexpand\B.noexpand&.string#092;E*
+% .noexpand.def.noexpand^B.noexpand&.string#094;E*
+% .noexpand.def.noexpand_B.noexpand&.string#095;E*
+% .noexpand.def.noexpand{B.noexpand&.string#123;E*
+% .noexpand.def.noexpand}B.noexpand&.string#125;E*
+% .noexpand.def.noexpand|B.noexpand&.string#124;E*
+% E
+%
+% .gdef.reduceXMLescapetokens
+% B.activateXMLescapetokens
+% .def#B.string#E*
+% .def$B.string$E*
+% .def%B.string%E*
+% .def\B.string\E*
+% .def^B.string^E*
+% .def_B.string_E*
+% .def{B.string{E*
+% .def}B.string}E*
+% .def|B.string|E*
+% E
+%
+% .gdef.ignoreXMLescapetokens
+% B.catcode`.$=.othercatcode
+% .catcode`.%=.othercatcode
+% .catcode`.\=.othercatcode
+% .catcode`.^=.othercatcode
+% .catcode`._=.othercatcode
+% .catcode`.{=.othercatcode
+% .catcode`.}=.othercatcode
+% .catcode`.|=.othercatcode
+% E
+%
+% * The following macro can be invokes when reading from
+% * an auxiliary file.
+%
+% .unexpanded.gdef.enableXMLelements
+% B.catcode60=.activecatcode * .catcode`.<=.activecatcode
+% .catcode62=.othercatcode * .catcode`.>=.other
+% .unexpanded.def<B.doXMLelementE*
+% .processingXMLtrue
+% E
+%
+% .unexpanded.gdef.disableXMLelements
+% B.catcode60=.activecatcode * .catcode`.<=.activecatcode
+% .catcode62=.othercatcode * .catcode`.>=.othercatcode
+% .let<.relax * new
+% .processingXMLfalse
+% E
+%
+% .global.let<.relax * new
+% .global.let&.relax * new
+%
+% .egroup
+%
+% \def\disableXML
+% {\setnormalcatcodes\processingXMLfalse}
+
+\defcatcodecommand\xmlcatcodese 046 \doXMLentity
+\defcatcodecommand\xmlcatcodese 060 \doXMLelement
+\defcatcodecommand\xmlcatcodesr 046 \doXMLentity
+\defcatcodecommand\xmlcatcodesr 060 \doXMLelement
+\defcatcodecommand\xmlcatcodesn 046 \doXMLentity
+\defcatcodecommand\xmlcatcodesn 060 \doXMLelement
+
+\letcatcodecommand\xmlcatcodesr 035 \letterhash
+\letcatcodecommand\xmlcatcodesr 036 \letterdollar
+\letcatcodecommand\xmlcatcodesr 037 \letterpercent
+\letcatcodecommand\xmlcatcodesr 092 \letterbackslash
+\letcatcodecommand\xmlcatcodesr 094 \letterhat
+\letcatcodecommand\xmlcatcodesr 095 \letterunderscore
+\letcatcodecommand\xmlcatcodesr 123 \letterleftbrace
+\letcatcodecommand\xmlcatcodesr 125 \letterrightbrace
+\letcatcodecommand\xmlcatcodesr 124 \letterbar
+
+\bgroup \catcode`\&=13 \let&\relax
+
+\xdef\entityhash {&\string#035;}
+\xdef\entitydollar {&\string#036;}
+\xdef\entitypercent {&\string#037;}
+\xdef\entitybackslash {&\string#092;}
+\xdef\entityhat {&\string#094;}
+\xdef\entityunderscore{&\string#095;}
+\xdef\entityleftbrace {&\string#123;}
+\xdef\entityrightbrace{&\string#125;}
+\xdef\entitybar {&\string#124;}
+
+\egroup
+
+\letcatcodecommand\xmlcatcodese 035 \entityhash
+\letcatcodecommand\xmlcatcodese 036 \entitydollar
+\letcatcodecommand\xmlcatcodese 037 \entitypercent
+\letcatcodecommand\xmlcatcodese 092 \entitybackslash
+\letcatcodecommand\xmlcatcodese 094 \entityhat
+\letcatcodecommand\xmlcatcodese 095 \entityunderscore
+\letcatcodecommand\xmlcatcodese 123 \entityleftbrace
+\letcatcodecommand\xmlcatcodese 125 \entityrightbrace
+\letcatcodecommand\xmlcatcodese 124 \entitybar
+
+% we speed things up by explicitly setting the active char's < &
+
+\doifmodeelse {mkiv} {
+
+ \def\mksetXMLtokensreduction % mkiv
+ {\setcatcodetable\xmlcatcodesn}
+
+} {
+
+ \def\mksetXMLtokensreduction % mkii
+ {\ifcase\XMLtokensreduction
+ \setcatcodetable\xmlcatcodese \or
+ \setcatcodetable\xmlcatcodesr \else
+ \setcatcodetable\xmlcatcodesn
+ \fi}
+
+}
+
+\bgroup \catcode`\<=13 \catcode`\&=13
+
+\gdef\enableXML
+ {\mksetXMLtokensreduction
+ \let&\doXMLentity
+ \unexpanded\def<{\doXMLelement}%
+ \processingXMLtrue
+ \the\everyenableXML}
+
+\gdef\disableXML
+ {\setcatcodetable\ctxcatcodes % maybe \texcatcodes
+ \processingXMLfalse}
+
+\gdef\enableXMLexpansion
+ {\def<{\doXMLelement}%
+ \let&\doXMLentity}
+
+\gdef\disableXMLexpansion
+ {\unexpanded\def<{\doXMLelement}%
+ \let&\doXMLentity}
+
+\unexpanded\gdef\enableXMLelements
+ {\catcode60=\activecatcode
+ \catcode62=\othercatcode
+ \unexpanded\def<{\doXMLelement}%
+ \processingXMLtrue}
+
+\unexpanded\gdef\disableXMLelements
+ {\catcode60=\activecatcode
+ \catcode62=\othercatcode
+ \let<\relax
+ \processingXMLfalse}
+
+\global\let<\relax
+\global\let&\relax
+
+\egroup
+
+%D An element can be singular or paired. A singular element is
+%D called an empty element. The following definitions are
+%D equivalent:
+%D
+%D \starttyping
+%D <eerste></eerste> <eerste/> <eerste />
+%D \stoptyping
+%D
+%D Empty elements can have arguments too. Conforming the
+%D standard, each key must have a value. These are separated
+%D by an \type {=} sign and the value is delimited by either
+%D \type {"} or \type {'}. There may be spaces around the
+%D equal sign.
+%D
+%D \starttyping
+%D <eerste a= "b" c ="d" /> <eerste a = "b" c="d"/>
+%D \stoptyping
+%D
+%D Officially the following definition is not valid:
+%D
+%D \starttyping
+%D <eerste>some text</eerste> <eerste/> <eerste />
+%D \stoptyping
+%D
+%D Although we can handle both cases independently, this is
+%D seldom needed.
+%D
+%D Processing instructions are identified by a~\type {?} and are
+%D like empty elements.
+%D
+%D \starttyping
+%D <?doel a="b" c="d"?> <?doel a="b" c="d" ?>
+%D \stoptyping
+%D
+%D Comment is formatted as follows.
+%D
+%D \starttyping
+%D <!-- comment -->
+%D \stoptyping
+%D
+%D Verbatim code inits purest form is called \type {CDATA} and
+%D is embedded in the following ugly and therefore recognizable
+%D way:
+%D
+%D \starttyping
+%D <![CDATA[
+%D Dit is nogal verbatim !
+%D Dit is nogal verbatim !
+%D Dit is nogal verbatim !
+%D ]]>
+%D \stoptyping
+
+%D The parser is implemented as a multi||step macro. Because
+%D \type {!} and \type {?} should be picked up correctly, we
+%D need to define a few macros in unprotected mode!
+%D
+%D Because \XML\ is defined with some restrictions in mind,
+%D parsing the elements is not that complicated. First we have
+%D to determine if we're dealing with a comment or processing
+%D instruction. We need a bit of grouping because we have to
+%D mess up with catcodes. We probably have to treat a few
+%D more catcode and first character cases. We need to use
+%D \type {\begingroup} here, otherwise we get funny spaces in
+%D math.
+
+%D Maybe I will remove grouping here and introduce \type
+%D {\obeyXMLlines}.
+
+%D By using a few {\expandafter}'s we can avoid a \type {\next}
+%D construction. We could speed the first char test up a bit
+%D by using an installer and something \typ {\getvalue
+%D {#1doXMLelement}} (todo).
+
+\protect % we need an normal ! ?
+
+% \long\def\doXMLelement#1%
+% {\if#1!\expandafter \xparseXMLescape \else
+% \if#1?\expandafter\expandafter\expandafter \xparseXMLprocess \else
+% \expandafter\expandafter\expandafter \xparseXMLelement \fi\fi
+% #1}
+
+\def\expandthree{\expandafter\expandafter\expandafter}
+
+\long\def\doXMLelement#1%
+ {\if#1!\expandafter \xparseXMLescape \else
+ \if#1?\expandthree \xparseXMLprocess \else
+ \expandthree \xparseXMLelement \fi\fi
+ #1}
+
+% does it end with ? or ?>
+
+\long\def\xparseXMLescape !#1 {\parseXMLescape{#1}}
+\long\def\xparseXMLprocess ?#1 #2>{\parseXMLprocess{#1}{#2}}
+\long\def\xparseXMLelement #1>{\parseXMLelement #1 >}
+
+%D The escape handler takes care of the fuzzy \type {<!}
+%D constructs. Unfortunately, we need to catch \type {<--text}
+%D too, so we need another handler:
+
+\long\def\xparseXMLescape !#1#2%
+ {\if#1-%
+ \if#2-%
+ \expandafter\expandafter\expandafter\xxparseXMLescape
+ \else
+ \expandafter\expandafter\expandafter\xyparseXMLescape
+ \fi
+ \else
+ \if#1[%
+ \expandafter\expandafter\expandafter\xzparseXMLescape
+ \else
+ \expandafter\expandafter\expandafter\xyparseXMLescape
+ \fi
+ \fi#1#2}
+
+\long\def\xxparseXMLescape--#1{\parseXMLescape{--}#1}
+\long\def\xyparseXMLescape#1 {\parseXMLescape{#1}}
+\long\def\xzparseXMLescape[#1[{\parseXMLescape{#1}}
+
+%D Now the real work can begin.
+
+\unprotect
+
+\def\defineXMLescape[#1]#2%
+ {\unspaceargument#1\to\ascii % get rid of {}, like in {CDATA[}
+ \long\setvalue{\@@XMLescape:\ascii}{#2}}
+
+\def\parseXMLescape#1% #2> parsing takes place in macros
+ {\executeifdefined{\@@XMLescape:#1}{\csname\@@XMLescape:\s!default\endcsname}}
+
+%D In our case, processing instructions are only needed if
+%D we want specific \CONTEXT\ support. This may be useful in
+%D applications where the data is generated by an
+%D application. We will implement a \CONTEXT\ code handler
+%D later.
+
+%D The processing instructions handler is implemented as
+%D follows.
+
+\long\def\defineXMLprocessor[#1]#2%
+ {\long\setvalue{\@@XMLinstruction:#1}{#2}}
+
+% \def\parseXMLprocess#1#2%
+% {\executeifdefined{\@@XMLinstruction:#1}\gobbleoneargument{#2}}
+
+%D Because we support \type {.. ?>} as well as \type {.. >}
+%D end||of||pi situations, we need to clean up the ending
+%D \type {?}.
+
+\protect
+
+\long\def\cleanupXMLprocess#1%
+ {\docleanupXMLprocess#1 ? \relax}
+
+\long\def\docleanupXMLprocess#1? #2\relax
+ {\def\currentXMLprocess{#1}}
+
+\unprotect
+
+\def\parseXMLprocess#1#2%
+ {\cleanupXMLprocess{#2}%
+ \defconvertedcommand\ascii{#1}%
+ %\writestatus{xml-process}{\ascii}
+ \expanded
+ {\executeifdefined
+ {\@@XMLinstruction:\ascii}
+ \noexpand\gobbleoneargument
+ {\expandafter\noexpand\currentXMLprocess}}}
+
+%D One never knows:
+
+\let\normalparseXMLescape \parseXMLescape
+\let\normalparseXMLelement\parseXMLelement
+\let\normalparseXMLprocess\parseXMLprocess
+
+%D Next we will implement the normal element handler. This
+%D piece of code is complicated by the fact that we need to
+%D handle namespaces.
+
+\let\currentXMLarguments \empty
+\let\currentXMLelement \empty % name
+\let\currentXMLidentifier\empty % name or name/
+\let\currentXMLnamespace \empty % the (remapped) namespace
+\let\originalXMLnamespace\empty % the unremapped namespace
+\let\rawXMLidentifier \empty
+
+\def\rawXMLnamespace
+ {\ifx\currentXMLnamespace\empty\else\currentXMLnamespace:\fi}
+
+\def\rawXMLelement{\rawXMLnamespace\rawXMLidentifier}
+
+%D The following token list register provided the user a hook
+%D for extensions.
+
+\newtoks\everyXMLelement
+
+%D We try to keep track of the nature of an element. This
+%D flag can be used for special purposes (as in the pretty
+%D printing macros).
+
+\chardef\kindofXMLelement=0
+
+\chardef\beginXMLtag=1
+\chardef\endXMLtag =2
+\chardef\emptyXMLtag=3
+
+%D We do a rather hard coded scan for the namespace attribute. This
+%D is needed because its value determines further namespace related
+%D actions.
+
+\def\openXMLargument{ /}
+
+\long\def\parseXMLelement#1#2 #3>%
+ {\def\currentXMLarguments{#3}% including end /
+ \if#1/%
+ \chardef\kindofXMLelement\endXMLtag
+ \def\currentXMLelement{#2}%
+ \else
+ \docleanupXMLelement#1#2/\empty\relax
+ \fi
+ \ifx\currentXMLarguments\openXMLargument
+ \chardef\kindofXMLelement\emptyXMLtag
+ \fi
+ \@EA\splitoffXMLnamespace\currentXMLelement::\relax
+ \ifcase\kindofXMLelement
+ % can't happen
+ \or
+ % begintag or emptytag with arguments or space before /
+ \the\everyXMLelement % only for begin/empty tag !
+ \ifx\currentXMLarguments\empty \else
+ \dogetXMLarguments\rawXMLelement#3>%
+ \fi
+ \or
+ % no arguments
+ \or
+ % empty element without arguments (but possible presets)
+ \the\everyXMLelement
+ \fi
+ \ifcase\kindofXMLelement\or
+ \let \currentXMLidentifier \rawXMLidentifier
+ \edef\currentXMLfullidentifier {\rawXMLelement }%
+ \or
+ \edef\currentXMLidentifier {/\rawXMLidentifier }%
+ \edef\currentXMLfullidentifier{/\rawXMLelement }%
+ \or
+ \edef\currentXMLidentifier {\rawXMLidentifier/}%
+ \edef\currentXMLfullidentifier {\rawXMLelement /}%
+ \fi
+ \iftraceXMLelements\traceXMLelement\fi
+ \executeXMLelement}
+
+\long\def\docleanupXMLelement#1/#2#3\relax
+ {\def\currentXMLelement{#1}% watch out: \empty == begin or empty tag
+ \chardef\kindofXMLelement\ifx#2\empty\beginXMLtag\else\emptyXMLtag\fi}
+
+\def\@@traceXMLelement
+ {\originalXMLfullidentifier
+ \ifx\originalXMLfullidentifier\currentXMLfullidentifier\else
+ \space=>\space\currentXMLfullidentifier
+ \fi
+ \ifx\currentXMLarguments\empty\else
+ \space\string|\space\currentXMLarguments
+ \fi}
+
+\long\def\traceXMLelement
+ {\edef\originalXMLfullidentifier{\someXMLelementID\currentXMLelement}%
+ \cleanupXMLarguments\writestatus{xml-element}{\@@traceXMLelement}}
+
+%D We split off the namespace part, construct the
+%D identifier, and remap the namespace if needed.
+
+\def\splitoffXMLnamespace#1:#2:#3\relax
+ {\def\rawXMLidentifier{#2}%
+ \ifx\rawXMLidentifier\empty
+ \let\currentXMLnamespace\empty
+ \edef\rawXMLidentifier{#1}%
+ \else
+ \edef\currentXMLnamespace{#1}%
+ \fi
+ \let\originalXMLnamespace\currentXMLnamespace
+ \checkXMLnamespace\rawXMLidentifier}
+
+\def\xsplitoffXMLnamespace% fast resplit
+ {\ifcsname\@@XMLnamespace:\currentXMLnamespace\endcsname
+ \csname\@@XMLnamespace:\currentXMLnamespace\endcsname
+ \fi}
+
+%D We will implement this macro later.
+
+\let\checkXMLnamespace\gobbleoneargument % see below
+
+%D The namespace attribute checking is part of the element
+%D parser, since the value of \type {xmlns} may influence other
+%D namespace mapping.
+
+\def\@@XMLns{xmlns}
+
+\def\checkXMLnamespaceattr#1% xmlns:\@@XMLname="\XMLns"
+ {\edef\XMLns{#1}%
+ \ifx\XMLns\empty \else
+ \ifcsname\@@XMLurlspace:\XMLns\endcsname
+ % get remapped namespace (from url)
+ % \edef\XMLns{\csname\@@XMLurlspace:\XMLns\endcsname}%
+ \@EA\let\@EA\XMLns\csname\@@XMLurlspace:\XMLns\endcsname
+ % remap this one
+ \ifx\@@XMLname\empty
+ % not watertight since no implicit grouping
+ \xautoXMLnamespace\XMLns
+ \else
+ \xremapXMLnamespace\@@XMLname\XMLns
+ % redo namespace remapping of self if needed
+ \ifx\XMLns\currentXMLnamespace
+ % i'm still not sure if this is ok
+ \else
+ \xsplitoffXMLnamespace
+ \fi
+ \fi
+ \fi
+ \fi}
+
+%D Although not really needed, we clean up the arguments.
+
+% \long\def\cleanupXMLarguments
+% {\ifnum\kindofXMLelement=\emptyXMLtag
+% \ifx\currentXMLarguments\empty \else
+% \@EA\docleanupXMLarguments\currentXMLarguments/\empty
+% \fi
+% \fi}
+%
+% \long\def\docleanupXMLarguments#1/#2\empty
+% {\edef\currentXMLarguments{#1}}
+%
+% we need to be ...="/" .... /> safe
+
+\long\def\cleanupXMLarguments
+ {\ifnum\kindofXMLelement=\emptyXMLtag
+ \ifx\currentXMLarguments\empty \else
+ \@EA\docleanupXMLarguments\currentXMLarguments/ \relax
+ \fi
+ \else\ifnum\kindofXMLelement=\beginXMLtag
+ \ifx\currentXMLarguments\space
+ \let\currentXMLarguments\empty
+ \fi
+ \fi\fi}
+
+% \long\def\docleanupXMLarguments#1/ #2\relax % space added earlier
+% {\edef\currentXMLarguments{#1}}
+%
+% \startbuffer
+% <xsl:value-of select="map[@att=$variable]/@att2"/>
+% \stopbuffer
+%
+% \showXMLbuffer
+%
+% No \type {\edef} in the following, else \showXMLbuffer fails:
+
+\long\def\docleanupXMLarguments#1/ #2\relax % space added earlier
+ {\def\currentXMLarguments{#1}} % no \edef, goes wrong in \showXML
+
+\def\executeXMLelementA % no fallback
+ {\ifcsname\@@XMLelement:\currentXMLfullidentifier\endcsname
+ \csname\@@XMLelement:\currentXMLfullidentifier\endcsname
+ \fi}
+
+\def\executeXMLelementB % default fallback
+ {\csname \@@XMLelement:%
+ \ifcsname\@@XMLelement:\currentXMLfullidentifier\endcsname
+ \currentXMLfullidentifier
+ \else
+ \defaultXMLelementID % was \s!default
+ \fi
+ \endcsname}
+
+\def\executeXMLelementC % no namespace of default fallback
+ {\csname \@@XMLelement:%
+ \ifcsname\@@XMLelement:\currentXMLfullidentifier\endcsname
+ \currentXMLfullidentifier
+ \else\ifcsname\@@XMLelement:\currentXMLidentifier\endcsname
+ \currentXMLidentifier
+ \else
+ \defaultXMLelementID % was \s!default
+ \fi\fi
+ \endcsname}
+
+\def\executeXMLelementD
+ {\csname
+ \ifcsname\@@XMLelement:\currentXMLfullidentifier\endcsname
+ \@@XMLelement:\currentXMLfullidentifier
+ \else\ifcsname\@@XMLelement:\currentXMLidentifier\endcsname
+ \@@XMLelement:\currentXMLidentifier
+ \else
+ \executeXMLelementDD % less skipping and thereby faster
+ \fi\fi
+ \endcsname}
+
+\def\executeXMLelementDD % now forget about tex mapping
+ {\ifcsname\normal@@XMLelement:\currentXMLfullidentifier\endcsname
+ \normal@@XMLelement:\currentXMLfullidentifier
+ \else\ifcsname\normal@@XMLelement:\currentXMLidentifier\endcsname
+ \normal@@XMLelement:\currentXMLidentifier
+ \else
+ \normal@@XMLelement:\defaultXMLelementID % was \@@XMLelement:\s!default
+ \fi\fi}
+
+\def\setXMLfallbackmode#1%
+ {\ifcase#1\relax
+ \let\executeXMLelement \executeXMLelementA
+ \let\automateXMLnamespace\automateXMLnamespaceA
+ \or % 1
+ \let\executeXMLelement \executeXMLelementB
+ \let\automateXMLnamespace\automateXMLnamespaceB
+ \or % 2
+ \let\executeXMLelement \executeXMLelementC
+ \let\automateXMLnamespace\automateXMLnamespaceC
+ \or % 3
+ \let\executeXMLelement \executeXMLelementD
+ \let\automateXMLnamespace\automateXMLnamespaceD
+ \fi}
+
+\setXMLfallbackmode3 % was 2
+
+%D An example of fall back modes is given below.
+
+%D The automated namespace stuff is new and yet undocumented
+%D (see resource libraries for usage).
+
+\def\xautoXMLnamespace#1% fast internal one
+ {\ifcsname\@@XMLnamespace-#1\endcsname\else
+ \@EA\appendtoks\csname\@@XMLnamespace-#1\endcsname\to\autoXMLnamespaces
+ \fi
+ \@EA\edef\csname\@@XMLnamespace-#1\endcsname
+ {\noexpand\edef\noexpand\@axmlns@{#1}% quicker #1 -> \#1
+ \noexpand\doautoXMLnamespace\noexpand\@axmlns@}}
+
+\def\doautoXMLnamespace#1% \done is set before list
+ {\ifdone\else\automateXMLnamespace#1\fi}
+
+\def\automateXMLnamespaceA#1%
+ {\ifcsname\@@XMLelement:#1:\checkedXMLnamespace\endcsname
+ \let\currentXMLnamespace#1%
+ \else\ifcsname\@@XMLelement:#1:\checkedXMLnamespace/\endcsname
+ \let\currentXMLnamespace#1%
+ \fi\fi}
+
+\let\automateXMLnamespaceB\automateXMLnamespaceA
+\let\automateXMLnamespaceC\automateXMLnamespaceA
+
+\def\automateXMLnamespaceD#1%
+ {\ifcsname\@@XMLelement:#1:\checkedXMLnamespace\endcsname
+ \let\currentXMLnamespace#1%
+ \else\ifcsname\normal@@XMLelement:#1:\checkedXMLnamespace\endcsname
+ \let\currentXMLnamespace#1%
+ \else
+ \automateXMLnamespaceDD#1%
+ \fi\fi}
+
+\def\automateXMLnamespaceDD#1%
+ {\ifcsname\@@XMLelement:#1:\checkedXMLnamespace/\endcsname
+ \let\currentXMLnamespace#1%
+ \else\ifcsname\normal@@XMLelement:#1:\checkedXMLnamespace/\endcsname
+ \let\currentXMLnamespace#1%
+ \fi\fi}
+
+%D Later we will implement the error handler, here we handle
+%D the default case.
+
+\def\someXMLelementID#1%
+ {\ifnum\kindofXMLelement=\endXMLtag /\fi
+ #1%
+ \ifnum\kindofXMLelement=\emptyXMLtag/\fi}
+
+\def\defaultXMLelementID
+ {\someXMLelementID\s!default}
+
+%D It is possible to keep track of nesting automatically,
+%D but this would kind of prohibit things like \type
+%D {\ignorespaces}. In the future we may provide an
+%D automatic depth tracking as an alternative (exclusive)
+%D mode of operation combined with space grabbing.
+
+\def\beginXMLelement
+ {\global\advance\XMLdepth\plusone
+ \global\@EA\let\csname\@@XMLdepth:\the\XMLdepth\endcsname\currentXMLelement
+ }%\writestatus{XML TRACE}{[begin] [\the\XMLdepth] [\XMLself]}}
+
+\def\endXMLelement
+ {%\writestatus{XML TRACE}{[end] [\the\XMLdepth] [\XMLself]}%
+ \global\@EA\let\csname\@@XMLdepth:\the\XMLdepth\endcsname\undefined
+ \global\advance\XMLdepth\minusone}
+
+% 0 = nothing
+% 1 = unknown
+% 2 = current element
+
+\chardef\XMLancestormode=2 % never change this one globally
+
+% \def\XMLancestor#1%
+% {\ifnum\numexpr(\XMLdepth-#1)>0
+% \csname\@@XMLdepth:\the\numexpr(\XMLdepth-#1)\endcsname
+% \else
+% \ifcase\XMLancestormode\or\s!unknown\or\currentXMLelement\fi
+% \fi}
+
+\def\XMLancestor#1%
+ {\ifnum\numexpr\XMLdepth-#1\relax>\zerocount
+ \csname\@@XMLdepth:\the\numexpr\XMLdepth-#1\relax\endcsname
+ \else
+ \ifcase\XMLancestormode\or\s!unknown\or\currentXMLelement\fi
+ \fi}
+
+% \def\XMLpureancestor#1%
+% {\ifnum\numexpr(\XMLdepth-#1)>0
+% \csname\@@XMLdepth:\the\numexpr(\XMLdepth-#1)\endcsname
+% \fi}
+
+\def\XMLpureancestor#1%
+ {\ifcase\numexpr\XMLdepth-#1\relax\or
+ \csname\@@XMLdepth:\the\numexpr\XMLdepth-#1\relax\endcsname
+ \fi}
+
+\def\XMLparent {\XMLancestor \plusone }
+\def\XMLself {\XMLancestor \zerocount}
+\def\XMLpureparent{\XMLpureancestor\plusone }
+\def\XMLpureself {\XMLpureancestor\zerocount}
+
+% \def\XMLpureancestor#1%
+% {\csname
+% \ifnum\numexpr(\XMLdepth-#1)>\zerocount
+% \@@XMLdepth:\the\numexpr(\XMLdepth-#1)%
+% \else
+% \s!empty
+% \fi
+% \endcsname}
+
+\def\XMLpureparent
+ {\XMLpureancestor\plusone}
+
+% probleem: depth is vast en dus ook ancestor
+
+% \XMLinh{...} will backtrack definitions (given that the elements
+% use begin/end, the backtracking stops when a non-empty value is
+% encountered; maybe we will add some keyword (inherit) some day
+
+\def\XMLinhpar#1#2%
+ {\@EA\ifx\csname\@@XMLvariable:#1:#2\endcsname\empty
+ \@EA\pXMLinh
+ \else
+ \csname\@@XMLvariable:#1:#2\endcsname
+ \@EA\gobbletwoarguments
+ \fi\XMLdepth{#2}}
+
+\def\XMLinh
+ {\XMLinhpar\currentXMLelement}
+
+% \def\pXMLinh#1%
+% {\@EA\ppXMLinh\@EA{\the\numexpr(#1-\plusone)}}
+
+\def\pXMLinh#1%
+ {\@EA\ppXMLinh\@EA{\the\numexpr#1-\plusone\relax}}
+
+\def\ppXMLinh#1#2%
+ {\@EA\ifx\csname\@@XMLvariable:#1:#2\endcsname\empty
+ \ifnum#1>\plusone
+ \@EAEAEA\pXMLinh
+ \else
+ \@EAEAEA\gobbletwoarguments
+ \fi
+ \else
+ \csname\@@XMLvariable:#1:#2\endcsname
+ \@EA\gobbletwoarguments
+ \fi{#1}{#2}}
+
+% better
+%
+% \def\XMLpureancestor#1%
+% {\ifcsname\@@XMLdepth:\the\numexpr(\XMLdepth-#1)\endcsname
+% \csname\@@XMLdepth:\the\numexpr(\XMLdepth-#1)\endcsname
+% \fi}
+
+% replaces macro in xtag-ini: ! ! !
+
+\def\edefXMLop#1#2% \macro{att}
+ {\edef#1%
+ {\csname\ifcsname\@@XMLvariable:\ownXMLelement:#2\endcsname
+ \@@XMLvariable:\ownXMLelement:#2\else\s!empty
+ \fi\endcsname}}
+
+\def\edefXMLinh#1#2% \macro{att}
+ {\edef#1{\XMLinh{#2}}}
+
+\def\edefXMLinhpar#1#2#3% \macro{tag}{att}
+ {\edef#1{\XMLinhpar{#2}{#3}}}
+
+% \def\doifXMLopdef#1#2% \macro{att}
+% {\ifcsname\@@XMLvariable:\ownXMLelement:#1\endcsname
+% \@EA\let\@EA#1\csname\@@XMLvariable:\ownXMLelement:#1\endcsname
+% \expandafter\firstofoneargument
+% \else
+% \expandafter\gobbleoneargument
+% \fi}
+
+\fetchruntimecommand \tracebackXMLattribute {\f!xtagprefix\s!run}
+\fetchruntimecommand \showXMLinh {\f!xtagprefix\s!run}
+
+% \defineXMLenvironment[one]
+% {\beginXMLelement}
+% {\endXMLelement}
+%
+% \defineXMLenvironment[two]
+% {\beginXMLelement
+% \starttabulatie
+% \NC ancestor 1 \NC \XMLancestor{1} \NC \NR
+% \NC ancestor 2 \NC \XMLancestor{2} \NC \NR
+% \NC ancestor 3 \NC \XMLancestor{3} \NC \NR
+% \NC ancestor 4 \NC \XMLancestor{4} \NC \NR
+% \stoptabulatie}
+% {\endXMLelement}
+%
+% \startbuffer
+% <x:one> <x:two> <one> <two> </two> </one> </x:two> </x:one>
+% \stopbuffer
+%
+% {fallback A: \setXMLfallbackmode 0 \processXMLbuffer}\par
+% {fallback B: \setXMLfallbackmode 1 \processXMLbuffer}\par
+% {fallback C: \setXMLfallbackmode 2 \processXMLbuffer}\par
+
+% todo: split #1 into raws en reconstruct, set current etc, push and pop
+%
+% \def\beginXMLelement
+% {\dosingleempty\dobeginXMLelement}
+%
+% \def\dobeginXMLelement[#1]%
+% {\global\advance\XMLdepth 1
+% \global\@EA\let\csname\@@XMLdepth:\the\XMLdepth\endcsname\currentXMLelement
+% \global\@EA\edef\csname\@@XMLdopth:\the\XMLdepth\endcsname{\ownXMLelement}%
+% \iffirstargument\edef\ownXMLelement{#1}\fi}
+%
+% \def\endXMLelement
+% {\@EA\let\@EA\ownXMLelement\csname\@@XMLdopth:\the\XMLdepth\endcsname
+% \global\advance\XMLdepth -1 }
+
+%D \defineXMLenvironment[one]
+%D {\beginXMLelement}
+%D {\endXMLelement}
+%D
+%D \defineXMLenvironment[two]
+%D {\beginXMLelement
+%D \starttabulate
+%D \NC parent 1 \NC \XMLancestor{1} \NC \NR
+%D \NC parent 2 \NC \XMLancestor{2} \NC \NR
+%D \NC parent 3 \NC \XMLancestor{3} \NC \NR
+%D \NC parent 4 \NC \XMLancestor{4} \NC \NR
+%D \stoptabulate}
+%D {\endXMLelement}
+%D
+%D \startbuffer
+%D <x:one> <x:two> <one> <two> </two> </one> </x:two> </x:one>
+%D \stopbuffer
+%D
+%D fallback A: \setXMLfallbackmode0 \processXMLbuffer
+%D fallback B: \setXMLfallbackmode1 \processXMLbuffer
+%D fallback C: \setXMLfallbackmode2 \processXMLbuffer
+
+%D Here we do the namespace (re)mapping. More examples are
+%D provided in the manual.
+%D
+%D \starttyping
+%D \supportXMLnamespace [test] % needed to get a namespace working
+%D \skipXMLnamespace [test] % slow
+%D \ignoreXMLnamespace [test] % faster
+%D \defineXMLenvironment [rubish:itemize] {[} {]}
+%D \defineXMLenvironment [rubish:item] {(} {)}
+%D \remapXMLnamespace [crap] [rubish]
+%D \remapXMLnamespace [con] [context]
+%D \remapXMLurlspace [http://www.pragma-ade.com/dtd/context] [context]
+%D \autoXMLnamespace [context] % fallback
+%D \autoXMLnamespace [whatever] % second fall back
+%D \stoptyping
+
+\newtoks\autoXMLnamespaces
+
+%D The automatically mapped namespaces (the fallbacks so to
+%D day) are collected in a token list.
+
+\let\checkedXMLnamespace\empty
+
+\def\checkXMLnamespace#1%
+ {\edef\checkedXMLnamespace{#1}%
+ \ifcsname\@@XMLnamespace:\currentXMLnamespace\endcsname
+ \csname\@@XMLnamespace:\currentXMLnamespace\endcsname
+ % forced namespace
+ \else\ifcsname\@@XMLelement:\currentXMLelement\endcsname
+ % natural element
+ \else\ifcsname\@@XMLelement:\currentXMLelement/\endcsname
+ % natural element
+ \else
+ % locate fallback
+ \donefalse\the\autoXMLnamespaces
+ \fi\fi\fi}
+
+\def\skipXMLnamespace[#1]%
+ {\letvalue{\@@XMLnamespace:#1}\doXMLskipnamespace}
+
+\def\doXMLskipnamespace
+ {\long\@EA\def\csname\@@XMLelement:\checkedXMLnamespace\endcsname
+ {\getXMLgroupedignore\checkedXMLnamespace}}
+
+\def\hideXMLnamespace[#1]%
+ {\letvalue{\@@XMLnamespace:#1}\doXMLhidenamespace}
+
+\def\doXMLhidenamespace
+ {\long\@EA\def\csname\@@XMLelement:\checkedXMLnamespace\endcsname
+ {\redoXMLignore\checkedXMLnamespace}}
+
+\def\ignoreXMLnamespace[#1]%
+ {\letvalue{\@@XMLnamespace:#1}\doXMLignorenamespace}
+
+\def\doXMLignorenamespace % \let binnen def
+ {\long\@EA\def\csname\@@XMLelement:\checkedXMLnamespace\endcsname
+ {\@EA\redoXMLignore\@EA{\checkedXMLnamespace}}} % EA ?
+
+\def\remapXMLnamespace
+ {\dodoubleargument\doremapXMLnamespace}
+
+\def\doremapXMLnamespace[#1][#2]%
+ {\ifsecondargument
+ \setvalue{\@@XMLnamespace:#1}{\def\currentXMLnamespace{#2}}%
+ \else
+ \letvalue{\@@XMLnamespace:#1}\relax
+ \fi}
+
+\def\supportXMLnamespace%
+ {\dosingleargument\dosupportXMLnamespace}
+
+\def\dosupportXMLnamespace[#1]%
+ {\setvalue{\@@XMLnamespace:#1}{\def\currentXMLnamespace{#1}}}
+
+\def\xremapXMLnamespace#1#2% fast internal one
+ {\@EA\edef\csname\@@XMLnamespace:#1\endcsname
+ {\def\noexpand\currentXMLnamespace{#2}}}
+
+\def\autoXMLnamespace[#1]%
+ {\xautoXMLnamespace{#1}}
+
+\def\xautoXMLnamespace#1% fast internal one
+ {\ifcsname\@@XMLnamespace-#1\endcsname\else
+ \@EA\appendtoks\csname\@@XMLnamespace-#1\endcsname\to\autoXMLnamespaces
+ \fi
+ \@EA\edef\csname\@@XMLnamespace-#1\endcsname
+ {\noexpand\doautoXMLnamespace{#1}}}
+
+\def\doautoXMLnamespace#1% \done is set before list
+ {\ifdone\else
+ \ifcsname\@@XMLelement:#1:\checkedXMLnamespace\endcsname
+ \def\currentXMLnamespace{#1}%
+ \else\ifcsname\@@XMLelement:#1:\checkedXMLnamespace/\endcsname
+ \def\currentXMLnamespace{#1}%
+ \fi\fi
+ \fi}
+
+\def\resetXMLnamespace[#1]%
+ {\letvalue{\@@XMLnamespace-#1}\gobbleoneargument
+ \letvalue{\@@XMLnamespace:#1}\gobbleoneargument}
+
+\def\remapXMLurlspace
+ {\dodoubleargument\doremapXMLurlspace}
+
+\def\doremapXMLurlspace[#1][#2]%
+ {\setvalue{\@@XMLurlspace:#1}{#2}}
+
+%D Entities needs a bit more work, as well as a connection
+%D with the encoding handlers.
+
+% we need to be able to do:
+%
+% \defineXMLentity[amp] {\FunnyAmp} \def\FunnyAmp#1;{\getXMLentity{#1}}
+%
+% \defineXMLentity [pound] {(why not use euro's?)}
+%
+% \startXMLdata
+% test &amp;pound; test
+% \stopXMLdata
+%
+% so we need an ifless implementation
+%
+% also .. this should work:
+%
+% \defineXMLentity[ctx-var-textwidth] {\textwidth}
+%
+% \defineXMLcommand[test][width=\textwidth]
+% {\the\dimexpr\XMLop{width}\relax}
+%
+% \startXMLdata
+% <test width=".45&ctx-var-textwidth;"/>
+% <test width="&ctx-var-textwidth;"/>
+% \stopXMLdata
+
+% \eacute -> simplified -> e (via raw encoding)
+% -> raw -> eacute (via handler)
+%
+% naming sucks
+
+\newif\ifXMLrawentities % proper fallback
+\newif\ifXMLsimpleentities % last resort
+
+\def\simpleXMLencoding{raw}
+
+\ifnum\texengine=\luatexengine
+ \def\simplifyXMLentities
+ {\XMLsimpleentitiestrue}
+\else
+ \def\simplifyXMLentities
+ {\fastenableencoding\simpleXMLencoding
+ \XMLsimpleentitiestrue}
+\fi
+
+\def\defineXMLentity
+ {\dodoubleempty\dodefineXMLentity}
+
+\def\dodefineXMLentity[#1][#2]#3%
+ {\ifsecondargument
+ \defineXMLentities[#1]{#2}{#3}%
+ \else
+ \dododefineXMLentity{#1}{#3}%
+ \fi}
+
+\def\defineXMLentities[#1]#2#3%
+ {\dododefineXMLentity{#1}{\ifXMLsimpleentities#2\else#3\fi}}
+
+\def\dododefineXMLentity#1#2%
+ {\unspaceargument#1\to\ascii % #1 can be {[} or so
+ \long\setvalue{\@@XMLentity:\@EA\firstofoneargument\ascii}{#2}}
+
+\def\setXMLentity#1% fast one
+ {\long\@EA\def\csname\@@XMLentity:#1\endcsname}
+
+%D May this wile become dodo (more in tune with rest);
+%D beware: also remapped in xtag-map.
+
+\def\doXMLentity#1#2;% interesting: # is now ##
+ {\if\string#1\letterhash
+ \@EA\parseXMLcharacter
+ \else\ifXMLrawentities
+ \@EAEAEA\firstofoneargument
+ \else
+ \@EAEAEA\executeXMLentity
+ \fi\fi{#1#2}}
+
+%D Here we need to get rid of the double hash and act upon the
+%D number. Proper hex/oct number support can be implemented by
+%D redefining \type {\executeXMLcharacter}.
+
+% \def\parseXMLcharacter#1% gobble the ##x
+% {\@EA\executeXMLcharacter\@EA{\gobblethreearguments#1}}
+%
+% single hash now
+%
+% \def\parseXMLcharacter#1%
+% {\@EA\executeXMLcharacter\@EA{\gobbleoneargument#1}}
+%
+% \def\executeXMLcharacter#1% can be overloaded
+% {\ifnum"#1<256
+% \@EA\getXMLcharacter
+% \else\ifXMLrawentities
+% \@EAEAEA\firstofoneargument
+% \else
+% \@EAEAEA\unknownXMLcharacter
+% \fi\fi{\number"#1}}
+%
+% \unexpanded\def\getXMLcharacter#1{\rawcharacter{#1}}
+
+\def\parseXMLcharacter#1%
+ {\@EA\executeXMLcharacter\gobbleoneargument#1\empty\relax}
+
+\def\executeXMLcharacter#1#2\relax
+ {\if#1x%
+ \@EA\noexecuteXMLhexcharacter
+ \else
+ \@EA\doexecuteXMLdeccharacter
+ \fi#1#2\relax}
+
+\def\noexecuteXMLhexcharacter x#1\relax
+ {\uppercase{\doexecuteXMLhexcharacter#1\relax}}
+
+% \unexpanded\def\getXMLcharacter#1%
+% {\ifXMLrawentities
+% \@EA\firstofoneargument
+% \else\ifcsname\@@XMLentity:#1\endcsname
+% \@EAEAEA\getXMLentity
+% \else
+% \@EAEAEA\unicodechar % was: \rawcharacter
+% \fi\fi{#1}}
+%
+% \def\doexecuteXMLhexcharacter#1\relax{\getXMLcharacter{"#1}}
+% \def\doexecuteXMLdeccharacter#1\relax{\getXMLcharacter {#1}}
+%
+% if we want to support x in entity overloading, we prefer:
+
+\unexpanded\def\getXMLdeccharacter#1%
+ {\ifXMLrawentities
+ \@EA\rawXMLdecentity
+ \else\ifcsname\@@XMLentity:#1\endcsname
+ \@EAEAEA\getXMLdecentity
+ \else
+ \@EAEAEA\unicodechar
+ \fi\fi{#1}}
+
+\unexpanded\def\getXMLhexcharacter#1%
+ {\ifXMLrawentities
+ \@EA\rawXMLhexentity
+ \else\ifcsname\@@XMLentity:x#1\endcsname
+ \@EAEAEA\getXMLhexentity
+ \else
+ \@EAEAEA\unicodehexchar
+ \fi\fi{#1}}
+
+\def\unicodehexchar#1{\unicodechar{"#1}}
+
+\let\getXMLcharacter\getXMLdeccharacter
+
+\def\getXMLdecentity#1{\getXMLentity {#1}}
+\def\getXMLhexentity#1{\getXMLentity{x#1}}
+
+\def\rawXMLdecentity#1{#1}
+\def\rawXMLhexentity#1{x#1}
+
+\def\doexecuteXMLhexcharacter#1\relax{\getXMLhexcharacter{#1}}
+\def\doexecuteXMLdeccharacter#1\relax{\getXMLdeccharacter{#1}}
+
+% \defineXMLentity[8218] {Adam}
+% \defineXMLentity[x007D]{Eve}
+%
+% \startbuffer
+% &#64; &#8216; &#8218; &#8220; &#8221; &#8222;&#8226;
+% &amp;
+% &#x0024; &#x007B; &#x007D; &#x00A0; &#x2026;
+% \stopbuffer
+%
+% \typebuffer \processXMLbuffer
+
+% left overs
+
+\def\unknownXMLcharacter#1{[#1]}
+
+\ifx\unicodechar\undefined\let\unicodechar\rawcharacter\fi % brrrr
+
+% \useXMLfilter[ent]
+%
+% \defineXMLsingular[test]{{\simplifyXMLentities\XMLpar{test}{bla}{}}}
+%
+% \startXMLdata
+% <test bla="&#xD3;bla&eacute;bla&tex;and$and&#xFC;ziezo&#xF99;" />
+% \stopXMLdata
+%
+% \defineXMLentity[45]{|it works|} % {|-|}
+%
+% \startXMLdata
+% text&#045;&#046;text
+% text&#x045;&#x046;text
+% \stopXMLdata
+
+%D May be this will change a bit ...
+
+\def\executeXMLentity#1% named one
+ {\getXMLentity{#1}}
+
+%\def\expandedXMLentity#1%
+% {\ifcsname\@@XMLentity:#1\endcsname\csname\@@XMLentity:#1\endcsname\fi}
+%
+%\unexpanded\def\getXMLentity#1%
+% {\ifcsname\@@XMLentity:#1\endcsname\csname\@@XMLentity:#1\endcsname\fi}
+%
+%\def\expandedXMLentity#1%
+% {\csname\@@XMLentity:#1\endcsname}
+%
+%\unexpanded\def\getXMLentity#1%
+% {\csname\@@XMLentity:#1\endcsname}
+
+\doifundefined{autoXMLentitiestrue}{\expandafter\newif\csname ifautoXMLentities\endcsname} % fall back on context commands
+
+\def\expandedXMLentity#1%
+ {\ifcsname\@@XMLentity:#1\endcsname \@EA \execXMLentity
+ \else\ifautoXMLentities \@EAEAEA \autoXMLentity
+ \else \@EAEAEA \crapXMLentity
+ \fi\fi{#1}}
+
+\def\execXMLentity#1{\csname\@@XMLentity:#1\endcsname}
+\def\crapXMLentity#1{\inframed[\c!offset=.1ex]{\tttf#1}}
+\def\autoXMLentity#1{\ifcsname#1\endcsname\csname#1\endcsname\fi}
+
+\unexpanded\def\getXMLentity{\expandedXMLentity}
+
+%\def\doifXMLentityelse#1#2#3%
+% {\ifcsname\@@XMLentity:#1\endcsname#2\else#3\fi}
+
+\def\doifXMLentityelse#1%
+ {\ifcsname\@@XMLentity:#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+% \letvalue{1@2}\firstoftwoarguments
+% \letvalue{2@2}\secondoftwoarguments
+%
+% \def\doifXMLentityelse#1%
+% {\csname\ifcsname\@@XMLentity:#1\endcsname1\else2\fi @2\endcsname}
+
+% see \defineXML... commands:
+%
+% [key=val] => \presetXMLarguments{element} => default key/vals
+% [blabla] => \theXMLarguments{blabla} => user key/vals
+% [blabla] [key=val] => \presetXMLarguments{element} => default key/vals
+% \theXMLarguments{blabla} => user key/vals
+%
+% <element key="val"> stored in case of [blabla] else set as \XMLpar
+%
+% see m-steps for an example of usage
+
+\let\@@XMLmapmap\empty
+\newif\ifXMLnamespace
+
+\long\def\getXMLarguments#1#2%
+ {\XMLnamespacefalse
+ \dogetXMLarguments{#1}#2>}
+
+\let\dosetXMLattributeA\gobbleoneargument
+
+\def\dosetXMLattributeB#1%
+ {\ifx\@@XMLspac\originalXMLnamespace
+ \@EA\def\csname\@@XMLvariable:\@@XMLclass:\@@XMLname\endcsname{#1}%
+ % maybe some day global handling here as well
+ \fi}
+
+\def\dosetXMLattributeC
+ {\@EA\def\csname\@@XMLvariable:\@@XMLclass\ifx\@@XMLspac
+ \originalXMLnamespace\else:\@@XMLspac\fi:\@@XMLname\endcsname}
+
+\def\dosetXMLattributeD
+ {\@EA\def\csname\@@XMLvariable:\@@XMLclass:\ifx\@@XMLspac
+ \originalXMLnamespace\currentXMLnamespace\else\@@XMLspac\fi:\@@XMLname\endcsname}
+
+\def\setXMLattributemode#1%
+ {\ifcase#1\relax
+ \let\dosetXMLattribute\dosetXMLattributeA
+ \or
+ \let\dosetXMLattribute\dosetXMLattributeB
+ \or
+ \let\dosetXMLattribute\dosetXMLattributeC
+ \or
+ \let\dosetXMLattribute\dosetXMLattributeD
+ \fi}
+
+\setXMLattributemode{2} % a reasonable default
+
+\let\@@XMLspac\empty % argumentnamespace
+
+\long\def\dogetXMLarguments#1%
+ {\XMLtoks\emptytoks
+ \ifcsname\@@XMLmap:#1\endcsname
+ \let\dodosetXMLargument\dodosetXMLargumentB
+ \else
+ \def\@@XMLclass{#1}%
+ \let\dodosetXMLargument\dodosetXMLargumentA
+ \fi
+ \let\dodoparseXMLarguments\doparseXMLarguments
+ \doparseXMLarguments}
+
+% \long\def\doparseXMLarguments#1% space goes ok
+% {\if#1>%
+% \let\dodoparseXMLarguments\empty
+% \else\if#1=%
+% \edef\@@XMLname{\the\XMLtoks}%
+% \XMLtoks\emptytoks
+% \else\if#1"%
+% \let\dodoparseXMLarguments\dodoparseXMLargumentsD
+% \else\if#1'%
+% \let\dodoparseXMLarguments\dodoparseXMLargumentsS
+% \else\if#1:%
+% \XMLnamespacetrue
+% \edef\@@XMLspac{\the\XMLtoks}%
+% \XMLtoks\emptytoks
+% \else\if#1/%
+% \chardef\kindofXMLelement\emptyXMLtag
+% \else
+% \XMLtoks\@EA{\the\XMLtoks#1}%
+% \fi\fi\fi\fi\fi\fi
+% \dodoparseXMLarguments}
+%
+% The next speed optimization is suggested by Taco. Since we
+% are dealing with validated code, we can grab larger chunks.
+%
+% \long\def\doparseXMLarguments#1% space goes ok
+% {\if#1>%
+% \let\dodoparseXMLarguments\empty
+% \else\if#1/%
+% \chardef\kindofXMLelement\emptyXMLtag
+% \else
+% \XMLtoks{#1}%
+% \let\dodoparseXMLarguments\dodoparseXMLargumentsX
+% \fi\fi
+% \dodoparseXMLarguments}
+%
+% we can get rid of one more assignment
+
+\long\def\doparseXMLarguments#1% space goes ok
+ {\if#1>%
+ %\let\dodoparseXMLarguments\empty
+ \expandafter\gobbleoneargument % speedup
+ \else\if#1/%
+ \chardef\kindofXMLelement\emptyXMLtag
+ \else
+ \XMLtoks{#1}%
+ \let\dodoparseXMLarguments\dodoparseXMLargumentsX
+ \fi\fi
+ \dodoparseXMLarguments}
+
+% slightly faster:
+%
+% \long\def\doparseXMLarguments#1% space goes ok
+% {\if#1>%
+% \@EA\gobbleoneargument
+% \else\if#1/%
+% \chardef\kindofXMLelement\emptyXMLtag
+% \@EAEAEA\gobbletwoarguments
+% \else
+% \@EAEAEA\dodoparseXMLargumentsX
+% \fi\fi#1}
+%
+% \def\dodoparseXMLargumentsX#1=#2%
+% {\def\@@XMLname{#1}%
+% \getXMLNSSSS#1:\relax
+% \if#2"%
+% \expandafter\dodoparseXMLargumentsD
+% \else
+% \expandafter\dodoparseXMLargumentsS
+% \fi}
+
+\def\dodoparseXMLargumentsX#1=#2%
+ {\edef\@@XMLname{\the\XMLtoks#1}%
+ \@EA\getXMLNSSSS\@@XMLname:\relax
+ \XMLtoks\emptytoks
+ \if#2"%
+ \let\dodoparseXMLarguments\dodoparseXMLargumentsD
+ \else
+ \let\dodoparseXMLarguments\dodoparseXMLargumentsS
+ \fi
+ \dodoparseXMLarguments}
+
+\def\gobbleuntilcolon#1:{#1}
+
+\def\getXMLNSSSS#1:#2\relax
+ {\def\!!stringa{#2}%
+ \ifx\!!stringa\empty \else
+ \XMLnamespacetrue
+ \edef\@@XMLname{\gobbleuntilcolon#2}%
+ \edef\@@XMLspac{#1}%
+ \fi}
+
+% ok ?
+%
+% \def\dodoparseXMLargumentsX#1=#2%
+% {\edef\@@XMLname{\the\XMLtoks#1}%
+% \@EA\getXMLNSSSS\@@XMLname:\relax
+% \XMLtoks\emptytoks
+% \if#2"%
+% \@EA\dodoparseXMLargumentsD
+% \else
+% \@EA\dodoparseXMLargumentsS
+% \fi}
+
+% Storing \type {#1} in a macro in order to minimize the
+% amount of data passed as argument does not improve
+% performance, so we keep the readable form.
+
+\def\dodoparseXMLargumentsD#1"{\dosetXMLargument{#1}}
+\def\dodoparseXMLargumentsS#1'{\dosetXMLargument{#1}}
+
+% the readable version
+%
+% \def\dosetXMLargument#1%
+% {\ifXMLnamespace
+% \ifx\@@XMLspac\@@XMLns
+% \checkXMLnamespaceattr{#1}% xmlns:\@@XMLname="#1"
+% \else
+% \dosetXMLattribute{#1}% some:\@@XMLname="#1"
+% \fi
+% \XMLnamespacefalse
+% \else\ifx\@@XMLname\@@XMLns
+% \checkXMLnamespaceattr{#1}% xmlns="#1"
+% \else
+% \dodosetXMLargument{#1}%
+% \fi\fi
+% \let\dodoparseXMLarguments\doparseXMLarguments
+% \dodoparseXMLarguments}
+%
+% the ugly alternative
+
+% \def\dosetXMLargument#1% ugly alternative
+% {\ifXMLnamespace
+% \XMLnamespacefalse
+% \ifx\@@XMLspac\@@XMLns
+% \@EAEAEA\checkXMLnamespaceattr % xmlns:\@@XMLname="#1"
+% \else
+% \@EAEAEA\dosetXMLattribute % some:\@@XMLname="#1"
+% \fi
+% \else\ifx\@@XMLname\@@XMLns
+% \@EAEAEA\checkXMLnamespaceattr % xmlns="#1"
+% \else
+% \@EAEAEA\dodosetXMLargument
+% \fi\fi{#1}%
+% \let\dodoparseXMLarguments\doparseXMLarguments
+% \dodoparseXMLarguments}
+
+\def\dosetXMLargument#1% ugly alternative
+ {\ifXMLnamespace
+ \XMLnamespacefalse
+ \ifx\@@XMLspac\@@XMLns
+ \@EAEAEA\checkXMLnamespaceattr % xmlns:\@@XMLname="#1"
+ \else
+ \@EAEAEA\dosetXMLattribute % some:\@@XMLname="#1"
+ \fi
+ \else\ifx\@@XMLname\@@XMLns
+ \@EAEAEA\checkXMLnamespaceattr % xmlns="#1"
+ \else
+ \@EAEAEA\dodosetXMLargument
+ \fi\fi{#1}%
+ \dodocopyXMLargument
+ \let\dodoparseXMLarguments\doparseXMLarguments
+ \dodoparseXMLarguments}
+
+\let\dodocopyXMLargument\relax
+
+% \def\dododocopyXMLargument
+% {\@EA\let\csname\@@XMLvariable:\the\numexpr(\XMLdepth+1):\@@XMLname\@EA\endcsname
+% \csname\@@XMLvariable:\@@XMLclass:\@@XMLname\endcsname}
+
+\def\dododocopyXMLargument
+ {\@EA\let\csname\@@XMLvariable:\the\numexpr\XMLdepth+\plusone\relax:\@@XMLname\@EA\endcsname
+ \csname\@@XMLvariable:\@@XMLclass:\@@XMLname\endcsname}
+
+\def\copyXMLargumentindeed
+ {\let\dodocopyXMLargument\dododocopyXMLargument
+ \let\copyXMLargumentindeed\relax}
+
+\def\dodosetXMLargumentA
+ {\@EA\def\csname\@@XMLvariable:\@@XMLclass:\@@XMLname\endcsname}
+
+% \def\dodosetXMLargumentB#1%
+% {\@EA\edef\csname\@@XMLmap:\@@XMLmapmap\endcsname
+% {\@EA\ifx\csname\@@XMLmap:\@@XMLmapmap\endcsname\empty\else
+% \csname\@@XMLmap:\@@XMLmapmap\endcsname,%
+% \fi
+% \@@XMLname=#1}}
+
+\def\dodosetXMLargumentB#1%
+ {\@EA\edef\csname\@@XMLmap:\@@XMLmapmap\endcsname
+ {\@EA\ifx\csname\@@XMLmap:\@@XMLmapmap\endcsname\empty\else
+ \csname\@@XMLmap:\@@XMLmapmap\endcsname,%
+ \fi
+ \@@XMLname={#1}}} % {} is needed for aa='bb,cc'
+
+\appendtoks
+ \resetXMLarguments{\rawXMLnamespace\rawXMLidentifier}%
+\to \everyXMLelement
+
+\def\resetXMLarguments#1%
+ {\ifcsname\@@XMLmap:#1\endcsname
+ \@EA\let\@EA\@@XMLmapmap\csname\@@XMLmap:#1\endcsname
+ \@EA\let\csname\@@XMLmap:\@@XMLmapmap\endcsname\empty
+ \fi}
+
+\def\theXMLarguments#1%
+ {\ifcsname\@@XMLmap:#1\endcsname\csname\@@XMLmap:#1\endcsname\fi}
+
+\def\doexpandXMLvalue#1#2%
+ {\ifcsname#2\endcsname
+ \bgroup
+ \enableXMLexpansion
+ \let\getXMLentity\expandedXMLentity
+ #1% simplify maps entities back to _ and alike
+ \expanded{\global\globalscratchtoks{\csname#2\endcsname}}%
+ \egroup
+ \@EA\edef\csname#2\endcsname{\the\globalscratchtoks}%
+ \fi}
+
+\def\expandXMLvalue {\doexpandXMLvalue\relax}
+\def\simplifyXMLvalue{\doexpandXMLvalue\XMLsimpleentitiestrue}
+
+\def\expandTEXpar #1#2{\expandXMLvalue{#1\interfaced{#2}}}
+\def\expandXMLpar #1#2{\expandXMLvalue{\@@XMLvariable:#1:#2}}
+\def\expandXMLarguments #1{\expandXMLvalue{\@@XMLmap:#1}}
+
+\def\simplifyTEXpar #1#2{\simplifyXMLvalue{#1\interfaced{#2}}}
+\def\simplifyXMLpar #1#2{\simplifyXMLvalue{\@@XMLvariable:#1:#2}}
+\def\simplifyXMLarguments#1{\simplifyXMLvalue{\@@XMLmap:#1}}
+
+%D \startbuffer[tex]
+%D \defineXMLsingular [fx:root]
+%D {\XMLNSpar{fx:root}{xml}{lang}{}
+%D \XMLpar{fx:root}{xml:lang}{}
+%D \starttabulate[||||]
+%D \HL
+%D \NC \bf mode \NC \bf call \NC \bf result \NC\NR
+%D \HL
+%D \NC 0\NC\asciistr{\XMLpar {fx:root} {crap} {}} \NC dirt \NC\NR
+%D \NC \NC\asciistr{\XMLpar {fx:root} {junk} {}} \NC \NC\NR
+%D \NC \NC\asciistr{\XMLNSpar {fx:root} {fx} {crap} {}}\NC \NC\NR
+%D \NC \NC\asciistr{\XMLNSpar {fx:root} {xml} {lang} {}}\NC \NC\NR
+%D \HL
+%D \NC 1\NC\asciistr{\XMLpar {fx:root} {crap} {}} \NC dirt \NC\NR
+%D \NC \NC\asciistr{\XMLpar {fx:root} {junk} {}} \NC junk \NC\NR
+%D \NC \NC\asciistr{\XMLNSpar {fx:root} {fx} {crap} {}}\NC \NC\NR
+%D \NC \NC\asciistr{\XMLNSpar {fx:root} {xml} {lang} {}}\NC \NC\NR
+%D \HL
+%D \NC 2\NC\asciistr{\XMLpar {fx:root} {crap} {}} \NC dirt \NC\NR
+%D \NC \NC\asciistr{\XMLpar {fx:root} {junk} {}} \NC junk \NC\NR
+%D \NC \NC\asciistr{\XMLNSpar {fx:root} {fx} {crap} {}}\NC \NC\NR
+%D \NC \NC\asciistr{\XMLNSpar {fx:root} {xml} {lang} {}}\NC en \NC\NR
+%D \HL
+%D \NC 3\NC\asciistr{\XMLpar {fx:root} {crap} {}} \NC dirt \NC\NR
+%D \NC \NC\asciistr{\XMLpar {fx:root} {junk} {}} \NC junk \NC\NR
+%D \NC \NC\asciistr{\XMLNSpar {fx:root} {fx} {crap} {}}\NC rubish\NC\NR
+%D \NC \NC\asciistr{\XMLNSpar {fx:root} {xml} {lang} {}}\NC en \NC\NR
+%D \HL
+%D \stoptabulate}
+%D
+%D \remapXMLurlspace [http://www.w3.org/1999/XSL/Format] [fx]
+%D \stopbuffer
+%D
+%D \startbuffer[xml]
+%D <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
+%D fo:crap="rubish"
+%D fo:junk="junk"
+%D xml:lang="en"
+%D crap="dirt" />
+%D \stopbuffer
+%D
+%D \typebuffer[tex] \processTEXbuffer[tex]
+%D \typebuffer[xml] \processXMLbuffer[xml]
+
+%D The previous macros were the basic parser and their working
+%D is left to the imagination of the reader. These macros
+%D will be improved over time. We use rather low level
+%D definitions so that the mappings will run as fast as
+%D possible.
+
+\bgroup \catcode`<=\activecatcode
+
+\long\gdef\dododefineXMLsingular#1#2%
+ {\long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2}}
+
+\long\gdef\dododefineXMLcommand#1#2%
+ {\long\@EA\def\csname\@@XMLelement:#1\endcsname{#2}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2}}
+
+\long\gdef\dododefineXMLgrouped#1#2%
+ {\long\@EA\def\csname\@@XMLelement:#1\endcsname{\groupedcommand{#2}\donothing\bgroup}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\egroup
+ \@EA\let\csname\@@XMLelement:#1/\endcsname\donothing}
+
+\long\gdef\dododefineXMLargument#1#2% watch the {} around ##1
+ {\long\@EA\def\csname\@@XMLelement:#1\endcsname{\redoXMLargument{#1}{#2}}
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2{}}}
+
+\long\gdef\redoXMLargument#1#2% potential optimization: globalnext
+ {\long\@EA\gdef\@EA\next\@EA##\@EA1\@EA<\@EA/\currentXMLelement>{#2{##1}}%
+ \next}
+
+\long\gdef\dododefineXMLignore#1%
+ {\@EA\def\csname\@@XMLelement:#1\endcsname{\redoXMLignore{#1}}
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \@EA\let\csname\@@XMLelement:#1/\endcsname\donothing}
+
+\long\gdef\redoXMLignore#1%
+ {\long\@EA\def\@EA\next\@EA##\@EA1\@EA<\@EA/\currentXMLelement>{}%
+ \next}
+
+\long\gdef\dododefineXMLpickup#1#2#3%
+ {\long\@EA\def\csname\@@XMLelement:#1\endcsname{\redoXMLpickup{#1}{#2}{#3}}
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2#3}}
+
+\long\gdef\redoXMLpickup#1#2#3%
+ {\long\@EA\def\@EA\next\@EA##\@EA1\@EA<\@EA/\currentXMLelement>{#2##1#3}%
+ \next}
+
+\long\gdef\dododefineXMLenvironment#1#2#3%
+ {\long\@EA\def\csname\@@XMLelement:#1\endcsname{#2}%
+ \long\@EA\def\csname\@@XMLelement:/#1\endcsname{#3}%
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2#3}}
+
+\long\gdef\dododefineXMLsave#1%
+ {\@EA\let\csname\@@XMLdata:#1\endcsname\longempty
+ \long\@EA\def\csname\@@XMLelement:#1\endcsname {\redoXMLsave{#1}}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{\@EA\let\csname\@@XMLdata:#1\endcsname\longempty}}
+
+\long\gdef\dododefineXMLsavecontent#1#2%
+ {\long\@EA\def\csname\@@XMLdata:#1\endcsname{#2}%
+ \long\@EA\def\csname\@@XMLelement:#1\endcsname{\redoXMLsave{#1}}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{\@EA\let\csname\@@XMLdata:#1\endcsname\longempty}}
+
+\long\gdef\redoXMLsave#1%
+ {\long\@EA\def\@EA\next\@EA##\@EA1\@EA<\@EA/\currentXMLelement>%
+ {\long\@EA\def\csname\@@XMLdata:#1\endcsname{##1}}%
+ \next}
+
+\long\gdef\dododefineXMLgsave#1%
+ {\global\@EA\let\csname\@@XMLdata:#1\endcsname\longempty
+ \long\@EA\def\csname\@@XMLelement:#1\endcsname{\redoXMLgsave{#1}}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{\global\@EA\let\csname\@@XMLdata:#1\endcsname\longempty}}
+
+\long\gdef\dododefineXMLgsavecontent#1#2%
+ {\long\@EA\gdef\csname\@@XMLdata:#1\endcsname{#2}%
+ \long\@EA\def\csname\@@XMLelement:#1\endcsname{\redoXMLgsave{#1}}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{\global\@EA\let\csname\@@XMLdata:#1\endcsname\longempty}}
+
+\long\gdef\redoXMLgsave#1%
+ {\long\@EA\def\@EA\next\@EA##\@EA1\@EA<\@EA/\currentXMLelement>%
+ {\long\@EA\gdef\csname\@@XMLdata:#1\endcsname{##1}}%
+ \next}
+
+\long\gdef\dododefineXMLenvironmentsave#1#2#3%
+ {\@EA\let\csname\@@XMLdata:#1\endcsname\longempty
+ \long\@EA\def\csname\@@XMLelement:#1\endcsname{\redoXMLenvironmentsave{#1}{#2}{#3}}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2\@EA\let\csname\@@XMLdata:#1\endcsname\longempty#3}}
+
+% maybe \globalnext
+
+\long\gdef\redoXMLenvironmentsave#1#2#3%
+ {\long\@EA\def\@EA\next\@EA##\@EA1\@EA<\@EA/\currentXMLelement>%
+ {#2\long\@EA\def\csname\@@XMLdata:#1\endcsname{##1}#3}%
+ \next}
+
+\long\gdef\dododefineXMLenvironmentgsave#1#2#3%
+ {\global\@EA\let\csname\@@XMLdata:#1\endcsname\longempty
+ \long\@EA\def\csname\@@XMLelement:#1\endcsname{\redoXMLenvironmentgsave{#1}{#2}{#3}}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2\global\@EA\let\csname\@@XMLdata:#1\endcsname\longempty#3}}
+
+\long\gdef\redoXMLenvironmentgsave#1#2#3%
+ {\long\@EA\def\@EA\next\@EA##\@EA1\@EA<\@EA/\currentXMLelement>%
+ {#2\long\@EA\gdef\csname\@@XMLdata:#1\endcsname{##1}#3}%
+ \next}
+
+\long\gdef\dododefineXMLprocess#1%
+ {\@EA\let\csname\@@XMLelement:#1\endcsname\donothing
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \@EA\let\csname\@@XMLelement:#1/\endcsname\donothing}
+
+\long\gdef\dododefineXMLnestedenvironment#1#2#3%
+ {\long\@EA\def\csname\@@XMLelement:#1\endcsname{\getXMLgroupedenvironment{#1}{#2}{#3}}%
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2#3}}
+
+\long\gdef\dododefineXMLnestedargument#1#2%
+ {\long\@EA\def\csname\@@XMLelement:#1\endcsname{\getXMLgroupedargument{#1}{#2}}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2{}}}
+
+\long\gdef\dododefineXMLnestedsave#1%
+ {\@EA\let\csname\@@XMLdata:#1\endcsname\longempty
+ \long\@EA\def\csname\@@XMLelement:#1\endcsname {\getXMLgroupednestedsave{#1}}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{\@EA\let\csname\@@XMLdata:#1\endcsname\longempty}}
+
+\long\unexpanded\gdef\getXMLgroupednestedsave#1%
+ {\collectXMLgroupedtrue
+ \long\def\dodogetgrouped{\long\@EA\edef\csname\@@XMLdata:#1\endcsname{\the\groupedtoks}}%
+ \getXMLgrouped{#1}}
+
+\long\gdef\dododefineXMLnestedenvironmentsave#1#2#3%
+ {\@EA\let\csname\@@XMLdata:#1\endcsname\longempty
+ \long\@EA\def\csname\@@XMLelement:#1\endcsname {\getXMLgroupednestedenvironmentsave{#1}{#2}{#3}}%
+ \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+ \long\@EA\def\csname\@@XMLelement:#1/\endcsname{#2\@EA\let\csname\@@XMLdata:#1\endcsname\longempty#3}}
+
+\long\unexpanded\gdef\getXMLgroupednestedenvironmentsave#1#2#3%
+ {\collectXMLgroupedtrue
+ \long\def\dodogetgrouped{#2\long\@EA\edef\csname\@@XMLdata:#1\endcsname{\the\groupedtoks}#3}%
+ \getXMLgrouped{#1}}
+
+\egroup
+
+%D The high level definition macros.
+
+\def\defineXMLsingular {\dotripleempty\dodefineXMLsingular}
+\def\defineXMLcommand {\dotripleempty\dodefineXMLcommand}
+\def\defineXMLgrouped {\dotripleempty\dodefineXMLgrouped}
+\def\defineXMLargument {\dotripleempty\dodefineXMLargument}
+\def\defineXMLignore {\dotripleempty\dodefineXMLignore}
+\def\defineXMLpickup {\dotripleempty\dodefineXMLpickup}
+\def\defineXMLenvironment {\dotripleempty\dodefineXMLenvironment}
+\def\defineXMLsave {\dotripleempty\dodefineXMLsave}
+\def\defineXMLsavecontent {\dotripleempty\dodefineXMLsavecontent}
+\def\defineXMLgsave {\dotripleempty\dodefineXMLgsave}
+\def\defineXMLgsavecontent {\dotripleempty\dodefineXMLgsavecontent}
+\def\defineXMLenvironmentsave {\dotripleempty\dodefineXMLenvironmentsave}
+\def\defineXMLenvironmentgsave {\dotripleempty\dodefineXMLenvironmentgsave}
+\def\defineXMLprocess {\dotripleempty\dodefineXMLprocess}
+\def\defineXMLnested {\dotripleempty\dodefineXMLnestedenvironment}
+\def\defineXMLnestedenvironment {\dotripleempty\dodefineXMLnestedenvironment}
+\def\defineXMLnestedargument {\dotripleempty\dodefineXMLnestedargument}
+\def\defineXMLnestedsave {\dotripleempty\dodefineXMLnestedsave}
+\def\defineXMLnestedenvironmentsave{\dotripleempty\dodefineXMLnestedenvironmentsave}
+
+%D We can nill definitions with:
+
+\def\resetXMLelement[#1]{\dododefineXMLprocess{#1}}
+
+%D This is equivalent to:
+%D
+%D \starttyping
+%D \def\resetXMLelement[#1]% handy in case only singular
+%D {\@EA\let\csname\@@XMLelement:#1\endcsname \donothing
+%D \@EA\let\csname\@@XMLelement:/#1\endcsname\donothing
+%D \@EA\let\csname\@@XMLelement:#1/\endcsname\donothing}
+%D \stoptyping
+
+% push is (not yet) a real push, so:
+
+\def\defineXMLpush {\dotripleempty\dodefineXMLsave}
+\def\defineXMLenvironmentpush{\dotripleempty\dodefineXMLenvironmentsave}
+
+% goes for all types
+
+\long\def\dodefineXMLsingular[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLsingular{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLcommand[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLcommand{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLgrouped[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLgrouped{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLargument[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLargument{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLignore[#1][#2][#3]%
+ {\defineXMLmethod\dododefineXMLignore{#1}{#2}{#3}{}{}}
+
+\long\def\dodefineXMLpickup[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLpickup{#1}{#2}{#3}{#4}{#5}}
+
+\long\def\dodefineXMLenvironment[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLenvironment{#1}{#2}{#3}{#4}{#5}}
+
+\long\def\dodefineXMLsave[#1][#2][#3]%
+ {\defineXMLmethod\dododefineXMLsave{#1}{#2}{#3}{}{}}
+
+\long\def\dodefineXMLsavecontent[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLsavecontent{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLgsave[#1][#2][#3]%
+ {\defineXMLmethod\dododefineXMLgsave{#1}{#2}{#3}{}{}}
+
+\long\def\dodefineXMLgsavecontent[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLgsavecontent{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLenvironmentsave[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLenvironmentsave{#1}{#2}{#3}{#4}{#5}}
+
+\long\def\dodefineXMLenvironmentgsave[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLenvironmentgsave{#1}{#2}{#3}{#4}{#5}}
+
+\long\def\dodefineXMLprocess[#1][#2][#3]%
+ {\defineXMLmethod\dododefineXMLprocess{#1}{#2}{#3}{}{}}
+
+\long\def\dodefineXMLnestedenvironment[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLnestedenvironment{#1}{#2}{#3}{#4}{#5}}
+
+\long\def\dodefineXMLnestedargument[#1][#2][#3]#4%
+ {\defineXMLmethod\dododefineXMLnestedargument{#1}{#2}{#3}{#4}{}}
+
+\long\def\dodefineXMLnestedsave[#1][#2][#3]%
+ {\defineXMLmethod\dododefineXMLnestedsave{#1}{#2}{#3}{}{}}
+
+\long\def\dodefineXMLnestedenvironmentsave[#1][#2][#3]#4#5%
+ {\defineXMLmethod\dododefineXMLnestedenvironmentsave{#1}{#2}{#3}{#4}{#5}}
+
+% [key=val] => \presetXMLarguments{element} => default key/vals
+% [blabla] => \theXMLarguments{blabla} => user key/vals
+% [blabla] [key=val] => \presetXMLarguments{element} => default key/vals
+% \theXMLarguments{blabla} => user key/vals
+
+% command element [map] [parlst] begin end
+
+\long\def\defineXMLmethod#1#2#3#4#5#6%
+ {\ifsecondargument
+ \setXMLarguments{#2}{#3}{#4}%
+ \else
+ \resetXMLarguments{#2}% new
+ \fi
+ #1{#2}{#5}{#6}}
+
+%D Arguments (attributes) \unknown
+
+% \long\def\setXMLarguments#1#2#3% element [tag] settings
+% {\doifassignmentelse{#2}
+% {\long\setvalue{\@@XMLpars:#1}{\getrawparameters[\@@XMLvariable:#1:][#2]}}
+% {\long\setvalue{\@@XMLmap :#1}{#2}% later we can init vars by this name
+% \doifsomething{#3}{\long\setvalue{\@@XMLpars:#1}{\getrawparameters[#2][#3]}}}}
+
+\long\def\setXMLarguments#1#2#3% element [tag] settings
+ {\doifassignmentelse{#2} % ROOM FOR OPTIMIZATION
+ {\letbeundefined{\@@XMLmap:#1}%
+ \long\setvalue{\@@XMLpars:#1}{\getrawparameters[\@@XMLvariable:#1:][#2]}}
+ {\long\setvalue{\@@XMLmap:#1}{#2}% later we can init vars by this name
+ \doifsomething{#3}{\long\setvalue{\@@XMLpars:#1}{\getrawparameters[#2][#3]}}}}
+
+\def\presetXMLarguments#1%
+ {\csname\@@XMLpars:\rawXMLnamespace#1\endcsname} % == \getvalue{}
+
+\prependtoks
+ \presetXMLarguments\rawXMLidentifier
+\to \everyXMLelement
+
+%D We now overload the previously defined argument setter by one
+%D that is faster when definitions are surrounded by
+%D
+%D \starttyping
+%D \startXMLcompiling ... \stopXMLcompiling
+%D \stoptyping
+%D
+%D This method is twice as fast on (for instance) 100K calls to
+%D an empty element with 10 arguments.
+
+% \long\def\prepareXMLargument#1#2#3%
+% {\scratchtoks\expandafter{\the\scratchtoks\@EA\def\csname#1#2\endcsname{#3}}}
+
+% \long\def\prepareXMLargument#1#2#3%
+% {\scratchtoks\@EA\@EA\@EA{\@EA\the\@EA\scratchtoks\@EA\def\csname\@@XMLvariable:#1:#2\endcsname{#3}}}
+
+% \let\@@globalprefix\empty
+
+% \long\def\prepareXMLargument#1#2#3%
+% {\expanded{\scratchtoks
+% {\the\scratchtoks
+% \def\@EA\noexpand\csname\@@XMLvariable:#1:#2\endcsname{#3}%
+% \noexpand\@EA\let\noexpand\csname\@@XMLvariable:\noexpand\the\numexpr(\XMLdepth+1):#2\endcsname
+% \@EA\noexpand\csname\@@XMLvariable:#1:#2\endcsname}}}
+
+\long\def\prepareXMLargument#1#2#3%
+ {\expanded{\scratchtoks
+ {\the\scratchtoks
+ \def\@EA\noexpand\csname\@@XMLvariable:#1:#2\endcsname{#3}%
+ \noexpand\@EA\let\noexpand\csname\@@XMLvariable:\noexpand\the\numexpr\XMLdepth+\plusone\relax:#2\endcsname
+ \@EA\noexpand\csname\@@XMLvariable:#1:#2\endcsname}}}
+
+\long\def\setXMLargumentsN#1#2#3% element [tag] settings
+ {\doifassignmentelse{#2}
+ {\letbeundefined{\@@XMLmap:#1}%
+ \long\setvalue{\@@XMLpars:#1}{\getrawparameters[\@@XMLvariable:#1:][#2]}}
+ {\long\setvalue{\@@XMLmap:#1}{#2}% later we can init vars by this name
+ \doifsomething{#3}{\long\setvalue{\@@XMLpars:#1}{\getrawparameters[#2][#3]}}}}
+
+\long\def\setXMLargumentsP#1#2#3% element settings empty (we cannot test for assignment)
+ {\letbeundefined{\@@XMLmap:#1}%
+ \bgroup
+ %def\XMLinheritance{\noexpand\XMLinheritance}
+ \def\XMLop##1{\noexpand\XMLpar{#1}{##1}{}}%
+ \def\XMLpar{\noexpand\XMLpar}%
+ \def\XMLanc{\noexpand\XMLanc}%
+ \def\XMLinh{\noexpand\XMLinh}%
+ \xdef\!!XMLattr{[#1][#2]}%
+ \scratchtoks\emptytoks
+ \@EA\dogetparameters\@EA\prepareXMLargument\!!XMLattr
+ \xdef\globalnext{\the\scratchtoks}%
+ \egroup
+ \letvalue{\@@XMLpars:#1}\globalnext
+ \globallet\globalnext\relax}
+
+\def\defineXMLattributeset{\dodoubleargument\dodefineXMLattributeset}
+\def\extendXMLattributeset{\dodoubleargument\doextendXMLattributeset}
+
+\def\dodefineXMLattributeset[#1][#2]{\setvalue {\@@XMLpars::#1}{#2}}
+\def\doextendXMLattributeset[#1][#2]{\appendvalue{\@@XMLpars::#1}{,#2}}
+
+\def\XMLattributeset #1{\executeifdefined{\@@XMLpars::#1}\empty}
+%def\XMLinheritance #1{\executeifdefined{\@@XMLpars:#1}\empty}
+\def\showXMLattributes#1{\showvalue{\@@XMLpars:#1}}
+
+\chardef\@@precompile\zerocount
+
+\def\setXMLarguments
+ {\ifcase\@@precompile
+ \expandafter\setXMLargumentsN
+ \else
+ \expandafter\setXMLargumentsP
+ \fi}
+
+\def\startXMLcompiling
+ {\dosingleargument\dostartXMLcompiling}
+
+% \def\dostartXMLcompiling[#1]%
+% {\iffirstargument
+% \copyXMLargumentindeed % when needed, from now on -)
+% \def\@@globalprefix{#1}%
+% \fi
+% \chardef\@@precompile\plusone}
+
+\def\dostartXMLcompiling[#1]%
+ {\doif{#1}\v!inherit
+ \copyXMLargumentindeed
+ \chardef\@@precompile\plusone}
+
+\def\stopXMLcompiling
+ {\chardef\@@precompile\zerocount} % no \let\@@globalprefix\empty
+
+%D Interesting what kind of things are needed \unknown
+
+\appendtoks
+ \ifdefined\disablelanguagespecifics\disablelanguagespecifics\fi
+\to \everyenableXML
+
+\long\def\longempty{}
+\long\def\longspace{ }
+
+% \def\doifelseXMLdata#1% always empty at start [gets a long assignment]
+% {\@EA\ifx\csname\@@XMLdata:#1\endcsname\longempty
+% \expandafter\secondoftwoarguments
+% \else
+% \expandafter\firstoftwoarguments
+% \fi}
+%
+% \def\doifXMLdata#1% always empty at start [gets a long assignment]
+% {\@EA\ifx\csname\@@XMLdata:#1\endcsname\longempty
+% \expandafter\gobbleoneargument
+% \else
+% \expandafter\firstofoneargument
+% \fi}
+%
+% \let\doifXMLdataelse\doifelseXMLdata
+
+\def\doifelseXMLdata#1% always empty at start [gets a long assignment]
+ {\@EA\ifx\csname\@@XMLdata:#1\endcsname\longempty
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\def\doifXMLdata#1% always empty at start [gets a long assignment]
+ {\@EA\ifx\csname\@@XMLdata:#1\endcsname\longempty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\let\doifXMLdataelse\doifelseXMLdata
+
+\def\doifelseXMLempty#1%
+ {\@EA\ifx\csname\@@XMLdata:#1\endcsname\longempty
+ \expandafter\firstoftwoarguments
+ \else\@EA\ifx\csname\@@XMLdata:#1\endcsname\longspace
+ \expandthree\firstoftwoarguments
+ \else
+ \expandthree\secondoftwoarguments
+ \fi\fi}
+
+% test case:
+%
+% \defineXMLenvironmentsave[test]
+% {}
+% {\message{[\XMLflush{test}]}
+% \message{\doifelseXMLdata {test}{}{no }data}
+% \message{/}
+% \message{\doifelseXMLempty{test}{}{not }empty}
+% \wait}
+%
+% \startXMLdata
+% <test>xxx</test>
+% <test></test>
+% <test> </test>
+% <test> </test>
+% <test> </test>
+% <test> x </test>
+% \stopXMLdata
+
+% \def\XMLflush#1% one level
+% {\csname\@@XMLdata:#1\endcsname}
+
+% evt meer van dit gedoe en alle \longempty's vervangen
+
+\def\XMLflush#1% one level
+ {\csname\ifcsname\@@XMLdata:#1\endcsname\@@XMLdata:#1\else\s!empty\fi\endcsname}
+
+%D \starttyping
+%D \defineXMLenvironmentsave[formula]{}{$\XMLtexdata{formula}$}
+%D
+%D \startXMLdata
+%D <formula>t+3+x+t\neq m\alpha\frac\theta\hbar</formula>
+%D \stopXMLdata
+%D \stoptyping
+
+\def\XMLtexdata#1%
+ {\begingroup
+ \disableXML
+ \scantokens\@EA\@EA\@EA{\csname\@@XMLdata:#1\endcsname}%
+ \endgroup}
+
+\def\XMLflushdata#1% see m-steps for usage
+ {\@EA\ifx\csname\@@XMLdata:#1\endcsname\longempty\else
+ %\@EAEAEA\XMLdata\@EA\@EA\@EA{\csname\@@XMLdata:#1\endcsname}%
+ \@EA\XMLdata\csname\@@XMLdata:#1\endcsname
+ \fi}
+
+\def\XMLflushasis#1%
+ {\detokenize\@EAEAEA{\csname\@@XMLdata:#1\endcsname}}
+
+\let\XMLpop \XMLflush
+\let\XMLpopdata\XMLflushdata
+
+\def\XMLappend#1#2% let to empty expands to nothing -)
+ {\long\@EA\edef\csname\@@XMLdata:#1\endcsname{\csname\@@XMLdata:#1\endcsname#2}}
+
+\def\XMLprepend#1#2% let to empty expands to nothing -)
+ {\long\@EA\edef\csname\@@XMLdata:#1\endcsname{#2\csname\@@XMLdata:#1\endcsname}}
+
+\def\XMLerase#1%
+ {\@EA\let\csname\@@XMLdata:#1\endcsname\longempty}
+
+\def\XMLassign#1%
+ {\long\@EA\def\csname\@@XMLdata:#1\endcsname}
+
+\def\dontparseXMLelement#1>{}
+
+\def\simplifyXMLelements{\let\parseXMLelement\dontparseXMLelement}
+
+\def\defXMLstring#1#2%
+ {\bgroup
+ \enableXMLexpansion
+ \simplifyXMLelements
+ \let\getXMLentity\firstofoneargument
+ \XMLrawentitiestrue
+ \utfunicodetracer\plusseven % new
+ \xdef\@@XML@@string{\csname\@@XMLdata:#2\endcsname}%
+ \egroup
+ \defconvertedcommand#1\@@XML@@string}
+
+% this has to expand nicely:
+%
+% <!DOCTYPE XXX SYSTEM "xxx" [ <!ENTITY aaa "../www/"> <!ENTITY bbb SYSTEM "&aaa;mmm.eps"> ]>
+%
+% so keep the following as is!
+
+\def\defXMLclean#1#2%
+ {\bgroup
+ \enableXMLexpansion
+ \simplifyXMLelements
+ \simplifyXMLentities
+ \utfunicodetracer\plusseven % new
+ \let\getXMLentity\expandedXMLentity % should this go in \simplify ?
+ \xdef\@@XML@@string{\csname\@@XMLdata:#2\endcsname}%
+ \egroup
+ \defconvertedcommand#1\@@XML@@string}
+
+\def\defXMLpar#1#2#3% to be documented
+ {\@EA\def\@EA#1\csname\ifcsname\@@XMLvariable:#2:#3\endcsname\@@XMLvariable:#2:#3\else\s!empty\fi\endcsname}
+
+\def\setvalueXMLpar#1#2#3% to be documented
+ {\@EA\let\csname#1\@EA\endcsname\csname\ifcsname\@@XMLvariable:#2:#3\endcsname\@@XMLvariable:#2:#3\else\s!empty\fi\endcsname}
+
+\def\XMLshow#1%
+ {\showvalue{\@@XMLdata:#1}}
+
+\def\XMLunspace#1% kan sneller
+ {\@EA\ifx\csname\@@XMLdata:#1\endcsname\longempty\else
+ \long\@EA\edef\csname\@@XMLdata:#1\endcsname
+ {\@EAEAEA\dounspaced\csname\@@XMLdata:#1\endcsname\end}%
+ \fi}
+
+\chardef\asciispacecode=32
+
+\def\defXMLlowerclean#1% lowercase ! evt tzt upper too
+ {\bgroup
+ \lccode`\#\asciispacecode
+ \lccode`\$\asciispacecode
+ \lccode`\%\asciispacecode
+ \lccode`\\\asciispacecode
+ \lccode`\^\asciispacecode
+ \lccode`\_\asciispacecode
+ \lccode`\{\asciispacecode
+ \lccode`\}\asciispacecode
+ \lccode`\|\asciispacecode
+ \lccode`\~\asciispacecode
+ \@EA\lowercase\@EA{\@EA\xdef\@EA#1\@EA{#1}}%
+ \egroup}
+
+\def\processXMLparelse#1#2#3#4%
+ {\processaction
+ [\XMLpar{#1}{#2}{}]
+ [#3,\s!unknown=>{#4},\s!default={#4}]}
+
+%D We can pick up key|/|value pairs, but we still need a way
+%D to process these.
+
+% bugged
+%
+% \def\mapXMLvalue#1#2#3% td align center -> middle
+% {\setvalue{\@@XMLvalue:#1:#2:#3}}
+
+\def\mapXMLvalue#1#2#3% td:align center -> middle
+ {\setvalue{\@@XMLvalue:#1:#2}{#3}} % keep #3 to grab spaces
+
+\def\XMLvar#1#2#3% td align center
+ {\ifcsname\@@XMLvariable:#1:#2\endcsname
+ \XMLval{#1}{#2}{\csname\@@XMLvariable:#1:#2\endcsname}%
+ \else
+ \XMLval{#1}{#2}{#3}% evt inline code
+ \fi}
+
+% \def\XMLvar#1#2#3% td align center
+% {\XMLval{#1}{#2}{\ifcsname\@@XMLvariable:#1:#2\endcsname
+% \csname\@@XMLvariable:#1:#2\endcsname\else#3\fi}}
+
+% \def\XMLval#1#2#3% td:align value default
+% {\ifcsname\@@XMLvalue:#1:#2\endcsname
+% \csname\@@XMLvalue:#1:#2\endcsname
+% \else
+% #3%
+% \fi}
+%
+% The next one permits commands instead of strings in #3
+
+\def\XMLval#1#2% #1=td:align #2=value #3=default
+ {\ifcsname\@@XMLvalue:#1:#2\endcsname
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi
+ {\csname\@@XMLvalue:#1:#2\endcsname}}
+
+\def\XMLpar#1#2#3%
+ {\ifcsname\@@XMLvariable:#1:#2\endcsname
+ \csname\@@XMLvariable:#1:#2\endcsname
+ \else
+ #3%
+ \fi}
+
+\def\XMLNSpar#1#2#3#4% element namespace name default
+ {\ifcsname\@@XMLvariable:#1:#2:#3\endcsname
+ \csname\@@XMLvariable:#1:#2:#3\endcsname
+ \else
+ #4%
+ \fi}
+
+% \def\setXMLpar#1#2%
+% {\@EA\def\csname\@@XMLvariable:#1:#2\endcsname}
+
+\def\letXMLpar #1#2{\@EA \let\csname\@@XMLvariable:#1:#2\endcsname}
+\def\setXMLpar #1#2{\@EA \def\csname\@@XMLvariable:#1:#2\endcsname}
+\def\setXMLepar#1#2{\@EA\edef\csname\@@XMLvariable:#1:#2\endcsname}
+
+% ancestor arguments:
+%
+% \defineXMLenvironment
+% [fo:root]
+% [test=unset]
+% {\beginXMLelement}
+% {\endXMLelement}
+%
+% \defineXMLenvironment
+% [fo:block-container]
+% [test=oeps]
+% {\beginXMLelement}
+% {\endXMLelement}
+%
+% \defineXMLenvironment
+% [fo:block]
+% {\beginXMLelement
+% \begingroup}
+% {\endgroup
+% \XMLanc{test}{}
+% \endXMLelement}
+%
+% \startXMLdata
+% <fo:root>
+% <fo:block-container test='first'><fo:block test='second'>second:</fo:block></fo:block-container>
+% <fo:block>unset:</fo:block>
+% <fo:block test='outer'><fo:block test='nested'><fo:block>deep:</fo:block>nested:</fo:block>outer:</fo:block>
+% <fo:block test='last'>last:</fo:block>
+% </fo:root>
+% \stopXMLdata
+%
+% \startXMLdata
+% <fo:root>
+% <fo:block-container test='first'><fo:block>second:</fo:block></fo:block-container>
+% <fo:block>unset:</fo:block>
+% <fo:block test='second'><fo:block><fo:block>deep:</fo:block>nested:</fo:block>outer:</fo:block>
+% <fo:block>last:</fo:block>
+% </fo:root>
+% \stopXMLdata
+%
+% \startXMLdata
+% <fo:root>
+% <fo:block-container test='first'><fo:block>second:</fo:block></fo:block-container>
+% <fo:block>unset:</fo:block>
+% <fo:block><fo:block><fo:block>deep:</fo:block>nested:</fo:block>outer:</fo:block>
+% <fo:block>last:</fo:block>
+% </fo:root>
+% \stopXMLdata
+
+% dit werkt alleen ok in niet <a> <b> <b> ... situaties omdat anders
+% de laatste b de attributen van de vorige heeft:
+
+\def\XMLanc#1%
+ {\ifcsname\@@XMLvariable:\currentXMLelement:#1\endcsname % \ownXMLelement
+ \csname\@@XMLvariable:\currentXMLelement:#1\endcsname % \ownXMLelement
+ \@EA\gobblethreearguments
+ \else
+ \@EA\pXMLanc
+ \fi\XMLdepth{#1}}
+
+% \def\pXMLanc#1%
+% {\@EA\ppXMLanc\@EA{\the\numexpr(#1-\plusone)}}
+
+\def\pXMLanc#1%
+ {\@EA\ppXMLanc\@EA{\the\numexpr#1-\plusone\relax}}
+
+\def\ppXMLanc#1#2#3%
+ {\ifcsname\@@XMLdepth:#1\endcsname % is er altijd dus redundant
+ \ifcsname\@@XMLvariable:\csname\@@XMLdepth:#1\endcsname:#2\endcsname
+ \csname\@@XMLvariable:\csname\@@XMLdepth:#1\endcsname:#2\endcsname
+ \@EAEAEA\gobblethreearguments
+ \else
+ \@EAEAEA\pppXMLanc
+ \fi
+ \else
+ \@EA\pppXMLanc
+ \fi{#1}{#2}{#3}}
+
+\def\pppXMLanc#1%
+ {\ifnum#1>\zerocount
+ \@EA\pXMLanc
+ \else
+ \@EA\thirdofthreearguments
+ \fi{#1}}
+
+%D Experimental (not sure if this will stay):
+%D
+%D \starttyping
+%D \startdefineXMLhandlers[one,two]
+%D
+%D \defineXMLenvironment[a=b,c=\XMLop{a}]
+%D {}{}
+%D
+%D \stopdefineXMLhandlers
+%D \stoptyping
+
+\long\def\startdefineXMLhandlers
+ {\bgroup\catcode\endoflineasciicode\spacecatcode
+ \dodoubleempty\dostartdefineXMLhandlers}
+
+\long\def\dostartdefineXMLhandlers[#1][#2]#3#4\stopdefineXMLhandlers % #2 is dummy
+ {\egroup
+ \long\def\dodefineXMLhandlers##1{#3[##1]#4}%
+ \processcommalist[#1]\dodefineXMLhandlers}
+
+\let\currentXMLhandler\s!unknown
+
+% \long\def\dostartdefineXMLhandlers[#1][#2]#3#4[#5]#6\stopdefineXMLhandlers % #2 is dummy
+% {\egroup
+% \pushmacro\XMLop
+% \pushmacro\XMLpar
+% \pushmacro\currentXMLhandler
+% \long\def\dodefineXMLhandlers##1%
+% {\edef\currentXMLhandler{##1}%
+% \def\XMLop####1{\noexpand\XMLpar{##1}{####1}{}}%
+% \def\XMLpar{\noexpand\XMLpar}%
+% \def\XMLanc{\noexpand\XMLanc}%
+% \edef\!!stringa{[##1][#5]}%
+% \expandafter#3\!!stringa#6}%
+% \processcommalist[#1]\dodefineXMLhandlers
+% \popmacro\currentXMLhandler
+% \popmacro\XMLpar
+% \popmacro\XMLop}
+
+\long\def\dostartdefineXMLhandlers[#1][#2]#3#4[#5]#6\stopdefineXMLhandlers % #2 is dummy
+ {\egroup
+ \long\def\dodefineXMLhandlers##1%
+ {\bgroup
+ \edef\currentXMLhandler{##1}%
+ \def\XMLop####1{\noexpand\XMLpar{##1}{####1}{}}%
+ \def\XMLpar{\noexpand\XMLpar}%
+ \def\XMLanc{\noexpand\XMLanc}%
+ \def\XMLinh{\noexpand\XMLinh}%
+ \xdef\!!XMLattr{[##1][#5]}%
+ \egroup
+ \expandafter#3\!!XMLattr#6}%
+ \processcommalist[#1]\dodefineXMLhandlers}
+
+\def\XMLpav#1#2#3#4%
+ {\XMLval{#1}{\XMLpar{#2}{#3}{}}{#4}}
+
+%D A few weird ones:
+
+\def\TEXpar#1#2%
+ {\csname#1\interfaced{#2}\endcsname}
+
+\let\texXMLpar\TEXpar % soon obsolete
+
+\let\XMLtex\TEXpar
+
+% handy one
+
+\def\XMLtyp#1#2#3%
+ {\ifcsname\@@XMLvariable:#1:#2\endcsname
+ \@EA\defconvertedcommand\@EA\ascii\csname\@@XMLvariable:#1:#2\endcsname
+ \else
+ \defconvertedargument\ascii{#3}%
+ \fi
+ \ascii}
+
+\defineXMLsingular [begingroup] {\begingroup}
+\defineXMLsingular [endgroup] {\endgroup}
+\defineXMLsingular [gobblespacetokens] {\gobblespacetokens}
+\defineXMLsingular [disableXML] {\disableXML}
+
+\long\def\XMLstr#1%
+ {{\enableXML\scantokens{#1}\unskip}}
+
+\long\def\XMLstr#1% test, does not work
+ {\ifprocessingXML
+ % \begingroup\enableXML\scantokens{#1<endgroup/><gobblespacetokens/>}%
+ \scantokens{#1<gobblespacetokens/>}%
+ \else
+ \begingroup\enableXML\scantokens{#1<endgroup/>\ignorespaces}%
+ \fi}
+
+\def\XMLgetvariable#1#2% hooks into generic \getvariable and setvariables
+ {\expanded{\XMLstr{\getvariable{#1}{#2}}}}
+
+\long\def\XMLstrpar#1#2#3% test
+ {\ifcsname\@@XMLvariable:#1:#2\endcsname
+ \scantokens\@EAEAEA{\@EA\begingroup\@EA\enableXML
+ \csname\@@XMLvariable:#1:#2\endcsname<endgroup/>}%
+ \else
+ \scantokens{\begingroup\enableXML#3<endgroup/>}%
+ \fi}
+
+\def\doifXMLvarelse#1#2% geen etex, \relax too
+ {\ifcsname\@@XMLvariable:#1:#2\endcsname
+ \expandafter\ifx\csname\@@XMLvariable:#1:#2\endcsname\empty
+ \@EAEAEA\secondoftwoarguments
+ \else
+ \@EAEAEA\firstoftwoarguments
+ \fi
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\def\doifXMLvar#1#2% geen etex, \relax too
+ {\ifcsname\@@XMLvariable:#1:#2\endcsname
+ \expandafter\ifx\csname\@@XMLvariable:#1:#2\endcsname\empty
+ \@EAEAEA\gobbleoneargument
+ \else
+ \@EAEAEA\firstofoneargument
+ \fi
+ \else
+ \@EA\gobbleoneargument
+ \fi}
+
+\def\doifXMLvalelse#1#2% geen etex, \relax too
+ {\ifcsname\@@XMLvalue:#1:#2\endcsname
+ \expandafter\ifx\csname\@@XMLvalue:#1:#2\endcsname\empty
+ \@EAEAEA\secondoftwoarguments
+ \else
+ \@EAEAEA\firstoftwoarguments
+ \fi
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\let\doifXMLparelse\doifXMLvarelse
+\let\doifXMLpar \doifXMLvar
+
+%D Used in x-fo: I really need to document this!
+
+\bgroup \catcode`\<=\activecatcode
+
+% usage: \expanded{\rescanXMLatttributes{fo:table-cell}}
+
+\gdef\rescanXMLattributes #1{\noexpand\dogetXMLarguments{#1}\currentXMLarguments>}
+\gdef\parseXMLattributes #1#2{\dogetXMLarguments{#1}#2>}
+
+\egroup
+
+\def\defXMLattributestring#1#2#3#4%
+ {\ifcsname\@@XMLvariable:#2:#3\endcsname
+ \@EA\defconvertedcommand\@EA#1\csname\@@XMLvariable:#2:#3\endcsname
+ \else
+ \defconvertedargument#1{#4}%
+ \fi}
+
+\def\XMLprocess#1%
+ {\begingroup\enableXML\XMLflush{#1}\endgroup}
+
+\bgroup \catcode`<=\activecatcode
+
+\long\gdef\ignoreuntilXMLelement#1<{<}
+\long\gdef\grabuntilXMLelement #1<\to#2{\def#2{#1}<}
+
+\egroup
+
+%D Saves tokens and typing.
+
+\def\XMLownvar {\XMLvar {\rawXMLnamespace\rawXMLidentifier}}
+\def\XMLownval {\XMLval {\rawXMLnamespace\rawXMLidentifier}}
+\def\XMLownpar {\XMLpar {\rawXMLnamespace\rawXMLidentifier}}
+\def\XMLownstrpar {\XMLstrpar {\rawXMLnamespace\rawXMLidentifier}}
+\def\doifXMLownvarelse{\doifXMLvarelse{\rawXMLnamespace\rawXMLidentifier}}
+\def\doifXMLownvalelse{\doifXMLvalelse{\rawXMLnamespace\rawXMLidentifier}}
+\def\doifXMLownparelse{\doifXMLparelse{\rawXMLnamespace\rawXMLidentifier}}
+
+\def\letXMLpar #1#2{\@EA \let\csname\@@XMLvariable:#1:#2\endcsname}
+\def\setXMLpar #1#2{\@EA \def\csname\@@XMLvariable:#1:#2\endcsname}
+\def\setXMLepar#1#2{\@EA\edef\csname\@@XMLvariable:#1:#2\endcsname}
+
+\def\ownXMLelement{\rawXMLnamespace\rawXMLidentifier}
+
+\def\XMLop#1% ownpar
+ {\csname\ifcsname\@@XMLvariable:\ownXMLelement:#1\endcsname
+ \@@XMLvariable:\ownXMLelement:#1\else\s!empty
+ \fi\endcsname}
+
+\def\XMLtp#1% texpar
+ {\csname\ifcsname\@@XMLmapmap\interfaced{#1}\endcsname
+ \@@XMLmapmap\interfaced{#1}\else\s!empty
+ \fi\endcsname}
+
+\def\doifelseXMLop#1{\doifelse{\XMLop{#1}}}
+\def\doifXMLop #1{\doif {\XMLop{#1}}}
+\def\doifnotXMLop #1{\doifnot {\XMLop{#1}}}
+
+\def\doifelsenothingXMLop#1{\doifelsenothing{\XMLop{#1}}}
+\def\doifsomethingXMLop #1{\doifsomething {\XMLop{#1}}}
+\def\doifnothingXMLop #1{\doifnothing {\XMLop{#1}}}
+
+\def\doifelseXMLtp#1{\doifelse{\XMLtp{#1}}}
+\def\doifXMLtp #1{\doif {\XMLtp{#1}}}
+\def\doifnotXMLtp #1{\doifnot {\XMLtp{#1}}}
+
+\def\doifelsenothingXMLtp#1{\doifelsenothing{\XMLtp{#1}}}
+\def\doifsomethingXMLtp #1{\doifsomething {\XMLtp{#1}}}
+\def\doifnothingXMLtp #1{\doifnothing {\XMLtp{#1}}}
+
+\def\XMLflushself{\csname\@@XMLdata:\ownXMLelement\endcsname}
+
+\def\showXMLdata#1{\showvalue{\@@XMLdata:#1}}
+
+\def\XMLta {\theXMLarguments\@@XMLmapmap}
+\def\getXMLta {\expanded{\getparameters[\@@XMLmapmap][\XMLta]}}
+\def\expandXMLta{\expandXMLarguments\@@XMLmapmap}
+\def\expandXMLtp{\expandTEXpar\@@XMLmapmap} % #1
+
+\def\getXMLparameters[#1]% faster than \rawgetparameters[#1][\theXMLar..]
+ {\ifcsname\@@XMLmap:#1\endcsname
+ \expanded{\rawgetparameters[#1][\csname\@@XMLmap:#1\endcsname]}%
+ \fi}
+
+\def\defXMLop#1#2{\@EA\let\@EA#1\csname\@@XMLvariable:\ownXMLelement:#2\endcsname}
+\def\defXMLtp#1#2{\@EA\let\@EA#1\csname\@@XMLmapmap\interfaced{#2}\endcsname}
+
+%D ...
+
+\def\protectXMLdata
+ {\catcode\tabasciicode \spacecatcode
+ \catcode\endoflineasciicode\spacecatcode
+ \catcode\formfeedasciicode \spacecatcode
+ \catcode\endoffileasciicode\spacecatcode
+ \catcode`\#\othercatcode}
+
+\long\def\startXMLcode
+ {\begingroup
+ \protectXMLdata
+ \dostartXMLcode}
+
+\long\def\dostartXMLcode[#1] #2 \stopXMLcode
+ {\@EA\gdef\csname\@@XMLcode:#1\endcsname{\startXMLdata#2\stopXMLdata}%
+ \endgroup}
+
+\def\getXMLcode[#1]% \expandXMLcode
+ {\csname\@@XMLcode:#1\endcsname}
+
+% \long\def\startXMLdata#1\stopXMLdata%
+% {\begingroup\enableXML\scantokens{#1}\endgroup}
+%
+% \defineXMLentity[tex-backslash] {\catchXMLpar}
+%
+% \def\catchXMLpar#1#2#3
+% {\if#1p\if#2a\if#3r\ifmmode\else\endgraf\fi
+% \else\texescape\fi\else\texescape\fi\else\texescape\fi}
+
+\long\def\startXMLdata
+ {\begingroup
+ \protectXMLdata
+ \dostartXMLdata}
+
+\long\def\dostartXMLdata#1\stopXMLdata % evt \everyeof{}
+ {\enableXML\scantokens{#1<gobblespacetokens/>}%
+ \endgroup
+ \ifhmode\unskip\unskip\fi}
+
+% suboptimal:
+%
+% \unexpanded\def\XMLdata#1% % \unexpanded added 22/5/2001
+% {\begingroup
+% \enableXML\scantokens{#1}\ifhmode\unskip\unskip\fi
+% \endgroup}
+%
+% better but does not work in tables:
+%
+% \unexpanded\def\XMLdata#1% % grouping changed 20/5/2001
+% {\scantokens{\begingroup\enableXML#1<endgroup/>\gobblespacetokens}}
+%
+% currently:
+
+\unexpanded\def\XMLdata % # safe
+ {\begingroup
+ \protectXMLdata
+ \doXMLdata}
+
+\def\doXMLdata#1%
+ {\enableXML
+ \scantokens{#1<gobblespacetokens/>}%
+ \endgroup}
+
+%D
+
+\def\bXMLs{\ifignoreXMLspaces\ignorespaces\fi}
+\def\eXMLs{\ifignoreXMLspaces\ifhmode\unskip\fi\fi}
+
+\protect
+
+% \defineXMLcommand{placeindex/}
+% {\placeindex[criterium=all]}
+%
+% \defineXMLargument{index}
+% {\index[\XMLvar{index}{key}{}]}
+
+%D Here we implement the handling of preformatted code.
+
+\unprotect
+
+\def\startXMLpreformatted#1%
+ {\startpacked
+ #1%
+ \fixedXMLfonttrue
+ \obeylines
+ \obeyspaces
+ \setbox\scratchbox=\hbox{x}%
+ \edef\obeyedspace{\noindent\noexpand\kern\the\wd\scratchbox}}
+
+\def\stopXMLpreformatted#1%
+ {\stoppacked}
+
+%D
+
+\def\XMLinput{\enableXML\input} \global\let\inputXML\XMLinput
+
+% options
+
+\def\processXMLfile #1{\enableXML\processfile{#1}}
+\def\processXMLfilegrouped#1{{\enableXML\processfile{#1}\relax\ifmmode\else\par\fi}}
+
+%D \type
+%D {processXMLbuffer}
+%D
+%D For illustrative purposes, we need to be able to reuse
+%D definitions, which is why we implement a buffer processor
+%D here. The macro \type {\processXMLbuffer} behaves like
+%D any buffer processor.
+
+\def\processXMLbuffer
+ {\dosingleempty\doprocessXMLbuffer}
+
+\def\doprocessXMLbuffer[#1]%
+ {\doifelsenothing{#1}
+ {\doprocessXMLbuffer[\jobname]}
+ {\begingroup
+ \enableXML
+ \def\dodoprocessXMLbuffer##1{\getbuffer[##1]}%
+ \processcommalist[#1]\dodoprocessXMLbuffer
+ \endgroup}}
+
+%D Loading specific modules takes place with \type
+%D {\useXMLfilters}.
+
+% todo: flag
+
+\def\useXMLfilter[#1]%
+ {\processcommalist[#1]\douseXMLfilter}
+
+\def\douseXMLfilter#1%
+ {\doifundefined{\c!file\f!xtagprefix#1}
+ {\letvalue{\c!file\f!xtagprefix#1}\empty
+ \startreadingfile
+ % \truefilename removed
+ \readsysfile{\f!xtagprefix#1.mkii}
+ {\writestatus{xml}{loading module #1.mkii}}
+ {\readsysfile{\f!xtagprefix#1.tex}
+ {\writestatus{xml}{loading module #1.tex}}
+ \donothing}%
+ \stopreadingfile}}
+
+%D Temporarily here.
+
+\newtoks\groupedtoks
+\newif\ifcollectXMLgrouped
+
+\bgroup \catcode`\<=\activecatcode
+
+\newtoks\XMLgtoks
+
+\long\unexpanded\gdef\getXMLgroupedenvironment#1#2#3%
+ {\collectXMLgroupedtrue
+ \XMLgtoks{#2}%
+ \long\def\dodogetgrouped{\@EA\the\@EA\XMLgtoks\the\groupedtoks#3}%
+ \getXMLgrouped{#1}}
+
+\long\unexpanded\gdef\getXMLgroupedargument#1#2%
+ {\collectXMLgroupedtrue
+ \XMLgtoks{#2}%
+ \long\def\dodogetgrouped{\@EA\the\@EA\XMLgtoks\@EA{\the\groupedtoks}}%
+ \getXMLgrouped{#1}}
+
+\long\unexpanded\gdef\getXMLgroupedignore#1%
+ {\collectXMLgroupedfalse
+ \let\dodogetgrouped\relax
+ \getXMLgrouped{#1}}
+
+\long\gdef\docountXMLgrouped#1\end#2\end % 1 relax is enough since it's
+ {\long\def\dosplitXMLstring##1#1##2\relax\relax##3\end % another regime
+ {\def\ascii{##2}%
+ \ifx\ascii\empty \else
+ \advance\scratchcounter \plusone
+ \dosplitXMLstring##2\relax\relax#1\relax\relax\end
+ \fi}%
+ \dosplitXMLstring#2\relax\relax#1\relax\relax\end}
+
+\long\unexpanded\gdef\getXMLgrouped#1% #1 kan weg % klopt dit nu?
+ {\groupedtoks\emptytoks
+ \scratchcounter\zerocount
+ \edef\theXMLnamespace
+ {\ifx\originalXMLnamespace\empty\else\originalXMLnamespace:\fi
+ \currentXMLidentifier}%
+ \expanded{\long\noexpand\def\noexpand\dogetgrouped####1\noexpand</\currentXMLelement>}%
+ {\ifcollectXMLgrouped\appendtoks##1\to\groupedtoks\fi
+ \@EA\docountXMLgrouped\@EA<\theXMLnamespace>\end##1\end
+ \@EAEAEA\docountXMLgrouped\@EA\@EA\@EA<\@EA\theXMLnamespace\space \end##1\end
+ \ifcase\scratchcounter
+ \let\dogetgrouped\dodogetgrouped
+ \else
+ \advance\scratchcounter \minusone
+ \ifcollectXMLgrouped\@EA\appendtoks\@EA<\@EA/\currentXMLelement>\to\groupedtoks\fi
+ \fi
+ \dogetgrouped}%
+ \dogetgrouped}
+
+\egroup
+
+% interesting and fully expandable
+
+\def\XMLownifequalelse#1#2%
+ {\@EAEAEA\@@ifequal\csname\@@XMLvariable:\ownXMLelement:#1\endcsname\relax\@@and#2\relax\@@then}
+
+% \def\XMLifequalelse#1#2#3%
+% {\@EAEAEA\@@ifequal\csname\@@XMLvariable:#1:#2\endcsname\relax\@@and#3\relax\@@then}
+
+\def\XMLifequalelse#1#2%
+ {\ifcsname\@@XMLvariable:#1:#2\endcsname
+ % \@EAEAEA\doXMLifequalelse\@EA\@EA\csname\@@XMLvariable:#1:#2\endcsname
+ \@EA\doXMLifequalelse\csname\@@XMLvariable:#1:#2\@EA\endcsname
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\def\doXMLifequalelse#1#2%
+ {\@EA\@@ifequal#1\relax\@@and#2\relax\@@then}
+
+%D \starttyping
+%D \defineXMLenvironment[test][a=1]
+%D {\XMLownifequalelse{a}{2}{YES}{NO}}
+%D {}
+%D
+%D \defineXMLenvironment[test][a=1]
+%D {\XMLifequalelse{test}{a}{1}{YES}{NO}}
+%D {}
+%D
+%D \startXMLdata
+%D <test a="1">test</test>
+%D \stopXMLdata
+%D \stoptyping
+
+\def\XMLyes#1{\XMLownifequalelse{#1}{yes}{#1}{}}
+
+%D The next macro will set the variable \type {\flattenedXMLcontent}
+%D to the content with elements removed and entity names.
+
+\bgroup
+
+\catcode`\<\activecatcode
+\catcode`\&\activecatcode
+
+\gdef\flattenXMLcontent#1% we need taco's 'over one group'
+ {\begingroup
+ \keeputfcharacters
+ \def<##1>{}%
+ \def&##1;{##1}%
+ \edef\flattenedXMLcontent{#1}%
+ \edef\flattenedXMLcontent{\expandafter\dounspaced\flattenedXMLcontent\end}%
+ \@EA\endgroup
+ \@EA\def\@EA\flattenedXMLcontent\@EA{\flattenedXMLcontent}}
+
+\egroup
+
+\def\defXMLexpanded#1#2%
+ {\begingroup
+ \let\getXMLentity\expandedXMLentity
+ \expanded{\endgroup\edef\noexpand#1{#2}}}
+
+\def\gdefXMLexpanded#1#2%
+ {\begingroup
+ \let\getXMLentity\expandedXMLentity
+ \expanded{\endgroup\xdef\noexpand#1{#2}}}
+
+\protect \endinput