xtag-pre.mkii / last modification: 2020-01-30 14:15
%D \module
%D   [       file=xtag-pre,
%D        version=2000.12.20,
%D          title=\CONTEXT\ XML Macros,
%D       subtitle=Predefined Things,
%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 / Predefined}

%D Here we predefine some escapes, processing instructions,
%D entities and other handy things.

\unprotect

%D For \MKIV:

\setvalue{@u@s@"}#1#2"{#2} \setvalue{@g@s@"}#1#2"{\scratchtoks{#2}}
\setvalue{@u@s@'}#1#2'{#2} \setvalue{@g@s@'}#1#2'{\scratchtoks{#2}}
\setvalue{@u@s@ }#1#2 {#2} \setvalue{@g@s@ }#1#2 {\scratchtoks{#2}}

\def\unstringed#1{\csname\ifcsname @u@s@#1\endcsname @u@s@#1\else\s!empty\fi\endcsname#1}
\def\grabstring#1{\csname\ifcsname @g@s@#1\endcsname @g@s@#1\else\s!empty\fi\endcsname#1}

\def\dowithgrabbedstring#1%
  {\def\@@dowithgrabbedstring{#1}%
   \afterassignment\@@dowithgrabbedstring\grabstring}

%D Let's get rid of ligatures:

% \definefonthandling [default] [noligs]

%D First we define the default error handler. When tracing is
%D activated, the unknown element is showed verbatim.

\defineXMLenvironment [\s!default] \defaultXMLelement \defaultXMLelement
\defineXMLsingular    [\s!default] \defaultXMLelement

% \def\defaultXMLelement
%   {\iftraceXMLelements[\currentXMLfullidentifier]\fi}

\def\defaultXMLelement
  {\iftraceXMLelements{\infofont<\currentXMLfullidentifier>}\fi}

%D We can use the default handler to implement automatic
%D element hiding. Beware: this overloads the tracer.

% \def\startXMLignore{\dododefineXMLignore \s!default}
% \def\stopXMLignore {\dododefineXMLprocess\s!default}

\newcount\xmlignoredepth

\def\startXMLignore{\ifcase\xmlignoredepth\dododefineXMLignore\s!default\fi\advance\xmlignoredepth\plusone}
\def\stopXMLignore {\advance\xmlignoredepth\minusone\ifcase\xmlignoredepth\dododefineXMLprocess\s!default\fi}

%D The following entities need to be defined anyway. They
%D may be overloaded later.

% rest also \letter

\defineXMLentities [amp]  {\letterampersand} {\&amp;}
\defineXMLentities [gt]   {\string>} {\mathematics{>}}
\defineXMLentities [lt]   {\string<} {\mathematics{<}}
\defineXMLentities [quot] {\string"} {\mathematics{"}}
\defineXMLentities [apos] {\string`} {\mathematics{'}}

%D Of course we define:

\defineXMLentities [tex]     {tex}     {\TeX}
\defineXMLentities [context] {context} {\ConTeXt}
\defineXMLentities [xml]     {xml}     {XML}
\defineXMLentities [xsd]     {xsd}     {XSD}
\defineXMLentities [html]    {html}    {HTML}

%D The following entities are used for internal purposes and
%D concern characters that are kind of problematic in \TEX\
%D input.

\defineXMLentities [tex-hash]       {\letterhash}       {\#}
\defineXMLentities [tex-dollar]     {\letterdollar}     {\$}
\defineXMLentities [tex-percent]    {\letterpercent}    {\%}
\defineXMLentities [tex-backslash]  {\letterbackslash}  {\texescape}
\defineXMLentities [tex-hat]        {\letterhat}        {\^{}}
\defineXMLentities [tex-underscore] {\letterunderscore} {\_}
\defineXMLentities [tex-leftbrace]  {\letterleftbrace}  {\leftargument}
\defineXMLentities [tex-rightbrace] {\letterrightbrace} {\rightargument}
\defineXMLentities [tex-bar]        {\letterbar}        {\vl}
\defineXMLentities [tex-tilde]      {\lettertilde}      {\~{}}

%D Some pretty printing macros will use color, for which we
%D define a dedicated palet here.

\definepalet
  [xtag]
  [0=darkgray,   1=darkred,  2=darkgreen,
   3=darkblue,   4=darkcyan, 5=darkmagenta,
   6=darkyellow, 7=black,    8=black]

%D An example of its usage can be found in the pretty
%D printing macros in the run time module.

\newif\ifautoXMLshow      \autoXMLshowtrue
\newif\ifshowXMLarguments \showXMLargumentstrue

\def\setupXMLfile{\dodoubleargument\getparameters[\??xf]}

\setupXMLfile
  [\c!inbetween=\blank,
   \c!level=1]

\fetchruntimecommand\showXMLfile  {\f!xtagprefix\s!run}
\fetchruntimecommand\showXMLbuffer{\f!xtagprefix\s!run}
\fetchruntimecommand\showXMLtext  {\f!xtagprefix\s!run}

\fetchruntimecommand\showXMLign   {\f!xtagprefix\s!run}
\fetchruntimecommand\showXMLnop   {\f!xtagprefix\s!run}
\fetchruntimecommand\showXMLtxt   {\f!xtagprefix\s!run}
\fetchruntimecommand\showXMLpar   {\f!xtagprefix\s!run}
\fetchruntimecommand\showXMLlin   {\f!xtagprefix\s!run}
\fetchruntimecommand\showXMLwrd   {\f!xtagprefix\s!run}
\fetchruntimecommand\showXMLemp   {\f!xtagprefix\s!run}

\fetchruntimecommand\showXMLbreak {\f!xtagprefix\s!run}

%D By default, we will ignore escape commands, preceded by
%D \type {<!} and ending in (presumably) a \type {>}.

\defineXMLescape [\s!default] {\gobbleuntil{>}}

%D The comment escape has the form:
%D
%D \starttyping
%D <!-- a couple of remarks -->
%D \stoptyping

\defineXMLescape [--] {\gobbleuntil{-->}}

%D The \type {CDATA} escape is kind of unique in its
%D strange syntax.
%D
%D \starttyping
%D <!CDATA[it starts here
%D whatever you like to be shown verbatim
%D and ends here]]>
%D \stoptyping
%D
%D Watch this rather obscure definition (we need to pass an
%D \type {[} to the macro.

\chardef\XMLcdatamethod=1

\newtoks \everyXMLcdata % \appendtoks \tt \to \everyXMLcdata

\setvalue{XMLcdatamethod1}%
  {\skipfirstverbatimlinefalse
   \processtaggeddisplayverbatim{]]>}}

\setvalue{XMLcdatamethod2}%
  {\begingroup
   \obeylines
   \obeyspaces
   \the\everyXMLcdata
   \processXMLcdata}

\long\def\processXMLcdata#1]]>%
  {#1\endgroup}

\defineXMLescape [CDATA]
  {\executeifdefined{XMLcdatamethod\number\XMLcdatamethod}{\begingroup\processXMLcdata}}

%D \starttyping
%D <!ELEMENT ...">
%D <!ATTLIST ...">
%D \stoptyping

\defineXMLescape [ATTLIST]{\gobbleuntil>}
\defineXMLescape [ELEMENT]{\gobbleuntil>}

%D \starttyping
%D <!ENTITY crap "very new [&#x7B;] crap">
%D <!ENTITY crap SYSTEM "crapfile.xml">
%D <!ENTITY crap SYSTEM "crapfile.pdf" NDATA ignoredanyway>
%D \stoptyping

\defineXMLescape [ENTITY] \handleXMLentityescape

\def\handleXMLentityescape#1>%
  {\dohandleXMLentityescape#1 @ @ @ @ @ @>}

\def\dohandleXMLentityescape#1 #2 #3 #4>
  {\doifnot{#1}\letterpercent
     {\doifelse{#2}{SYSTEM}
        {\dohandleXMLentitySYSTEM#1 #2 #3 #4>}
        {\dohandleXMLentityDEFINE#1 #2 #3 #4>}}}

\def\dohandleXMLentitySYSTEM#1 #2 #3 #4 #5 #6>% name SYSTEM ....
  {\doifelse{#4}{@}
     {\expanded{\defineXMLentity[#1]{\noexpand\readXMLsystem{\unstringed#3}}}}
     {\doif{#4}{NDATA} % maybe we should also store the NDATA
        {\expanded{\defineXMLentity[#1]{\noexpand\readXMLndata{\unstringed#3}}}}}}

\def\readXMLsystem#1%
  {\readfile{#1}
     {\writestatus{xml-system}{reading #1}}
     {\writestatus{xml-system}{unable to locate #1}}}

\def\readXMLndata#1%
  {#1} % {\externalfigure[#1]}

\def\dohandleXMLentityDEFINE#1 %#2 #3 #4 #5 #6>% name replacement
  {\def\docommand##1>{\expanded{\defineXMLentity[#1]{\the\scratchtoks}}}%
   \afterassignment\docommand\grabstring}

%D Such entities can be encapsulated in a \type {DOCTYPE}
%D element. Therefore we remove the outer level of document
%D type definitions.
%D
%D \starttyping
%D <!DOCTYPE Something>
%D <!DOCTYPE Something >
%D <!DOCTYPE Something [ ... ]>
%D <!DOCTYPE Something SYSTEM "... ...">
%D <!DOCTYPE Something SYSTEM "... ..." >
%D <!DOCTYPE Something SYSTEM "... ..." [ ... ]>
%D <!DOCTYPE Something PUBLIC "... ..." "...">
%D <!DOCTYPE Something PUBLIC "... ..." "..." >
%D <!DOCTYPE Something PUBLIC "... ..." "..." [ ... ]>
%D \stoptyping

\defineXMLescape [DOCTYPE] \handleXMLdoctype

\def\handleXMLdoctype
  {\let\XMLdoctype\empty
   \dohandleXMLdoctype}

\def\dohandleXMLdoctype
  {\futurelet\nexttoken\dohandleXMLdoctok}

\def\dohandleXMLdoctok
  {\ifx\nexttoken>%
   % [doctype: \XMLdoctype]
     \@EA\gobbleuntil\@EA>%
   \else\ifx\nexttoken\blankspace
   % [doctype: \XMLdoctype]
     \@EAEAEA\dodohandleXMLdoctype
   \else
     \@EAEAEA\redoXMLdoctype
   \fi\fi}

\def\redoXMLdoctype#1%
  {\edef\XMLdoctype{\XMLdoctype#1}\dohandleXMLdoctype}

\def\dodohandleXMLdoctype#1%
  {\executeifdefined{XMLdoctype#1}{\gobbleuntil>}}

\setvalue{XMLdoctype>}{}
\setvalue{XMLdoctype[}{\processuntil{]>}} % or \gobbleuntil{]>}}

\def\XMLdoctypeS YSTEM %
  {\dowithgrabbedstring\dodohandleXMLdoctype}

\def\XMLdoctypeP UBLIC %
  {\dowithgrabbedstring{\dowithgrabbedstring\dodohandleXMLdoctype}}

% wrong
%
% \def\XMLdoctypeS YSTEM {\XMLgrabstring}
% \def\XMLdoctypeP UBLIC {\XMLgrabstring}
%
% \def\XMLgrabstring
%   {\doifnextcharelse>{\gobbleuntil>}{\dowithgrabbedstring\XMLgrabstring}}

%D Some day we may need to support entities within a
%D document type namespace.

%D As an example of processing instructions, we implement a
%D \CONTEXT\ code handler:

\defineXMLprocessor [context]         \contextXMLcommand
\defineXMLprocessor [context-command] \contextXMLcommand

% we need to get rid of the endlinechar inserted by \scantokens
%
% \def\saveendlinechar%
%   {\ifx\restoreendlinechar\undefined
%      \edef\restoreendlinechar{\endlinechar\the\endlinechar\space}%
%    \fi
%    \endlinechar=-1 }
%
% \def\scanXMLtokens#1%
%   {\saveendlinechar\scantokens{#1}\restoreendlinechar}

%D For security reasons, we provide a switch to turn this
%D mechanism on and off. When turned off, there is no way to
%D turn it on from within an \XML\ encoded document, simply
%D because the possibility to process \CONTEXT\ commands is
%D gone.

\setupXMLprocessing[\c!command=\v!yes]

%\def\contextXMLcommand#1%
%  {\doif\@@xpcommando\v!ja
%     {\pushmacro\disableXML
%      \def\disableXML{\global\let\afterXMLprocessor\empty}%
%      \global\let\afterXMLprocessor\enableXML
%      \setnormalcatcodes\scantokens{#1}\afterXMLprocessor
%      \popmacro\disableXML}}

\def\contextXMLcommand#1% we don't use #1 here
  {\doif\@@xpcommand\v!yes
     {\disableXML\scantokens\@EA{\currentXMLprocess}\enableXML}}

%D The indirect method (using the macro \type
%D {\currentXMLprocess} instead of \type {#}) is needed
%D because of the \type {\scantokens}. Given the previous
%D definition, and given that \ETEX\ is used, we can now
%D say:
%D
%D \starttyping
%D <?context-command {\bf Start Of Some \TeX\ Text} ?>
%D \stoptyping
%D
%D A non||\ETEX\ solution is also possible, using buffers,
%D but for the moment we assume that \ETEX\ is used.

%D Next we implement a general purpose directive. This one
%D can be used to set variables that can be accessed with
%D \type {\XMLvar}.

\defineXMLprocessor [context-directive] \contextXMLdirective

\def\contextXMLdirective#1%
  {\docontextXMLdirective#1 @ @ @\end}

\def\docontextXMLdirective#1 #2 #3 #4\end % class variable value
  {\expandafter\def\csname\@@XMLvariable:#1:#2\endcsname{#3}}

%D A simple processing instruction is the following. It just
%D writes a message to the screen.

\defineXMLprocessor [context-message] {\writestatus{xml-message}}

%D The following processing instruction permits you to tag
%D parts of the file in such a way that you can filter data.
%D We use this method when documenting schemas.

\defineXMLprocessor [context-block] \handleXMLcontextblock

\def\handleXMLcontextblock#1%
  {\dohandleXMLcontextblock#1 \relax}

\def\dohandleXMLcontextblock#1 #2 #3\relax
  {\dodohandleXMLcontextblock{#1}{#2}}

\let\dodohandleXMLcontextblock\gobbletwoarguments

\def\hideXMLcontextblock[#1]%
  {\def\dodohandleXMLcontextblock
     {\dododohandleXMLcontextblock\doifinset{#1}}}

\def\videXMLcontextblock[#1]%
  {\def\dodohandleXMLcontextblock
     {\dododohandleXMLcontextblock\doifnotinset{#1}}}

\protect

\def\dododohandleXMLcontextblock#1#2#3#4%
  {\let\next\relax
   \doifelse{#3}{begin}
     {#1{#4}{#2}
       {%\writestatus{xml-block}{skipping begin #4}%
        \long\def\next##1?context-block end #4 ##2?>{}}}
     {\doif{#3}{name}
        {#1{#4}{#2}
          {%\writestatus{xml-block}{skipping name #4}%
           \long\def\next##1?context-block ##2?>{}}}}%
   \next}

\unprotect

%D Say that a file contains blocks like the following:
%D
%D \starttyping
%D <?context-block begin whatevername ?>
%D
%D <to/> <be> <or/> maybe <not/> so much <to/> </be>
%D
%D <?context-block end whatevername ?>
%D \stoptyping
%D
%D The following commands will show only this block:
%D
%D \starttyping
%D \videXMLcontextblock[whatevername] \showXMLfile{yourfile}
%D \stoptyping
%D
%D You can also mark blocks in the following way, thereby
%D saving yourself some work:
%D
%D \starttyping
%D <?context-block what ?>
%D
%D <what>What do you want?</what>
%D
%D <?context-block how ?>
%D
%D <how>How do you want?</how>
%D
%D <?context-block done ?>
%D \stoptyping

% yet undocumented and experimental

% \defineXMLprocessor [context-eof] {\endinput}

% already defined in xtag-ini

% \defineXMLsingular [begingroup] {\begingroup}
% \defineXMLsingular [endgroup]   {\endgroup}
%
% \defineXMLsingular [gobblespacetokens] {\gobblespacetokens}

%D We automatically switch regimes (beware of nested files!):
%D
%D \starttyping
%D \startXMLdata
%D <?xml version='1.0' encoding='utf-8'?>
%D ÀÁÂÃÄÅàáâãäåÆÇæç
%D ÈÉÊËèéêëÌÍÎÏÞìíîïþ
%D ÐðÑñÒÓÔÕÖòóôõöØø
%D ÙÚÛÜùúûÝýÿß
%D \stopXMLdata
%D \stoptyping

\defineXMLprocessor [xml]   {\handleXMLbanner}

\def\handleXMLbanner#1%
  {\getXMLarguments{xml}{\s!encoding='' #1}%
   \doifsomething{\XMLpar{xml}\s!encoding\empty}
     {\doif\currentregime\s!default % style regimes will take precedence
        {\enableregime[\XMLpar{xml}\s!encoding\empty]}\donothing}}

\protect \endinput