summaryrefslogtreecommitdiff
path: root/tex/context/base/xtag-map.tex
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/xtag-map.tex')
-rw-r--r--tex/context/base/xtag-map.tex746
1 files changed, 746 insertions, 0 deletions
diff --git a/tex/context/base/xtag-map.tex b/tex/context/base/xtag-map.tex
new file mode 100644
index 000000000..f8471d6a7
--- /dev/null
+++ b/tex/context/base/xtag-map.tex
@@ -0,0 +1,746 @@
+%D \module
+%D [ file=xtag-map,
+%D version=2000.12.20,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=Remapping,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D There is a more versatile mapper available in \type {xtag-rem.tex}!
+
+%D We also need something that lets content as-is, like for
+%D instance XML embedded in a chemical caption.
+
+\writestatus{loading}{ConTeXt XML Macros / Remapping}
+
+%D A fundamental characteristic of \TEX\ is that much
+%D processing depends on picking up one or more arguments and
+%D acting upon them. In \type {xtag-ini} we have implemented
+%D the normal (high) level interface between \XML\ and
+%D \CONTEXT, and there we already saw some ways to pick up an
+%D element as argument.
+%D
+%D In this module we will implement a preprocessor. An element
+%D that feeds its content to the preprocessor, becomes a token
+%D list consisting of \TEX\ macros, which in turn may expand to
+%D their meanings.
+%D
+%D This module is only tested with \ETEX. In principle we can
+%D make it work with good old \TEX, but we see no objection
+%D against using \ETEX, especially since it's part of every
+%D grown up \TEX\ distribution.
+
+\unprotect
+
+\let\normalparseXMLescape \parseXMLescape
+\let\normalparseXMLelement\parseXMLelement
+\let\normalparseXMLprocess\parseXMLprocess
+
+\let\normaldoXMLelement \doXMLelement
+\let\normaldoXMLentity \doXMLentity
+
+\def\setnormalXMLhandler
+ {\let\doXMLelement \normaldoXMLelement
+ \let\parseXMLelement\normalparseXMLelement
+ \let\parseXMLescape \normalparseXMLescape
+ \let\parseXMLprocess\normalparseXMLprocess
+ \let\doXMLentity \normaldoXMLentity}
+
+%D A careful reader will notice that we do a full expansion of
+%D the content of the element, although commands that are
+%D protected will stay untouched. In this stage we also
+%D collect key|/|value pairs and pass them onto the \TEX\
+%D macros if needed. Again, we need a fully expandable parser
+%D to handle this, which make the core macros slightly
+%D unreadable.
+%D
+%D The interface presented here evolved from an older module,
+%D written on top of \type {m-sgml}, that could take care of
+%D \MATHML\ (version 1). The implementation here is more
+%D advanced in the sense that it permits all kind of parsers.
+
+\def\findendofXMLelement#1% space after 0/1 prevents auto \relax
+ {\if#1>0 \else
+ \if#1/1 \endofXMLelementE\else
+ \if#1"\endofXMLelementD \else
+ \if#1'\endofXMLelementS \else
+ \endofXMLelementN \fi\fi\fi\fi}
+
+\def\endofXMLelementE#1\fi\fi\fi\fi#2>{\fi\fi}
+\def\endofXMLelementD#1\fi\fi\fi\fi#2"{\fi\fi\fi \findendofXMLelement}
+\def\endofXMLelementS#1\fi\fi\fi\fi#2'{\fi\fi\fi\fi\findendofXMLelement}
+\def\endofXMLelementN \fi\fi\fi\fi {\fi\fi\fi\fi\findendofXMLelement}
+
+% not faster
+%
+% \def\findendofXMLelement#1%
+% {\csname**\if#1>>\else\if#1//\else\if#1""\else\if#1''\else.\fi\fi\fi\fi\endcsname}
+%
+% \def\findendofXMLelement#1%
+% {\csname**\ifcsname**#1\endcsname#1\else.\fi\endcsname}
+%
+% \setvalue{**>}{0 }
+% \setvalue{**/}#1>{1 }
+% \setvalue{**"}#1"{\findendofXMLelement}
+% \setvalue{**'}#1'{\findendofXMLelement}
+% \letvalue{**.}\findendofXMLelement
+
+\newif\ifremapXMLunknown
+
+%D We need three steps to avoid namespace: tag since comment
+%D and processing instructions don't have a namespace. The
+%D first step distinguishes between comment, processing
+%D instructions and elements. The second step (which is
+%D defined in the main mapping macro) either or not grabs the
+%D namespace. We may extend this model later to a more
+%D versatile one, using remapping.
+
+%D Parsing escapes is done by specific macros. For the
+%D moment we assume that the sequence ends with an \type {>}
+%D (which is definietly not the case for \type {CDATA}).
+
+\long\def\remapXMLescape#1#2>{}
+
+%D Processing instructions are remapped and only certain
+%D cases are handled.
+
+\long\def\remapXMLprocess#1#2{\xmlp{procins/}{X}{#1}{#2}}
+
+%D This one is more efficient (although no one will notice
+%D this since this macro is used seldom).
+
+\long\def\remapXMLprocess{\xmlp{procins/}{X}}
+
+%D Element need a bit more work; \type {#4} consumes spaces.
+
+% \def\remapXMLunknownONE#1#2% name args
+% {\ifremapXMLunknown\remapXMLone{\s!unknown}{#1 #2}\fi}
+%
+% \def\remapXMLunknownTWO#1#2% name args
+% {\ifremapXMLunknown\remapXMLtwo{\s!unknown}{#1 #2}\fi}
+%
+% \def\remapXMLunknownTHREE#1#2% name args
+% {\ifremapXMLunknown\remapXMLthree{\s!unknown/}{#1 #2}\fi}
+%
+% \long\def\remapXMLelement#1#2 #3>#4% todo: we need to get rid of the end /
+% {\ifcase\findendofXMLelement#2#3>%
+% \if#1/%
+% \expandafter\ifx\csname\@@XML\@@XMLmapping:#2:M\endcsname\relax
+% \remapXMLunknownONE{#2}{}%
+% \else
+% \remapXMLone{#2}{}%
+% \fi
+% \else
+% \expandafter\ifx\csname\@@XML\@@XMLmapping:#1#2:M\endcsname\relax
+% \remapXMLunknownTWO{#1#2}{#3}%
+% \else
+% \remapXMLtwo{#1#2}{#3}%
+% \fi
+% \fi
+% \else
+% \expandafter\ifx\csname\@@XML\@@XMLmapping:#1#2:M\endcsname\relax
+% \expandafter\ifx\csname\@@XML\@@XMLmapping:#1#2/:M\endcsname\relax
+% \remapXMLunknownTHREE{#1#2}{#3}%
+% \else
+% \remapXMLthree{#1#2/}{#3}%
+% \fi
+% \else
+% \remapXMLthree{#1#2}{#3}%
+% \fi
+% \fi#4}
+
+\def\remapXMLthreeempty#1%
+ {\remapXMLthree{#1/}}
+
+\def\remapXMLunknownONE#1#2% name args
+ {\ifremapXMLunknown\remapXMLone\s!unknown{#1 #2}\fi}
+
+\def\remapXMLunknownTWO#1#2% name args
+ {\ifremapXMLunknown\remapXMLtwo\s!unknown{#1 #2}\fi}
+
+\def\remapXMLunknownTHREE#1#2% name args
+ {\ifremapXMLunknown\remapXMLthreeempty\s!unknown{#1 #2}\fi}
+
+\long\def\remapXMLelement#1#2 #3>#4% todo: we need to get rid of the end /
+ {\ifcase\findendofXMLelement#2#3>%
+ \if#1/%
+ \expandafter\ifx\csname\@@XML\@@XMLmapping:#2:M\endcsname\relax
+ \@EA\remapXMLunknownONE
+ \else
+ \@EA\remapXMLone
+ \fi{#2}\empty
+ \else
+ \expandafter\ifx\csname\@@XML\@@XMLmapping:#1#2:M\endcsname\relax
+ \@EA\remapXMLunknownTWO
+ \else
+ \@EA\remapXMLtwo
+ \fi{#1#2}{#3}%
+ \fi
+ \else
+ \expandafter\ifx\csname\@@XML\@@XMLmapping:#1#2:M\endcsname\relax
+ \expandafter\ifx\csname\@@XML\@@XMLmapping:#1#2/:M\endcsname\relax
+ \@EAEAEA\remapXMLunknownTHREE
+ \else
+ \@EAEAEA\remapXMLthreeempty
+ \fi
+ \else
+ \@EA\remapXMLthree
+ \fi{#1#2}{#3}%
+ \fi#4}
+
+\unexpanded\def\xmlr#1#2{\csname\@@XML\@@XMLmapping:#1:#2\endcsname}
+\unexpanded\def\xmlp#1#2{\csname\@@XML :#1:#2\endcsname}
+\def \expandedxmlr#1#2{\csname\@@XML\@@XMLmapping:#1:#2\endcsname}
+
+\def\expandXMLremapping{\let\xmlr\expandedxmlr}
+
+\def\@@XMLremap{XMLremap}
+
+\def\remapXMLone#1#2%
+ {\ifcase\csname\@@XMLremap\csname\@@XML\@@XMLmapping:#1:M\endcsname\endcsname
+ \or % GCPA
+ \XMLeg\XMLeg
+ \or % GCP-
+ \XMLeg
+ \or % GC-A
+ \XMLeg\XMLeg
+ \or % GC--
+ \XMLeg
+ \or % -CPA
+ \XMLeg
+ \or % -CP-
+ %
+ \or % -C-A
+ \XMLeg
+ \or % -C--
+ %
+ \or % G---
+ \XMLeg
+ \or % GLR-
+ \xmlr{#1}{R}\XMLeg
+ \or % -LR-
+ \xmlr{#1}{R}%
+ \fi}
+
+\def\remapXMLtwo#1#2%
+ {\ifcase\csname\@@XMLremap\csname\@@XML\@@XMLmapping:#1:M\endcsname\endcsname
+ \or % GCPA
+ \XMLbg\xmlr{#1}{X}{#2}\XMLbg
+ \or % GCP-
+ \XMLbg\xmlr{#1}{X}{#2}%
+ \or % GC-A
+ \XMLbg\xmlr{#1}{X}\XMLbg
+ \or % GC--
+ \XMLbg\xmlr{#1}{X}%
+ \or % -CPA
+ \xmlr{#1}{X}{#2}\XMLbg
+ \or % -CP-
+ \xmlr{#1}{X}{#2}%
+ \or % -C-A
+ \xmlr{#1}{X}\XMLbg
+ \or % -C--
+ \xmlr{#1}{X}%
+ \or % G---
+ \XMLbg
+ \or % GLR-
+ \XMLbg\xmlr{#1}{L}%
+ \or % -LR-
+ \xmlr{#1}{L}%
+ \fi}
+
+\def\remapXMLthree#1#2%
+ {\ifcase\csname\@@XMLremap\csname\@@XML\@@XMLmapping:#1:M\endcsname\endcsname
+ \or % GCPA
+ \XMLbg\xmlr{#1}{X}{#2}\XMLbg\XMLeg\XMLeg
+ \or % GCP-
+ \XMLbg\xmlr{#1}{X}{#2}\XMLeg
+ \or % GC-A
+ \XMLbg\xmlr{#1}{X}\XMLbg\XMLeg\XMLeg
+ \or % GC--
+ \XMLbg\xmlr{#1}{X}\XMLeg
+ \or % -CPA
+ \xmlr{#1}{X}{#2}\XMLbg\XMLeg
+ \or % -CP-
+ \xmlr{#1}{X}{#2}%
+ \or % -C-A
+ \xmlr{#1}{X}\XMLbg\XMLeg
+ \or % -C--
+ \xmlr{#1}{X}%
+ \or % G---
+ \XMLbg\XMLeg
+ \fi}
+
+\scratchtoks\@EA{\string{} \edef\XMLbg{\the\scratchtoks}
+\scratchtoks\@EA{\string}} \edef\XMLeg{\the\scratchtoks}
+
+\chardef\XMLremapGCPA = 1 % {\command {arg} { } }
+\chardef\XMLremapGCP = 2 % {\command {arg} } %
+\chardef\XMLremapGCA = 3 % {\command { } }
+\chardef\XMLremapGC = 4 % {\command } %
+\chardef\XMLremapCPA = 5 % \command {arg} { }
+\chardef\XMLremapCP = 6 % \command {arg} %
+\chardef\XMLremapCA = 7 % \command { }
+\chardef\XMLremapC = 8 % \command %
+\chardef\XMLremapG = 9 % { }
+\chardef\XMLremapGLR = 10 % { \bcom \ecom }
+\chardef\XMLremapLR = 11 % \bcom \ecom
+
+%D The remapping is controlled by only a few definition
+%D macros, that both deal with elements. We distinguish
+%D between normal and empty elements.
+%D
+%D \starttyping
+%D \remapXMLsequence [name] [result map] \unexpandablecommand
+%D \remapXMLsequence [name] [result map] \unexpandablecommand
+%D \stoptyping
+%D
+%D The \MATHML\ module demonstrates how these can be used.
+%D The element is converted into a sequence with one or more
+%D of the following components.
+%D
+%D \starttyping
+%D { \command {parameters} {argument} }
+%D \stoptyping
+%D
+%D The following combinations are supported.
+%D
+%D \starttabulate[|c|c|c|c|c|]
+%D \NC GCPA \NC grouped \NC command \NC parameters \NC argument \NC \NR
+%D \NC GCP \NC grouped \NC command \NC parameters \NC \NC \NR
+%D \NC GCA \NC grouped \NC command \NC \NC argument \NC \NR
+%D \NC GC \NC grouped \NC command \NC \NC \NC \NR
+%D \NC CPA \NC \NC command \NC parameters \NC argument \NC \NR
+%D \NC CP \NC \NC command \NC parameters \NC \NC \NR
+%D \NC CA \NC \NC command \NC \NC argument \NC \NR
+%D \NC C \NC \NC command \NC \NC \NC \NR
+%D \NC G \NC grouped \NC \NC \NC \NC \NR
+%D \stoptabulate
+%D
+%D Empty elements (singular ones) never get an argument,
+%D which makes sense, since they have at most parameters.
+
+\def\remapXMLsequence{\doquadrupleargument\doremapXML []}
+\def\remapXMLsingular{\doquadrupleargument\doremapXML[/]}
+
+\def\doremapXML[#1][#2][#3][#4]%
+ {\iffourthargument
+ \def\next{\dodoremapXML[#2][#1][#3][#4]}%
+ \else
+ \def\next{\dodoremapXML[\@@XMLmapping][#1][#2][#3]}%
+ \fi
+ \next}
+
+%\def\dodoremapXML[#1][#2][#3][#4]% class / name pattern
+% {\doifinstringelse{LR}{#4}
+% {\let\next\doremapXMLtwo}
+% {\let\next\doremapXMLone}%
+% \next[#1][#2][#3][#4]}%
+
+\def\dodoremapXML[#1][#2][#3][#4]% class / name pattern
+ {\doifinstringelse{LR}{#4}\doremapXMLtwo\doremapXMLone[#1][#2][#3][#4]}
+
+\def\doremapXMLone[#1][#2][#3][#4]#5%
+ {\setvalue{\@@XML#1:#3#2:M}{#4}%
+ \setvalue{\@@XML#1:#3#2:X}{#5}}
+
+\def\doremapXMLtwo[#1][#2][#3][#4]#5#6%
+ {\setvalue{\@@XML#1:#3:M}{#4}%
+ \setvalue{\@@XML#1:#3:L}{#5}%
+ \setvalue{\@@XML#1:#3:R}{#6}}
+
+\let\dowithentity\empty
+
+%D We handle processing instructions and unknown elements with:
+
+\remapXMLsingular [procins] [CPA] \normalparseXMLprocess
+\remapXMLsingular [\s!unknown] [CPA] \doXMLunknownSI
+\remapXMLsequence [\s!unknown] [CPA] \doXMLunknownSE
+
+\def\doXMLunknownSI#1#2{{\tttf[#1 #2]}}
+\def\doXMLunknownSE#1#2{{\tttf[#1 #2]}}
+
+%D In a similar way, we can remap entities.
+
+\def\remapXMLentity#1;#2%
+ {\doremapXMLentity{#1}#2}%
+
+\def\doremapXMLentity
+ {\xmlrent}
+
+% \unexpanded\def\xmlrent#1%
+% {\getXMLentity{#1}}
+%
+% replaced by:
+
+\unexpanded\def\xmlrent#1%
+ {\doXMLentity#1;}
+
+%D The remapping is taken care of by the following macro,
+%D which takes three arguments.
+%D
+%D \starttyping
+%D \XMLremapdata{before}{after}{content}
+%D \stoptyping
+%D
+%D After the remapping, the content is executed (expanded)
+%D under the normal \TEX\ catcode regime. The intermediate
+%D result can be traced by turning on the following switch.
+
+\newif\iftraceXMLremapping
+
+\newtoks \everyXMLremapping
+
+\appendtoks
+ \defineXMLentity[tex-hash]{\letterhash}%
+ \defineXMLentity[tex-bar]{\myspecialnormalvert}%
+\to \everyXMLremapping
+
+\def\setnormalXMLentities% will change ! ! ! ! !
+ {\defineXMLentity[tex-hash]\letterhash
+ \defineXMLentity[tex-dollar]\letterdollar
+ \defineXMLentity[tex-percent]\letterpercent
+ \defineXMLentity[tex-backslash]\letterbackslash
+ \defineXMLentity[tex-hat]\letterhat
+ \defineXMLentity[tex-underscore]\letterunderscore
+ \defineXMLentity[tex-leftbrace]\letterbgroup
+ \defineXMLentity[tex-rightbrace]\letteregroup
+ \defineXMLentity[tex-bar]\letterbar}
+
+\let\XMLremappedpar\empty
+
+%D Here we implement the second step in the element grabber.
+
+\long\def\XMLremapdata
+ {\dosingleempty\doXMLremapdata}
+
+\long\def\doXMLremapdata[#1]#2#3#4%
+ {\bgroup
+ \startXMLmapping[#1]%
+ % enable unknown elements (should be macro)
+ \doifsomething{#1}
+ {\doifdefinedelse{\@@XML#1:\s!unknown:M}
+ {\remapXMLunknowntrue}{\remapXMLunknownfalse}}%
+ %
+ \pushmacro\doXMLentity % needed ?
+ % this will change, proper split in element itself
+ \ifx\currentXMLnamespace\empty
+ \let\parseXMLelement\remapXMLelement
+ \else
+ % here we need to get rid of the namespace; we also
+ % have to preserve the leading / if present
+ \@EA\long\@EA\def\@EA\parseXMLelement\@EA
+ ##\@EA1\currentXMLnamespace:{\remapXMLelement##1}%
+ % ##2 removes leading spaces
+ \fi
+ %
+ \let\parseXMLescape \remapXMLescape
+ \let\parseXMLprocess\remapXMLprocess
+ %
+ \let\doXMLentity \remapXMLentity
+ %
+ \enableXML % sets entities
+ \enableXMLexpansion
+ \let\par\XMLremappedpar
+ \the\everyXMLremapping
+ %\ignorelines
+ \catcode`\^^I=\@@space
+ \catcode`\^^M=\@@space
+ \catcode`\^^L=\@@space
+ \catcode`\^^Z=\@@space
+ \pushmacro\unicodechar
+ \let\unicodechar\relax
+ \xdef\remappedXMLdata{#4\empty}%
+ \popmacro\unicodechar
+ \let\par\endgraf
+ \popmacro\doXMLentity % needed ?
+ \disableXMLexpansion
+ \catcode`\{=\@@begingroup
+ \catcode`\}=\@@endgroup
+ \catcode`\\=\@@escape
+ \iftraceXMLremapping
+ \ifmmode\vbox\fi\bgroup
+ \defconvertedcommand\ascii\remappedXMLdata
+ \tttf\veryraggedright\ascii\par
+ \writestatus{xml-remap}{\ascii}%
+ \egroup
+ \fi
+ #2\scantokens\@EA{\remappedXMLdata\empty\empty}#3%
+ \stopXMLmapping
+ \egroup}
+
+% testcase:
+%
+% aap‒noot coördinatie – één
+%
+% \startXMLdata
+% aap‒noot coördinatie – één
+% <formula><math><mtext>aap‒noot coördinatie – één</mtext></math></formula>
+% \stopXMLdata
+%
+% weird case:
+%
+% \chardef\XMLtokensreduction\zerocount
+% \startXMLdata
+% <formula><math><mtext>\"{a}\"{o}\"{u}\v{c}\v{s}\v{z}</mtext></math></formula>
+% \stopXMLdata
+%
+% \chardef\XMLtokensreduction\plustwo
+% \startXMLdata
+% <formula><math><mtext>\"{a}\"{o}\"{u}\v{c}\v{s}\v{z}</mtext></math></formula>
+% \stopXMLdata
+
+% rename to better names
+
+\newtoks \XMLRtoks
+\newcount \nofXMLRchildren
+
+\def\naturalxmlr#1#2{\getvalue{\@@XML\@@XMLmapping:#1:#2}}
+
+\def\ignoreXMLRelement#1#2{}
+\def\normalXMLRelement#1#2{#2}
+
+\let\nextXMLRelement \empty
+\let\firstXMLRelement \empty
+\let\secondXMLRelement\empty
+
+% \def\withnextXMLRelement#1%
+% {\pushmacro\dowithnextXMLRelement
+% \def\dowithnextXMLRelement##1##2##3##4##5%
+% {\popmacro\dowithnextXMLRelement
+% \def\nextXMLRelement{##1{##2}{##3}{##4}{##5}}%
+% #1}%
+% \doifnextcharelse\empty\empty\dowithnextXMLRelement}
+%
+% better and faster:
+
+\def\dowithnextXMLRelement#1#2#3#4#5#6%
+ {\def\nextXMLRelement{#2{#3}{#4}{#5}{#6}}#1}%
+
+\def\withnextXMLRelement#1%
+ {\doifnextcharelse\empty\empty{\dowithnextXMLRelement{#1}}}
+
+\def\withnexttwoXMLRelements#1%
+ {\pushmacro\firstXMLRelement
+ \pushmacro\secondXMLRelement
+ \withnextXMLRelement
+ {\let\firstXMLRelement\nextXMLRelement
+ \withnextXMLRelement
+ {\let\secondXMLRelement\nextXMLRelement
+ #1%
+ \popmacro\secondXMLRelement
+ \popmacro\firstXMLRelement}}}
+
+\def\withnextthreeXMLRelements#1% korter, met two
+ {\pushmacro\firstXMLRelement
+ \pushmacro\secondXMLRelement
+ \pushmacro\thirdXMLRelement
+ \withnextXMLRelement
+ {\let\firstXMLRelement\nextXMLRelement
+ \withnextXMLRelement
+ {\let\secondXMLRelement\nextXMLRelement
+ \withnextXMLRelement
+ {\let\thirdXMLRelement\nextXMLRelement
+ #1%
+ \popmacro\thirdXMLRelement
+ \popmacro\secondXMLRelement
+ \popmacro\firstXMLRelement}}}}
+
+\def\doifXMLRchildelse#1#2#3#4%
+ {\pushmacro\xmlr
+ \def\next{#4}%
+ \def\xmlr##1##2##3##4% the / should be sorted out in the mapper
+ {\rawdoifinsetelse{##1}{#1}
+ {\def\next{#3}}
+ {\doif{##1}{#1/}{\def\next{#3}}}}%
+ #2\empty
+ \popmacro\xmlr
+ \next}
+
+\def\doifXMLRchild#1#2#3%
+ {\pushmacro\xmlr
+ \let\next\empty
+ \def\xmlr##1##2##3##4% the / should be sorted out in the mapper
+ {\rawdoifinsetelse{##1}{#1}
+ {\def\next{#3}}
+ {\doif{##1}{#1/}{\def\next{#3}}}}%
+ #2\empty
+ \popmacro\xmlr
+ \next}
+
+\def\encapsulateXMLRchild#1#2#3#4#5%
+ {\pushmacro\xmlr
+ \def\xmlr##1##2##3##4%
+ {\doifelse{##1}{#1}
+ {\def\next{\doencapsulateXMLRchild{#2}{#3}{#4}{##4}}}
+ {\let\next\empty}%
+ \next}%
+ #5\empty
+ \popmacro\xmlr}
+
+\def\encapsulateXMLRchildren#1#2#3#4#5%
+ {\pushmacro\xmlr
+ \pushmacro\betweenXMLRchild
+ \def\betweenXMLRchild{\def\betweenXMLRchild{#3}}%
+ \def\xmlr##1##2##3##4%
+ {\rawdoifinsetelse{##1}{#1}
+ {\pushmacro\xmlr
+ \let\xmlr\naturalxmlr
+ \betweenXMLRchild\xmlr{##1}{##2}{##3}{##4}%
+ \popmacro\xmlr}
+ {}}%
+ #2#5\empty#4%
+ \popmacro\betweenXMLRchild
+ \popmacro\xmlr}
+
+\def\doencapsulateXMLRchild#1#2#3#4%
+ {\pushmacro\xmlr
+ \pushmacro\betweenXMLRchild
+ \def\betweenXMLRchild{\def\betweenXMLRchild{#2}}%
+ \def\xmlr##1##2##3##4%
+ {\pushmacro\xmlr
+ \let\xmlr\naturalxmlr
+ \betweenXMLRchild\xmlr{##1}{##2}{##3}{##4}%
+ \popmacro\xmlr}%
+ #1#4\empty#3%
+ \popmacro\betweenXMLRchild
+ \popmacro\xmlr}
+
+\let\encapsulateXMLR\doencapsulateXMLRchild
+
+\def\withnextXMLRelementelse#1#2%
+ {\def\xdowithnextXMLRelement##1##2##3##4##5%
+ {\def\nextXMLRelement{##1{##2}{##3}{##4}{##5}}#1}%
+ \def\xnowithnextXMLRelement%
+ {\let\nextXMLRelement\empty#2}%
+ \doifnextcharelse\xmlr\xdowithnextXMLRelement\xnowithnextXMLRelement}
+
+\def\encapsulatenextXMLRelements#1#2#3#4% oude bewaren
+ {\pushmacro\betweenXMLRchild
+ \pushmacro\afterXMLRchild
+ \def\betweenXMLRchild{#1\def\betweenXMLRchild{#2}}%
+ \let\afterXMLRchild\empty
+ \withnextXMLRelementelse
+ {\betweenXMLRchild
+ \def\afterXMLRchild{#3}%
+ \nextXMLRelement
+ \doifnextcharelse\empty\xnowithnextXMLRelement\xdowithnextXMLRelement}
+ {\afterXMLRchild
+ \popmacro\afterXMLRchild
+ \popmacro\betweenXMLRchild}%
+ #4}
+
+\def\collectXMLRchild#1#2%
+ {\XMLRtoks\emptytoks
+ \pushmacro\xmlr
+ \def\xmlr##1##2##3##4%
+ {\doif{##1}{#1}{\appendtoks##4\to\XMLRtoks}}%
+ #2\empty
+ \popmacro\xmlr}
+
+\def\doifelseXMLRneighbors#1#2%
+ {\XMLRtoks\emptytoks
+ \pushmacro\xmlr
+ \donefalse
+ \let\prevXMLRchild\empty
+ \def\xmlr##1##2##3##4%
+ {\doif{##1}{#1}{\doif{##1}\prevXMLRchild{\donetrue}}%
+ \def\prevXMLRchild{##1}}%
+ #2\empty
+ \popmacro\xmlr
+ \ifdone
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\collectbetweenXMLRchild#1#2#3%
+ {\XMLRtoks\emptytoks
+ \pushmacro\xmlr
+ \pushmacro\betweenXMLRchild
+ \def\betweenXMLRchild{\def\betweenXMLRchild{\appendtoks#2\to\XMLRtoks}}%
+ \def\xmlr##1##2##3##4%
+ {\rawdoifinsetelse{##1}{#1}
+ {\betweenXMLRchild\appendtoks\xmlr{##1}{##2}{##3}{##4}\to\XMLRtoks}{}}%
+ #3\empty
+ \popmacro\betweenXMLRchild
+ \popmacro\xmlr}
+
+\def\dorawcollectbetweenXMLR#1#2%
+ {\pushmacro\xmlr
+ \pushmacro\betweenXMLRchild
+ \def\betweenXMLRchild{\def\betweenXMLRchild{#1}}%
+ \def\xmlr##1##2##3##4%
+ {\betweenXMLRchild\appendtoks\xmlr{##1}{##2}{##3}{##4}\to\XMLRtoks}%
+ #2\empty
+ \popmacro\betweenXMLRchild
+ \popmacro\xmlr}
+
+\def\rawcollectbetweenXMLR%
+ {\XMLRtoks\emptytoks\dorawcollectbetweenXMLR}
+
+\def\docollectbetweenXMLR#1%
+ {\dorawcollectbetweenXMLR{\appendtoks#1\to\XMLRtoks}}
+
+\def\collectbetweenXMLR%
+ {\XMLRtoks\emptytoks\docollectbetweenXMLR}
+
+\def\processXMLRchildren#1%
+ {\pushmacro\xmlr
+ \let\xmlr\naturalxmlr
+ #1\empty
+ \popmacro\xmlr}
+
+\def\processXMLRchild#1#2% slow but more versatile
+ {\pushmacro\xmlr
+ \XMLRtoks\emptytoks
+ \def\xmlr##1##2##3##4%
+ {\rawdoifinsetelse{##1}{#1}
+ {\appendtoks\xmlr{##1}{##2}{##3}{##4}\to\XMLRtoks}{}}%
+ #2%
+ \popmacro\xmlr
+ \the\XMLRtoks\empty}
+
+\def\countXMLRchildren#1%
+ {\pushmacro\xmlr
+ \nofXMLRchildren=0
+ \def\xmlr##1##2##3##4{\advance\nofXMLRchildren\plusone}
+ #1\empty
+ \popmacro\xmlr}
+
+\def\countXMLRchild#1#2%
+ {\pushmacro\xmlr
+ \nofXMLRchildren=0
+ \def\xmlr##1##2##3##4%
+ {\rawdoifinsetelse{##1}{#1}{\advance\nofXMLRchildren\plusone}{}}
+ #2\empty
+ \popmacro\xmlr}
+
+\def\installXMLunknownremapping
+ {\remapXMLsingular[\s!unknown][CPA]\doXMLunknownSI
+ \remapXMLsequence[\s!unknown][CPA]\doXMLunknownSE}
+
+\bgroup \catcode`<=\active
+
+\gdef\revertXMLremapping
+ {\gdef\doXMLunknownSE##1##2{<##1>##2</##1>}%
+ \gdef\doXMLunknownSI##1##2{<##1>}}
+
+\gdef\unmapXMLdata#1#2% todo: singular, evt ##2 space ervoor en ##1##2
+ {\bgroup
+ \revertXMLremapping
+ \expandXMLremapping % now we can roll back
+ \setnormalXMLhandler % using the normal parser
+ \resetXMLmapping % and leaving the mapping namespace
+ \xdef\unmappedXMLdata{#2}% recreate the original
+ \enableXMLelements % enable normal handler
+ \unmappedXMLdata % off we go ...
+ \egroup}
+
+\egroup
+
+\protect \endinput