%D \module
%D [ file=xtag-pre,
%D version=2000.12.20,
%D title=\CONTEXT\ XML Support,
%D subtitle=Predefined Things,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
\beginTEX
\endinput
\endTEX
\writestatus{loading}{Context XML Macros (predefined)}
%D Here we predefine some escapes, processing instructions,
%D entities and other handy things.
\unprotect
%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}
%D The following entities need to be defined anyway. They
%D may be overloaded later.
% rest also \letter
\defineXMLentities [amp] {\letterampersand} {\&}
\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] {\letterhar} {\^{}}
\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 {}.
\defineXMLescape [\s!default] {\gobbleuntil{>}}
%D The comment escape has the form:
%D
%D \starttyping
%D
%D \stoptyping
\defineXMLescape [--] {\gobbleuntil{-->}}
%D The \type {CDATA} escape is kind of unique in its
%D strange syntax.
%D
%D \starttyping
%D
%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
%D
%D \stoptyping
\defineXMLescape [ATTLIST]{\gobbleuntil>}
\defineXMLescape [ELEMENT]{\gobbleuntil>}
%D \starttyping
%D
%D
%D
%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
%D
%D
%D
%D
%D
%D
%D
%D
%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
%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
%D
%D maybe so much
%D
%D
%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
%D
%D What do you want?
%D
%D
%D
%D How do you want?
%D
%D
%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
%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