%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 {} 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 {} %D We will be dealing with elements, which means that we have %D to take care of \type {} and \type {}, but %D also with \type {} and \type {}. 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} % \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\@@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} % =.othercatcode % .catcode`."=.othercatcode % .catcode`./=.othercatcode % .catcode`.'=.othercatcode % .catcode`.~=.othercatcode % .catcode`.#=.othercatcode % .let &=.doXMLentity % .unexpanded.def=.other % .unexpanded.def=.othercatcode % .let<.relax * new % .processingXMLfalse % E % % .global.let<.relax * new % .global.let&.relax * new % % .egroup % % \def\disableXML % {\setnormalcatcodes\processingXMLfalse} \defcatcodecommand\xmlcatcodese `\& \doXMLentity \defcatcodecommand\xmlcatcodese `\< \doXMLelement \defcatcodecommand\xmlcatcodesr `\& \doXMLentity \defcatcodecommand\xmlcatcodesr `\< \doXMLelement \defcatcodecommand\xmlcatcodesn `\& \doXMLentity \defcatcodecommand\xmlcatcodesn `\< \doXMLelement \letcatcodecommand\xmlcatcodesr `\# \letterhash \letcatcodecommand\xmlcatcodesr `\$ \letterdollar \letcatcodecommand\xmlcatcodesr `\% \letterpercent \letcatcodecommand\xmlcatcodesr `\\ \letterbackslash \letcatcodecommand\xmlcatcodesr `\^ \letterhat \letcatcodecommand\xmlcatcodesr `\_ \letterunderscore \letcatcodecommand\xmlcatcodesr `\{ \letterleftbrace \letcatcodecommand\xmlcatcodesr `\} \letterrightbrace \letcatcodecommand\xmlcatcodesr `\| \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 `\# \entityhash \letcatcodecommand\xmlcatcodese `\$ \entitydollar \letcatcodecommand\xmlcatcodese `\% \entitypercent \letcatcodecommand\xmlcatcodese `\\ \entitybackslash \letcatcodecommand\xmlcatcodese `\^ \entityhat \letcatcodecommand\xmlcatcodese `\_ \entityunderscore \letcatcodecommand\xmlcatcodese `\{ \entityleftbrace \letcatcodecommand\xmlcatcodese `\} \entityrightbrace \letcatcodecommand\xmlcatcodese `\| \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 %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 %D \stoptyping %D %D Officially the following definition is not valid: %D %D \starttyping %D some text %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 %D \stoptyping %D %D Comment is formatted as follows. %D %D \starttyping %D %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 %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 { 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 % % \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 % % \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 %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 &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 % % % \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 % @ ‘ ‚ “ ” „• % & % $ { }   … % \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 % % \stopXMLdata % % \defineXMLentity[45]{|it works|} % {|-|} % % \startXMLdata % text-.text % textEFtext % \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 % % 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 %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 % xxx % % % % % x % \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 t+3+x+t\neq m\alpha\frac\theta\hbar %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: % % ]> % % 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 % % second: % unset: % deep:nested:outer: % last: % % \stopXMLdata % % \startXMLdata % % second: % unset: % deep:nested:outer: % last: % % \stopXMLdata % % \startXMLdata % % second: % unset: % deep:nested:outer: % last: % % \stopXMLdata % dit werkt alleen ok in niet ... 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}% \scantokens{#1}% \else \begingroup\enableXML\scantokens{#1\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}% \else \scantokens{\begingroup\enableXML#3}% \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}% \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\gobblespacetokens}} % % currently: \unexpanded\def\XMLdata % # safe {\begingroup \protectXMLdata \doXMLdata} \def\doXMLdata#1% {\enableXML \scantokens{#1}% \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}% {\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 %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