%D \module
%D [ file=xtag-ext,
%D version=2001.03.21,
%D title=\CONTEXT\ XML Macros,
%D subtitle=Extra Macros,
%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 / Extras}
\unprotect
%D \macros
%D {startXMLmapping}
%D
%D You can define macros within a namespace, so that they
%D will not conflict (don't confuse this with \XML\
%D namespaces.)
%D
%D \starttyping
%D \startXMLmapping [tag] | [-] [tag] | [+] [tag]
%D definitions
%D \stopXMLmapping
%D \stoptyping
%D
%D When a \type {[+]} is specified, the mappings will
%D nest.
\def\resetXMLmapping
{\let\@@XMLelement\normal@@XMLelement
\let\@@XMLmapping\empty}
\resetXMLmapping
\def\startXMLmapping
{\dodoubleempty\dostartXMLmapping}
% \def\dostartXMLmapping[#1][#2]% sneller maken
% {\pushmacro\@@XMLelement
% \pushmacro\@@XMLmapping
% \ifsecondargument
% \doifelse{#1}{-}
% {\donostartXMLmapping{#2}}
% {\doifelse{#1}{+}
% {\dodostartXMLmapping{#2}}
% {\donostartXMLmapping{#2}}}%
% \else
% \donostartXMLmapping{#1}%
% \fi
% \unprotect}
\def\dostartXMLmapping[#1#2][#3]%
{\pushmacro\@@XMLelement
\pushmacro\@@XMLmapping
\ifsecondargument
\if\noexpand#1-%
\@EA\donostartXMLmapping
\else\if\noexpand#1+%
\@EAEAEA\dodostartXMLmapping
\else
\@EAEAEA\donostartXMLmapping
\fi\fi{#3}%
\else
\donostartXMLmapping{#1#2}%
\fi
\unprotect}
\def\donostartXMLmapping#1%
{\let\@@XMLprevelement\@@XMLelement
\edef\@@XMLmapping{#1}%
\edef\@@XMLelement{\normal@@XMLelement+#1}}
\def\dodostartXMLmapping#1%
{\let\@@XMLprevelement\@@XMLelement
\edef\@@XMLmapping{\@@XMLmapping+#1}%
\edef\@@XMLelement{\@@XMLelement+#1}}
\def\stopXMLmapping
{\protect
\popmacro\@@XMLmapping
\popmacro\@@XMLelement}
%D \macros
%D {startXMLmappinggroup}
%D
%D Imagine something:
%D
%D \starttyping
%D \defineXMLenvironment [something]
%D {\startXMLmapping[whatever]}
%D {\stopXMLmapping}
%D \stoptyping
%D
%D Here the \type {\stopXMLmapping} will never be reached
%D because we are in a mapping. Therefore we need:
\def\startXMLmappinggroup
{\dodoubleempty\dostartXMLmappinggroup}
\def\dostartXMLmappinggroup[#1][#2]%
{\bgroup
\letcscsname\savedXMLmeaning\csname\@@XMLelement:/\currentXMLelement\endcsname
\dostartXMLmapping[#1][#2]% do ! else wrong !
\letcsnamecs\csname\@@XMLelement:/\currentXMLelement\endcsname\savedXMLmeaning}
\def\stopXMLmappinggroup
{\stopXMLmapping
\egroup}
%D Context Directives:
\def\@@CTXML{@@CTXML}
\def\defineXMLdirective
{\dodoubleempty\dodefineXMLdirective}
\long\def\dodefineXMLdirective[#1][#2]#3%
{\defineXMLprocessor[context-#1-directive]{\dohandleXMLdirective{#1}{#3}}%
\ifsecondargument
\long\setvalue{\@@CTXML-#1-#2}{#3}%
\fi}
\def\dohandleXMLdirective#1#2#3%
{\dodohandleXMLdirective#3 @ @ @\end{#1}{#2}}
%\def\dodohandleXMLdirective#1 #2 #3 #4\end#5#6%
% {\doifdefinedelse{\@@CTXML-#5-#1}
% {\getvalue{\@@CTXML-#5-#1}[#2=#3]}
% {#6[#1][#2=#3]}}
\def\dodohandleXMLdirective#1 #2 #3 #4\end#5#6%
{\executeifdefined{\@@CTXML-#5-#1}{#6[#1]}[#2=#3]}
% \defineXMLdirective [mathml] \setupMMLappearance % [#1][#2=#3]
% \defineXMLdirective [flowchart] [shapes] \setupFLOWshapes % [#2=#3]
% \defineXMLdirective [flowchart] [lines] \setupFLOWlines % [#2=#3]
\defineXMLprocessor [context-begin-group] {\bgroup\gobbleoneargument}
\defineXMLprocessor [context-end-group] {\egroup\gobbleoneargument}
% \def\XMLnspart#1:#2\empty{#1} % call ...:\empty\empty
% \def\XMLidpart#1:#2#3\empty{\ifx#2\empty#1\else\XMLidpart#2#3\empty\empty\fi}
% trial macros (used in setupx), to be sped up !
\bgroup \catcode`\<=\activecatcode
\gdef\saveXMLasdata#1#2% name raw data
{\dodoglobal\setevalue{\@@XMLsave:#1}{#2}} % \edef!
\gdef\saveXMLdata#1#2% name data-name ; definitely no \edef
{\dodoglobal\copycsname\@@XMLsave:#1\endcsname\csname\@@XMLdata:#2\endcsname}
% \gdef\saveXMLdatainelement#1#2#3% name element data
% {\dodoglobal\setevalue{\@@XMLsave:#1}% todo: one level expansion
% {<#2 \currentXMLarguments>\XMLflush{#3}#2>}}
%
% \gdef\saveXMLdatastructure#1#2#3#4#5#6% name element args before data after
% {\dodoglobal\setevalue{\@@XMLsave:#1}% todo: one level expansion
% {<#2 #3 \currentXMLarguments>#4\XMLflush{#5}#6#2>}}
%
% better (no expansion):
\newtoks\XMLdatatoks
\gdef\saveXMLdatainelement#1#2#3% name element data
{\XMLdatatoks\@EAEAEA{\csname\@@XMLdata:#3\endcsname}% no check
\dodoglobal\setevalue{\@@XMLsave:#1}{<#2 \currentXMLarguments>\the\XMLdatatoks#2>}}
\gdef\saveXMLdatastructure#1#2#3#4#5#6% name element args before data after
{\XMLdatatoks\@EAEAEA{\csname\@@XMLdata:#5\endcsname}% no check
\dodoglobal\setevalue{\@@XMLsave:#1}{<#2 #3 \currentXMLarguments>#4\the\XMLdatatoks#6#2>}}
\gdef\gsaveXMLasdata {\doglobal\saveXMLasdata}
\gdef\gsaveXMLdata {\doglobal\saveXMLdata}
\gdef\gsaveXMLdatainelement{\doglobal\saveXMLdatainelement}
\gdef\gsaveXMLdatastructure{\doglobal\saveXMLdatastructure}
\gdef\doifelseXMLelement#1%
{\doifdefinedelse{\@@XMLsave:#1}}
\gdef\doifelseXMLelementcontent#1%
{\ifcsname\@@XMLsave:#1\endcsname
\bgroup
\@EA\defconvertedcommand\@EA\ascii\csname\@@XMLsave:#1\endcsname
\setbox\scratchbox\hbox{\ignorespaces\ascii\unskip\unskip\unskip}%
\ifdim\wd\scratchbox>\zeropoint
\egroup\@EAEAEA\firstoftwoarguments
\else
\egroup\@EAEAEA\secondoftwoarguments
\fi
\else
\@EA\secondoftwoarguments
\fi}
\gdef\doifelseXMLelementequals#1#2%
{\ifcsname\@@XMLsave:#1\endcsname
\bgroup
\@EA\defconvertedcommand\@EA\asciia\csname\@@XMLsave:#1\endcsname
\defconvertedargument\asciib{#2}%
\ifx\asciia\asciib
\egroup\@EAEAEA\firstoftwoarguments
\else
\egroup\@EAEAEA\secondoftwoarguments
\fi
\else
\@EA\secondoftwoarguments
\fi}
\gdef\doifXMLtextelse#1% new
{\doiftextelse{\simplifyXMLelements#1}}
\gdef\doifXMLtext#1#2% new
{\doiftextelse{\simplifyXMLelements#1}{#2}\donothing}
\gdef\convertXMLelement#1\to#2%
{\ifcsname\@@XMLsave:#1\endcsname
\@EA\defconvertedcommand\@EA#2\csname\@@XMLsave:#1\endcsname
\else
\let#2\ascii
\fi}
\gdef\flushXMLelement#1%
{\csname
\@@XMLsave:\ifcsname\@@XMLsave:#1\endcsname#1\else\@@XMLsave\fi
\endcsname}
\gdef\defXMLelement#1#2%
{\@EA\let\@EA#1\csname
\@@XMLsave:\ifcsname\@@XMLsave:#2\endcsname#2\else\@@XMLsave\fi
\endcsname}
\letgvalueempty{\@@XMLsave:\@@XMLsave}
\gdef\showXMLelement#1%
{\showvalue{\@@XMLsave:#1}}
\gdef\eraseXMLelement#1%
{\dodoglobal\letbeundefined{\@@XMLsave:#1}}
\gdef\geraseXMLelement
{\doglobal\eraseXMLelement}
\gdef\processXMLelement#1%
{\bgroup
\enableXMLelements
\getvalue{\@@XMLsave:#1}%
\egroup}
\gdef\texXMLelement#1%
{\begingroup
% \setnormalcatcodes
\disableXML
\scantokens\@EA\@EA\@EA{\csname\@@XMLsave:#1\endcsname}%
\endgroup}
\gdef\reduceXMLescapeentities
{\setXMLentity{amp}{\string&}%
\setXMLentity{lt}{\string<}%
\setXMLentity{gt}{\string>}%
\setXMLentity{quot}{\string'}%
\setXMLentity{dquot}{\string"}}
\gdef\reduceXMLelement#1\to#2%
{\ifcsname\@@XMLsave:#1\endcsname
\bgroup
\reduceXMLescapetokens
\reduceXMLescapeentities
\expanded{\egroup\noexpand\def\noexpand#2{\csname\@@XMLsave:#1\endcsname}}%
\else
\let#2\empty
\fi}
\egroup
% \defineXMLcommand
% [whatever]
% [test=unknown]
% {\XMLop{test}}
%
% \startXMLdata
%
% \stopXMLdata
%
% \defineXMLcommand
% [whatever]
% [test=unknown]
% {\defXMLtex\SomethingTex{\XMLop{test}}%
% \SomethingTex}
%
% \startXMLdata
%
% \stopXMLdata
\def\defXMLtex#1#2% the appended space will go away when
{\begingroup % \scantokens is fixed
\disableXML
\everyeof{\noexpand}% br's hack
\edef\ascii{#2}%
\edef\ascii{\scantokens\expandafter{\ascii}}% space appended
\expandafter\endgroup\expandafter\def\expandafter#1\expandafter{\ascii}}
\def\potentialXMLentity#1%
{\doifXMLentityelse{#1}{\getXMLentity{#1}}{#1}}
% \def\XMLnoschema{standalone='yes'}
\def\writtenXMLelement #1#2{<#1>#2#1>}
\def\writtenXMLstart #1{<#1>}
\def\writtenXMLend #1{#1>}
\def\writtenXMLempty #1{<#1/>}
\def\writtenXMLelementcs#1#2{\ifx#2\empty\else<#1>#2#1>\fi}
\def\writtenXMLemptycs #1#2{\ifx#2\empty<#1/>\else<#1>#2#1>\fi}
%D This one can be used to get sound tuo files.
%D
%D \starttyping
%D \setuphead[chapter][expansion=xml]
%D % \setuplist[chapter][textcommand=\enableXML]
%D
%D \enableregime[utf] \autoXMLentitiestrue
%D \stoptyping
%D
%D with:
%D
%D \starttyping
%D test ë test &ediaeresis; test ediaeresis
%D \stoptyping
%D
%D This gives:
%D
%D \starttyping
%D test ë test ediaeresis test ediaeresis
%D \stoptyping
\def\XMLprocessingparameter#1%
{\csname\??xp#1\endcsname}
\appendtoks
\defineXMLargument[\XMLprocessingparameter\c!escape]\getXMLentity
\to \aftersetupXMLprocessing
\setupXMLprocessing
[\c!escape=e]
\bgroup \catcode`\<=\activecatcode
\long\gdef\defexpandedxmlargument#1#2#3%
{\begingroup
\let\uppercase\firstofoneargument
\def\getXMLhexcharacter##1{\numbertoutp{"##1}}% maps to private if needed
\def\getXMLdeccharacter##1{\numbertoutp {##1}}% maps to private if needed
\def\getXMLentity##1{##1}%
\def<{\noexpand<}%
\ifcase\xmlexpandmode
\or
% 1 = default
\or
% 2 = keep utf
\keeputfcharacters % new, needed for chinese and such
\fi
\let\uchar\relax
\let\unicodechar\relax
\xdef\@@globalexpanded{#3}%
\endgroup
#1#2\@@globalexpanded}
\egroup
% test.xml: test % test
%
% \starttext
% \enableregime[utf] \chardef\XMLtokensreduction=0
% \setuphead[chapter][expansion=xml]
% \defineXMLargument[test]{\chapter}
% \placelist[chapter][criterium=text]
% \processXMLfilegrouped{test.xml}
% \stoptext
% obsolete in mkiv
\chardef\xmlexpandmode\plusone
\def\defexpandedxmlargumentcmd {\chardef\xmlexpandmode\plusone\defexpandedxmlargument\defconvertedcommand}
\def\defexpandedxmlargumentutf {\chardef\xmlexpandmode\plustwo\defexpandedxmlargument\defconvertedcommand}
\def\gdefexpandedxmlargumentcmd{\chardef\xmlexpandmode\plusone\defexpandedxmlargument\gdefconvertedcommand}
\def\gdefexpandedxmlargumentutf{\chardef\xmlexpandmode\plustwo\defexpandedxmlargument\gdefconvertedcommand}
\installexpander {xml} \defexpandedxmlargumentcmd \gdefexpandedxmlargumentcmd
\installexpander {xml:cmd} \defexpandedxmlargumentcmd \gdefexpandedxmlargumentcmd
\installexpander {xml:utf} \defexpandedxmlargumentutf \gdefexpandedxmlargumentutf
\def\XMLtexmath#1{\begingroup\setnormalcatcodes\scantokens{\mathematics{#1}\ignorespaces}\endgroup}
% \defineXMLargument[tm]{\XMLtexmath}
%
% \startbuffer[test]
% Sometimes it makes sense to use simple math, as in: e=mc^2.
% \stopbuffer
%
% \processXMLbuffer[test]
%D Undocumented ...
\def\defineXMLstore {\doquadrupleargument\dodefineXMLstore[\saveXMLasdata]}
\def\defineXMLgstore{\doquadrupleargument\dodefineXMLstore[\gsaveXMLasdata]}
\def\dodefineXMLstore[#1][#2][#3][#4]% element attribute prefix % will become faster
{\defineXMLargument[#2][#3=\s!dummy]{#1{#4:\XMLop{#3}}}}
\def\countXMLchildren[#1]#2%
{\startnointerference
\doglobal\newcounter\nofXMLchildren
\defineXMLargument[#1]{\doglobal\increment\nofXMLchildren}%
\startXMLignore
#2%
\stopXMLignore
\stopnointerference}
% Typical \MKII. We will not explore this route any further as in \MKIV\ we
% have better ways.
\prependtoks \setnormalcatcodes \to \everyTEXinputmode
\appendtoks \processingXMLfalse \to \everyTEXinputmode
\let\normalenableXML\enableXML % some day we move the normal \enableXML into the toks
\prependtoks \normalenableXML \to \everyXMLinputmode
\appendtoks \processingXMLtrue \to \everyXMLinputmode
\unexpanded\def\enableXML {\setinputmode[XML]} % \enableXML is used in edef's and marks
\unexpanded\def\disableXML{\setinputmode[TEX]}
\protect \endinput