diff options
70 files changed, 5689 insertions, 5131 deletions
diff --git a/doc/context/documents/general/manuals/luatex.pdf b/doc/context/documents/general/manuals/luatex.pdf Binary files differindex d24fd65c0..9cf5e932b 100644 --- a/doc/context/documents/general/manuals/luatex.pdf +++ b/doc/context/documents/general/manuals/luatex.pdf diff --git a/doc/context/documents/general/manuals/xml-mkiv.pdf b/doc/context/documents/general/manuals/xml-mkiv.pdf Binary files differindex f8b8c34c2..6508f2ecc 100644 --- a/doc/context/documents/general/manuals/xml-mkiv.pdf +++ b/doc/context/documents/general/manuals/xml-mkiv.pdf diff --git a/doc/context/documents/general/qrcs/setup-cs.pdf b/doc/context/documents/general/qrcs/setup-cs.pdf Binary files differindex 1380998c0..99f1cce8e 100644 --- a/doc/context/documents/general/qrcs/setup-cs.pdf +++ b/doc/context/documents/general/qrcs/setup-cs.pdf diff --git a/doc/context/documents/general/qrcs/setup-de.pdf b/doc/context/documents/general/qrcs/setup-de.pdf Binary files differindex ffda60e11..5024d4ec1 100644 --- a/doc/context/documents/general/qrcs/setup-de.pdf +++ b/doc/context/documents/general/qrcs/setup-de.pdf diff --git a/doc/context/documents/general/qrcs/setup-en.pdf b/doc/context/documents/general/qrcs/setup-en.pdf Binary files differindex c92ba194a..e12fb62d5 100644 --- a/doc/context/documents/general/qrcs/setup-en.pdf +++ b/doc/context/documents/general/qrcs/setup-en.pdf diff --git a/doc/context/documents/general/qrcs/setup-fr.pdf b/doc/context/documents/general/qrcs/setup-fr.pdf Binary files differindex e7ae18eda..3c8f9d85d 100644 --- a/doc/context/documents/general/qrcs/setup-fr.pdf +++ b/doc/context/documents/general/qrcs/setup-fr.pdf diff --git a/doc/context/documents/general/qrcs/setup-it.pdf b/doc/context/documents/general/qrcs/setup-it.pdf Binary files differindex c44b7defc..72ff7fd90 100644 --- a/doc/context/documents/general/qrcs/setup-it.pdf +++ b/doc/context/documents/general/qrcs/setup-it.pdf diff --git a/doc/context/documents/general/qrcs/setup-mapping-cs.pdf b/doc/context/documents/general/qrcs/setup-mapping-cs.pdf Binary files differindex ffd8d2127..431448870 100644 --- a/doc/context/documents/general/qrcs/setup-mapping-cs.pdf +++ b/doc/context/documents/general/qrcs/setup-mapping-cs.pdf diff --git a/doc/context/documents/general/qrcs/setup-mapping-de.pdf b/doc/context/documents/general/qrcs/setup-mapping-de.pdf Binary files differindex d4e801f0a..c3cf3fa4e 100644 --- a/doc/context/documents/general/qrcs/setup-mapping-de.pdf +++ b/doc/context/documents/general/qrcs/setup-mapping-de.pdf diff --git a/doc/context/documents/general/qrcs/setup-mapping-en.pdf b/doc/context/documents/general/qrcs/setup-mapping-en.pdf Binary files differindex 81eb49286..fe1e5d5fe 100644 --- a/doc/context/documents/general/qrcs/setup-mapping-en.pdf +++ b/doc/context/documents/general/qrcs/setup-mapping-en.pdf diff --git a/doc/context/documents/general/qrcs/setup-mapping-fr.pdf b/doc/context/documents/general/qrcs/setup-mapping-fr.pdf Binary files differindex 1f7e467f5..048f2440a 100644 --- a/doc/context/documents/general/qrcs/setup-mapping-fr.pdf +++ b/doc/context/documents/general/qrcs/setup-mapping-fr.pdf diff --git a/doc/context/documents/general/qrcs/setup-mapping-it.pdf b/doc/context/documents/general/qrcs/setup-mapping-it.pdf Binary files differindex 7b13337ce..3e69835e6 100644 --- a/doc/context/documents/general/qrcs/setup-mapping-it.pdf +++ b/doc/context/documents/general/qrcs/setup-mapping-it.pdf diff --git a/doc/context/documents/general/qrcs/setup-mapping-nl.pdf b/doc/context/documents/general/qrcs/setup-mapping-nl.pdf Binary files differindex 90177e867..08d14f24c 100644 --- a/doc/context/documents/general/qrcs/setup-mapping-nl.pdf +++ b/doc/context/documents/general/qrcs/setup-mapping-nl.pdf diff --git a/doc/context/documents/general/qrcs/setup-mapping-ro.pdf b/doc/context/documents/general/qrcs/setup-mapping-ro.pdf Binary files differindex f4c443e86..0185a98c9 100644 --- a/doc/context/documents/general/qrcs/setup-mapping-ro.pdf +++ b/doc/context/documents/general/qrcs/setup-mapping-ro.pdf diff --git a/doc/context/documents/general/qrcs/setup-nl.pdf b/doc/context/documents/general/qrcs/setup-nl.pdf Binary files differindex 14f885db1..d1f2b6477 100644 --- a/doc/context/documents/general/qrcs/setup-nl.pdf +++ b/doc/context/documents/general/qrcs/setup-nl.pdf diff --git a/doc/context/documents/general/qrcs/setup-ro.pdf b/doc/context/documents/general/qrcs/setup-ro.pdf Binary files differindex a8f773569..c17e699a1 100644 --- a/doc/context/documents/general/qrcs/setup-ro.pdf +++ b/doc/context/documents/general/qrcs/setup-ro.pdf diff --git a/doc/context/sources/general/manuals/luatex/luatex-modifications.tex b/doc/context/sources/general/manuals/luatex/luatex-modifications.tex index b1b803d48..50d23fb1b 100644 --- a/doc/context/sources/general/manuals/luatex/luatex-modifications.tex +++ b/doc/context/sources/general/manuals/luatex/luatex-modifications.tex @@ -572,7 +572,7 @@ something (as it comes from the backend it's normally a sequence of tokens). \stopsubsection -\startsubsection[title={\lpr{pdfextension}, \lpr {pdfvariable} and \lpr {pdffeedback}}] +\startsubsection[title={\lpr{pdfextension}, \lpr {pdfvariable} and \lpr {pdffeedback}},reference=sec:pdfextensions] In order for \LUATEX\ to be more than just \TEX\ you need to enable primitives. That has already been the case right from the start. If you want the traditional \PDFTEX\ @@ -643,6 +643,7 @@ The configuration related registers have become: \edef\pdfignoreunknownimages {\pdfvariable ignoreunknownimages} \edef\pdfgentounicode {\pdfvariable gentounicode} \edef\pdfomitcidset {\pdfvariable omitcidset} +\edef\pdfomitcharset {\pdfvariable omitcharset} \edef\pdfpagebox {\pdfvariable pagebox} \edef\pdfminorversion {\pdfvariable minorversion} \edef\pdfuniqueresname {\pdfvariable uniqueresname} @@ -891,6 +892,7 @@ The engine sets the following defaults. \pdfignoreunknownimages 0 \pdfgentounicode 0 \pdfomitcidset 0 +\pdfomitcharset 0 \pdfpagebox 0 \pdfminorversion 4 \pdfuniqueresname 0 diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-commands.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-commands.tex new file mode 100644 index 000000000..ab9989895 --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-commands.tex @@ -0,0 +1,893 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-commands + +\startchapter[title={Commands}] + +\startsection[title={nodes and lpaths}] + +The amount of commands available for manipulating the \XML\ file is rather large. +Many of the commands cooperate with the already discussed setups, a fancy name +for a collection of macro calls either or not mixed with text. + +Most of the commands are just shortcuts to \LUA\ calls, which means that the real +work is done by \LUA. In fact, what happens is that we have a continuous transfer +of control from \TEX\ to \LUA, where \LUA\ prints back either data (like element +content or attribute values) or just invokes a setup whereby it passes a +reference to the node resolved conform the path expression. The invoked setup +itself might return control to \LUA\ again, etc. + +This sounds complicated but examples will show what we mean here. First we +present the whole repertoire of commands. Because users can read the source code, +they might uncover more commands, but only the ones discussed here are official. +The commands are grouped in categories. + +In the following sections \cmdinternal {cd:node} means a reference to a node: +this can be the identifier of the root (the loaded xml tree) or a reference to a +node in that tree (often the result of some lookup. A \cmdinternal {cd:lpath} is +a fancy name for a path expression (as with \XSLT) but resolved by \LUA. + +\stopsection + +\startsection[title={commands}] + +There are a lot of commands available but you probably can ignore most of them. +We try to be complete which means that there is for instance \type {\xmlfirst} as +well as \type {\xmllast} but you probably never need the last one. There are also +commands that were used when testing this interface and we see no reason to +remove them. Some obscure ones are used in modules and after a while even I often +forget that they exist. To give you an idea of what commands are important we +show their use in generating the \CONTEXT\ command definitions (\type +{x-set-11.mkiv}) per January 2016: + +\startcolumns[n=2,balance=yes] +\starttabulate[|l|r|] +\NC \type {\xmlall} \NC 1 \NC \NR +\NC \type {\xmlatt} \NC 23 \NC \NR +\NC \type {\xmlattribute} \NC 1 \NC \NR +\NC \type {\xmlcount} \NC 1 \NC \NR +\NC \type {\xmldoif} \NC 2 \NC \NR +\NC \type {\xmldoifelse} \NC 1 \NC \NR +\NC \type {\xmlfilterlist} \NC 4 \NC \NR +\NC \type {\xmlflush} \NC 5 \NC \NR +\NC \type {\xmlinclude} \NC 1 \NC \NR +\NC \type {\xmlloadonly} \NC 1 \NC \NR +\NC \type {\xmlregisterdocumentsetup} \NC 1 \NC \NR +\NC \type {\xmlsetsetup} \NC 1 \NC \NR +\NC \type {\xmlsetup} \NC 4 \NC \NR +\stoptabulate +\stopcolumns + +As you can see filtering, flushing and accessing attributes score high. Below we show +the statistics of a quite complex rendering (5 variants of schoolbooks: basic book, +answers, teachers guide, worksheets, full blown version with extensive tracing). + +\startcolumns[n=2,balance=yes] +\starttabulate[|l|r|] +\NC \type {\xmladdindex} \NC 3 \NC \NR +\NC \type {\xmlall} \NC 5 \NC \NR +\NC \type {\xmlappendsetup} \NC 1 \NC \NR +\NC \type {\xmlapplyselectors} \NC 1 \NC \NR +\NC \type {\xmlatt} \NC 40 \NC \NR +\NC \type {\xmlattdef} \NC 9 \NC \NR +\NC \type {\xmlattribute} \NC 10 \NC \NR +\NC \type {\xmlbadinclusions} \NC 3 \NC \NR +\NC \type {\xmlconcat} \NC 3 \NC \NR +\NC \type {\xmlcount} \NC 1 \NC \NR +\NC \type {\xmldelete} \NC 11 \NC \NR +\NC \type {\xmldoif} \NC 39 \NC \NR +\NC \type {\xmldoifelse} \NC 28 \NC \NR +\NC \type {\xmldoifelsetext} \NC 13 \NC \NR +\NC \type {\xmldoifnot} \NC 2 \NC \NR +\NC \type {\xmldoifnotselfempty} \NC 1 \NC \NR +\NC \type {\xmlfilter} \NC 100 \NC \NR +\NC \type {\xmlfirst} \NC 51 \NC \NR +\NC \type {\xmlflush} \NC 69 \NC \NR +\NC \type {\xmlflushcontext} \NC 2 \NC \NR +\NC \type {\xmlinclude} \NC 1 \NC \NR +\NC \type {\xmlincludeoptions} \NC 5 \NC \NR +\NC \type {\xmlinclusion} \NC 16 \NC \NR +\NC \type {\xmlinjector} \NC 1 \NC \NR +\NC \type {\xmlloaddirectives} \NC 1 \NC \NR +\NC \type {\xmlmapvalue} \NC 4 \NC \NR +\NC \type {\xmlmatch} \NC 1 \NC \NR +\NC \type {\xmlprependsetup} \NC 5 \NC \NR +\NC \type {\xmlregisterdocumentsetup} \NC 2 \NC \NR +\NC \type {\xmlregistersetup} \NC 1 \NC \NR +\NC \type {\xmlremapnamespace} \NC 1 \NC \NR +\NC \type {\xmlsetfunction} \NC 2 \NC \NR +\NC \type {\xmlsetinjectors} \NC 2 \NC \NR +\NC \type {\xmlsetsetup} \NC 11 \NC \NR +\NC \type {\xmlsetup} \NC 76 \NC \NR +\NC \type {\xmlstrip} \NC 1 \NC \NR +\NC \type {\xmlstripanywhere} \NC 1 \NC \NR +\NC \type {\xmltag} \NC 1 \NC \NR +\NC \type {\xmltext} \NC 53 \NC \NR +\NC \type {\xmlvalue} \NC 2 \NC \NR +\stoptabulate +\stopcolumns + +Here many more are used but this is an exceptional case. The top is again +dominated by filtering, flushing and attribute consulting. The list can actually +be smaller. For instance, the \type {\xmlcount} can just as well be \type +{\xmlfilter} with a \type {count} finalizer. There are also some special ones, +like the injectors, that are needed for finetuning the final result. + +\stopsection + +\startsection[title={loading}] + +\startxmlcmd {\cmdbasicsetup{xmlloadfile}} + loads the file \cmdinternal {cd:file} and registers it under \cmdinternal + {cd:name} and applies either given or standard \cmdinternal + {cd:xmlsetup} (alias: \type {\xmlload}) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlloadbuffer}} + loads the buffer \cmdinternal {cd:buffer} and registers it under + \cmdinternal {cd:name} and applies either given or standard + \cmdinternal {cd:xmlsetup} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlloaddata}} + loads \cmdinternal {cd:text} and registers it under \cmdinternal + {cd:name} and applies either given or standard \cmdinternal + {cd:xmlsetup} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlloadonly}} + loads \cmdinternal {cd:text} and registers it under \cmdinternal + {cd:name} and applies either given or standard \cmdinternal + {cd:xmlsetup} but doesn't flush the content +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlinclude}} + includes the file specified by attribute \cmdinternal {cd:name} of the + element located by \cmdinternal {cd:lpath} at node \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlprocessfile}} + registers file \cmdinternal {cd:file} as \cmdinternal {cd:name} and + process the tree starting with \cmdinternal {cd:xmlsetup} (alias: + \type {\xmlprocess}) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlprocessbuffer}} + registers buffer \cmdinternal {cd:name} as \cmdinternal {cd:name} and process + the tree starting with \cmdinternal {cd:xmlsetup} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlprocessdata}} + registers \cmdinternal {cd:text} as \cmdinternal {cd:name} and process + the tree starting with \cmdinternal {cd:xmlsetup} +\stopxmlcmd + +The initial setup defaults to \type {xml:process} that is defined +as follows: + +\starttyping +\startsetups xml:process + \xmlregistereddocumentsetups\xmldocument + \xmlmain\xmldocument +\stopsetups +\stoptyping + +First we apply the setups associated with the document (including common setups) +and then we flush the whole document. The macro \type {\xmldocument} expands to +the current document id. There is also \type {\xmlself} which expands to the +current node number (\type {#1} in setups). + +\startxmlcmd {\cmdbasicsetup{xmlmain}} + returns the whole document +\stopxmlcmd + +Normally such a flush will trigger a chain reaction of setups associated with the +child elements. + +\stopsection + +\startsection[title={saving}] + +\startxmlcmd {\cmdbasicsetup{xmlsave}} + saves the given node \cmdinternal {cd:node} in the file \cmdinternal {cd:file} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmltofile}} + saves the match of \cmdinternal {cd:lpath} in the file \cmdinternal {cd:file} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmltobuffer}} + saves the match of \cmdinternal {cd:lpath} in the buffer \cmdinternal {cd:buffer} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmltobufferverbose}} + saves the match of \cmdinternal {cd:lpath} verbatim in the buffer \cmdinternal + {cd:buffer} +\stopxmlcmd + +% \startxmlcmd {\cmdbasicsetup{xmltoparameters}} +% converts the match of \cmdinternal {cd:lpath} to key|/|values (for tracing) +% \stopxmlcmd + +The next command is only needed when you have messed with the tree using +\LUA\ code. + +\startxmlcmd {\cmdbasicsetup{xmladdindex}} + (re)indexes a tree +\stopxmlcmd + +The following macros are only used in special situations and are not really meant +for users. + +\startxmlcmd {\cmdbasicsetup{xmlraw}} + flush the content if \cmdinternal {cd:node} with original entities +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{startxmlraw}} + flush the wrapped content with original entities +\stopxmlcmd + +\stopsection + +\startsection[title={flushing data}] + +When we flush an element, the associated \XML\ setups are expanded. The most +straightforward way to flush an element is the following. Keep in mind that the +returned values itself can trigger setups and therefore flushes. + +\startxmlcmd {\cmdbasicsetup{xmlflush}} + returns all nodes under \cmdinternal {cd:node} +\stopxmlcmd + +You can restrict flushing by using commands that accept a specification. + +\startxmlcmd {\cmdbasicsetup{xmltext}} + returns the text of the matching \cmdinternal {cd:lpath} under \cmdinternal + {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlpure}} + returns the text of the matching \cmdinternal {cd:lpath} under \cmdinternal + {cd:node} without \type {\Ux} escaped special \TEX\ characters +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlflushtext}} + returns the text of the \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlflushpure}} + returns the text of the \cmdinternal {cd:node} without \type {\Ux} escaped + special \TEX\ characters +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlnonspace}} + returns the text of the matching \cmdinternal {cd:lpath} under \cmdinternal + {cd:node} without embedded spaces +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlall}} + returns all nodes under \cmdinternal {cd:node} that matches \cmdinternal + {cd:lpath} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmllastmatch}} + returns all nodes found in the last match +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlfirst}} + returns the first node under \cmdinternal {cd:node} that matches \cmdinternal + {cd:lpath} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmllast}} + returns the last node under \cmdinternal {cd:node} that matches \cmdinternal + {cd:lpath} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlfilter}} + at a match of \cmdinternal {cd:lpath} a given filter \type {filter} is applied + and the result is returned +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlsnippet}} + returns the \cmdinternal {cd:number}\high{th} element under \cmdinternal + {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlposition}} + returns the \cmdinternal {cd:number}\high{th} match of \cmdinternal + {cd:lpath} at node \cmdinternal {cd:node}; a negative number starts at the + end (alias: \type {\xmlindex}) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlelement}} + returns the \cmdinternal {cd:number}\high{th} child of node \cmdinternal {cd:node}; + a negative number starts at the end +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlpos}} + returns the index (position) in the parent node of \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlconcat}} + returns the sequence of nodes that match \cmdinternal {cd:lpath} at + \cmdinternal {cd:node} whereby \cmdinternal {cd:text} is put between each + match +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlconcatrange}} + returns the \cmdinternal {cd:first}\high {th} upto \cmdinternal + {cd:last}\high {th} of nodes that match \cmdinternal {cd:lpath} at + \cmdinternal {cd:node} whereby \cmdinternal {cd:text} is put between each + match +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlcommand}} + apply the given \cmdinternal {cd:xmlsetup} to each match of \cmdinternal + {cd:lpath} at node \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlstrip}} + remove leading and trailing spaces from nodes under \cmdinternal {cd:node} + that match \cmdinternal {cd:lpath} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlstripped}} + remove leading and trailing spaces from nodes under \cmdinternal {cd:node} + that match \cmdinternal {cd:lpath} and return the content afterwards +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlstripnolines}} + remove leading and trailing spaces as well as collapse embedded spaces + from nodes under \cmdinternal {cd:node} that match \cmdinternal {cd:lpath} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlstrippednolines}} + remove leading and trailing spaces as well as collapse embedded spaces from + nodes under \cmdinternal {cd:node} that match \cmdinternal {cd:lpath} and + return the content afterwards +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlverbatim}} + flushes the content verbatim code (without any wrapping, i.e. no fonts + are selected and such) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlinlineverbatim}} + return the content of the node as inline verbatim code; no further + interpretation (expansion) takes place and spaces are honoured; it uses the + following wrapper +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{startxmlinlineverbatim}} + wraps inline verbatim mode using the environment specified (a prefix \type + {xml:} is added to the environment name) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldisplayverbatim}} + return the content of the node as display verbatim code; no further + interpretation (expansion) takes place and leading and trailing spaces and + newlines are treated special; it uses the following wrapper +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{startxmldisplayverbatim}} + wraps the content in display verbatim using the environment specified (a prefix + \type {xml:} is added to the environment name) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlprettyprint}} + pretty print (with colors) the node \cmdinternal {cd:node}; use the \CONTEXT\ + \SCITE\ lexers when available (\type {\usemodule [scite]}) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlflushspacewise}} + flush node \cmdinternal {cd:node} obeying spaces and newlines +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlflushlinewise}} + flush node \cmdinternal {cd:node} obeying newlines +\stopxmlcmd + +\stopsection + +\startsection[title={information}] + +The following commands return strings. Normally these are used in tests. + +\startxmlcmd {\cmdbasicsetup{xmlname}} + returns the complete name (including namespace prefix) of the + given \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlnamespace}} + returns the namespace of the given \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmltag}} + returns the tag of the element, without namespace prefix +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlcount}} + returns the number of matches of \cmdinternal {cd:lpath} at node \cmdinternal + {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlatt}} + returns the value of attribute \cmdinternal {cd:name} or empty if no such + attribute exists +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlattdef}} + returns the value of attribute \cmdinternal {cd:name} or \cmdinternal + {cd:string} if no such attribute exists +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlrefatt}} + returns the value of attribute \cmdinternal {cd:name} or empty if no such + attribute exists; a leading \type {#} is removed (nicer for tex) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlchainatt}} + returns the value of attribute \cmdinternal {cd:name} or empty if no such + attribute exists; backtracks till a match is found +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlchainattdef}} + returns the value of attribute \cmdinternal {cd:name} or \cmdinternal + {cd:string} if no such attribute exists; backtracks till a match is found +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlattribute}} + finds a first match for \cmdinternal {cd:lpath} at \cmdinternal {cd:node} and + returns the value of attribute \cmdinternal {cd:name} or empty if no such + attribute exists +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlattributedef}} + finds a first match for \cmdinternal {cd:lpath} at \cmdinternal {cd:node} and + returns the value of attribute \cmdinternal {cd:name} or \cmdinternal + {cd:text} if no such attribute exists +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmllastatt}} + returns the last attribute found (this avoids a lookup) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlsetatt}} + set the value of attribute \cmdinternal {cd:name} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlsetattribute}} + set the value of attribute \cmdinternal {cd:name} for each match of \cmdinternal + {cd:lpath} +\stopxmlcmd + +\stopsection + +\startsection[title={manipulation}] + +You can use \LUA\ code to manipulate the tree and it makes no sense to duplicate +this in \TEX. In the future we might provide an interface to some of this +functionality. Keep in mind that manipuating the tree might have side effects as +we maintain several indices into the tree that also needs to be updated then. + +\stopsection + +\startsection[title={integration}] + +If you write a module that deals with \XML, for instance processing cals tables, +then you need ways to control specific behaviour. For instance, you might want to +add a background to the table. Such directives are collected in \XML\ files and +can be loaded on demand. + +\startxmlcmd {\cmdbasicsetup{xmlloaddirectives}} + loads \CONTEXT\ directives from \cmdinternal {cd:file} that will get + interpreted when processing documents +\stopxmlcmd + +A directives definition file looks as follows: + +\starttyping +<?xml version="1.0" standalone="yes"?> + +<directives> + <directive attribute='id' value="100" + setup="cdx:100"/> + <directive attribute='id' value="101" + setup="cdx:101"/> + <directive attribute='cdx' value="colors" element="cals:table" + setup="cdx:cals:table:colors"/> + <directive attribute='cdx' value="vertical" element="cals:table" + setup="cdx:cals:table:vertical"/> + <directive attribute='cdx' value="noframe" element="cals:table" + setup="cdx:cals:table:noframe"/> + <directive attribute='cdx' value="*" element="cals:table" + setup="cdx:cals:table:*"/> +</directives> +\stoptyping + +Examples of usage can be found in \type {x-cals.mkiv}. The directive is triggered +by an attribute. Instead of a setup you can specify a setup to be applied before +and after the node gets flushed. + +\startxmlcmd {\cmdbasicsetup{xmldirectives}} + apply the setups directive associated with the node +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldirectivesbefore}} + apply the before directives associated with the node +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldirectivesafter}} + apply the after directives associated with the node +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlinstalldirective}} + defines a directive that hooks into a handler +\stopxmlcmd + +Normally a directive will be put in the \XML\ file, for instance as: + +\starttyping +<?context-mathml-directive minus reduction yes ?> +\stoptyping + +Here the \type {mathml} is the general class of directives and \type {minus} a +subclass, in our case a specific element. + +\stopsection + +\startsection[title={setups}] + +The basic building blocks of \XML\ processing are setups. These are just +collections of macros that are expanded. These setups get one argument passed +(\type {#1}): + +\starttyping +\startxmlsetups somedoc:somesetup + \xmlflush{#1} +\stopxmlsetups +\stoptyping + +This argument is normally a number that internally refers to a specific node in +the \XML\ tree. The user should see it as an abstract reference and not depend on +its numeric property. Just think of it as \quote {the current node}. You can (and +probably will) call such setups using: + +\startxmlcmd {\cmdbasicsetup{xmlsetup}} + expands setup \cmdinternal {cd:setup} and pass \cmdinternal {cd:node} as + argument +\stopxmlcmd + +However, in most cases the setups are associated to specific elements, +something that users of \XSLT\ might recognize as templates. + +\startxmlcmd {\cmdbasicsetup{xmlsetfunction}} + associates function \cmdinternal {cd:luafunction} to the elements in + namespace \cmdinternal {cd:name} that match \cmdinternal {cd:lpath} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlsetsetup}} + associates setups \cmdinternal {cd:setup} (\TEX\ code) with the matching + nodes of \cmdinternal {cd:lpath} or root \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlprependsetup}} + pushes \cmdinternal {cd:setup} to the front of global list of setups +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlappendsetup}} + adds \cmdinternal {cd:setup} to the global list of setups to be applied + (alias: \type{\xmlregistersetup}) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlbeforesetup}} + pushes \cmdinternal {cd:setup} into the global list of setups; the + last setup is the position +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlaftersetup}} + adds \cmdinternal {cd:setup} to the global list of setups; the last setup + is the position +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlremovesetup}} + removes \cmdinternal {cd:setup} from the global list of setups +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlprependdocumentsetup}} + pushes \cmdinternal {cd:setup} to the front of list of setups to be applied + to \cmdinternal {cd:name} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlappenddocumentsetup}} + adds \cmdinternal {cd:setup} to the list of setups to be applied to + \cmdinternal {cd:name} (you can also use the alias: \type + {\xmlregisterdocumentsetup}) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlbeforedocumentsetup}} + pushes \cmdinternal {cd:setup} into the setups to be applied to \cmdinternal + {cd:name}; the last setup is the position +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlafterdocumentsetup}} + adds \cmdinternal {cd:setup} to the setups to be applied to \cmdinternal + {cd:name}; the last setup is the position +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlremovedocumentsetup}} + removes \cmdinternal {cd:setup} from the global list of setups to be applied + to \cmdinternal {cd:name} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlresetsetups}} + removes all global setups +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlresetdocumentsetups}} + removes all setups from the \cmdinternal {cd:name} specific list of setups to + be applied +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlflushdocumentsetups}{setup}} + applies \cmdinternal {cd:setup} (can be a list) to \cmdinternal {cd:name} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlregisteredsetups}} + applies all global setups to the current document +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlregistereddocumentsetups}} + applies all document specific \cmdinternal {cd:setup} to document + \cmdinternal {cd:name} +\stopxmlcmd + +\stopsection + +\startsection[title={testing}] + +The following test macros all take a \cmdinternal {cd:node} as first argument +and an \cmdinternal {cd:lpath} as second: + +\startxmlcmd {\cmdbasicsetup{xmldoif}} + expands to \cmdinternal {cd:true} when \cmdinternal {cd:lpath} matches at + node \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifnot}} + expands to \cmdinternal {cd:true} when \cmdinternal {cd:lpath} does not match + at node \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifelse}} + expands to \cmdinternal {cd:true} when \cmdinternal {cd:lpath} matches at + node \cmdinternal {cd:node} and to \cmdinternal {cd:false} otherwise +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoiftext}} + expands to \cmdinternal {cd:true} when the node matching \cmdinternal + {cd:lpath} at node \cmdinternal {cd:node} has some content +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifnottext}} + expands to \cmdinternal {cd:true} when the node matching \cmdinternal + {cd:lpath} at node \cmdinternal {cd:node} has no content +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifelsetext}} + expands to \cmdinternal {cd:true} when the node matching \cmdinternal + {cd:lpath} at node \cmdinternal {cd:node} has content and to \cmdinternal + {cd:false} otherwise +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifatt}} + expands to \cmdinternal {cd:true} when the attribute matching \cmdinternal + {cd:node} and the name given as second argument matches the third argument +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifnotatt}} + expands to \cmdinternal {cd:true} when the attribute matching \cmdinternal + {cd:node} and the name given as second argument differs from the third + argument +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifelseatt}} + expands to \cmdinternal {cd:true} when the attribute matching \cmdinternal + {cd:node} and the name given as second argument matches the third argument + and to \cmdinternal {cd:false} otherwise +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifelseempty}} + expands to \cmdinternal {cd:true} when the node matching \cmdinternal + {cd:lpath} at node \cmdinternal {cd:node} is empty and to \cmdinternal + {cd:false} otherwise +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifelseselfempty}} + expands to \cmdinternal {cd:true} when the node is empty and to \cmdinternal + {cd:false} otherwise +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifselfempty}} + expands to \cmdinternal {cd:true} when \cmdinternal {cd:node} is empty +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifnotselfempty}} + expands to \cmdinternal {cd:true} when \cmdinternal {cd:node} is not empty +\stopxmlcmd + +\stopsection + +\startsection[title={initialization}] + +The general setup command (not to be confused with setups) that deals with the +\MKIV\ tree handler is \type {\setupxml}. There are currently only a few options. + +\cmdfullsetup{setupxml} + +When you set \type {default} to \cmdinternal {cd:text} elements with no setup +assigned will end up as text. When set to \type {hidden} such elements will be +hidden. You can apply the default yourself using: + +\startxmlcmd {\cmdbasicsetup{xmldefaulttotext}} + presets the tree with root \cmdinternal {cd:node} to the handlers set up with + \type {\setupxml} option \cmdinternal{default} +\stopxmlcmd + +You can set \type {compress} to \type {yes} in which case comment is stripped +from the tree when the file is read. + +\startxmlcmd {\cmdbasicsetup{xmlregisterns}} + associates an internal namespace (like \type {mml}) with one given in the + document as \URL\ (like mathml) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlremapname}} + changes the namespace and tag of the matching elements +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlremapnamespace}} + replaces all references to the given namespace to a new one (applied + recursively) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlchecknamespace}} + sets the namespace of the matching elements unless a namespace is already set +\stopxmlcmd + +\stopsection + +\startsection[title={helpers}] + +Often an attribute will determine the rendering and this may result in many +tests. Especially when we have multiple attributes that control the output such +tests can become rather extensive and redundant because one gets $n\times m$ or +more such tests. + +Therefore we have a convenient way to map attributes onto for instance strings or +commands. + +\startxmlcmd {\cmdbasicsetup{xmlmapvalue}} + associate a \cmdinternal {cd:text} with a \cmdinternal {cd:category} and + \cmdinternal {cd:name} (alias: \type{\xmlmapval}) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlvalue}} + expand the value associated with a \cmdinternal {cd:category} and + \cmdinternal {cd:name} and if not resolved, expand to the \cmdinternal + {cd:text} (alias: \type{\xmlval}) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmldoifelsevalue}} + associate a \cmdinternal {cd:text} with a \cmdinternal {cd:category} and + \cmdinternal {cd:name} +\stopxmlcmd + +This is used as follows. We define a couple of mappings in the same category: + +\starttyping +\xmlmapvalue{emph}{bold} {\bf} +\xmlmapvalue{emph}{italic}{\it} +\stoptyping + +Assuming that we have associated the following setup with the \type {emph} +element, we can say (with \type {#1} being the current element): + +\starttyping +\startxmlsetups demo:emph + \begingroup + \xmlvalue{emph}{\xmlatt{#1}{type}}{} + \endgroup +\stopxmlsetups +\stoptyping + +In this case we have no default. The \type {type} attribute triggers the actions, +as in: + +\starttyping +normal <emph type='bold'>bold</emph> normal +\stoptyping + +This mechanism is not really bound to elements and attributes so you can use this +mechanism for other purposes as well. + +\stopsection + +\startsection[title={Parameters}] + +\startbuffer[test] +<something whatever="alpha"> + <what> + beta + </what> +</something> +\stopbuffer + +\startbuffer +\startxmlsetups xml:mysetups + \xmlsetsetup{\xmldocument}{*}{xml:*} +\stopxmlsetups + +\xmlregistersetup{xml:mysetups} + +\startxmlsetups xml:something + parameter : \xmlpar {#1}{whatever}\par + attribute : \xmlatt {#1}{whatever}\par + text : \xmlfirst {#1}{what} \par + \xmlsetpar{#1}{whatever}{gamma} + parameter : \xmlpar {#1}{whatever}\par + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:what + what: \xmlflush{#1}\par + parameter : \xmlparam{#1}{..}{whatever}\par +\stopxmlsetups + +\xmlprocessbuffer{main}{test}{} +\stopbuffer + +Say that we have this \XML\ blob: + +\typebuffer[test] + +With: + +\typebuffer + +we get: + +\getbuffer + +Parameters are stored with a node. + +\startxmlcmd {\cmdbasicsetup{xmlpar}} + returns the value of parameter \cmdinternal {cd:name} or empty if no such + parameter exists +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlparam}} + finds a first match for \cmdinternal {cd:lpath} at \cmdinternal {cd:node} and + returns the value of parameter \cmdinternal {cd:name} or empty if no such + parameter exists +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmllastpar}} + returns the last parameter found (this avoids a lookup) +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlsetpar}} + set the value of parameter \cmdinternal {cd:name} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlsetparam}} + set the value of parameter \cmdinternal {cd:name} for each match of \cmdinternal + {cd:lpath} +\stopxmlcmd + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-contents.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-contents.tex new file mode 100644 index 000000000..e0787ec5f --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-contents.tex @@ -0,0 +1,12 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-contents + +\starttitle[title=Contents] + +\placelist + [chapter,section] + +\stoptitle + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-converter.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-converter.tex new file mode 100644 index 000000000..a457f962b --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-converter.tex @@ -0,0 +1,300 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-converter + +\startchapter[title={Setting up a converter}] + +\startsection[title={from structure to setup}] + +We use a very simple document structure for demonstrating how a converter is +defined. In practice a mapping will be more complex, especially when we have a +style with complex chapter openings using data coming from all kind of places, +different styling of sections with the same name, selectively (out of order) +flushed content, special formatting, etc. + +\typefile{manual-demo-1.xml} + +Say that this document is stored in the file \type {demo.xml}, then the following +code can be used as starting point: + +\starttyping +\startxmlsetups xml:demo:base + \xmlsetsetup{#1}{document|section|p}{xml:demo:*} +\stopxmlsetups + +\xmlregisterdocumentsetup{demo}{xml:demo:base} + +\startxmlsetups xml:demo:document + \starttitle[title={Contents}] + \placelist[chapter] + \stoptitle + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:demo:section + \startchapter[title=\xmlfirst{#1}{/title}] + \xmlfirst{#1}{/content} + \stopchapter +\stopxmlsetups + +\startxmlsetups xml:demo:p + \xmlflush{#1}\endgraf +\stopxmlsetups + +\xmlprocessfile{demo}{demo.xml}{} +\stoptyping + +Watch out! These are not just setups, but specific \XML\ setups which get an +argument passed (the \type {#1}). If for some reason your \XML\ processing fails, +it might be that you mistakenly have used a normal setup definition. The argument +\type {#1} represents the current node (element) and is a unique identifier. For +instance a \type {<p>..</p>} can have an identifier {demo::5}. So, we can get +something: + +\starttyping +\xmlflush{demo::5}\endgraf +\stoptyping + +but as well: + +\starttyping +\xmlflush{demo::6}\endgraf +\stoptyping + +Keep in mind that the references tor the actual nodes (elements) are +abstractions, you never see those \type {<id>::<number>}'s, because we will use +either the abstract \type {#1} (any node) or an explicit reference like \type +{demo}. The previous setup when issued will be like: + +\starttyping +\startchapter[title=\xmlfirst{demo::3}{/title}] + \xmlfirst{demo::4}{/content} +\stopchapter +\stoptyping + +Here the \type {title} is used to typeset the chapter title but also for an entry +in the table of contents. At the moment the title is typeset the \XML\ node gets +looked up and expanded in real text. However, for the list it gets stored for +later use. One can argue that this is not needed for \XML, because one can just +filter all the titles and use page references, but then one also looses the +control one normally has over such titles. For instance it can be that some +titles are rendered differently and for that we need to keep track of usage. +Doing that with transformations or filtering is often more complex than leaving +that to \TEX. As soon as the list gets typeset, the reference (\type {demo::#3}) +is used for the lookup. This is because by default the title is stored as given. +So, as long as we make sure the \XML\ source is loaded before the table of +contents is typeset we're ok. Later we will look into this in more detail, for +now it's enough to know that in most cases the abstract \type {#1} reference will +work out ok. + +Contrary to the style definitions this interface looks rather low level (with no +optional arguments) and the main reason for this is that we want processing to be +fast. So, the basic framework is: + +\starttyping +\startxmlsetups xml:demo:base + % associate setups with elements +\stopxmlsetups + +\xmlregisterdocumentsetup{demo}{xml:demo:base} + +% define setups for matches + +\xmlprocessfile{demo}{demo.xml}{} +\stoptyping + +In this example we mostly just flush the content of an element and in the case of +a section we flush explicit child elements. The \type {#1} in the example code +represents the current element. The line: + +\starttyping +\xmlsetsetup{demo}{*}{-} +\stoptyping + +sets the default for each element to \quote {just ignore it}. A \type {+} would +make the default to always flush the content. This means that at this point we +only handle: + +\starttyping +<section> + <title>Some title</title> + <content> + <p>a paragraph of text</p> + </content> +</section> +\stoptyping + +In the next section we will deal with the slightly more complex itemize and +figure placement. At first sight all these setups may look overkill but keep in +mind that normally the number of elements is rather limited. The complexity is +often in the style and having access to each snippet of content is actually +quite handy for that. + +\stopsection + +\startsection[title={alternative solutions}] + +Dealing with an itemize is rather simple (as long as we forget about +attributes that control the behaviour): + +\starttyping +<itemize> + <item>first</item> + <item>second</item> +</itemize> +\stoptyping + +First we need to add \type {itemize} to the setup assignment (unless we've used +the wildcard \type {*}): + +\starttyping +\xmlsetsetup{demo}{document|section|p|itemize}{xml:demo:*} +\stoptyping + +The setup can look like: + +\starttyping +\startxmlsetups xml:demo:itemize + \startitemize + \xmlfilter{#1}{/item/command(xml:demo:itemize:item)} + \stopitemize +\stopxmlsetups + +\startxmlsetups xml:demo:itemize:item + \startitem + \xmlflush{#1} + \stopitem +\stopxmlsetups +\stoptyping + +An alternative is to map item directly: + +\starttyping +\xmlsetsetup{demo}{document|section|p|itemize|item}{xml:demo:*} +\stoptyping + +and use: + +\starttyping +\startxmlsetups xml:demo:itemize + \startitemize + \xmlflush{#1} + \stopitemize +\stopxmlsetups + +\startxmlsetups xml:demo:item + \startitem + \xmlflush{#1} + \stopitem +\stopxmlsetups +\stoptyping + +Sometimes, a more local solution using filters and \type {/command(...)} makes more +sense, especially when the \type {item} tag is used for other purposes as well. + +Explicit flushing with \type {command} is definitely the way to go when you have +complex products. In one of our projects we compose math school books from many +thousands of small \XML\ files, and from one source set several products are +typeset. Within a book sections get done differently, content gets used, ignored +or interpreted differently depending on the kind of content, so there is a +constant checking of attributes that drive the rendering. In that a generic setup +for a title element makes less sense than explicit ones for each case. (We're +talking of huge amounts of files here, including multiple images on each rendered +page.) + +When using \type {command} you can pass two arguments, the first is the setup for +the match, the second one for the miss, as in: + +\starttyping +\xmlfilter{#1}{/element/command(xml:true,xml:false)} +\stoptyping + +Back to the example, this leaves us with dealing with the resources, like +figures: + +\starttyping +<resource type='figure'> + <caption>A picture of a cow.</caption> + <content><external file="cow.pdf"/></content> +</resource> +\stoptyping + +Here we can use a more restricted match: + +\starttyping +\xmlsetsetup{demo}{resource[@type='figure']}{xml:demo:figure} +\xmlsetsetup{demo}{external}{xml:demo:*} +\stoptyping + +and the definitions: + +\starttyping +\startxmlsetups xml:demo:figure + \placefigure + {\xmlfirst{#1}{/caption}} + {\xmlfirst{#1}{/content}} +\stopxmlsetups + +\startxmlsetups xml:demo:external + \externalfigure[\xmlatt{#1}{file}] +\stopxmlsetups +\stoptyping + +At this point it is good to notice that \type {\xmlatt{#1}{file}} is passed as it +is: a macro call. This means that when a macro like \type {\externalfigure} uses +the first argument frequently without first storing its value, the lookup is done +several times. A solution for this is: + +\starttyping +\startxmlsetups xml:demo:external + \expanded{\externalfigure[\xmlatt{#1}{file}]} +\stopxmlsetups +\stoptyping + +Because the lookup is rather fast, normally there is no need to bother about this +too much because internally \CONTEXT\ already makes sure such expansion happens +only once. + +An alternative definition for placement is the following: + +\starttyping +\xmlsetsetup{demo}{resource}{xml:demo:resource} +\stoptyping + +with: + +\starttyping +\startxmlsetups xml:demo:resource + \placefloat + [\xmlatt{#1}{type}] + {\xmlfirst{#1}{/caption}} + {\xmlfirst{#1}{/content}} +\stopxmlsetups +\stoptyping + +This way you can specify \type {table} as type too. Because you can define your +own float types, more complex variants are also possible. In that case it makes +sense to provide some default behaviour too: + +\starttyping +\definefloat[figure-here][figure][default=here] +\definefloat[figure-left][figure][default=left] +\definefloat[table-here] [table] [default=here] +\definefloat[table-left] [table] [default=left] + +\startxmlsetups xml:demo:resource + \placefloat + [\xmlattdef{#1}{type}{figure}-\xmlattdef{#1}{location}{here}] + {\xmlfirst{#1}{/caption}} + {\xmlfirst{#1}{/content}} +\stopxmlsetups +\stoptyping + +In this example we support two types and two locations. We default to a figure +placed (when possible) at the current location. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-examples.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-examples.tex new file mode 100644 index 000000000..064510d6d --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-examples.tex @@ -0,0 +1,948 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-examples + +\startchapter[title=Examples] + +\startsection[title=attribute chains] + +In \CSS, when an attribute is not present, the parent element is checked, and when +not found again, the lookup follows the chain till a match is found or the root is +reached. The following example demonstrates how such a chain lookup works. + +\startbuffer[test] +<something mine="1" test="one" more="alpha"> + <whatever mine="2" test="two"> + <whocares mine="3"> + <!-- this is a test --> + </whocares> + </whatever> +</something> +\stopbuffer + +\typebuffer[test] + +We apply the following setups to this tree: + +\startbuffer[setups] +\startxmlsetups xml:common + [ + \xmlchainatt{#1}{mine}, + \xmlchainatt{#1}{test}, + \xmlchainatt{#1}{more}, + \xmlchainatt{#1}{none} + ]\par +\stopxmlsetups + +\startxmlsetups xml:something + something: \xmlsetup{#1}{xml:common} + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:whatever + whatever: \xmlsetup{#1}{xml:common} + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:whocares + whocares: \xmlsetup{#1}{xml:common} + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:mysetups + \xmlsetsetup{#1}{something|whatever|whocares}{xml:*} +\stopxmlsetups + +\xmlregisterdocumentsetup{example-1}{xml:mysetups} + +\xmlprocessbuffer{example-1}{test}{} +\stopbuffer + +\typebuffer[setups] + +This gives: + +\start + \getbuffer[setups] +\stop + +\stopsection + +\startsection[title=conditional setups] + +Say that we have this code: + +\starttyping +\xmldoifelse {#1} {/what[@a='1']} { + \xmlfilter {#1} {/what/command('xml:yes')} +} { + \xmlfilter {#1} {/what/command('xml:nop')} +} +\stoptyping + +Here we first determine if there is a child \type {what} with attribute \type {a} +set to \type {1}. Depending on the outcome again we check the child nodes for +being named \type {what}. A faster solution which also takes less code is this: + +\starttyping +\xmlfilter {#1} {/what[@a='1']/command('xml:yes','xml:nop')} +\stoptyping + +\stopsection + +\startsection[title=manipulating] + +Assume that we have the following \XML\ data: + +\startbuffer[test] +<A> + <B>right</B> + <B>wrong</B> +</A> +\stopbuffer + +\typebuffer[test] + +But, instead of \type {right} we want to see \type {okay}. We can do that with a +finalizer: + +\startbuffer +\startluacode +local rehash = { + ["right"] = "okay", +} + +function xml.finalizers.tex.Okayed(collected,what) + for i=1,#collected do + if what == "all" then + local str = xml.text(collected[i]) + context(rehash[str] or str) + else + context(str) + end + end +end +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\startxmlsetups xml:A + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:B + (It's \xmlfilter{#1}{./Okayed("all")}) +\stopxmlsetups + +\startxmlsetups xml:testsetups + \xmlsetsetup{#1}{A|B}{xml:*} +\stopxmlsetups + +\xmlregisterdocumentsetup{example-2}{xml:testsetups} +\xmlprocessbuffer{example-2}{test}{} +\stopbuffer + +\typebuffer + +The result is: \start \inlinebuffer \stop + +\stopsection + +\startsection[title=cross referencing] + +A rather common way to add cross references to \XML\ files is to borrow the +asymmetrical id's from \HTML. This means that one cannot simply use a value +of (say) \type {href} to locate an \type {id}. The next example came up on +the \CONTEXT\ mailing list. + +\startbuffer[test] +<doc> + <p>Text + <a href="#fn1" class="footnoteref" id="fnref1"><sup>1</sup></a> and + <a href="#fn2" class="footnoteref" id="fnref2"><sup>2</sup></a> + </p> + <div class="footnotes"> + <hr /> + <ol> + <li id="fn1"><p>A footnote.<a href="#fnref1">↩</a></p></li> + <li id="fn2"><p>A second footnote.<a href="#fnref2">↩</a></p></li> + </ol> + </div> +</doc> +\stopbuffer + +\typebuffer[test] + +We give two variants for dealing with such references. The first solution does +lookups and depending on the size of the file can be somewhat inefficient. + +\startbuffer +\startxmlsetups xml:doc + \blank + \xmlflush{#1} + \blank +\stopxmlsetups + +\startxmlsetups xml:p + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:footnote + (variant 1)\footnote + {\xmlfirst + {example-3-1} + {div[@class='footnotes']/ol/li[@id='\xmlrefatt{#1}{href}']}} +\stopxmlsetups + +\startxmlsetups xml:initialize + \xmlsetsetup{#1}{p|doc}{xml:*} + \xmlsetsetup{#1}{a[@class='footnoteref']}{xml:footnote} + \xmlsetsetup{#1}{div[@class='footnotes']}{xml:nothing} +\stopxmlsetups + +\xmlresetdocumentsetups{*} +\xmlregisterdocumentsetup{example-3-1}{xml:initialize} + +\xmlprocessbuffer{example-3-1}{test}{} +\stopbuffer + +\typebuffer + +This will typeset two footnotes. + +\getbuffer + +The second variant collects the references so that the time spend on lookups is +less. + +\startbuffer +\startxmlsetups xml:doc + \blank + \xmlflush{#1} + \blank +\stopxmlsetups + +\startxmlsetups xml:p + \xmlflush{#1} +\stopxmlsetups + +\startluacode + userdata.notes = {} +\stopluacode + +\startxmlsetups xml:collectnotes + \ctxlua{userdata.notes['\xmlrefatt{#1}{id}'] = '#1'} +\stopxmlsetups + +\startxmlsetups xml:footnote + (variant 2)\footnote + {\xmlflush + {\cldcontext{userdata.notes['\xmlrefatt{#1}{href}']}}} +\stopxmlsetups + +\startxmlsetups xml:initialize + \xmlsetsetup{#1}{p|doc}{xml:*} + \xmlsetsetup{#1}{a[@class='footnoteref']}{xml:footnote} + \xmlfilter{#1}{div[@class='footnotes']/ol/li/command(xml:collectnotes)} + \xmlsetsetup{#1}{div[@class='footnotes']}{} +\stopxmlsetups + +\xmlregisterdocumentsetup{example-3-2}{xml:initialize} + +\xmlprocessbuffer{example-3-2}{test}{} +\stopbuffer + +\typebuffer + +This will again typeset two footnotes: + +\getbuffer + +\stopsection + +\startsection[title=mapping values] + +One way to process options \type {frame} in the example below is to map the +values to values known by \CONTEXT. + +\startbuffer[test] +<a> + <nattable frame="on"> + <tr><td>#1</td><td>#2</td><td>#3</td><td>#4</td></tr> + <tr><td>#5</td><td>#6</td><td>#7</td><td>#8</td></tr> + </nattable> + <nattable frame="off"> + <tr><td>#1</td><td>#2</td><td>#3</td><td>#4</td></tr> + <tr><td>#5</td><td>#6</td><td>#7</td><td>#8</td></tr> + </nattable> + <nattable frame="no"> + <tr><td>#1</td><td>#2</td><td>#3</td><td>#4</td></tr> + <tr><td>#5</td><td>#6</td><td>#7</td><td>#8</td></tr> + </nattable> +</a> +\stopbuffer + +\typebuffer[test] + +\startbuffer +\startxmlsetups xml:a + \xmlflush{#1} +\stopxmlsetups + +\xmlmapvalue {nattable:frame} {on} {on} +\xmlmapvalue {nattable:frame} {yes} {on} +\xmlmapvalue {nattable:frame} {off} {off} +\xmlmapvalue {nattable:frame} {no} {off} + +\startxmlsetups xml:nattable + \startplacetable[title=#1] + \setupTABLE[frame=\xmlval{nattable:frame}{\xmlatt{#1}{frame}}{on}]% + \bTABLE + \xmlflush{#1} + \eTABLE + \stopplacetable +\stopxmlsetups + +\startxmlsetups xml:tr + \bTR + \xmlflush{#1} + \eTR +\stopxmlsetups + +\startxmlsetups xml:td + \bTD + \xmlflush{#1} + \eTD +\stopxmlsetups + +\startxmlsetups xml:testsetups + \xmlsetsetup{example-4}{a|nattable|tr|td|}{xml:*} +\stopxmlsetups + +\xmlregisterdocumentsetup{example-4}{xml:testsetups} + +\xmlprocessbuffer{example-4}{test}{} +\stopbuffer + +The \type {\xmlmapvalue} mechanism is rather efficient and involves a minimum +of testing. + +\typebuffer + +We get: + +\getbuffer + +\stopsection + +\startsection[title=using \LUA] + +In this example we demonstrate how you can delegate rendering to \LUA. We +will construct a so called extreme table. The input is: + +\startbuffer[demo] +<?xml version="1.0" encoding="utf-8"?> + +<a> + <b> <c>1</c> <d>Text</d> </b> + <b> <c>2</c> <d>More text</d> </b> + <b> <c>2</c> <d>Even more text</d> </b> + <b> <c>2</c> <d>And more</d> </b> + <b> <c>3</c> <d>And even more</d> </b> + <b> <c>2</c> <d>The last text</d> </b> +</a> +\stopbuffer + +\typebuffer[demo] + +The processor code is: + +\startbuffer[process] +\startxmlsetups xml:test_setups + \xmlsetsetup{#1}{a|b|c|d}{xml:*} +\stopxmlsetups + +\xmlregisterdocumentsetup{example-5}{xml:test_setups} + +\xmlprocessbuffer{example-5}{demo}{} +\stopbuffer + +\typebuffer + +We color a sequence of the same titles (numbers here) differently. The first +solution remembers the last title: + +\startbuffer +\startxmlsetups xml:a + \startembeddedxtable + \xmlflush{#1} + \stopembeddedxtable +\stopxmlsetups + +\startxmlsetups xml:b + \xmlfunction{#1}{test_ba} +\stopxmlsetups + +\startluacode +local lasttitle = nil + +function xml.functions.test_ba(t) + local title = xml.text(t, "/c") + local content = xml.text(t, "/d") + context.startxrow() + context.startxcell { + background = "color", + backgroundcolor = lasttitle == title and "colorone" or "colortwo", + foregroundstyle = "bold", + foregroundcolor = "white", + } + context(title) + lasttitle = title + context.stopxcell() + context.startxcell() + context(content) + context.stopxcell() + context.stopxrow() +end +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +The \type {embeddedxtable} environment is needed because the table is picked up +as argument. + +\startlinecorrection \getbuffer[process] \stoplinecorrection + +The second implemetation remembers what titles are already processed so here we +can color the last one too. + +\startbuffer +\startxmlsetups xml:a + \ctxlua{xml.functions.reset_bb()} + \startembeddedxtable + \xmlflush{#1} + \stopembeddedxtable +\stopxmlsetups + +\startxmlsetups xml:b + \xmlfunction{#1}{test_bb} +\stopxmlsetups + +\startluacode +local titles + +function xml.functions.reset_bb(t) + titles = { } +end + +function xml.functions.test_bb(t) + local title = xml.text(t, "/c") + local content = xml.text(t, "/d") + context.startxrow() + context.startxcell { + background = "color", + backgroundcolor = titles[title] and "colorone" or "colortwo", + foregroundstyle = "bold", + foregroundcolor = "white", + } + context(title) + titles[title] = true + context.stopxcell() + context.startxcell() + context(content) + context.stopxcell() + context.stopxrow() +end +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +\startlinecorrection \getbuffer[process] \stoplinecorrection + +A solution without any state variable is given below. + +\startbuffer +\startxmlsetups xml:a + \startembeddedxtable + \xmlflush{#1} + \stopembeddedxtable +\stopxmlsetups + +\startxmlsetups xml:b + \xmlfunction{#1}{test_bc} +\stopxmlsetups + +\startluacode +function xml.functions.test_bc(t) + local title = xml.text(t, "/c") + local content = xml.text(t, "/d") + context.startxrow() + local okay = xml.text(t,"./preceding-sibling::/[-1]") == title + context.startxcell { + background = "color", + backgroundcolor = okay and "colorone" or "colortwo", + foregroundstyle = "bold", + foregroundcolor = "white", + } + context(title) + context.stopxcell() + context.startxcell() + context(content) + context.stopxcell() + context.stopxrow() +end +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +\startlinecorrection \getbuffer[process] \stoplinecorrection + +Here is a solution that delegates even more to \LUA. The previous variants were +actually not that safe with repect to special characters and didn't handle +nested elements either but the next one does. + +\startbuffer[demo] +<?xml version="1.0" encoding="utf-8"?> + +<a> + <b> <c>#1</c> <d>Text</d> </b> + <b> <c>#2</c> <d>More text</d> </b> + <b> <c>#2</c> <d>Even more text</d> </b> + <b> <c>#2</c> <d>And more</d> </b> + <b> <c>#3</c> <d>And even more</d> </b> + <b> <c>#2</c> <d>Something <i>nested</i> </d> </b> +</a> +\stopbuffer + +\typebuffer[demo] + +We also need to map the \type {i} element. + +\startbuffer +\startxmlsetups xml:a + \starttexcode + \xmlfunction{#1}{test_a} + \stoptexcode +\stopxmlsetups + +\startxmlsetups xml:c + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:d + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:i + {\em\xmlflush{#1}} +\stopxmlsetups + +\startluacode +function xml.functions.test_a(t) + context.startxtable() + local previous = false + for b in xml.collected(lxml.getid(t),"/b") do + context.startxrow() + local current = xml.text(b,"/c") + context.startxcell { + background = "color", + backgroundcolor = (previous == current) and "colorone" or "colortwo", + foregroundstyle = "bold", + foregroundcolor = "white", + } + lxml.first(b,"/c") + context.stopxcell() + context.startxcell() + lxml.first(b,"/d") + context.stopxcell() + previous = current + context.stopxrow() + end + context.stopxtable() +end +\stopluacode + +\startxmlsetups xml:test_setups + \xmlsetsetup{#1}{a|b|c|d|i}{xml:*} +\stopxmlsetups + +\xmlregisterdocumentsetup{example-5}{xml:test_setups} + +\xmlprocessbuffer{example-5}{demo}{} +\stopbuffer + +\typebuffer + +\startlinecorrection \getbuffer \stoplinecorrection + +The question is, do we really need \LUA ? Often we don't, apart maybe from an +occasional special finalizer. A pure \TEX\ solution is given next: + +\startbuffer +\startxmlsetups xml:a + \glet\MyPreviousTitle\empty + \glet\MyCurrentTitle \empty + \startembeddedxtable + \xmlflush{#1} + \stopembeddedxtable +\stopxmlsetups + +\startxmlsetups xml:b + \startxrow + \xmlflush{#1} + \stopxrow +\stopxmlsetups + +\startxmlsetups xml:c + \xdef\MyCurrentTitle{\xmltext{#1}{.}} + \doifelse {\MyPreviousTitle} {\MyCurrentTitle} { + \startxcell + [background=color, + backgroundcolor=colorone, + foregroundstyle=bold, + foregroundcolor=white] + } { + \glet\MyPreviousTitle\MyCurrentTitle + \startxcell + [background=color, + backgroundcolor=colortwo, + foregroundstyle=bold, + foregroundcolor=white] + } + \xmlflush{#1} + \stopxcell +\stopxmlsetups + +\startxmlsetups xml:d + \startxcell + \xmlflush{#1} + \stopxcell +\stopxmlsetups + +\startxmlsetups xml:i + {\em\xmlflush{#1}} +\stopxmlsetups + +\startxmlsetups xml:test_setups + \xmlsetsetup{#1}{*}{xml:*} +\stopxmlsetups + +\xmlregisterdocumentsetup{example-5}{xml:test_setups} + +\xmlprocessbuffer{example-5}{demo}{} +\stopbuffer + +\typebuffer + +\startlinecorrection \getbuffer \stoplinecorrection + +You can even save a few lines of code: + +\starttyping +\startxmlsetups xml:c + \xdef\MyCurrentTitle{\xmltext{#1}{.}} + \startxcell + [background=color, + backgroundcolor=color\ifx\MyPreviousTitle\MyCurrentTitle one\else two\fi, + foregroundstyle=bold, + foregroundcolor=white] + \xmlflush{#1} + \stopxcell + \glet\MyPreviousTitle\MyCurrentTitle +\stopxmlsetups +\stoptyping + +Or if you prefer: + +\starttyping +\startxmlsetups xml:c + \xdef\MyCurrentTitle{\xmltext{#1}{.}} + \doifelse {\MyPreviousTitle} {\MyCurrentTitle} { + \xmlsetup{#1}{xml:c:one} + } { + \xmlsetup{#1}{xml:c:two} + } +\stopxmlsetups + +\startxmlsetups xml:c:one + \startxcell + [background=color, + backgroundcolor=colorone, + foregroundstyle=bold, + foregroundcolor=white] + \xmlflush{#1} + \stopxcell +\stopxmlsetups + +\startxmlsetups xml:c:two + \startxcell + [background=color, + backgroundcolor=colortwo, + foregroundstyle=bold, + foregroundcolor=white] + \xmlflush{#1} + \stopxcell + \global\let\MyPreviousTitle\MyCurrentTitle +\stopxmlsetups +\stoptyping + +These examples demonstrate that it doesn't hurt to know a little bit of \TEX\ +programming: defining macros and basic comparisons can come in handy. There are +examples in the test suite, you can peek in the source code, you can consult +the wiki or you can just ask on the list. + +\stopsection + +\startsection[title=last match] + +For the next example we use the following \XML\ input: + +\startbuffer[demo] +<?xml version "1.0"?> +<document> + <section id="1"> + <content> + <p>first</p> + <p>second</p> + </content> + </section> + <section id="2"> + <content> + <p>third</p> + <p>fourth</p> + </content> + </section> +</document> +\stopbuffer + +\typebuffer[demo] + +If you check if some element is present and then act accordingly, you can +end up with doing the same lookup twice. Although it might sound inefficient, +in practice it's often not measureable. + +\startbuffer +\startxmlsetups xml:demo:document + \type{\xmlall{#1}{/section[@id='2']/content/p}}\par + \xmldoif{#1}{/section[@id='2']/content/p} { + \xmlall{#1}{/section[@id='2']/content/p} + } + \type{\xmllastmatch}\par + \xmldoif{#1}{/section[@id='2']/content/p} { + \xmllastmatch + } + \type{\xmlall{#1}{last-match::}}\par + \xmldoif{#1}{/section[@id='2']/content/p} { + \xmlall{#1}{last-match::} + } + \type{\xmlfilter{#1}{last-match::/command(xml:demo:p)}}\par + \xmldoif{#1}{/section[@id='2']/content/p} { + \xmlfilter{#1}{last-match::/command(xml:demo:p)} + } +\stopxmlsetups + +\startxmlsetups xml:demo:p + \quad\xmlflush{#1}\endgraf +\stopxmlsetups + +\startxmlsetups xml:demo:base + \xmlsetsetup{#1}{document|p}{xml:demo:*} +\stopxmlsetups + +\xmlregisterdocumentsetup{example-6}{xml:demo:base} + +\xmlprocessbuffer{example-6}{demo}{} +\stopbuffer + +\typebuffer + +In the second check we just flush the last match, so effective we do an \type +{\xmlall} here. The third and fourth alternatives demonstrate how we can use +\type {last-match} as axis. The gain is 10\% or more on the lookup but of course +typesetting often takes relatively more time than the lookup. + +\startpacked +\getbuffer +\stoppacked + +\stopsection + +\startsection[title=Finalizers] + +The \XML\ parser is also available outside \TEX. Here is an example of its usage. +We pipe the result to \TEX\ but you can do with \type {t} whatever you like. + +\startbuffer +local x = xml.load("manual-demo-1.xml") +local t = { } + +for c in xml.collected(x,"//*") do + if not c.special and not t[c.tg] then + t[c.tg] = true + end +end + +context.tocontext(table.sortedkeys(t)) +\stopbuffer + +% \typebuffer + +This returns: + +\ctxluabuffer + +We can wrap this in a finalizer: + +\startbuffer +xml.finalizers.taglist = function(collected) + local t = { } + for i=1,#collected do + local c = collected[i] + if not c.special then + local tg = c.tg + if tg and not t[tg] then + t[tg] = true + end + end + end + return table.sortedkeys(t) +end +\stopbuffer + +\typebuffer + +Or in a more extensive one: + +\startbuffer +xml.finalizers.taglist = function(collected,parenttoo) + local t = { } + for i=1,#collected do + local c = collected[i] + if not c.special then + local tg = c.tg + if tg and not t[tg] then + t[tg] = true + end + if parenttoo then + local p = c.__p__ + if p and not p.special then + local tg = p.tg .. ":" .. tg + if tg and not t[tg] then + t[tg] = true + end + end + end + end + end + return table.sortedkeys(t) +end +\stopbuffer + +\typebuffer \ctxluabuffer + +Usage is as follows: + +\startbuffer +local x = xml.load("manual-demo-1.xml") +local t = xml.applylpath(x,"//*/taglist()") + +context.tocontext(t) +\stopbuffer + +\typebuffer + +And indeed we get: + +\ctxluabuffer + +But we can also say: + +\startbuffer +local x = xml.load("manual-demo-1.xml") +local t = xml.applylpath(x,"//*/taglist(true)") + +context.tocontext(t) +\stopbuffer + +\typebuffer + +Now we get: + +\ctxluabuffer + +\stopsection + +\startsection[title=Pure xml] + +One might wonder how a \TEX\ macro package would look like when backslashes, +dollars and percent signs would have no special meaning. In fact, it would be +rather useless as interpreting commands are triggered by such characters. Any +formatting or coding system needs such characters. Take \XML: angle brackets and +ampersands are really special. So, no matter what system we use, we do have to +deal with the (common) case where these characters need to be seen as they are. +Normally escaping is the solution. + +The \CONTEXT\ interface for \XML\ suffers from this as well. You really don't +want to know how many tricks are used for dealing with special characters and +entities: there are several ways these travel through the system and it is +possible to adapt and cheat. Especially roundtripped data (via tuc file) puts +some demands on the system because when ts \XML\ can become \TEX\ and vise versa. +The next example (derived from a mail on the list) demonstrates this: + +\starttyping +\startbuffer[demo] +<doc> + <pre><code>\ConTeXt\ is great</code></pre> + + <pre><code>but you need to know some tricks</code></pre> +</doc> +\stopbuffer + +\startxmlsetups xml:initialize + \xmlsetsetup{#1}{doc|p|code}{xml:*} + \xmlsetsetup{#1}{pre/code}{xml:pre:code} +\stopxmlsetups + +\xmlregistersetup{xml:initialize} + +\startxmlsetups xml:doc + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:pre:code + no solution + \comment[symbol=Key, location=inmargin,color=yellow]{\xmlflush{#1}} + \par + solution one \begingroup + \expandUx + \comment[symbol=Key, location=inmargin,color=yellow]{\xmlflush{#1}} + \endgroup + \par + solution two + \comment[symbol=Key, location=inmargin,color=yellow]{\xmlpure{#1}} + \par + \xmlprettyprint{#1}{tex} +\stopxmlsetups + +\xmlprocessbuffer{main}{demo}{} +\stoptyping + +The first comment (an interactive feature of \PDF\ comes out as: + +\starttyping +\Ux {5C}ConTeXt\Ux {5C} is great +\stoptyping + +The second and third comment are okay. It's one of the reasons why we have \type +{\xmlpure}. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-expressions.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-expressions.tex new file mode 100644 index 000000000..0c126f2f8 --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-expressions.tex @@ -0,0 +1,645 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-expressions + +\startchapter[title={Expressions and filters}] + +\startsection[title={path expressions}] + +In the previous chapters we used \cmdinternal {cd:lpath} expressions, which are a variant +on \type {xpath} expressions as in \XSLT\ but in this case more geared towards +usage in \TEX. This mechanisms will be extended when demands are there. + +A path is a sequence of matches. A simple path expression is: + +\starttyping +a/b/c/d +\stoptyping + +Here each \type {/} goes one level deeper. We can go backwards in a lookup with +\type {..}: + +\starttyping +a/b/../d +\stoptyping + +We can also combine lookups, as in: + +\starttyping +a/(b|c)/d +\stoptyping + +A negated lookup is preceded by a \type {!}: + +\starttyping +a/(b|c)/!d +\stoptyping + +A wildcard is specified with a \type {*}: + +\starttyping +a/(b|c)/!d/e/*/f +\stoptyping + +In addition to these tag based lookups we can use attributes: + +\starttyping +a/(b|c)/!d/e/*/f[@type=whatever] +\stoptyping + +An \type {@} as first character means that we are dealing with an attribute. +Within the square brackets there can be boolean expressions: + +\starttyping +a/(b|c)/!d/e/*/f[@type=whatever and @id>100] +\stoptyping + +You can use functions as in: + +\starttyping +a/(b|c)/!d/e/*/f[something(text()) == "oeps"] +\stoptyping + +There are a couple of predefined functions: + +\starttabulate[|l|l|p|] +\NC \type{rootposition} \type{order} \NC number \NC the index of the matched root element (kind of special) \NC \NR +\NC \type{position} \NC number \NC the current index of the matched element in the match list \NC \NR +\NC \type{match} \NC number \NC the current index of the matched element sub list with the same parent \NC \NR +\NC \type{first} \NC number \NC \NC \NR +\NC \type{last} \NC number \NC \NC \NR +\NC \type{index} \NC number \NC the current index of the matched element in its parent list \NC \NR +\NC \type{firstindex} \NC number \NC \NC \NR +\NC \type{lastindex} \NC number \NC \NC \NR +\NC \type{element} \NC number \NC the element's index \NC \NR +\NC \type{firstelement} \NC number \NC \NC \NR +\NC \type{lastelement} \NC number \NC \NC \NR +\NC \type{text} \NC string \NC the textual representation of the matched element \NC \NR +\NC \type{content} \NC table \NC the node of the matched element \NC \NR +\NC \type{name} \NC string \NC the full name of the matched element: namespace and tag \NC \NR +\NC \type{namespace} \type{ns} \NC string \NC the namespace of the matched element \NC \NR +\NC \type{tag} \NC string \NC the tag of the matched element \NC \NR +\NC \type{attribute} \NC string \NC the value of the attribute with the given name of the matched element \NC \NR +\stoptabulate + +There are fundamental differences between \type {position}, \type {match} and +\type {index}. Each step results in a new list of matches. The \type {position} +is the index in this new (possibly intermediate) list. The \type {match} is also +an index in this list but related to the specific match of element names. The +\type {index} refers to the location in the parent element. + +Say that we have: + +\starttyping +<collection> + <resources> + <manual> + <screen>.1.</screen> + <paper>.1.</paper> + </manual> + <manual> + <paper>.2.</paper> + <screen>.2.</screen> + </manual> + <resources> + <resources> + <manual> + <screen>.3.</screen> + <paper>.3.</paper> + </manual> + <resources> +<collection> +\stoptyping + +The following then applies: + +\starttabulate[|l|l|] +\NC \type {collection/resources/manual[position()==1]/paper} \NC \type{.1.} \NC \NR +\NC \type {collection/resources/manual[match()==1]/paper} \NC \type{.1.} \type{.3.} \NC \NR +\NC \type {collection/resources/manual/paper[index()==1]} \NC \type{.2.} \NC \NR +\stoptabulate + +In most cases the \type {position} test is more restrictive than the \type +{match} test. + +You can pass your own functions too. Such functions are defined in the \type +{xml.expressions} namespace. We have defined a few shortcuts: + +\starttabulate[|l|l|] +\NC \type {find(str,pattern)} \NC \type{string.find} \NC \NR +\NC \type {contains(str)} \NC \type{string.find} \NC \NR +\NC \type {oneof(str,...)} \NC is \type{str} in list \NC \NR +\NC \type {upper(str)} \NC \type{characters.upper} \NC \NR +\NC \type {lower(str)} \NC \type{characters.lower} \NC \NR +\NC \type {number(str)} \NC \type{tonumber} \NC \NR +\NC \type {boolean(str)} \NC \type{toboolean} \NC \NR +\NC \type {idstring(str)} \NC removes leading hash \NC \NR +\NC \type {name(index)} \NC full tag name \NC \NR +\NC \type {tag(index)} \NC tag name \NC \NR +\NC \type {namespace(index)} \NC namespace of tag \NC \NR +\NC \type {text(index)} \NC content \NC \NR +\NC \type {error(str)} \NC quit and show error \NC \NR +\NC \type {quit()} \NC quit \NC \NR +\NC \type {print()} \NC print message \NC \NR +\NC \type {count(pattern)} \NC number of matches \NC \NR +\NC \type {child(pattern)} \NC take child that matches \NC \NR +\stoptabulate + + +You can also use normal \LUA\ functions as long as you make sure that you pass +the right arguments. There are a few predefined variables available inside such +functions. + +\starttabulate[|Tl|l|p|] +\NC \type{list} \NC table \NC the list of matches \NC \NR +\NC \type{l} \NC number \NC the current index in the list of matches \NC \NR +\NC \type{ll} \NC element \NC the current element that matched \NC \NR +\NC \type{order} \NC number \NC the position of the root of the path \NC \NR +\stoptabulate + +The given expression between \type {[]} is converted to a \LUA\ expression so you +can use the usual operators: + +\starttyping +== ~= <= >= < > not and or () +\stoptyping + +In addition, \type {=} equals \type {==} and \type {!=} is the same as \type +{~=}. If you mess up the expression, you quite likely get a \LUA\ error message. + +\stopsection + +\startsection[title={css selectors}] + +\startbuffer[selector-001] +<?xml version="1.0" ?> + +<a> + <b class="one">b.one</b> + <b class="two">b.two</b> + <b class="one two">b.one.two</b> + <b class="three">b.three</b> + <b id="first">b#first</b> + <c>c</c> + <d>d e</d> + <e>d e</e> + <e>d e e</e> + <d>d f</d> + <f foo="bar">@foo = bar</f> + <f bar="foo">@bar = foo</f> + <f bar="foo1">@bar = foo1</f> + <f bar="foo2">@bar = foo2</f> + <f bar="foo3">@bar = foo3</f> + <f bar="foo+4">@bar = foo+4</f> + <g>g</g> + <g><gg><d>g gg d</d></gg></g> + <g><gg><f>g gg f</f></gg></g> + <g><gg><f class="one">g gg f.one</f></gg></g> + <g>g</g> + <g><gg><f class="two">g gg f.two</f></gg></g> + <g><gg><f class="three">g gg f.three</f></gg></g> + <g><f class="one">g f.one</f></g> + <g><f class="three">g f.three</f></g> + <h whatever="four five six">@whatever = four five six</h> +</a> +\stopbuffer + +\xmlloadbuffer{selector-001}{selector-001} + +\startxmlsetups xml:selector:demo + \advance\scratchcounter\plusone + \inleftmargin{\the\scratchcounter}\ignorespaces\xmlverbatim{#1}\par +\stopxmlsetups + +\unexpanded\def\showCSSdemo#1#2% + {\blank + \textrule{\tttf#2} + \startlines + \dontcomplain + \tttf \obeyspaces + \scratchcounter\zerocount + \xmlcommand{#1}{#2}{xml:selector:demo} + \stoplines + \blank} + +The \CSS\ approach to filtering is a bit different from the path based one and is +supported too. In fact, you can combine both methods. Depending on what you +select, the \CSS\ one can be a little bit faster too. It has the advantage that +one can select more in one go but at the same time looks a bit less attractive. +This method was added just to show that it can be done but might be useful too. A +selector is given between curly braces (after all \CSS\ uses them and they have no +function yet in the parser. + +\starttyping +\xmlall{#1}{{foo bar .whatever, bar foo .whatever}} +\stoptyping + +The following methods are supported: + +\starttabulate[|T||] +\NC element \NC all tags element \NC \NR +\NC element-1 > element-2 \NC all tags element-2 with parent tag element-1 \NC \NR +\NC element-1 + element-2 \NC all tags element-2 preceded by tag element-1 \NC \NR +\NC element-1 ~ element-2 \NC all tags element-2 preceded by tag element-1 \NC \NR +\NC element-1 element-2 \NC all tags element-2 inside tag element-1 \NC \NR +\NC [attribute] \NC has attribute \NC \NR +\NC [attribute=value] \NC attribute equals value\NC \NR +\NC [attribute\lettertilde =value] \NC attribute contains value (space is separator) \NC \NR +\NC [attribute\letterhat ="value"] \NC attribute starts with value \NC \NR +\NC [attribute\letterdollar="value"] \NC attribute ends with value \NC \NR +\NC [attribute*="value"] \NC attribute contains value \NC \NR +\NC .class \NC has class \NC \NR +\NC \letterhash id \NC has id \NC \NR +\NC :nth-child(n) \NC the child at index n \NC \NR +\NC :nth-last-child(n) \NC the child at index n from the end \NC \NR +\NC :first-child \NC the first child \NC \NR +\NC :last-child \NC the last child \NC \NR +\NC :nth-of-type(n) \NC the match at index n \NC \NR +\NC :nth-last-of-type(n) \NC the match at index n from the end \NC \NR +\NC :first-of-type \NC the first match \NC \NR +\NC :last-of-type \NC the last match \NC \NR +\NC :only-of-type \NC the only match or nothing \NC \NR +\NC :only-child \NC the only child or nothing \NC \NR +\NC :empty \NC only when empty \NC \NR +\NC :root \NC the whole tree \NC \NR +\stoptabulate + +The next pages show some examples. For that we use the demo file: + +\typebuffer[selector-001] + +The class and id selectors often only make sense in \HTML\ like documents but they +are supported nevertheless. They are after all just shortcuts for filtering by +attribute. The class filtering is special in the sense that it checks for a class +in a list of classes given in an attribute. + +\showCSSdemo{selector-001}{{.one}} +\showCSSdemo{selector-001}{{.one, .two}} +\showCSSdemo{selector-001}{{.one, .two, \letterhash first}} + +Attributes can be filtered by presence, value, partial value and such. Quotes are +optional but we advice to use them. + +\showCSSdemo{selector-001}{{[foo], [bar=foo]}} +\showCSSdemo{selector-001}{{[bar\lettertilde=foo]}} +\showCSSdemo{selector-001}{{[bar\letterhat="foo"]}} +\showCSSdemo{selector-001}{{[whatever\lettertilde="five"]}} + +You can of course combine the methods as in: + +\showCSSdemo{selector-001}{{g f .one, g f .three}} +\showCSSdemo{selector-001}{{g > f .one, g > f .three}} +\showCSSdemo{selector-001}{{d + e}} +\showCSSdemo{selector-001}{{d ~ e}} +\showCSSdemo{selector-001}{{d ~ e, g f .one, g f .three}} + +You can also negate the result by using \type {:not} on a simple expression: + +\showCSSdemo{selector-001}{{:not([whatever\lettertilde="five"])}} +\showCSSdemo{selector-001}{{:not(d)}} + +The child and match selectors are also supported: + +\showCSSdemo{selector-001}{{a:nth-child(3)}} +\showCSSdemo{selector-001}{{a:nth-last-child(3)}} +\showCSSdemo{selector-001}{{g:nth-of-type(3)}} +\showCSSdemo{selector-001}{{g:nth-last-of-type(3)}} +\showCSSdemo{selector-001}{{a:first-child}} +\showCSSdemo{selector-001}{{a:last-child}} +\showCSSdemo{selector-001}{{e:first-of-type}} +\showCSSdemo{selector-001}{{gg d:only-of-type}} + +Instead of numbers you can also give the \type {an} and \type {an+b} formulas +as well as the \type {odd} and \type {even} keywords: + +\showCSSdemo{selector-001}{{a:nth-child(even)}} +\showCSSdemo{selector-001}{{a:nth-child(odd)}} +\showCSSdemo{selector-001}{{a:nth-child(3n+1)}} +\showCSSdemo{selector-001}{{a:nth-child(2n+3)}} + +There are a few special cases: + +\showCSSdemo{selector-001}{{g:empty}} +\showCSSdemo{selector-001}{{g:root}} +\showCSSdemo{selector-001}{{*}} + +Combining the \CSS\ methods with the regular ones is possible: + +\showCSSdemo{selector-001}{{g gg f .one}} +\showCSSdemo{selector-001}{g/gg/f[@class='one']} +\showCSSdemo{selector-001}{g/{gg f .one}} + +\startbuffer[selector-002] +<?xml version="1.0" ?> + +<document> + <title class="one" >title 1</title> + <title class="two" >title 2</title> + <title class="one" >title 3</title> + <title class="three">title 4</title> +</document> +\stopbuffer + +The next examples we use this file: + +\typebuffer[selector-002] + +\xmlloadbuffer{selector-002}{selector-002} + +When we filter from this (not too well structured) tree we can use both +methods to achieve the same: + +\showCSSdemo{selector-002}{{document title .one, document title .three}} + +\showCSSdemo{selector-002}{/document/title[(@class='one') or (@class='three')]} + +However, imagine this file: + +\startbuffer[selector-003] +<?xml version="1.0" ?> + +<document> + <title class="one">title 1</title> + <subtitle class="sub">title 1.1</subtitle> + <title class="two">title 2</title> + <subtitle class="sub">title 2.1</subtitle> + <title class="one">title 3</title> + <subtitle class="sub">title 3.1</subtitle> + <title class="two">title 4</title> + <subtitle class="sub">title 4.1</subtitle> +</document> +\stopbuffer + +\typebuffer[selector-003] + +\xmlloadbuffer{selector-003}{selector-003} + +The next filter in easier with the \CSS\ selector methods because these accumulate +independent (simple) expressions: + +\showCSSdemo{selector-003}{{document title .one + subtitle, document title .two + subtitle}} + +Watch how we get an output in the document order. Because we render a sequential document +a combined filter will trigger a sorting pass. + +\stopsection + +\startsection[title={functions as filters}] + +At the \LUA\ end a whole \cmdinternal {cd:lpath} expression results in a (set of) node(s) +with its environment, but that is hardly usable in \TEX. Think of code like: + +\starttyping +for e in xml.collected(xml.load('text.xml'),"title") do + -- e = the element that matched +end +\stoptyping + +The older variant is still supported but you can best use the previous variant. + +\starttyping +for r, d, k in xml.elements(xml.load('text.xml'),"title") do + -- r = root of the title element + -- d = data table + -- k = index in data table +end +\stoptyping + +Here \type {d[k]} points to the \type {title} element and in this case all titles +in the tree pass by. In practice this kind of code is encapsulated in function +calls, like those returning elements one by one, or returning the first or last +match. The result is then fed back into \TEX, possibly after being altered by an +associated setup. We've seen the wrappers to such functions already in a previous +chapter. + +In addition to the previously discussed expressions, one can add so called +filters to the expression, for instance: + +\starttyping +a/(b|c)/!d/e/text() +\stoptyping + +In a filter, the last part of the \cmdinternal {cd:lpath} expression is a +function call. The previous example returns the text of each element \type {e} +that results from matching the expression. When running \TEX\ the following +functions are available. Some are also available when using pure \LUA. In \TEX\ +you can often use one of the macros like \type {\xmlfirst} instead of a \type +{\xmlfilter} with finalizer \type {first()}. The filter can be somewhat faster +but that is hardly noticeable. + +\starttabulate[|l|l|p|] +\NC \type {context()} \NC string \NC the serialized text with \TEX\ catcode regime \NC \NR +%NC \type {ctxtext()} \NC string \NC \NC \NR +\NC \type {function()} \NC string \NC depends on the function \NC \NR +% +\NC \type {name()} \NC string \NC the (remapped) namespace \NC \NR +\NC \type {tag()} \NC string \NC the name of the element \NC \NR +\NC \type {tags()} \NC list \NC the names of the element \NC \NR +% +\NC \type {text()} \NC string \NC the serialized text \NC \NR +\NC \type {upper()} \NC string \NC the serialized text uppercased \NC \NR +\NC \type {lower()} \NC string \NC the serialized text lowercased \NC \NR +\NC \type {stripped()} \NC string \NC the serialized text stripped \NC \NR +\NC \type {lettered()} \NC string \NC the serialized text only letters (cf. \UNICODE) \NC \NR +% +\NC \type {count()} \NC number \NC the number of matches \NC \NR +\NC \type {index()} \NC number \NC the matched index in the current path \NC \NR +\NC \type {match()} \NC number \NC the matched index in the preceding path \NC \NR +% +%NC \type {lowerall()} \NC string \NC \NC \NR +%NC \type {upperall()} \NC string \NC \NC \NR +% +\NC \type {attribute(name)} \NC content \NC returns the attribute with the given name \NC \NR +\NC \type {chainattribute(name)} \NC content \NC sidem, but backtracks till one is found \NC \NR +\NC \type {command(name)} \NC content \NC expands the setup with the given name for each found element \NC \NR +\NC \type {position(n)} \NC content \NC processes the \type {n}\high{th} instance of the found element \NC \NR +\NC \type {all()} \NC content \NC processes all instances of the found element \NC \NR +%NC \type {default} \NC content \NC all \NC \NR +\NC \type {reverse()} \NC content \NC idem in reverse order \NC \NR +\NC \type {first()} \NC content \NC processes the first instance of the found element \NC \NR +\NC \type {last()} \NC content \NC processes the last instance of the found element \NC \NR +\NC \type {concat(...)} \NC content \NC concatinates the match \NC \NC \NR +\NC \type {concatrange(from,to,...)} \NC content \NC concatinates a range of matches \NC \NC \NR +\stoptabulate + +The extra arguments of the concatinators are: \type {separator} (string), \type +{lastseparator} (string) and \type {textonly} (a boolean). + +These filters are in fact \LUA\ functions which means that if needed more of them +can be added. Indeed this happens in some of the \XML\ related \MKIV\ modules, +for instance in the \MATHML\ processor. + +\stopsection + +\startsection[title={example}] + +The number of commands is rather large and if you want to avoid them this is +often possible. Take for instance: + +\starttyping +\xmlall{#1}{/a/b[position()>3]} +\stoptyping + +Alternatively you can use: + +\starttyping +\xmlfilter{#1}{/a/b[position()>3]/all()} +\stoptyping + +and actually this is also faster as internally it avoids a function call. Of +course in practice this is hardly measurable. + +In previous examples we've already seen quite some expressions, and it might be +good to point out that the syntax is modelled after \XSLT\ but is not quite the +same. The reason is that we started with a rather minimal system and have already +styles in use that depend on compatibility. + +\starttyping +namespace:// axis node(set) [expr 1]..[expr n] / ... / filter +\stoptyping + +When we are inside a \CONTEXT\ run, the namespace is \type {tex}. Hoewever, if +you want not to print back to \TEX\ you need to be more explicit. Say that we +typeset examns and have a (not that logical) structure like: + +\starttyping +<question> + <text>...</text> + <answer> + <item>one</item> + <item>two</item> + <item>three</item> + </answer> + <alternative> + <condition>true</condition> + <score>1</score> + </alternative> + <alternative> + <condition>false</condition> + <score>0</score> + </alternative> + <alternative> + <condition>true</condition> + <score>2</score> + </alternative> +</question> +\stoptyping + +Say that we typeset the questions with: + +\starttyping +\startxmlsetups question + \blank + score: \xmlfunction{#1}{totalscore} + \blank + \xmlfirst{#1}{text} + \startitemize + \xmlfilter{#1}{/answer/item/command(answer:item)} + \stopitemize + \endgraf + \blank +\stopxmlsetups +\stoptyping + +Each item in the answer results in a call to: + +\starttyping +\startxmlsetups answer:item + \startitem + \xmlflush{#1} + \endgraf + \xmlfilter{#1}{../../alternative[position()=rootposition()]/ + condition/command(answer:condition)} + \stopitem +\stopxmlsetups +\stoptyping + +\starttyping +\startxmlsetups answer:condition + \endgraf + condition: \xmlflush{#1} + \endgraf +\stopxmlsetups +\stoptyping + +Now, there are two rather special filters here. The first one involves +calculating the total score. As we look forward we use a function to deal with +this. + +\starttyping +\startluacode +function xml.functions.totalscore(root) + local score = 0 + for e in xml.collected(root,"/alternative") do + score = score + xml.filter(e,"xml:///score/number()") or 0 + end + tex.write(score) +end +\stopluacode +\stoptyping + +Watch how we use the namespace to keep the results at the \LUA\ end. + +The second special trick shown here is to limit a match using the current +position of the root (\type {#}) match. + +As you can see, a path expression can be more than just filtering a few nodes. At +the end of this manual you will find a bunch of examples. + +\stopsection + +\startsection[title={tables}] + +If you want to know how the internal \XML\ tables look you can print such a +table: + +\starttyping +print(table.serialize(e)) +\stoptyping + +This produces for instance: + +% s = xml.convert("<document><demo label='whatever'>some text</demo></document>") +% print(table.serialize(xml.filter(s,"demo")[1])) + +\starttyping +t={ + ["at"]={ + ["label"]="whatever", + }, + ["dt"]={ "some text" }, + ["ns"]="", + ["rn"]="", + ["tg"]="demo", +} +\stoptyping + +The \type {rn} entry is the renamed namespace (when renaming is applied). If you +see tags like \type {@pi@} this means that we don't have an element, but (in this +case) a processing instruction. + +\starttabulate[|l|p|] +\NC \type {@rt@} \NC the root element \NC \NR +\NC \type {@dd@} \NC document definition \NC \NR +\NC \type {@cm@} \NC comment, like \type {<!-- whatever -->} \NC \NR +\NC \type {@cd@} \NC so called \type {CDATA} \NC \NR +\NC \type {@pi@} \NC processing instruction, like \type {<?whatever we want ?>} \NC \NR +\stoptabulate + +There are many ways to deal with the content, but in the perspective of \TEX\ +only a few matter. + +\starttabulate[|l|p|] +\NC \type {xml.sprint(e)} \NC print the content to \TEX\ and apply setups if needed \NC \NR +\NC \type {xml.tprint(e)} \NC print the content to \TEX\ (serialize elements verbose) \NC \NR +\NC \type {xml.cprint(e)} \NC print the content to \TEX\ (used for special content) \NC \NR +\stoptabulate + +Keep in mind that anything low level that you uncover is not part of the official +interface unless mentioned in this manual. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-filtering.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-filtering.tex new file mode 100644 index 000000000..5bb5a35de --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-filtering.tex @@ -0,0 +1,262 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-filtering + +\startchapter[title={Filtering content}] + +\startsection[title={\TEX\ versus \LUA}] + +It will not come as a surprise that we can access \XML\ files from \TEX\ as well +as from \LUA. In fact there are two methods to deal with \XML\ in \LUA. First +there are the low level \XML\ functions in the \type {xml} namespace. On top of +those functions there is a set of functions in the \type {lxml} namespace that +deals with \XML\ in a more \TEX ie way. Most of these have similar commands at +the \TEX\ end. + +\startbuffer +\startxmlsetups first:demo:one + \xmlfilter {#1} {artist/name[text()='Randy Newman']/.. + /albums/album[position()=3]/command(first:demo:two)} +\stopxmlsetups + +\startxmlsetups first:demo:two + \blank \start \tt + \xmldisplayverbatim{#1} + \stop \blank +\stopxmlsetups + +\xmlprocessfile{demo}{music-collection.xml}{first:demo:one} +\stopbuffer + +\typebuffer + +This gives the following snippet of verbatim \XML\ code. The indentation is +conform the indentation in the whole \XML\ file. \footnote {The (probably +outdated) \XML\ file contains the collection stores on my slimserver instance. +You can use the \type {mtxrun --script flac} to generate such files.} + +\doifmodeelse {atpragma} { + \getbuffer +} { + \typefile{xml-mkiv-01.xml} +} + +An alternative written in \LUA\ looks as follows: + +\startbuffer +\blank \start \tt \startluacode + local m = lxml.load("mine","music-collection.xml") -- m == lxml.id("mine") + local p = "artist/name[text()='Randy Newman']/../albums/album[position()=4]" + local l = lxml.filter(m,p) -- returns a list (with one entry) + lxml.displayverbatim(l[1]) +\stopluacode \stop \blank +\stopbuffer + +\typebuffer + +This produces: + +\doifmodeelse {atpragma} { + \getbuffer +} { + \typefile{xml-mkiv-02.xml} +} + +You can use both methods mixed but in practice we will use the \TEX\ commands in +regular styles and the mixture in modules, for instance in those dealing with +\MATHML\ and cals tables. For complex matters you can write your own finalizers +(the last action to be taken in a match) in \LUA\ and use them at the \TEX\ end. + +\stopsection + +\startsection[title={a few details}] + +In \CONTEXT\ setups are a rather common variant on macros (\TEX\ commands) but +with their own namespace. An example of a setup is: + +\starttyping +\startsetup doc:print + \setuppapersize[A4][A4] +\stopsetup + +\startsetup doc:screen + \setuppapersize[S6][S4] +\stopsetup +\stoptyping + +Given the previous definitions, later on we can say something like: + +\starttyping +\doifmodeelse {paper} { + \setup[doc:print] +} { + \setup[doc:screen] +} +\stoptyping + +Another example is: + +\starttyping +\startsetup[doc:header] + \marking[chapter] + \space + -- + \space + \pagenumber +\stopsetup +\stoptyping + +in combination with: + +\starttyping +\setupheadertexts[\setup{doc:header}] +\stoptyping + +Here the advantage is that instead of ending up with an unreadable header +definitions, we use a nicely formatted setup. An important property of setups and +the reason why they were introduced long ago is that spaces and newlines are +ignored in the definition. This means that we don't have to worry about so called +spurious spaces but it also means that when we do want a space, we have to use +the \type {\space} command. + +The only difference between setups and \XML\ setups is that the following ones +get an argument (\type {#1}) that reflects the current node in the \XML\ tree. + +\stopsection + +\startsection[title={CDATA}] + +What to do with \type {CDATA}? There are a few methods at tle \LUA\ end for +dealing with it but here we just mention how you can influence the rendering. +There are four macros that play a role here: + +\starttyping +\unexpanded\def\xmlcdataobeyedline {\obeyedline} +\unexpanded\def\xmlcdataobeyedspace{\strut\obeyedspace} +\unexpanded\def\xmlcdatabefore {\begingroup\tt} +\unexpanded\def\xmlcdataafter {\endgroup} +\stoptyping + +Technically you can overload them but beware of side effects. Normally you won't +see much \type {CDATA} and whenever we do, it involves special data that needs +very special treatment anyway. + +\stopsection + +\startsection[title={Entities}] + +As usual with any way of encoding documents you need escapes in order to encode +the characters that are used in tagging the content, embedding comments, escaping +special characters in strings (in programming languages), etc. In \XML\ this +means that in order characters like \type {<} you need an escape like \type +{<} and in order then to encode an \type {&} you need \type {&}. + +In a typesetting workflow using a programming language like \TEX, another problem +shows up. There we have different special characters, like \type {$ $} for triggering +math, but also the backslash, braces etc. Even one such special character is already +enough to have yet another escaping mechanism at work. + +Ideally a user should not worry about these issues but it helps figuring out issues +when you know what happens under the hood. Also it is good to know that in the +code there are several ways to deal with these issues. Take the following document: + +\starttyping +<text> + Here we have a bit of a <&mess>: + + # # + % % + \ \ + { { + | | + } } + ~ ~ +</text> +\stoptyping + +When the file is read the \type {<} entity will be replaced by \type {<} and +the \type {>} by \type {>}. The numeric entities will be replaced by the +characters they refer to. The \type {&mess} is kind of special. We do preload +a huge list of more or less standardized entities but \type {mess} is not in +there. However, it is possible to have it defined in the document preamble, like: + +\starttyping +<!DOCTYPE dummy SYSTEM "dummy.dtd" [ + <!ENTITY mess "what a mess" > +]> +\stoptyping + +or even this: + +\starttyping +<!DOCTYPE dummy SYSTEM "dummy.dtd" [ + <!ENTITY mess "<p>what a mess</p>" > +]> +\stoptyping + +You can also define it in your document style using one of: + +\startxmlcmd {\cmdbasicsetup{xmlsetentity}} + replaces entity with name \cmdinternal {cd:name} by \cmdinternal {cd:text} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmltexentity}} + replaces entity with name \cmdinternal {cd:name} by \cmdinternal {cd:text} + typeset under a \TEX\ regime +\stopxmlcmd + +Such a definition will always have a higher priority than the one defined +in the document. Anyway, when the document is read in all entities are +resolved and those that need a special treatment because they map to some +text are stored in such a way that we can roundtrip them. As a consequence, +as soon as the content gets pushed into \TEX, we need not only to intercept +special characters but also have to make sure that the following works: + +\starttyping +\xmltexentity {tex} {\TEX} +\stoptyping + +Here the backslash starts a control sequence while in regular content a +backslash is just that: a backslash. + +Special characters are really special when we have to move text around +in a \TEX\ ecosystem. + +\starttyping +<text> + <title>About #3</title> +</text> +\stoptyping + +If we map and define title as follows: + +\starttyping +\startxmlsetup xml:title + \title{\xmlflush{#1}} +\stopxmlsetup +\stoptyping + +normally something \type {\xmlflush {id::123}} will be written to the +auxiliary file and in most cases that is quite okay, but if we have this: + +\starttyping +\setuphead[title][expansion=yes] +\stoptyping + +then we don't want the \type {#} to end up as hash because later on \TEX\ +can get very confused about it because it sees some argument then in a +probably unexpected way. This is solved by escaping the hash like this: + +\starttyping +About \Ux{23}3 +\stoptyping + +The \type {\Ux} command will convert its hexadecimal argument into a +character. Of course one then needs to typeset such a text under a \TEX\ +character regime but that is normally the case anyway. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-introduction.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-introduction.tex new file mode 100644 index 000000000..e7f0124da --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-introduction.tex @@ -0,0 +1,42 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-introduction + +\startchapter[title={Introduction}] + +This manual presents the \MKIV\ way of dealing with \XML. Although the +traditional \MKII\ streaming parser has a charming simplicity in its control, for +complex documents the tree based \MKIV\ method is more convenient. It is for this +reason that the old method has been removed from \MKIV. If you are familiar with +\XML\ processing in \MKII, then you will have noticed that the \MKII\ commands +have \type {XML} in their name. The \MKIV\ commands have a lowercase \type {xml} +in their names. That way there is no danger for confusion or a mixup. + +You may wonder why we do these manipulations in \TEX\ and not use \XSLT\ (or +other transformation methods) instead. The advantage of an integrated approach is +that it simplifies usage. Think of not only processing the document, but also +using \XML\ for managing resources in the same run. An \XSLT\ approach is just as +verbose (after all, you still need to produce \TEX\ code) and probably less +readable. In the case of \MKIV\ the integrated approach is also faster and gives +us the option to manipulate content at runtime using \LUA. It has the additional +advantage that to some extend we can handle a mix of \TEX\ and \XML\ because we +know when we're doing one or the other. + +This manual is dedicated to Taco Hoekwater, one of the first \CONTEXT\ users, and +also the first to use it for processing \XML. Who could have thought at that time +that we would have a more convenient way of dealing with those angle brackets. +The second version for this manual is dedicated to Thomas Schmitz, a power user +who occasionally became victim of the evolving mechanisms. + +\blank + +\startlines +Hans Hagen +\PRAGMA +Hasselt NL +2008\endash2016 +\stoplines + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-lookups.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-lookups.tex new file mode 100644 index 000000000..e6afaa948 --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-lookups.tex @@ -0,0 +1,314 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-lookups + +\startchapter[title={Lookups using lpaths}] + +\startsection[title={introduction}] + +There is not that much system in the following examples. They resulted from tests +with different documents. The current implementation evolved out of the +experimental code. For instance, I decided to add the multiple expressions in row +handling after a few email exchanges with Jean|-|Michel Huffen. + +One of the main differences between the way \XSLT\ resolves a path and our way is +the anchor. Take: + +\starttyping +/something +something +\stoptyping + +The first one anchors in the current (!) element so it will only consider direct +children. The second one does a deep lookup and looks at the descendants as well. +Furthermore we have a few extra shortcuts like \type {**} in \type {a/**/b} which +represents all descendants. + +The expressions (between square brackets) has to be valid \LUA\ and some +preprocessing is done to resolve the built in functions. So, you might use code +like: + +\starttyping +my_lpeg_expression:match(text()) == "whatever" +\stoptyping + +given that \type {my_lpeg_expression} is known. In the examples below we use the +visualizer to show the steps. Some are shown more than once as part of a set. + +\stopsection + +\startsection[title={special cases}] + +\xmllshow{} +\xmllshow{*} +\xmllshow{.} +\xmllshow{/} + +\stopsection + +\startsection[title={wildcards}] + +\xmllshow{*} +\xmllshow{*:*} +\xmllshow{/*} +\xmllshow{/*:*} +\xmllshow{*/*} +\xmllshow{*:*/*:*} + +\xmllshow{a/*} +\xmllshow{a/*:*} +\xmllshow{/a/*} +\xmllshow{/a/*:*} + +\xmllshow{/*} +\xmllshow{/**} +\xmllshow{/***} + +\stopsection + +\startsection[title={multiple steps}] + +\xmllshow{answer} +\xmllshow{answer/test/*} +\xmllshow{answer/test/child::} +\xmllshow{answer/*} +\xmllshow{answer/*[tag()='p' and position()=1 and text()!='']} + +\stopsection + +\startsection[title={pitfals}] + +\xmllshow{[oneof(lower(@encoding),'tex','context','ctx')]} +\xmllshow{.[oneof(lower(@encoding),'tex','context','ctx')]} + +\stopsection + +\startsection[title={more special cases}] + +\xmllshow{**} +\xmllshow{*} +\xmllshow{..} +\xmllshow{.} +\xmllshow{//} +\xmllshow{/} + +\xmllshow{**/} +\xmllshow{**/*} +\xmllshow{**/.} +\xmllshow{**//} + +\xmllshow{*/} +\xmllshow{*/*} +\xmllshow{*/.} +\xmllshow{*//} + +\xmllshow{/**/} +\xmllshow{/**/*} +\xmllshow{/**/.} +\xmllshow{/**//} + +\xmllshow{/*/} +\xmllshow{/*/*} +\xmllshow{/*/.} +\xmllshow{/*//} + +\xmllshow{./} +\xmllshow{./*} +\xmllshow{./.} +\xmllshow{.//} + +\xmllshow{../} +\xmllshow{../*} +\xmllshow{../.} +\xmllshow{..//} + +\stopsection + +\startsection[title={more wildcards}] + +\xmllshow{one//two} +\xmllshow{one/*/two} +\xmllshow{one/**/two} +\xmllshow{one/***/two} +\xmllshow{one/x//two} +\xmllshow{one//x/two} +\xmllshow{//x/two} + +\stopsection + +\startsection[title={special axis}] + +\xmllshow{descendant::whocares/ancestor::whoknows} +\xmllshow{descendant::whocares/ancestor::whoknows/parent::} +\xmllshow{descendant::whocares/ancestor::} +\xmllshow{child::something/child::whatever/child::whocares} +\xmllshow{child::something/child::whatever/child::whocares|whoknows} +\xmllshow{child::something/child::whatever/child::(whocares|whoknows)} +\xmllshow{child::something/child::whatever/child::!(whocares|whoknows)} +\xmllshow{child::something/child::whatever/child::(whocares)} +\xmllshow{child::something/child::whatever/child::(whocares)[position()>2]} +\xmllshow{child::something/child::whatever[position()>2][position()=1]} +\xmllshow{child::something/child::whatever[whocares][whocaresnot]} +\xmllshow{child::something/child::whatever[whocares][not(whocaresnot)]} +\xmllshow{child::something/child::whatever/self::whatever} + +There is also \type {last-match::} that starts with the last found set of nodes. +This can save some run time when you do lots of tests combined with a same check +afterwards. There is however one pitfall: you never know what is done with that +last match in the setup that gets called nested. Take the following example: + +\starttyping +\startbuffer[test] +<something> + <crap> <crapa> <crapb> <crapc> <crapd> + <crape> + done 1 + </crape> + </crapd> </crapc> </crapb> </crapa> + <crap> <crapa> <crapb> <crapc> <crapd> + <crape> + done 2 + </crape> + </crapd> </crapc> </crapb> </crapa> + <crap> <crapa> <crapb> <crapc> <crapd> + <crape> + done 3 + </crape> + </crapd> </crapc> </crapb> </crapa> +</something> +\stopbuffer +\stoptyping + +One way to filter the content is this: + +\starttyping +\xmldoif {#1} {/crap/crapa/crapb/crapc/crapd/crape} { + some action +} +\stoptyping + +It is not unlikely that you will do something like this: + +\starttyping +\xmlfirst {#1} {/crap/crapa/crapb/crapc/crapd/crape} { + \xmlfirst{#1}{/crap/crapa/crapb/crapc/crapd/crape} +} +\stoptyping + +This means that the path is resolved twice but that can be avoided as +follows: + +\starttyping +\xmldoif{#1}{/crap/crapa/crapb/crapc/crapd/crape}{ + \xmlfirst{#1}{last-match::} +} +\stoptyping + +But the next is now guaranteed to work: + +\starttyping +\xmldoif{#1}{/crap/crapa/crapb/crapc/crapd/crape}{ + \xmlfirst{#1}{last-match::} + \xmllast{#1}{last-match::} +} +\stoptyping + +Because the first one can have done some lookup the last match can be replaced +and the second call will give unexpected results. You can overcome this with: + +\starttyping +\xmldoif{#1}{/crap/crapa/crapb/crapc/crapd/crape}{ + \xmlpushmatch + \xmlfirst{#1}{last-match::} + \xmlpopmatch +} +\stoptyping + +Does it pay off? Here are some timings of a 10.000 times text and lookup +like the previous (on a decent January 2016 laptop): + +\starttabulate[|r|l|] +\NC 0.239 \NC \type {\xmldoif {...} {...}} \NC \NR +\NC 0.292 \NC \type {\xmlfirst {...} {...}} \NC \NR +\NC 0.538 \NC \type {\xmldoif {...} {...} + \xmlfirst {...} {...}} \NC \NR +\NC 0.338 \NC \type {\xmldoif {...} {...} + \xmlfirst {...} {last-match::}} \NC \NR +\NC 0.349 \NC \type {+ \xmldoif {...} {...} + \xmlfirst {...} {last-match::}-} \NC \NR +\stoptabulate + +So, pushing and popping (the last row) is a bit slower than not doing that but it +is still much faster than not using \type {last-match::} at all. As a shortcut +you can use \type {=}, as in: + +\starttyping +\xmlfirst{#1}{=} +\stoptyping + +You can even do this: + +\starttyping +\xmlall{#1}{last-match::/text()} +\stoptyping + +or + +\starttyping +\xmlall{#1}{=/text()} +\stoptyping + + +\stopsection + +\startsection[title={some more examples}] + +\xmllshow{/something/whatever} +\xmllshow{something/whatever} +\xmllshow{/**/whocares} +\xmllshow{whoknows/whocares} +\xmllshow{whoknows} +\xmllshow{whocares[contains(text(),'f') or contains(text(),'g')]} +\xmllshow{whocares/first()} +\xmllshow{whocares/last()} +\xmllshow{whatever/all()} +\xmllshow{whocares/position(2)} +\xmllshow{whocares/position(-2)} +\xmllshow{whocares[1]} +\xmllshow{whocares[-1]} +\xmllshow{whocares[2]} +\xmllshow{whocares[-2]} +\xmllshow{whatever[3]/attribute(id)} +\xmllshow{whatever[2]/attribute('id')} +\xmllshow{whatever[3]/text()} +\xmllshow{/whocares/first()} +\xmllshow{/whocares/last()} + +\xmllshow{xml://whatever/all()} +\xmllshow{whatever/all()} +\xmllshow{//whocares} +\xmllshow{..[2]} +\xmllshow{../*[2]} + +\xmllshow{/(whocares|whocaresnot)} +\xmllshow{/!(whocares|whocaresnot)} +\xmllshow{/!whocares} + +\xmllshow{/interface/command/command(xml:setups:register)} +\xmllshow{/interface/command[@name='xxx']/command(xml:setups:typeset)} +\xmllshow{/arguments/*} +\xmllshow{/sequence/first()} +\xmllshow{/arguments/text()} +\xmllshow{/sequence/variable/first()} +\xmllshow{/interface/define[@name='xxx']/first()} +\xmllshow{/parameter/command(xml:setups:parameter:measure)} + +\xmllshow{/(*:library|figurelibrary)/*:figure/*:label} +\xmllshow{/(*:library|figurelibrary)/figure/*:label} +\xmllshow{/(*:library|figurelibrary)/figure/label} +\xmllshow{/(*:library|figurelibrary)/figure:*/label} + +\xmlshow {whatever//br[tag(1)='br']} + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-lpath.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-lpath.tex new file mode 100644 index 000000000..9c8b853c8 --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-lpath.tex @@ -0,0 +1,207 @@ +\input lxml-ctx.mkiv + +\ctxlua{dofile("t:/sources/lxml-lpt.lua")} + +\startbuffer[xmltest] +<?xml version='1.0'?> + +<!-- this is a test file --> + +<something id='1'> + <x:whatever id='1.1'> + <whocares id='1.1.1'> + test a + </whocares> + <whocaresnot id='1.1.2'> + test b + </whocaresnot> + </x:whatever> + <whatever id='2'> + <whocares id='2.1'> + test c + </whocares> + <whocaresnot id='2.2'> + test d + </whocaresnot> + </whatever> + <whatever id='3'> + test e + </whatever> + <whatever id='4' test="xxx"> + <whocares id='4.1'> + test f + </whocares> + <whocares id='4.2'> + test g + </whocares> + </whatever> + <whatever id='5' test="xxx"> + <whoknows id='5.1'> + <whocares id='5.1.1'> + test h + </whocares> + </whoknows> + <whoknows id='5.2'> + <whocaresnot id='5.2.1'> + test i + </whocaresnot> + </whoknows> + <whoknows id='5.3'> + <whocares id='5.3.1'> + test j + </whocares> + </whoknows> + </whatever> +</something> +\stopbuffer + +% \enabletrackers[xml.lparse] + +\setuplayout[width=middle,height=middle,header=1cm,footer=1cm,topspace=2cm,backspace=2cm] +\setupbodyfont[10pt] + +\setfalse\xmllshowbuffer + +\starttext + +\xmllshow{/(*:library|figurelibrary)/*:figure/*:label} +\xmllshow{/(*:library|figurelibrary)/figure/*:label} +\xmllshow{/(*:library|figurelibrary)/figure/label} +\xmllshow{/(*:library|figurelibrary)/figure:*/label} + +% \xmllshow{collection[@version='all']/resources/manual[match()==1]/paper/command(xml:overview)} +% \xmllshow{collection/resources/manual[match()=1]/paper/command(xml:overview)} + +% \xmllshow{answer//oeps} +% \xmllshow{answer/*/oeps} +% \xmllshow{answer/**/oeps} +% \xmllshow{answer/***/oeps} +% \xmllshow{answer/x//oeps} +% \xmllshow{answer//x/oeps} +% \xmllshow{//x/oeps} +% \xmllshow{answer/test/*} +% \xmllshow{answer/test/child::} +% \xmllshow{answer/*} +% \xmllshow{ oeps / answer / .. / * [tag()='p' and position()=1 and text()!=''] / oeps()} + +% \xmllshow{ artist / name [text()='Randy Newman'] / .. / albums / album [position()=3] / command(first:demo:two)} +% \xmllshow{/exa:selectors/exa:selector/exa:list/component[count()>1]} + +\stoptext + +\xmllshow{/*} +\xmllshow{child::} +\xmllshow{child::test} +\xmllshow{/test/test} +\xmllshow{../theory/sections/section/exercises} +\xmllshow{../training/practicalassignments} +\xmllshow{../../Outcome[position()=rootposition()]/Condition/command(xml:answer:mc:condition)} + +% \stoptext + +% \typebuffer[xmltest] \page + +\xmllshowbuffer{xmltest}{**}{id} +\xmllshowbuffer{xmltest}{*}{id} +\xmllshowbuffer{xmltest}{..}{id} +\xmllshowbuffer{xmltest}{.}{id} +\xmllshowbuffer{xmltest}{//}{id} +\xmllshowbuffer{xmltest}{/}{id} + +\xmllshowbuffer{xmltest}{**/}{id} +\xmllshowbuffer{xmltest}{**/*}{id} +\xmllshowbuffer{xmltest}{**/.}{id} +\xmllshowbuffer{xmltest}{**//}{id} + +\xmllshowbuffer{xmltest}{*/}{id} +\xmllshowbuffer{xmltest}{*/*}{id} +\xmllshowbuffer{xmltest}{*/.}{id} +\xmllshowbuffer{xmltest}{*//}{id} + +\xmllshowbuffer{xmltest}{/**/}{id} +\xmllshowbuffer{xmltest}{/**/*}{id} +\xmllshowbuffer{xmltest}{/**/.}{id} +\xmllshowbuffer{xmltest}{/**//}{id} + +\xmllshowbuffer{xmltest}{/*/}{id} +\xmllshowbuffer{xmltest}{/*/*}{id} +\xmllshowbuffer{xmltest}{/*/.}{id} +\xmllshowbuffer{xmltest}{/*//}{id} + +\xmllshowbuffer{xmltest}{./}{id} +\xmllshowbuffer{xmltest}{./*}{id} +\xmllshowbuffer{xmltest}{./.}{id} +\xmllshowbuffer{xmltest}{.//}{id} + +\xmllshowbuffer{xmltest}{../}{id} +\xmllshowbuffer{xmltest}{../*}{id} +\xmllshowbuffer{xmltest}{../.}{id} +\xmllshowbuffer{xmltest}{..//}{id} + +\xmllshowbuffer{xmltest}{descendant::whocares/ancestor::whoknows}{id} +\xmllshowbuffer{xmltest}{descendant::whocares/ancestor::whoknows/parent::}{id} +\xmllshowbuffer{xmltest}{descendant::whocares/ancestor::}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever/child::whocares}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever/child::whocares|whoknows}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever/child::(whocares|whoknows)}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever/child::!(whocares|whoknows)}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever/child::(whocares)}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever/child::(whocares)[position()>2]}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever[position()>2][position()=1]}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever[whocares][whocaresnot]}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever[whocares][not(whocaresnot)]}{id} +\xmllshowbuffer{xmltest}{child::something/child::whatever/self::whatever}{id} +\xmllshowbuffer{xmltest}{/something/whatever}{id} +\xmllshowbuffer{xmltest}{something/whatever}{id} +\xmllshowbuffer{xmltest}{/**/whocares}{id} +\xmllshowbuffer{xmltest}{whoknows/whocares}{id} +\xmllshowbuffer{xmltest}{whoknows}{id} +\xmllshowbuffer{xmltest}{whocares[contains(text(),'f') or contains(text(),'g')]}{id} +\xmllshowbuffer{xmltest}{whocares/first()}{id} +\xmllshowbuffer{xmltest}{whocares/last()}{id} +\xmllshowbuffer{xmltest}{whatever/all()}{id} +\xmllshowbuffer{xmltest}{whocares/position(2)}{id} +\xmllshowbuffer{xmltest}{whocares/position(-2)}{id} +\xmllshowbuffer{xmltest}{whocares[1]}{id} +\xmllshowbuffer{xmltest}{whocares[-1]}{id} +\xmllshowbuffer{xmltest}{whocares[2]}{id} +\xmllshowbuffer{xmltest}{whocares[-2]}{id} +\xmllshowbuffer{xmltest}{whatever[3]/attribute(id)}{id} +\xmllshowbuffer{xmltest}{whatever[2]/attribute('id')}{id} +\xmllshowbuffer{xmltest}{whatever[3]/text()}{id} +\xmllshowbuffer{xmltest}{/whocares/first()}{id} +\xmllshowbuffer{xmltest}{/whocares/last()}{id} + +\xmllshowbuffer{xmltest}{xml://whatever/all()}{id} +\xmllshowbuffer{xmltest}{whatever/all()}{id} +\xmllshowbuffer{xmltest}{//whocares}{id} +\xmllshowbuffer{xmltest}{..[2]}{id} +\xmllshowbuffer{xmltest}{../*[2]}{id} + +\xmllshowbuffer{xmltest}{/(whocares|whocaresnot)}{id} +\xmllshowbuffer{xmltest}{/!(whocares|whocaresnot)}{id} +\xmllshowbuffer{xmltest}{/!whocares}{id} + +% \page + +% \xmllshow{/interface/command/command(xml:setups:register)} +% \xmllshow{/interface/command[@name='xxx']/command(xml:setups:typeset)} +% \xmllshow{/arguments/*} +% \xmllshow{/sequence/first()} +% \xmllshow{/arguments/text()} +% \xmllshow{/sequence/variable/first()} +% \xmllshow{/interface/define[@name='xxx']/first()} +% \xmllshow{/parameter/command(xml:setups:parameter:measure)} + +% \page + +% \xmllshow{interface/command/command(xml:setups:register)} +% \xmllshow{interface/command[@name='xxx']/command(xml:setups:typeset)} +% \xmllshow{arguments/*} +% \xmllshow{sequence/first()} +% \xmllshow{arguments/text()} +% \xmllshow{sequence/variable/first()} +% \xmllshow{interface/define[@name='xxx']/first()} +% \xmllshow{parameter/command(xml:setups:parameter:measure)} + +\stoptext diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-style.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-style.tex new file mode 100644 index 000000000..8bcd74086 --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-style.tex @@ -0,0 +1,155 @@ +\startenvironment xml-mkiv-style + +\input lxml-ctx.mkiv + +\settrue \xmllshowtitle +\setfalse\xmllshowwarning + +\usemodule[set-11] + +\loadsetups[i-context] + +% \definehspace[squad][1em plus .25em minus .25em] + +\usemodule[abr-02] + +\setuplayout + [location=middle, + marking=on, + backspace=20mm, + cutspace=20mm, + topspace=15mm, + header=15mm, + footer=15mm, + height=middle, + width=middle] + +\setuppagenumbering + [alternative=doublesided, + location=] + +\setupfootertexts + [][pagenumber] + +\setupheadertexts + [][chapter] + +\setupheader + [color=colortwo, + style=bold] + +\setupfooter + [color=colortwo, + style=bold] + +\setuphead + [chapter] + [page={yes,header,right}, + header=empty, + style=\bfc] + +\setupsectionblock + [page={yes,header,right}] + +\starttexdefinition unexpanded section:chapter:number #1 + \doifmode{*sectionnumber} { + \bf + \llap{<\enspace}#1\enspace> + } +\stoptexdefinition + +\starttexdefinition unexpanded section:section:number #1 + \doifmode{*sectionnumber} { + \bf + \llap{<<\enspace}#1\enspace>> + } +\stoptexdefinition + +\starttexdefinition unexpanded section:subsection:number #1 + \doifmode{*sectionnumber} { + \bf + \llap{<<<\enspace}#1\enspace>>> + } +\stoptexdefinition + +\setuphead[chapter] [numbercolor=black,numbercommand=\texdefinition{section:chapter:number}] +\setuphead[section] [numbercolor=black,numbercommand=\texdefinition{section:section:number}] +\setuphead[subsection] [numbercolor=black,numbercommand=\texdefinition{section:subsection:number}] +\setuphead[subsubsection][numbercolor=,numbercommand=,before=\blank,after=\blank] + +\setuphead + [section] + [style=\bfa] + +\setuplist + [chapter] + [style=bold] + +\setupinteractionscreen + [option=doublesided] + +\setupalign + [tolerant,stretch] + +\setupwhitespace + [big] + +\setuptolerance + [tolerant] + +\doifelsemode {atpragma} { + \setupbodyfont[lucidaot,10pt] +} { + \setupbodyfont[dejavu,10pt] +} + +\definecolor[colorone] [b=.5] +\definecolor[colortwo] [s=.3] +\definecolor[colorthree][y=.5] + +\setuptype + [color=colorone] + +\setuptyping + [color=colorone] + +\setuphead + [lshowtitle] + [style=\tt, + color=colorone] + +\setuphead + [chapter,section] + [numbercolor=colortwo, + color=colorone] + +\definedescription + [xmlcmd] + [alternative=hanging, + width=line, + distance=1em, + margin=2em, + headstyle=monobold, + headcolor=colorone] + +\setupframedtext + [setuptext] + [framecolor=colorone, + rulethickness=1pt, + corner=round] + +\usemodule[punk] + +\usetypescript[punk] + +\definelayer + [page] + [width=\paperwidth, + height=\paperheight] + +\definestartstop + [smallexample] + [before={\blank\bgroup\ss\small\setupwhitespace[medium]\setupblank[medium]}, + after={\par\egroup\blank}] + +\stopenvironment diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-titlepage.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-titlepage.tex new file mode 100644 index 000000000..427557214 --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-titlepage.tex @@ -0,0 +1,47 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-titlepage + +\setuplayout[page] + +\startstandardmakeup + \startfontclass[none] % nil the current fontclass since it may append its features + \EnableRandomPunk + \setlayerframed + [page] + [width=\paperwidth,height=\paperheight, + background=color,backgroundcolor=colorone,backgroundoffset=1ex,frame=off] + {} + \definedfont[demo@punk at 18pt] + \setbox\scratchbox\vbox { + \hsize\dimexpr\paperwidth+2ex\relax + \setupinterlinespace + \baselineskip 1\baselineskip plus 1pt minus 1pt + \raggedcenter + \color[colortwo]{\dorecurse{1000}{XML }} + } + \setlayer + [page] + [preset=middle] + {\vsplit\scratchbox to \dimexpr\paperheight+2ex\relax} + \definedfont[demo@punk at 90pt] + \setstrut + \setlayerframed + [page] + [preset=rightbottom,offset=10mm] + [foregroundcolor=colorthree,align=flushright,offset=overlay,frame=off] + {Dealing\\with XML in\\Con\TeX t MkIV} + \definedfont[demo@punk at 18pt] + \setstrut + \setlayerframed + [page] + [preset=righttop,offset=10mm,x=3mm,rotation=90] + [foregroundcolor=colorthree,align=flushright,offset=overlay,frame=off] + {Hans Hagen, Pragma ADE, \currentdate} + \tightlayer[page] + \stopfontclass +\stopstandardmakeup + +\setuplayout + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv-tricks.tex b/doc/context/sources/general/manuals/xml/xml-mkiv-tricks.tex new file mode 100644 index 000000000..f8c65ecc9 --- /dev/null +++ b/doc/context/sources/general/manuals/xml/xml-mkiv-tricks.tex @@ -0,0 +1,814 @@ +\environment xml-mkiv-style + +\startcomponent xml-mkiv-tricks + +\startchapter[title={Tips and tricks}] + +\startsection[title={tracing}] + +It can be hard to debug code as much happens kind of behind the screens. +Therefore we have a couple of tracing options. Of course you can typeset some +status information, using for instance: + +\startxmlcmd {\cmdbasicsetup{xmlshow}} + typeset the tree given by \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlinfo}} + typeset the name in the element given by \cmdinternal {cd:node} +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlpath}} + returns the complete path (including namespace prefix and index) of the + given \cmdinternal {cd:node} +\stopxmlcmd + +\startbuffer[demo] +<?xml version "1.0"?> +<document> + <section> + <content> + <p>first</p> + <p><b>second</b></p> + </content> + </section> + <section> + <content> + <p><b>third</b></p> + <p>fourth</p> + </content> + </section> +</document> +\stopbuffer + +Say that we have the following \XML: + +\typebuffer[demo] + +and the next definitions: + +\startbuffer +\startxmlsetups xml:demo:base + \xmlsetsetup{#1}{p|b}{xml:demo:*} +\stopxmlsetups + +\startxmlsetups xml:demo:p + \xmlflush{#1} + \par +\stopxmlsetups + +\startxmlsetups xml:demo:b + \par + \xmlpath{#1} : \xmlflush{#1} + \par +\stopxmlsetups + +\xmlregisterdocumentsetup{example-10}{xml:demo:base} + +\xmlprocessbuffer{example-10}{demo}{} +\stopbuffer + +\typebuffer + +This will give us: + +\blank \startpacked \getbuffer \stoppacked \blank + +If you use \type {\xmlshow} you will get a complete subtree which can +be handy for tracing but can also lead to large documents. + +We also have a bunch of trackers that can be enabled, like: + +\starttyping +\enabletrackers[xml.show,xml.parse] +\stoptyping + +The full list (currently) is: + +\starttabulate[|lT|p|] +\NC xml.entities \NC show what entities are seen and replaced \NC \NR +\NC xml.path \NC show the result of parsing an lpath expression \NC \NR +\NC xml.parse \NC show stepwise resolving of expressions \NC \NR +\NC xml.profile \NC report all parsed lpath expressions (in the log) \NC \NR +\NC xml.remap \NC show what namespaces are remapped \NC \NR +\NC lxml.access \NC report errors with respect to resolving (symbolic) nodes \NC \NR +\NC lxml.comments \NC show the comments that are encountered (if at all) \NC \NR +\NC lxml.loading \NC show what files are loaded and converted \NC \NR +\NC lxml.setups \NC show what setups are being associated to elements \NC \NR +\stoptabulate + +In one of our workflows we produce books from \XML\ where the (educational) +content is organized in many small files. Each book has about 5~chapters and each +chapter is made of sections that contain text, exercises, resources, etc.\ and so +the document is assembled from thousands of files (don't worry, runtime inclusion +is pretty fast). In order to see where in the sources content resides we can +trace the filename. + +\startxmlcmd {\cmdbasicsetup{xmlinclusion}} + returns the file where the node comes from +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlinclusions}} + returns the list of files where the node comes from +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlbadinclusions}} + returns a list of files that were not included due to some problem +\stopxmlcmd + +Of course you have to make sure that these names end up somewhere visible, for +instance in the margin. + +\stopsection + +\startsection[title={expansion}] + +For novice users the concept of expansion might sound frightening and to some +extend it is. However, it is important enough to spend some words on it here. + +It is good to realize that most setups are sort of immediate. When one setup is +issued, it can call another one and so on. Normally you won't notice that but +there are cases where that can be a problem. In \TEX\ you can define a macro, +take for instance: + +\starttyping +\startxmlsetups xml:foo + \def\foobar{\xmlfirst{#1}{/bar}} +\stopxmlsetups +\stoptyping + +you store the reference top node \type {bar} in \type {\foobar} maybe for later use. In +this case the content is not yet fetched, it will be done when \type {\foobar} is +called. + +\starttyping +\startxmlsetups xml:foo + \edef\foobar{\xmlfirst{#1}{/bar}} +\stopxmlsetups +\stoptyping + +Here the content of \type {bar} becomes the body of the macro. But what if +\type {bar} itself contains elements that also contain elements. When there +is a setup for \type {bar} it will be triggered and so on. + +When that setup looks like: + +\starttyping +\startxmlsetups xml:bar + \def\barfoo{\xmlflush{#1}} +\stopxmlsetups +\stoptyping + +Here we get something like: + +\starttyping +\foobar => {\def\barfoo{...}} +\stoptyping + +When \type {\barfoo} is not defined we get an error and when it is known and expands +to something weird we might also get an error. + +Especially when you don't know what content can show up, this can result in errors +when an expansion fails, for example because some macro being used is not defined. +To prevent this we can define a macro: + +\starttyping +\starttexdefinition unexpanded xml:bar:macro #1 + \def\barfoo{\xmlflush{#1}} +\stoptexdefinition + +\startxmlsetups xml:bar + \texdefinition{xml:bar:macro}{#1} +\stopxmlsetups +\stoptyping + +The setup \type {xml:bar} will still expand but the replacement text now is just the +call to the macro, think of: + +\starttyping +\foobar => {\texdefinition{xml:bar:macro}{#1}} +\stoptyping + +But this is often not needed, most \CONTEXT\ commands can handle the expansions +quite well but it's good to know that there is a way out. So, now to some +examples. Imagine that we have an \XML\ file that looks as follows: + +\starttyping +<?xml version='1.0' ?> +<demo> + <chapter> + <title>Some <em>short</em> title</title> + <content> + zeta + <index> + <key>zeta</key> + <content>zeta again</content> + </index> + alpha + <index> + <key>alpha</key> + <content>alpha <em>again</em></content> + </index> + gamma + <index> + <key>gamma</key> + <content>gamma</content> + </index> + beta + <index> + <key>beta</key> + <content>beta</content> + </index> + delta + <index> + <key>delta</key> + <content>delta</content> + </index> + done! + </content> + </chapter> +</demo> +\stoptyping + +There are a few structure related elements here: a chapter (with its list entry) +and some index entries. Both are multipass related and therefore travel around. +This means that when we let data end up in the auxiliary file, we need to make +sure that we end up with either expanded data (i.e.\ no references to the \XML\ +tree) or with robust forward and backward references to elements in the tree. + +Here we discuss three approaches (and more may show up later): pushing \XML\ into +the auxiliary file and using references to elements either or not with an +associated setup. We control the variants with a switch. + +\starttyping +\newcount\TestMode + +\TestMode=0 % expansion=xml +\TestMode=1 % expansion=yes, index, setup +\TestMode=2 % expansion=yes +\stoptyping + +We apply a couple of setups: + +\starttyping +\startxmlsetups xml:mysetups + \xmlsetsetup{\xmldocument}{demo|index|content|chapter|title|em}{xml:*} +\stopxmlsetups + +\xmlregistersetup{xml:mysetups} +\stoptyping + +The main document is processed with: + +\starttyping +\startxmlsetups xml:demo + \xmlflush{#1} + \subject{contents} + \placelist[chapter][criterium=all] + \subject{index} + \placeregister[index][criterium=all] + \page % else buffer is forgotten when placing header +\stopxmlsetups +\stoptyping + +First we show three alternative ways to deal with the chapter. The first case +expands the \XML\ reference so that we have an \XML\ stream in the auxiliary +file. This stream is processed as a small independent subfile when needed. The +second case registers a reference to the current element (\type {#1}). This means +that we have access to all data of this element, like attributes, title and +content. What happens depends on the given setup. The third variant does the same +but here the setup is part of the reference. + +\starttyping +\startxmlsetups xml:chapter + \ifcase \TestMode + % xml code travels around + \setuphead[chapter][expansion=xml] + \startchapter[title=eh: \xmltext{#1}{title}] + \xmlfirst{#1}{content} + \stopchapter + \or + % index is used for access via setup + \setuphead[chapter][expansion=yes,xmlsetup=xml:title:flush] + \startchapter[title=\xmlgetindex{#1}] + \xmlfirst{#1}{content} + \stopchapter + \or + % tex call to xml using index is used + \setuphead[chapter][expansion=yes] + \startchapter[title=hm: \xmlreference{#1}{xml:title:flush}] + \xmlfirst{#1}{content} + \stopchapter + \fi +\stopxmlsetups + +\startxmlsetups xml:title:flush + \xmltext{#1}{title} +\stopxmlsetups +\stoptyping + +We need to deal with emphasis and the content of the chapter. + +\starttyping +\startxmlsetups xml:em + \begingroup\em\xmlflush{#1}\endgroup +\stopxmlsetups + +\startxmlsetups xml:content + \xmlflush{#1} +\stopxmlsetups +\stoptyping + +A similar approach is followed with the index entries. Watch how we use the +numbered entries variant (in this case we could also have used just \type +{entries} and \type {keys}). + +\starttyping +\startxmlsetups xml:index + \ifcase \TestMode + \setupregister[index][expansion=xml,xmlsetup=] + \setstructurepageregister + [index] + [entries:1=\xmlfirst{#1}{content}, + keys:1=\xmltext{#1}{key}] + \or + \setupregister[index][expansion=yes,xmlsetup=xml:index:flush] + \setstructurepageregister + [index] + [entries:1=\xmlgetindex{#1}, + keys:1=\xmltext{#1}{key}] + \or + \setupregister[index][expansion=yes,xmlsetup=] + \setstructurepageregister + [index] + [entries:1=\xmlreference{#1}{xml:index:flush}, + keys:1=\xmltext{#1}{key}] + \fi +\stopxmlsetups + +\startxmlsetups xml:index:flush + \xmlfirst{#1}{content} +\stopxmlsetups +\stoptyping + +Instead of this flush, you can use the predefined setup \type {xml:flush} +unless it is overloaded by you. + +The file is processed by: + +\starttyping +\starttext + \xmlprocessfile{main}{test.xml}{} +\stoptext +\stoptyping + +We don't show the result here. If you're curious what the output is, you can test +it yourself. In that case it also makes sense to peek into the \type {test.tuc} +file to see how the information travels around. The \type {metadata} fields carry +information about how to process the data. + +The first case, the \XML\ expansion one, is somewhat special in the sense that +internally we use small pseudo files. You can control the rendering by tweaking +the following setups: + +\starttyping +\startxmlsetups xml:ctx:sectionentry + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups xml:ctx:registerentry + \xmlflush{#1} +\stopxmlsetups +\stoptyping + +{\em When these methods work out okay the other structural elements will be +dealt with in a similar way.} + +\stopsection + +\startsection[title={special cases}] + +Normally the content will be flushed under a special (so called) catcode regime. +This means that characters that have a special meaning in \TEX\ will have no such +meaning in an \XML\ file. If you want content to be treated as \TEX\ code, you can +use one of the following: + +\startxmlcmd {\cmdbasicsetup{xmlflushcontext}} + flush the given \cmdinternal {cd:node} using the \TEX\ character + interpretation scheme +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlcontext}} + flush the match of \cmdinternal {cd:lpath} for the given \cmdinternal + {cd:node} using the \TEX\ character interpretation scheme +\stopxmlcmd + +We use this in cases like: + +\starttyping +.... + \xmlsetsetup {#1} { + tm|texformula| + } {xml:*} +.... + +\startxmlsetups xml:tm + \mathematics{\xmlflushcontext{#1}} +\stopxmlsetups + +\startxmlsetups xml:texformula + \placeformula\startformula\xmlflushcontext{#1}\stopformula +\stopxmlsetups +\stoptyping + +\stopsection + +\startsection[title={collecting}] + +Say that your document has + +\starttyping +<table> + <tr> + <td>foo</td> + <td>bar<td> + </tr> +</table> +\stoptyping + +And that you need to convert that to \TEX\ speak like: + +\starttyping +\bTABLE + \bTR + \bTD foo \eTD + \bTD bar \eTD + \eTR +\eTABLE +\stoptyping + +A simple mapping is: + +\starttyping +\startxmlsetups xml:table + \bTABLE \xmlflush{#1} \eTABLE +\stopxmlsetups +\startxmlsetups xml:tr + \bTR \xmlflush{#1} \eTR +\stopxmlsetups +\startxmlsetups xml:td + \bTD \xmlflush{#1} \eTD +\stopxmlsetups +\stoptyping + +The \type {\bTD} command is a so called delimited command which means that it +picks up its argument by looking for an \type {\eTD}. For the simple case here +this works quite well because the flush is inside the pair. This is not the case +in the following variant: + +\starttyping +\startxmlsetups xml:td:start + \bTD +\stopxmlsetups +\startxmlsetups xml:td:stop + \eTD +\stopxmlsetups +\startxmlsetups xml:td + \xmlsetup{#1}{xml:td:start} + \xmlflush{#1} + \xmlsetup{#1}{xml:td:stop} +\stopxmlsetups +\stoptyping + +When for some reason \TEX\ gets confused you can revert to a mechanism that +collects content. + +\starttyping +\startxmlsetups xml:td:start + \startcollect + \bTD + \stopcollect +\stopxmlsetups +\startxmlsetups xml:td:stop + \startcollect + \eTD + \stopcollect +\stopxmlsetups +\startxmlsetups xml:td + \startcollecting + \xmlsetup{#1}{xml:td:start} + \xmlflush{#1} + \xmlsetup{#1}{xml:td:stop} + \stopcollecting +\stopxmlsetups +\stoptyping + +You can even implement solutions that effectively do this: + +\starttyping +\startcollecting + \startcollect \bTABLE \stopcollect + \startcollect \bTR \stopcollect + \startcollect \bTD \stopcollect + \startcollect foo\stopcollect + \startcollect \eTD \stopcollect + \startcollect \bTD \stopcollect + \startcollect bar\stopcollect + \startcollect \eTD \stopcollect + \startcollect \eTR \stopcollect + \startcollect \eTABLE \stopcollect +\stopcollecting +\stoptyping + +Of course you only need to go that complex when the situation demands it. Here is +another weird one: + +\starttyping +\startcollecting + \startcollect \setupsomething[\stopcollect + \startcollect foo=\stopcollect + \startcollect FOO,\stopcollect + \startcollect bar=\stopcollect + \startcollect BAR,\stopcollect + \startcollect ]\stopcollect +\stopcollecting +\stoptyping + +\stopsection + +\startsection[title={selectors and injectors}] + +This section describes a bit special feature, one that we needed for a project +where we could not touch the original content but could add specific sections for +our own purpose. Hopefully the example demonstrates its useability. + +\enabletrackers[lxml.selectors] + +\startbuffer[foo] +<?xml version="1.0" encoding="UTF-8"?> + +<?context-directive message info 1: this is a demo file ?> +<?context-message-directive info 2: this is a demo file ?> + +<one> + <two> + <?context-select begin t1 t2 t3 ?> + <three> + t1 t2 t3 + <?context-directive injector crlf t1 ?> + t1 t2 t3 + </three> + <?context-select end ?> + <?context-select begin t4 ?> + <four> + t4 + </four> + <?context-select end ?> + <?context-select begin t8 ?> + <four> + t8.0 + t8.0 + </four> + <?context-select end ?> + <?context-include begin t4 ?> + <!-- + <three> + t4.t3 + <?context-directive injector crlf t1 ?> + t4.t3 + </three> + --> + <three> + t3 + <?context-directive injector crlf t1 ?> + t3 + </three> + <?context-include end ?> + <?context-select begin t8 ?> + <four> + t8.1 + t8.1 + </four> + <?context-select end ?> + <?context-select begin t8 ?> + <four> + t8.2 + t8.2 + </four> + <?context-select end ?> + <?context-select begin t4 ?> + <four> + t4 + t4 + </four> + <?context-select end ?> + <?context-directive injector page t7 t8 ?> + foo + <?context-directive injector blank t1 ?> + bar + <?context-directive injector page t7 t8 ?> + bar + </two> +</one> +\stopbuffer + +\typebuffer[foo] + +First we show how to plug in a directive. Processing instructions like the +following are normally ignored by an \XML\ processor, unless they make sense +to it. + +\starttyping +<?context-directive message info 1: this is a demo file ?> +<?context-message-directive info 2: this is a demo file ?> +\stoptyping + +We can define a message handler as follows: + +\startbuffer +\def\MyMessage#1#2#3{\writestatus{#1}{#2 #3}} + +\xmlinstalldirective{message}{MyMessage} +\stopbuffer + +\typebuffer \getbuffer + +When this file is processed you will see this on the console: + +\starttyping +info > 1: this is a demo file +info > 2: this is a demo file +\stoptyping + +The file has some sections that can be used or ignored. The recipe for +obeying \type {t1} and \type {t4} is the following: + +\startbuffer +\xmlsetinjectors[t1] +\xmlsetinjectors[t4] + +\startxmlsetups xml:initialize + \xmlapplyselectors{#1} + \xmlsetsetup {#1} { + one|two|three|four + } {xml:*} +\stopxmlsetups + +\xmlregistersetup{xml:initialize} + +\startxmlsetups xml:one + [ONE \xmlflush{#1} ONE] +\stopxmlsetups + +\startxmlsetups xml:two + [TWO \xmlflush{#1} TWO] +\stopxmlsetups + +\startxmlsetups xml:three + [THREE \xmlflush{#1} THREE] +\stopxmlsetups + +\startxmlsetups xml:four + [FOUR \xmlflush{#1} FOUR] +\stopxmlsetups +\stopbuffer + +\typebuffer \getbuffer + +This typesets: + +\startnarrower +\xmlprocessbuffer{main}{foo}{} +\stopnarrower + +The include coding is kind of special: it permits adding content (in a comment) +and ignoring the rest so that we indeed can add something without interfering +with the original. Of course in a normal workflow such messy solutions are +not needed, but alas, often workflows are not that clean, especially when one +has no real control over the source. + +\startxmlcmd {\cmdbasicsetup{xmlsetinjectors}} + enables a list of injectors that will be used +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlresetinjectors}} + resets the list of injectors +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlinjector}} + expands an injection (command); normally this one is only used + (in some setup) or for testing +\stopxmlcmd + +\startxmlcmd {\cmdbasicsetup{xmlapplyselectors}} + analyze the tree \cmdinternal {cd:node} for marked sections that + will be injected +\stopxmlcmd + +We have some injections predefined: + +\starttyping +\startsetups xml:directive:injector:page + \page +\stopsetups + +\startsetups xml:directive:injector:column + \column +\stopsetups + +\startsetups xml:directive:injector:blank + \blank +\stopsetups +\stoptyping + +In the example we see: + +\starttyping +<?context-directive injector page t7 t8 ?> +\stoptyping + +When we set \type {\xmlsetinjector[t7]} a pagebreak will injected in that spot. +Tags like \type {t7}, \type {t8} etc.\ can represent versions. + +\stopsection + +\startsection[title=preprocessing] + +% local match = lpeg.match +% local replacer = lpeg.replacer("BAD TITLE:","<bold>BAD TITLE:</bold>") +% +% function lxml.preprocessor(data,settings) +% return match(replacer,data) +% end + +\startbuffer[pre-code] +\startluacode + function lxml.preprocessor(data,settings) + return string.find(data,"BAD TITLE:") + and string.gsub(data,"BAD TITLE:","<bold>BAD TITLE:</bold>") + or data + end +\stopluacode +\stopbuffer + +\startbuffer[pre-xml] +\startxmlsetups pre:demo:initialize + \xmlsetsetup{#1}{*}{pre:demo:*} +\stopxmlsetups + +\xmlregisterdocumentsetup{pre:demo}{pre:demo:initialize} + +\startxmlsetups pre:demo:root + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups pre:demo:bold + \begingroup\bf\xmlflush{#1}\endgroup +\stopxmlsetups + +\starttext + \xmlprocessbuffer{pre:demo}{demo}{} +\stoptext +\stopbuffer + +Say that you have the following \XML\ setup: + +\typebuffer[pre-xml] + +and that (such things happen) the input looks like this: + +\startbuffer[demo] +<root> +BAD TITLE: crap crap crap ... + +BAD TITLE: crap crap crap ... +</root> +\stopbuffer + +\typebuffer[demo] + +You can then clean up these \type {BAD TITLE}'s as follows: + +\typebuffer[pre-code] + +and get as result: + +\start \getbuffer[pre-code,pre-xml] \stop + +The preprocessor function gets as second argument the current settings, an d +the field \type {currentresource} can be used to limit the actions to +specific resources, in our case it's \type {buffer: demo}. Afterwards you can +reset the proprocessor with: + +\startluacode +lxml.preprocessor = nil +\stopluacode + +Future versions might give some more control over preprocessors. For now consider +it to be a quick hack. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/xml/xml-mkiv.tex b/doc/context/sources/general/manuals/xml/xml-mkiv.tex index 37f321646..77054e79c 100644 --- a/doc/context/sources/general/manuals/xml/xml-mkiv.tex +++ b/doc/context/sources/general/manuals/xml/xml-mkiv.tex @@ -31,4385 +31,25 @@ % % \xmldirect -\input lxml-ctx.mkiv - -\settrue \xmllshowtitle -\setfalse\xmllshowwarning - -\usemodule[set-11] - -\loadsetups[i-context] - -% \definehspace[squad][1em plus .25em minus .25em] - -\usemodule[abr-02] - -\setuplayout - [location=middle, - marking=on, - backspace=20mm, - cutspace=20mm, - topspace=15mm, - header=15mm, - footer=15mm, - height=middle, - width=middle] - -\setuppagenumbering - [alternative=doublesided, - location=] - -\setupfootertexts - [][pagenumber] - -\setupheadertexts - [][chapter] - -\setupheader - [color=colortwo, - style=bold] - -\setupfooter - [color=colortwo, - style=bold] - -\setuphead - [chapter] - [page={yes,header,right}, - header=empty, - style=\bfc] - -\setupsectionblock - [page={yes,header,right}] - -\starttexdefinition unexpanded section:chapter:number #1 - \doifmode{*sectionnumber} { - \bf - \llap{<\enspace}#1\enspace> - } -\stoptexdefinition - -\starttexdefinition unexpanded section:section:number #1 - \doifmode{*sectionnumber} { - \bf - \llap{<<\enspace}#1\enspace>> - } -\stoptexdefinition - -\starttexdefinition unexpanded section:subsection:number #1 - \doifmode{*sectionnumber} { - \bf - \llap{<<<\enspace}#1\enspace>>> - } -\stoptexdefinition - -\setuphead[chapter] [numbercolor=black,numbercommand=\texdefinition{section:chapter:number}] -\setuphead[section] [numbercolor=black,numbercommand=\texdefinition{section:section:number}] -\setuphead[subsection][numbercolor=black,numbercommand=\texdefinition{section:subsection:number}] - -\setuphead - [section] - [style=\bfa] - -\setuplist - [chapter] - [style=bold] - -\setupinteractionscreen - [option=doublesided] - -\setupalign - [tolerant,stretch] - -\setupwhitespace - [big] - -\setuptolerance - [tolerant] - -\doifelsemode {atpragma} { - \setupbodyfont[lucidaot,10pt] -} { - \setupbodyfont[dejavu,10pt] -} - -\definecolor[colorone] [b=.5] -\definecolor[colortwo] [s=.3] -\definecolor[colorthree][y=.5] - -\setuptype - [color=colorone] - -\setuptyping - [color=colorone] - -\setuphead - [lshowtitle] - [style=\tt, - color=colorone] - -\setuphead - [chapter,section] - [numbercolor=colortwo, - color=colorone] - -\definedescription - [xmlcmd] - [alternative=hanging, - width=line, - distance=1em, - margin=2em, - headstyle=monobold, - headcolor=colorone] - -\setupframedtext - [setuptext] - [framecolor=colorone, - rulethickness=1pt, - corner=round] - -\usemodule[punk] - -\usetypescript[punk] - -\definelayer - [page] - [width=\paperwidth, - height=\paperheight] +\environment xml-mkiv-style \starttext -\setuplayout[page] - -\startstandardmakeup - \startfontclass[none] % nil the current fontclass since it may append its features - \EnableRandomPunk - \setlayerframed - [page] - [width=\paperwidth,height=\paperheight, - background=color,backgroundcolor=colorone,backgroundoffset=1ex,frame=off] - {} - \definedfont[demo@punk at 18pt] - \setbox\scratchbox\vbox { - \hsize\dimexpr\paperwidth+2ex\relax - \setupinterlinespace - \baselineskip 1\baselineskip plus 1pt minus 1pt - \raggedcenter - \color[colortwo]{\dorecurse{1000}{XML }} - } - \setlayer - [page] - [preset=middle] - {\vsplit\scratchbox to \dimexpr\paperheight+2ex\relax} - \definedfont[demo@punk at 90pt] - \setstrut - \setlayerframed - [page] - [preset=rightbottom,offset=10mm] - [foregroundcolor=colorthree,align=flushright,offset=overlay,frame=off] - {Dealing\\with XML in\\Con\TeX t MkIV} - \definedfont[demo@punk at 18pt] - \setstrut - \setlayerframed - [page] - [preset=righttop,offset=10mm,x=3mm,rotation=90] - [foregroundcolor=colorthree,align=flushright,offset=overlay,frame=off] - {Hans Hagen, Pragma ADE, \currentdate} - \tightlayer[page] - \stopfontclass -\stopstandardmakeup - -\setuplayout +\component xml-mkiv-titlepage \startfrontmatter - -\starttitle[title=Contents] - -\placelist - [chapter,section] - -\stoptitle - -\startchapter[title={Introduction}] - -This manual presents the \MKIV\ way of dealing with \XML. Although the -traditional \MKII\ streaming parser has a charming simplicity in its control, for -complex documents the tree based \MKIV\ method is more convenient. It is for this -reason that the old method has been removed from \MKIV. If you are familiar with -\XML\ processing in \MKII, then you will have noticed that the \MKII\ commands -have \type {XML} in their name. The \MKIV\ commands have a lowercase \type {xml} -in their names. That way there is no danger for confusion or a mixup. - -You may wonder why we do these manipulations in \TEX\ and not use \XSLT\ (or -other transformation methods) instead. The advantage of an integrated approach is -that it simplifies usage. Think of not only processing the document, but also -using \XML\ for managing resources in the same run. An \XSLT\ approach is just as -verbose (after all, you still need to produce \TEX\ code) and probably less -readable. In the case of \MKIV\ the integrated approach is also faster and gives -us the option to manipulate content at runtime using \LUA. It has the additional -advantage that to some extend we can handle a mix of \TEX\ and \XML\ because we -know when we're doing one or the other. - -This manual is dedicated to Taco Hoekwater, one of the first \CONTEXT\ users, and -also the first to use it for processing \XML. Who could have thought at that time -that we would have a more convenient way of dealing with those angle brackets. -The second version for this manual is dedicated to Thomas Schmitz, a power user -who occasionally became victim of the evolving mechanisms. - -\blank - -\startlines -Hans Hagen -\PRAGMA -Hasselt NL -2008\endash2016 -\stoplines - -\stopchapter - + \component xml-mkiv-contents + \component xml-mkiv-introduction \stopfrontmatter \startbodymatter - -\startchapter[title={Setting up a converter}] - -\startsection[title={from structure to setup}] - -We use a very simple document structure for demonstrating how a converter is -defined. In practice a mapping will be more complex, especially when we have a -style with complex chapter openings using data coming from all kind of places, -different styling of sections with the same name, selectively (out of order) -flushed content, special formatting, etc. - -\typefile{manual-demo-1.xml} - -Say that this document is stored in the file \type {demo.xml}, then the following -code can be used as starting point: - -\starttyping -\startxmlsetups xml:demo:base - \xmlsetsetup{#1}{document|section|p}{xml:demo:*} -\stopxmlsetups - -\xmlregisterdocumentsetup{demo}{xml:demo:base} - -\startxmlsetups xml:demo:document - \starttitle[title={Contents}] - \placelist[chapter] - \stoptitle - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:demo:section - \startchapter[title=\xmlfirst{#1}{/title}] - \xmlfirst{#1}{/content} - \stopchapter -\stopxmlsetups - -\startxmlsetups xml:demo:p - \xmlflush{#1}\endgraf -\stopxmlsetups - -\xmlprocessfile{demo}{demo.xml}{} -\stoptyping - -Watch out! These are not just setups, but specific \XML\ setups which get an -argument passed (the \type {#1}). If for some reason your \XML\ processing fails, -it might be that you mistakenly have used a normal setup definition. The argument -\type {#1} represents the current node (element) and is a unique identifier. For -instance a \type {<p>..</p>} can have an identifier {demo::5}. So, we can get -something: - -\starttyping -\xmlflush{demo::5}\endgraf -\stoptyping - -but as well: - -\starttyping -\xmlflush{demo::6}\endgraf -\stoptyping - -Keep in mind that the references tor the actual nodes (elements) are -abstractions, you never see those \type {<id>::<number>}'s, because we will use -either the abstract \type {#1} (any node) or an explicit reference like \type -{demo}. The previous setup when issued will be like: - -\starttyping -\startchapter[title=\xmlfirst{demo::3}{/title}] - \xmlfirst{demo::4}{/content} -\stopchapter -\stoptyping - -Here the \type {title} is used to typeset the chapter title but also for an entry -in the table of contents. At the moment the title is typeset the \XML\ node gets -looked up and expanded in real text. However, for the list it gets stored for -later use. One can argue that this is not needed for \XML, because one can just -filter all the titles and use page references, but then one also looses the -control one normally has over such titles. For instance it can be that some -titles are rendered differently and for that we need to keep track of usage. -Doing that with transformations or filtering is often more complex than leaving -that to \TEX. As soon as the list gets typeset, the reference (\type {demo::#3}) -is used for the lookup. This is because by default the title is stored as given. -So, as long as we make sure the \XML\ source is loaded before the table of -contents is typeset we're ok. Later we will look into this in more detail, for -now it's enough to know that in most cases the abstract \type {#1} reference will -work out ok. - -Contrary to the style definitions this interface looks rather low level (with no -optional arguments) and the main reason for this is that we want processing to be -fast. So, the basic framework is: - -\starttyping -\startxmlsetups xml:demo:base - % associate setups with elements -\stopxmlsetups - -\xmlregisterdocumentsetup{demo}{xml:demo:base} - -% define setups for matches - -\xmlprocessfile{demo}{demo.xml}{} -\stoptyping - -In this example we mostly just flush the content of an element and in the case of -a section we flush explicit child elements. The \type {#1} in the example code -represents the current element. The line: - -\starttyping -\xmlsetsetup{demo}{*}{-} -\stoptyping - -sets the default for each element to \quote {just ignore it}. A \type {+} would -make the default to always flush the content. This means that at this point we -only handle: - -\starttyping -<section> - <title>Some title</title> - <content> - <p>a paragraph of text</p> - </content> -</section> -\stoptyping - -In the next section we will deal with the slightly more complex itemize and -figure placement. At first sight all these setups may look overkill but keep in -mind that normally the number of elements is rather limited. The complexity is -often in the style and having access to each snippet of content is actually -quite handy for that. - -\stopsection - -\startsection[title={alternative solutions}] - -Dealing with an itemize is rather simple (as long as we forget about -attributes that control the behaviour): - -\starttyping -<itemize> - <item>first</item> - <item>second</item> -</itemize> -\stoptyping - -First we need to add \type {itemize} to the setup assignment (unless we've used -the wildcard \type {*}): - -\starttyping -\xmlsetsetup{demo}{document|section|p|itemize}{xml:demo:*} -\stoptyping - -The setup can look like: - -\starttyping -\startxmlsetups xml:demo:itemize - \startitemize - \xmlfilter{#1}{/item/command(xml:demo:itemize:item)} - \stopitemize -\stopxmlsetups - -\startxmlsetups xml:demo:itemize:item - \startitem - \xmlflush{#1} - \stopitem -\stopxmlsetups -\stoptyping - -An alternative is to map item directly: - -\starttyping -\xmlsetsetup{demo}{document|section|p|itemize|item}{xml:demo:*} -\stoptyping - -and use: - -\starttyping -\startxmlsetups xml:demo:itemize - \startitemize - \xmlflush{#1} - \stopitemize -\stopxmlsetups - -\startxmlsetups xml:demo:item - \startitem - \xmlflush{#1} - \stopitem -\stopxmlsetups -\stoptyping - -Sometimes, a more local solution using filters and \type {/command(...)} makes more -sense, especially when the \type {item} tag is used for other purposes as well. - -Explicit flushing with \type {command} is definitely the way to go when you have -complex products. In one of our projects we compose math school books from many -thousands of small \XML\ files, and from one source set several products are -typeset. Within a book sections get done differently, content gets used, ignored -or interpreted differently depending on the kind of content, so there is a -constant checking of attributes that drive the rendering. In that a generic setup -for a title element makes less sense than explicit ones for each case. (We're -talking of huge amounts of files here, including multiple images on each rendered -page.) - -When using \type {command} you can pass two arguments, the first is the setup for -the match, the second one for the miss, as in: - -\starttyping -\xmlfilter{#1}{/element/command(xml:true,xml:false)} -\stoptyping - -Back to the example, this leaves us with dealing with the resources, like -figures: - -\starttyping -<resource type='figure'> - <caption>A picture of a cow.</caption> - <content><external file="cow.pdf"/></content> -</resource> -\stoptyping - -Here we can use a more restricted match: - -\starttyping -\xmlsetsetup{demo}{resource[@type='figure']}{xml:demo:figure} -\xmlsetsetup{demo}{external}{xml:demo:*} -\stoptyping - -and the definitions: - -\starttyping -\startxmlsetups xml:demo:figure - \placefigure - {\xmlfirst{#1}{/caption}} - {\xmlfirst{#1}{/content}} -\stopxmlsetups - -\startxmlsetups xml:demo:external - \externalfigure[\xmlatt{#1}{file}] -\stopxmlsetups -\stoptyping - -At this point it is good to notice that \type {\xmlatt{#1}{file}} is passed as it -is: a macro call. This means that when a macro like \type {\externalfigure} uses -the first argument frequently without first storing its value, the lookup is done -several times. A solution for this is: - -\starttyping -\startxmlsetups xml:demo:external - \expanded{\externalfigure[\xmlatt{#1}{file}]} -\stopxmlsetups -\stoptyping - -Because the lookup is rather fast, normally there is no need to bother about this -too much because internally \CONTEXT\ already makes sure such expansion happens -only once. - -An alternative definition for placement is the following: - -\starttyping -\xmlsetsetup{demo}{resource}{xml:demo:resource} -\stoptyping - -with: - -\starttyping -\startxmlsetups xml:demo:resource - \placefloat - [\xmlatt{#1}{type}] - {\xmlfirst{#1}{/caption}} - {\xmlfirst{#1}{/content}} -\stopxmlsetups -\stoptyping - -This way you can specify \type {table} as type too. Because you can define your -own float types, more complex variants are also possible. In that case it makes -sense to provide some default behaviour too: - -\starttyping -\definefloat[figure-here][figure][default=here] -\definefloat[figure-left][figure][default=left] -\definefloat[table-here] [table] [default=here] -\definefloat[table-left] [table] [default=left] - -\startxmlsetups xml:demo:resource - \placefloat - [\xmlattdef{#1}{type}{figure}-\xmlattdef{#1}{location}{here}] - {\xmlfirst{#1}{/caption}} - {\xmlfirst{#1}{/content}} -\stopxmlsetups -\stoptyping - -In this example we support two types and two locations. We default to a figure -placed (when possible) at the current location. - -\stopsection - -\stopchapter - -\startchapter[title={Filtering content}] - -\startsection[title={\TEX\ versus \LUA}] - -It will not come as a surprise that we can access \XML\ files from \TEX\ as well -as from \LUA. In fact there are two methods to deal with \XML\ in \LUA. First -there are the low level \XML\ functions in the \type {xml} namespace. On top of -those functions there is a set of functions in the \type {lxml} namespace that -deals with \XML\ in a more \TEX ie way. Most of these have similar commands at -the \TEX\ end. - -\startbuffer -\startxmlsetups first:demo:one - \xmlfilter {#1} {artist/name[text()='Randy Newman']/.. - /albums/album[position()=3]/command(first:demo:two)} -\stopxmlsetups - -\startxmlsetups first:demo:two - \blank \start \tt - \xmldisplayverbatim{#1} - \stop \blank -\stopxmlsetups - -\xmlprocessfile{demo}{music-collection.xml}{first:demo:one} -\stopbuffer - -\typebuffer - -This gives the following snippet of verbatim \XML\ code. The indentation is -conform the indentation in the whole \XML\ file. \footnote {The (probably -outdated) \XML\ file contains the collection stores on my slimserver instance. -You can use the \type {mtxrun --script flac} to generate such files.} - -\doifmodeelse {atpragma} { - \getbuffer -} { - \typefile{xml-mkiv-01.xml} -} - -An alternative written in \LUA\ looks as follows: - -\startbuffer -\blank \start \tt \startluacode - local m = lxml.load("mine","music-collection.xml") -- m == lxml.id("mine") - local p = "artist/name[text()='Randy Newman']/../albums/album[position()=4]" - local l = lxml.filter(m,p) -- returns a list (with one entry) - lxml.displayverbatim(l[1]) -\stopluacode \stop \blank -\stopbuffer - -\typebuffer - -This produces: - -\doifmodeelse {atpragma} { - \getbuffer -} { - \typefile{xml-mkiv-02.xml} -} - -You can use both methods mixed but in practice we will use the \TEX\ commands in -regular styles and the mixture in modules, for instance in those dealing with -\MATHML\ and cals tables. For complex matters you can write your own finalizers -(the last action to be taken in a match) in \LUA\ and use them at the \TEX\ end. - -\stopsection - -\startsection[title={a few details}] - -In \CONTEXT\ setups are a rather common variant on macros (\TEX\ commands) but -with their own namespace. An example of a setup is: - -\starttyping -\startsetup doc:print - \setuppapersize[A4][A4] -\stopsetup - -\startsetup doc:screen - \setuppapersize[S6][S4] -\stopsetup -\stoptyping - -Given the previous definitions, later on we can say something like: - -\starttyping -\doifmodeelse {paper} { - \setup[doc:print] -} { - \setup[doc:screen] -} -\stoptyping - -Another example is: - -\starttyping -\startsetup[doc:header] - \marking[chapter] - \space - -- - \space - \pagenumber -\stopsetup -\stoptyping - -in combination with: - -\starttyping -\setupheadertexts[\setup{doc:header}] -\stoptyping - -Here the advantage is that instead of ending up with an unreadable header -definitions, we use a nicely formatted setup. An important property of setups and -the reason why they were introduced long ago is that spaces and newlines are -ignored in the definition. This means that we don't have to worry about so called -spurious spaces but it also means that when we do want a space, we have to use -the \type {\space} command. - -The only difference between setups and \XML\ setups is that the following ones -get an argument (\type {#1}) that reflects the current node in the \XML\ tree. - -\stopsection - -\startsection[title={CDATA}] - -What to do with \type {CDATA}? There are a few methods at tle \LUA\ end for -dealing with it but here we just mention how you can influence the rendering. -There are four macros that play a role here: - -\starttyping -\unexpanded\def\xmlcdataobeyedline {\obeyedline} -\unexpanded\def\xmlcdataobeyedspace{\strut\obeyedspace} -\unexpanded\def\xmlcdatabefore {\begingroup\tt} -\unexpanded\def\xmlcdataafter {\endgroup} -\stoptyping - -Technically you can overload them but beware of side effects. Normally you won't -see much \type {CDATA} and whenever we do, it involves special data that needs -very special treatment anyway. - -\stopsection - -\startsection[title={Entities}] - -As usual with any way of encoding documents you need escapes in order to encode -the characters that are used in tagging the content, embedding comments, escaping -special characters in strings (in programming languages), etc. In \XML\ this -means that in order characters like \type {<} you need an escape like \type -{<} and in order then to encode an \type {&} you need \type {&}. - -In a typesetting workflow using a programming language like \TEX, another problem -shows up. There we have different special characters, like \type {$ $} for triggering -math, but also the backslash, braces etc. Even one such special character is already -enough to have yet another escaping mechanism at work. - -Ideally a user should not worry about these issues but it helps figuring out issues -when you know what happens under the hood. Also it is good to know that in the -code there are several ways to deal with these issues. Take the following document: - -\starttyping -<text> - Here we have a bit of a <&mess>: - - # # - % % - \ \ - { { - | | - } } - ~ ~ -</text> -\stoptyping - -When the file is read the \type {<} entity will be replaced by \type {<} and -the \type {>} by \type {>}. The numeric entities will be replaced by the -characters they refer to. The \type {&mess} is kind of special. We do preload -a huge list of more or less standardized entities but \type {mess} is not in -there. However, it is possible to have it defined in the document preamble, like: - -\starttyping -<!DOCTYPE dummy SYSTEM "dummy.dtd" [ - <!ENTITY mess "what a mess" > -]> -\stoptyping - -or even this: - -\starttyping -<!DOCTYPE dummy SYSTEM "dummy.dtd" [ - <!ENTITY mess "<p>what a mess</p>" > -]> -\stoptyping - -You can also define it in your document style using one of: - -\startxmlcmd {\cmdbasicsetup{xmlsetentity}} - replaces entity with name \cmdinternal {cd:name} by \cmdinternal {cd:text} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmltexentity}} - replaces entity with name \cmdinternal {cd:name} by \cmdinternal {cd:text} - typeset under a \TEX\ regime -\stopxmlcmd - -Such a definition will always have a higher priority than the one defined -in the document. Anyway, when the document is read in all entities are -resolved and those that need a special treatment because they map to some -text are stored in such a way that we can roundtrip them. As a consequence, -as soon as the content gets pushed into \TEX, we need not only to intercept -special characters but also have to make sure that the following works: - -\starttyping -\xmltexentity {tex} {\TEX} -\stoptyping - -Here the backslash starts a control sequence while in regular content a -backslash is just that: a backslash. - -Special characters are really special when we have to move text around -in a \TEX\ ecosystem. - -\starttyping -<text> - <title>About #3</title> -</text> -\stoptyping - -If we map and define title as follows: - -\starttyping -\startxmlsetup xml:title - \title{\xmlflush{#1}} -\stopxmlsetup -\stoptyping - -normally something \type {\xmlflush {id::123}} will be written to the -auxiliary file and in most cases that is quite okay, but if we have this: - -\starttyping -\setuphead[title][expansion=yes] -\stoptyping - -then we don't want the \type {#} to end up as hash because later on \TEX\ -can get very confused about it because it sees some argument then in a -probably unexpected way. This is solved by escaping the hash like this: - -\starttyping -About \Ux{23}3 -\stoptyping - -The \type {\Ux} command will convert its hexadecimal argument into a -character. Of course one then needs to typeset such a text under a \TEX\ -character regime but that is normally the case anyway. - -\stopsection - -\stopchapter - -\startchapter[title={Commands}] - -\startsection[title={nodes and lpaths}] - -The amount of commands available for manipulating the \XML\ file is rather large. -Many of the commands cooperate with the already discussed setups, a fancy name -for a collection of macro calls either or not mixed with text. - -Most of the commands are just shortcuts to \LUA\ calls, which means that the real -work is done by \LUA. In fact, what happens is that we have a continuous transfer -of control from \TEX\ to \LUA, where \LUA\ prints back either data (like element -content or attribute values) or just invokes a setup whereby it passes a -reference to the node resolved conform the path expression. The invoked setup -itself might return control to \LUA\ again, etc. - -This sounds complicated but examples will show what we mean here. First we -present the whole repertoire of commands. Because users can read the source code, -they might uncover more commands, but only the ones discussed here are official. -The commands are grouped in categories. - -In the following sections \cmdinternal {cd:node} means a reference to a node: -this can be the identifier of the root (the loaded xml tree) or a reference to a -node in that tree (often the result of some lookup. A \cmdinternal {cd:lpath} is -a fancy name for a path expression (as with \XSLT) but resolved by \LUA. - -\stopsection - -\startsection[title={commands}] - -There are a lot of commands available but you probably can ignore most of them. -We try to be complete which means that there is for instance \type {\xmlfirst} as -well as \type {\xmllast} but you probably never need the last one. There are also -commands that were used when testing this interface and we see no reason to -remove them. Some obscure ones are used in modules and after a while even I often -forget that they exist. To give you an idea of what commands are important we -show their use in generating the \CONTEXT\ command definitions (\type -{x-set-11.mkiv}) per January 2016: - -\startcolumns[n=2,balance=yes] -\starttabulate[|l|r|] -\NC \type {\xmlall} \NC 1 \NC \NR -\NC \type {\xmlatt} \NC 23 \NC \NR -\NC \type {\xmlattribute} \NC 1 \NC \NR -\NC \type {\xmlcount} \NC 1 \NC \NR -\NC \type {\xmldoif} \NC 2 \NC \NR -\NC \type {\xmldoifelse} \NC 1 \NC \NR -\NC \type {\xmlfilterlist} \NC 4 \NC \NR -\NC \type {\xmlflush} \NC 5 \NC \NR -\NC \type {\xmlinclude} \NC 1 \NC \NR -\NC \type {\xmlloadonly} \NC 1 \NC \NR -\NC \type {\xmlregisterdocumentsetup} \NC 1 \NC \NR -\NC \type {\xmlsetsetup} \NC 1 \NC \NR -\NC \type {\xmlsetup} \NC 4 \NC \NR -\stoptabulate -\stopcolumns - -As you can see filtering, flushing and accessing attributes score high. Below we show -the statistics of a quite complex rendering (5 variants of schoolbooks: basic book, -answers, teachers guide, worksheets, full blown version with extensive tracing). - -\startcolumns[n=2,balance=yes] -\starttabulate[|l|r|] -\NC \type {\xmladdindex} \NC 3 \NC \NR -\NC \type {\xmlall} \NC 5 \NC \NR -\NC \type {\xmlappendsetup} \NC 1 \NC \NR -\NC \type {\xmlapplyselectors} \NC 1 \NC \NR -\NC \type {\xmlatt} \NC 40 \NC \NR -\NC \type {\xmlattdef} \NC 9 \NC \NR -\NC \type {\xmlattribute} \NC 10 \NC \NR -\NC \type {\xmlbadinclusions} \NC 3 \NC \NR -\NC \type {\xmlconcat} \NC 3 \NC \NR -\NC \type {\xmlcount} \NC 1 \NC \NR -\NC \type {\xmldelete} \NC 11 \NC \NR -\NC \type {\xmldoif} \NC 39 \NC \NR -\NC \type {\xmldoifelse} \NC 28 \NC \NR -\NC \type {\xmldoifelsetext} \NC 13 \NC \NR -\NC \type {\xmldoifnot} \NC 2 \NC \NR -\NC \type {\xmldoifnotselfempty} \NC 1 \NC \NR -\NC \type {\xmlfilter} \NC 100 \NC \NR -\NC \type {\xmlfirst} \NC 51 \NC \NR -\NC \type {\xmlflush} \NC 69 \NC \NR -\NC \type {\xmlflushcontext} \NC 2 \NC \NR -\NC \type {\xmlinclude} \NC 1 \NC \NR -\NC \type {\xmlincludeoptions} \NC 5 \NC \NR -\NC \type {\xmlinclusion} \NC 16 \NC \NR -\NC \type {\xmlinjector} \NC 1 \NC \NR -\NC \type {\xmlloaddirectives} \NC 1 \NC \NR -\NC \type {\xmlmapvalue} \NC 4 \NC \NR -\NC \type {\xmlmatch} \NC 1 \NC \NR -\NC \type {\xmlprependsetup} \NC 5 \NC \NR -\NC \type {\xmlregisterdocumentsetup} \NC 2 \NC \NR -\NC \type {\xmlregistersetup} \NC 1 \NC \NR -\NC \type {\xmlremapnamespace} \NC 1 \NC \NR -\NC \type {\xmlsetfunction} \NC 2 \NC \NR -\NC \type {\xmlsetinjectors} \NC 2 \NC \NR -\NC \type {\xmlsetsetup} \NC 11 \NC \NR -\NC \type {\xmlsetup} \NC 76 \NC \NR -\NC \type {\xmlstrip} \NC 1 \NC \NR -\NC \type {\xmlstripanywhere} \NC 1 \NC \NR -\NC \type {\xmltag} \NC 1 \NC \NR -\NC \type {\xmltext} \NC 53 \NC \NR -\NC \type {\xmlvalue} \NC 2 \NC \NR -\stoptabulate -\stopcolumns - -Here many more are used but this is an exceptional case. The top is again -dominated by filtering, flushing and attribute consulting. The list can actually -be smaller. For instance, the \type {\xmlcount} can just as well be \type -{\xmlfilter} with a \type {count} finalizer. There are also some special ones, -like the injectors, that are needed for finetuning the final result. - -\stopsection - -\startsection[title={loading}] - -\startxmlcmd {\cmdbasicsetup{xmlloadfile}} - loads the file \cmdinternal {cd:file} and registers it under \cmdinternal - {cd:name} and applies either given or standard \cmdinternal - {cd:xmlsetup} (alias: \type {\xmlload}) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlloadbuffer}} - loads the buffer \cmdinternal {cd:buffer} and registers it under - \cmdinternal {cd:name} and applies either given or standard - \cmdinternal {cd:xmlsetup} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlloaddata}} - loads \cmdinternal {cd:text} and registers it under \cmdinternal - {cd:name} and applies either given or standard \cmdinternal - {cd:xmlsetup} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlloadonly}} - loads \cmdinternal {cd:text} and registers it under \cmdinternal - {cd:name} and applies either given or standard \cmdinternal - {cd:xmlsetup} but doesn't flush the content -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlinclude}} - includes the file specified by attribute \cmdinternal {cd:name} of the - element located by \cmdinternal {cd:lpath} at node \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlprocessfile}} - registers file \cmdinternal {cd:file} as \cmdinternal {cd:name} and - process the tree starting with \cmdinternal {cd:xmlsetup} (alias: - \type {\xmlprocess}) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlprocessbuffer}} - registers buffer \cmdinternal {cd:name} as \cmdinternal {cd:name} and process - the tree starting with \cmdinternal {cd:xmlsetup} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlprocessdata}} - registers \cmdinternal {cd:text} as \cmdinternal {cd:name} and process - the tree starting with \cmdinternal {cd:xmlsetup} -\stopxmlcmd - -The initial setup defaults to \type {xml:process} that is defined -as follows: - -\starttyping -\startsetups xml:process - \xmlregistereddocumentsetups\xmldocument - \xmlmain\xmldocument -\stopsetups -\stoptyping - -First we apply the setups associated with the document (including common setups) -and then we flush the whole document. The macro \type {\xmldocument} expands to -the current document id. There is also \type {\xmlself} which expands to the -current node number (\type {#1} in setups). - -\startxmlcmd {\cmdbasicsetup{xmlmain}} - returns the whole document -\stopxmlcmd - -Normally such a flush will trigger a chain reaction of setups associated with the -child elements. - -\stopsection - -\startsection[title={saving}] - -\startxmlcmd {\cmdbasicsetup{xmlsave}} - saves the given node \cmdinternal {cd:node} in the file \cmdinternal {cd:file} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmltofile}} - saves the match of \cmdinternal {cd:lpath} in the file \cmdinternal {cd:file} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmltobuffer}} - saves the match of \cmdinternal {cd:lpath} in the buffer \cmdinternal {cd:buffer} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmltobufferverbose}} - saves the match of \cmdinternal {cd:lpath} verbatim in the buffer \cmdinternal - {cd:buffer} -\stopxmlcmd - -% \startxmlcmd {\cmdbasicsetup{xmltoparameters}} -% converts the match of \cmdinternal {cd:lpath} to key|/|values (for tracing) -% \stopxmlcmd - -The next command is only needed when you have messed with the tree using -\LUA\ code. - -\startxmlcmd {\cmdbasicsetup{xmladdindex}} - (re)indexes a tree -\stopxmlcmd - -The following macros are only used in special situations and are not really meant -for users. - -\startxmlcmd {\cmdbasicsetup{xmlraw}} - flush the content if \cmdinternal {cd:node} with original entities -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{startxmlraw}} - flush the wrapped content with original entities -\stopxmlcmd - -\stopsection - -\startsection[title={flushing data}] - -When we flush an element, the associated \XML\ setups are expanded. The most -straightforward way to flush an element is the following. Keep in mind that the -returned values itself can trigger setups and therefore flushes. - -\startxmlcmd {\cmdbasicsetup{xmlflush}} - returns all nodes under \cmdinternal {cd:node} -\stopxmlcmd - -You can restrict flushing by using commands that accept a specification. - -\startxmlcmd {\cmdbasicsetup{xmltext}} - returns the text of the matching \cmdinternal {cd:lpath} under \cmdinternal - {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlpure}} - returns the text of the matching \cmdinternal {cd:lpath} under \cmdinternal - {cd:node} without \type {\Ux} escaped special \TEX\ characters -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlflushtext}} - returns the text of the \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlflushpure}} - returns the text of the \cmdinternal {cd:node} without \type {\Ux} escaped - special \TEX\ characters -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlnonspace}} - returns the text of the matching \cmdinternal {cd:lpath} under \cmdinternal - {cd:node} without embedded spaces -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlall}} - returns all nodes under \cmdinternal {cd:node} that matches \cmdinternal - {cd:lpath} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmllastmatch}} - returns all nodes found in the last match -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlfirst}} - returns the first node under \cmdinternal {cd:node} that matches \cmdinternal - {cd:lpath} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmllast}} - returns the last node under \cmdinternal {cd:node} that matches \cmdinternal - {cd:lpath} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlfilter}} - at a match of \cmdinternal {cd:lpath} a given filter \type {filter} is applied - and the result is returned -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlsnippet}} - returns the \cmdinternal {cd:number}\high{th} element under \cmdinternal - {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlposition}} - returns the \cmdinternal {cd:number}\high{th} match of \cmdinternal - {cd:lpath} at node \cmdinternal {cd:node}; a negative number starts at the - end (alias: \type {\xmlindex}) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlelement}} - returns the \cmdinternal {cd:number}\high{th} child of node \cmdinternal {cd:node}; - a negative number starts at the end -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlpos}} - returns the index (position) in the parent node of \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlconcat}} - returns the sequence of nodes that match \cmdinternal {cd:lpath} at - \cmdinternal {cd:node} whereby \cmdinternal {cd:text} is put between each - match -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlconcatrange}} - returns the \cmdinternal {cd:first}\high {th} upto \cmdinternal - {cd:last}\high {th} of nodes that match \cmdinternal {cd:lpath} at - \cmdinternal {cd:node} whereby \cmdinternal {cd:text} is put between each - match -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlcommand}} - apply the given \cmdinternal {cd:xmlsetup} to each match of \cmdinternal - {cd:lpath} at node \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlstrip}} - remove leading and trailing spaces from nodes under \cmdinternal {cd:node} - that match \cmdinternal {cd:lpath} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlstripped}} - remove leading and trailing spaces from nodes under \cmdinternal {cd:node} - that match \cmdinternal {cd:lpath} and return the content afterwards -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlstripnolines}} - remove leading and trailing spaces as well as collapse embedded spaces - from nodes under \cmdinternal {cd:node} that match \cmdinternal {cd:lpath} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlstrippednolines}} - remove leading and trailing spaces as well as collapse embedded spaces from - nodes under \cmdinternal {cd:node} that match \cmdinternal {cd:lpath} and - return the content afterwards -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlverbatim}} - flushes the content verbatim code (without any wrapping, i.e. no fonts - are selected and such) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlinlineverbatim}} - return the content of the node as inline verbatim code; no further - interpretation (expansion) takes place and spaces are honoured; it uses the - following wrapper -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{startxmlinlineverbatim}} - wraps inline verbatim mode using the environment specified (a prefix \type - {xml:} is added to the environment name) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldisplayverbatim}} - return the content of the node as display verbatim code; no further - interpretation (expansion) takes place and leading and trailing spaces and - newlines are treated special; it uses the following wrapper -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{startxmldisplayverbatim}} - wraps the content in display verbatim using the environment specified (a prefix - \type {xml:} is added to the environment name) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlprettyprint}} - pretty print (with colors) the node \cmdinternal {cd:node}; use the \CONTEXT\ - \SCITE\ lexers when available (\type {\usemodule [scite]}) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlflushspacewise}} - flush node \cmdinternal {cd:node} obeying spaces and newlines -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlflushlinewise}} - flush node \cmdinternal {cd:node} obeying newlines -\stopxmlcmd - -\stopsection - -\startsection[title={information}] - -The following commands return strings. Normally these are used in tests. - -\startxmlcmd {\cmdbasicsetup{xmlname}} - returns the complete name (including namespace prefix) of the - given \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlnamespace}} - returns the namespace of the given \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmltag}} - returns the tag of the element, without namespace prefix -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlcount}} - returns the number of matches of \cmdinternal {cd:lpath} at node \cmdinternal - {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlatt}} - returns the value of attribute \cmdinternal {cd:name} or empty if no such - attribute exists -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlattdef}} - returns the value of attribute \cmdinternal {cd:name} or \cmdinternal - {cd:string} if no such attribute exists -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlrefatt}} - returns the value of attribute \cmdinternal {cd:name} or empty if no such - attribute exists; a leading \type {#} is removed (nicer for tex) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlchainatt}} - returns the value of attribute \cmdinternal {cd:name} or empty if no such - attribute exists; backtracks till a match is found -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlchainattdef}} - returns the value of attribute \cmdinternal {cd:name} or \cmdinternal - {cd:string} if no such attribute exists; backtracks till a match is found -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlattribute}} - finds a first match for \cmdinternal {cd:lpath} at \cmdinternal {cd:node} and - returns the value of attribute \cmdinternal {cd:name} or empty if no such - attribute exists -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlattributedef}} - finds a first match for \cmdinternal {cd:lpath} at \cmdinternal {cd:node} and - returns the value of attribute \cmdinternal {cd:name} or \cmdinternal - {cd:text} if no such attribute exists -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmllastatt}} - returns the last attribute found (this avoids a lookup) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlsetatt}} - set the value of attribute \cmdinternal {cd:name} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlsetattribute}} - set the value of attribute \cmdinternal {cd:name} for each match of \cmdinternal - {cd:lpath} -\stopxmlcmd - -\stopsection - -\startsection[title={manipulation}] - -You can use \LUA\ code to manipulate the tree and it makes no sense to duplicate -this in \TEX. In the future we might provide an interface to some of this -functionality. Keep in mind that manipuating the tree might have side effects as -we maintain several indices into the tree that also needs to be updated then. - -\stopsection - -\startsection[title={integration}] - -If you write a module that deals with \XML, for instance processing cals tables, -then you need ways to control specific behaviour. For instance, you might want to -add a background to the table. Such directives are collected in \XML\ files and -can be loaded on demand. - -\startxmlcmd {\cmdbasicsetup{xmlloaddirectives}} - loads \CONTEXT\ directives from \cmdinternal {cd:file} that will get - interpreted when processing documents -\stopxmlcmd - -A directives definition file looks as follows: - -\starttyping -<?xml version="1.0" standalone="yes"?> - -<directives> - <directive attribute='id' value="100" - setup="cdx:100"/> - <directive attribute='id' value="101" - setup="cdx:101"/> - <directive attribute='cdx' value="colors" element="cals:table" - setup="cdx:cals:table:colors"/> - <directive attribute='cdx' value="vertical" element="cals:table" - setup="cdx:cals:table:vertical"/> - <directive attribute='cdx' value="noframe" element="cals:table" - setup="cdx:cals:table:noframe"/> - <directive attribute='cdx' value="*" element="cals:table" - setup="cdx:cals:table:*"/> -</directives> -\stoptyping - -Examples of usage can be found in \type {x-cals.mkiv}. The directive is triggered -by an attribute. Instead of a setup you can specify a setup to be applied before -and after the node gets flushed. - -\startxmlcmd {\cmdbasicsetup{xmldirectives}} - apply the setups directive associated with the node -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldirectivesbefore}} - apply the before directives associated with the node -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldirectivesafter}} - apply the after directives associated with the node -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlinstalldirective}} - defines a directive that hooks into a handler -\stopxmlcmd - -Normally a directive will be put in the \XML\ file, for instance as: - -\starttyping -<?context-mathml-directive minus reduction yes ?> -\stoptyping - -Here the \type {mathml} is the general class of directives and \type {minus} a -subclass, in our case a specific element. - -\stopsection - -\startsection[title={setups}] - -The basic building blocks of \XML\ processing are setups. These are just -collections of macros that are expanded. These setups get one argument passed -(\type {#1}): - -\starttyping -\startxmlsetups somedoc:somesetup - \xmlflush{#1} -\stopxmlsetups -\stoptyping - -This argument is normally a number that internally refers to a specific node in -the \XML\ tree. The user should see it as an abstract reference and not depend on -its numeric property. Just think of it as \quote {the current node}. You can (and -probably will) call such setups using: - -\startxmlcmd {\cmdbasicsetup{xmlsetup}} - expands setup \cmdinternal {cd:setup} and pass \cmdinternal {cd:node} as - argument -\stopxmlcmd - -However, in most cases the setups are associated to specific elements, -something that users of \XSLT\ might recognize as templates. - -\startxmlcmd {\cmdbasicsetup{xmlsetfunction}} - associates function \cmdinternal {cd:luafunction} to the elements in - namespace \cmdinternal {cd:name} that match \cmdinternal {cd:lpath} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlsetsetup}} - associates setups \cmdinternal {cd:setup} (\TEX\ code) with the matching - nodes of \cmdinternal {cd:lpath} or root \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlprependsetup}} - pushes \cmdinternal {cd:setup} to the front of global list of setups -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlappendsetup}} - adds \cmdinternal {cd:setup} to the global list of setups to be applied - (alias: \type{\xmlregistersetup}) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlbeforesetup}} - pushes \cmdinternal {cd:setup} into the global list of setups; the - last setup is the position -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlaftersetup}} - adds \cmdinternal {cd:setup} to the global list of setups; the last setup - is the position -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlremovesetup}} - removes \cmdinternal {cd:setup} from the global list of setups -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlprependdocumentsetup}} - pushes \cmdinternal {cd:setup} to the front of list of setups to be applied - to \cmdinternal {cd:name} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlappenddocumentsetup}} - adds \cmdinternal {cd:setup} to the list of setups to be applied to - \cmdinternal {cd:name} (you can also use the alias: \type - {\xmlregisterdocumentsetup}) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlbeforedocumentsetup}} - pushes \cmdinternal {cd:setup} into the setups to be applied to \cmdinternal - {cd:name}; the last setup is the position -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlafterdocumentsetup}} - adds \cmdinternal {cd:setup} to the setups to be applied to \cmdinternal - {cd:name}; the last setup is the position -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlremovedocumentsetup}} - removes \cmdinternal {cd:setup} from the global list of setups to be applied - to \cmdinternal {cd:name} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlresetsetups}} - removes all global setups -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlresetdocumentsetups}} - removes all setups from the \cmdinternal {cd:name} specific list of setups to - be applied -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlflushdocumentsetups}{setup}} - applies \cmdinternal {cd:setup} (can be a list) to \cmdinternal {cd:name} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlregisteredsetups}} - applies all global setups to the current document -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlregistereddocumentsetups}} - applies all document specific \cmdinternal {cd:setup} to document - \cmdinternal {cd:name} -\stopxmlcmd - -\stopsection - -\startsection[title={testing}] - -The following test macros all take a \cmdinternal {cd:node} as first argument -and an \cmdinternal {cd:lpath} as second: - -\startxmlcmd {\cmdbasicsetup{xmldoif}} - expands to \cmdinternal {cd:true} when \cmdinternal {cd:lpath} matches at - node \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifnot}} - expands to \cmdinternal {cd:true} when \cmdinternal {cd:lpath} does not match - at node \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifelse}} - expands to \cmdinternal {cd:true} when \cmdinternal {cd:lpath} matches at - node \cmdinternal {cd:node} and to \cmdinternal {cd:false} otherwise -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoiftext}} - expands to \cmdinternal {cd:true} when the node matching \cmdinternal - {cd:lpath} at node \cmdinternal {cd:node} has some content -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifnottext}} - expands to \cmdinternal {cd:true} when the node matching \cmdinternal - {cd:lpath} at node \cmdinternal {cd:node} has no content -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifelsetext}} - expands to \cmdinternal {cd:true} when the node matching \cmdinternal - {cd:lpath} at node \cmdinternal {cd:node} has content and to \cmdinternal - {cd:false} otherwise -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifatt}} - expands to \cmdinternal {cd:true} when the attribute matching \cmdinternal - {cd:node} and the name given as second argument matches the third argument -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifnotatt}} - expands to \cmdinternal {cd:true} when the attribute matching \cmdinternal - {cd:node} and the name given as second argument differs from the third - argument -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifelseatt}} - expands to \cmdinternal {cd:true} when the attribute matching \cmdinternal - {cd:node} and the name given as second argument matches the third argument - and to \cmdinternal {cd:false} otherwise -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifelseempty}} - expands to \cmdinternal {cd:true} when the node matching \cmdinternal - {cd:lpath} at node \cmdinternal {cd:node} is empty and to \cmdinternal - {cd:false} otherwise -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifelseselfempty}} - expands to \cmdinternal {cd:true} when the node is empty and to \cmdinternal - {cd:false} otherwise -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifselfempty}} - expands to \cmdinternal {cd:true} when \cmdinternal {cd:node} is empty -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifnotselfempty}} - expands to \cmdinternal {cd:true} when \cmdinternal {cd:node} is not empty -\stopxmlcmd - -\stopsection - -\startsection[title={initialization}] - -The general setup command (not to be confused with setups) that deals with the -\MKIV\ tree handler is \type {\setupxml}. There are currently only a few options. - -\cmdfullsetup{setupxml} - -When you set \type {default} to \cmdinternal {cd:text} elements with no setup -assigned will end up as text. When set to \type {hidden} such elements will be -hidden. You can apply the default yourself using: - -\startxmlcmd {\cmdbasicsetup{xmldefaulttotext}} - presets the tree with root \cmdinternal {cd:node} to the handlers set up with - \type {\setupxml} option \cmdinternal{default} -\stopxmlcmd - -You can set \type {compress} to \type {yes} in which case comment is stripped -from the tree when the file is read. - -\startxmlcmd {\cmdbasicsetup{xmlregisterns}} - associates an internal namespace (like \type {mml}) with one given in the - document as \URL\ (like mathml) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlremapname}} - changes the namespace and tag of the matching elements -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlremapnamespace}} - replaces all references to the given namespace to a new one (applied - recursively) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlchecknamespace}} - sets the namespace of the matching elements unless a namespace is already set -\stopxmlcmd - -\stopsection - -\startsection[title={helpers}] - -Often an attribute will determine the rendering and this may result in many -tests. Especially when we have multiple attributes that control the output such -tests can become rather extensive and redundant because one gets $n\times m$ or -more such tests. - -Therefore we have a convenient way to map attributes onto for instance strings or -commands. - -\startxmlcmd {\cmdbasicsetup{xmlmapvalue}} - associate a \cmdinternal {cd:text} with a \cmdinternal {cd:category} and - \cmdinternal {cd:name} (alias: \type{\xmlmapval}) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlvalue}} - expand the value associated with a \cmdinternal {cd:category} and - \cmdinternal {cd:name} and if not resolved, expand to the \cmdinternal - {cd:text} (alias: \type{\xmlval}) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmldoifelsevalue}} - associate a \cmdinternal {cd:text} with a \cmdinternal {cd:category} and - \cmdinternal {cd:name} -\stopxmlcmd - -This is used as follows. We define a couple of mappings in the same category: - -\starttyping -\xmlmapvalue{emph}{bold} {\bf} -\xmlmapvalue{emph}{italic}{\it} -\stoptyping - -Assuming that we have associated the following setup with the \type {emph} -element, we can say (with \type {#1} being the current element): - -\starttyping -\startxmlsetups demo:emph - \begingroup - \xmlvalue{emph}{\xmlatt{#1}{type}}{} - \endgroup -\stopxmlsetups -\stoptyping - -In this case we have no default. The \type {type} attribute triggers the actions, -as in: - -\starttyping -normal <emph type='bold'>bold</emph> normal -\stoptyping - -This mechanism is not really bound to elements and attributes so you can use this -mechanism for other purposes as well. - -\stopsection - -\startsection[title={Parameters}] - -\startbuffer[test] -<something whatever="alpha"> - <what> - beta - </what> -</something> -\stopbuffer - -\startbuffer -\startxmlsetups xml:mysetups - \xmlsetsetup{\xmldocument}{*}{xml:*} -\stopxmlsetups - -\xmlregistersetup{xml:mysetups} - -\startxmlsetups xml:something - parameter : \xmlpar {#1}{whatever}\par - attribute : \xmlatt {#1}{whatever}\par - text : \xmlfirst {#1}{what} \par - \xmlsetpar{#1}{whatever}{gamma} - parameter : \xmlpar {#1}{whatever}\par - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:what - what: \xmlflush{#1}\par - parameter : \xmlparam{#1}{..}{whatever}\par -\stopxmlsetups - -\xmlprocessbuffer{main}{test}{} -\stopbuffer - -Say that we have this \XML\ blob: - -\typebuffer[test] - -With: - -\typebuffer - -we get: - -\getbuffer - -Parameters are stored with a node. - -\startxmlcmd {\cmdbasicsetup{xmlpar}} - returns the value of parameter \cmdinternal {cd:name} or empty if no such - parameter exists -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlparam}} - finds a first match for \cmdinternal {cd:lpath} at \cmdinternal {cd:node} and - returns the value of parameter \cmdinternal {cd:name} or empty if no such - parameter exists -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmllastpar}} - returns the last parameter found (this avoids a lookup) -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlsetpar}} - set the value of parameter \cmdinternal {cd:name} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlsetparam}} - set the value of parameter \cmdinternal {cd:name} for each match of \cmdinternal - {cd:lpath} -\stopxmlcmd - -\stopsection - -\stopchapter - -\startchapter[title={Expressions and filters}] - -\startsection[title={path expressions}] - -In the previous chapters we used \cmdinternal {cd:lpath} expressions, which are a variant -on \type {xpath} expressions as in \XSLT\ but in this case more geared towards -usage in \TEX. This mechanisms will be extended when demands are there. - -A path is a sequence of matches. A simple path expression is: - -\starttyping -a/b/c/d -\stoptyping - -Here each \type {/} goes one level deeper. We can go backwards in a lookup with -\type {..}: - -\starttyping -a/b/../d -\stoptyping - -We can also combine lookups, as in: - -\starttyping -a/(b|c)/d -\stoptyping - -A negated lookup is preceded by a \type {!}: - -\starttyping -a/(b|c)/!d -\stoptyping - -A wildcard is specified with a \type {*}: - -\starttyping -a/(b|c)/!d/e/*/f -\stoptyping - -In addition to these tag based lookups we can use attributes: - -\starttyping -a/(b|c)/!d/e/*/f[@type=whatever] -\stoptyping - -An \type {@} as first character means that we are dealing with an attribute. -Within the square brackets there can be boolean expressions: - -\starttyping -a/(b|c)/!d/e/*/f[@type=whatever and @id>100] -\stoptyping - -You can use functions as in: - -\starttyping -a/(b|c)/!d/e/*/f[something(text()) == "oeps"] -\stoptyping - -There are a couple of predefined functions: - -\starttabulate[|l|l|p|] -\NC \type{rootposition} \type{order} \NC number \NC the index of the matched root element (kind of special) \NC \NR -\NC \type{position} \NC number \NC the current index of the matched element in the match list \NC \NR -\NC \type{match} \NC number \NC the current index of the matched element sub list with the same parent \NC \NR -\NC \type{first} \NC number \NC \NC \NR -\NC \type{last} \NC number \NC \NC \NR -\NC \type{index} \NC number \NC the current index of the matched element in its parent list \NC \NR -\NC \type{firstindex} \NC number \NC \NC \NR -\NC \type{lastindex} \NC number \NC \NC \NR -\NC \type{element} \NC number \NC the element's index \NC \NR -\NC \type{firstelement} \NC number \NC \NC \NR -\NC \type{lastelement} \NC number \NC \NC \NR -\NC \type{text} \NC string \NC the textual representation of the matched element \NC \NR -\NC \type{content} \NC table \NC the node of the matched element \NC \NR -\NC \type{name} \NC string \NC the full name of the matched element: namespace and tag \NC \NR -\NC \type{namespace} \type{ns} \NC string \NC the namespace of the matched element \NC \NR -\NC \type{tag} \NC string \NC the tag of the matched element \NC \NR -\NC \type{attribute} \NC string \NC the value of the attribute with the given name of the matched element \NC \NR -\stoptabulate - -There are fundamental differences between \type {position}, \type {match} and -\type {index}. Each step results in a new list of matches. The \type {position} -is the index in this new (possibly intermediate) list. The \type {match} is also -an index in this list but related to the specific match of element names. The -\type {index} refers to the location in the parent element. - -Say that we have: - -\starttyping -<collection> - <resources> - <manual> - <screen>.1.</screen> - <paper>.1.</paper> - </manual> - <manual> - <paper>.2.</paper> - <screen>.2.</screen> - </manual> - <resources> - <resources> - <manual> - <screen>.3.</screen> - <paper>.3.</paper> - </manual> - <resources> -<collection> -\stoptyping - -The following then applies: - -\starttabulate[|l|l|] -\NC \type {collection/resources/manual[position()==1]/paper} \NC \type{.1.} \NC \NR -\NC \type {collection/resources/manual[match()==1]/paper} \NC \type{.1.} \type{.3.} \NC \NR -\NC \type {collection/resources/manual/paper[index()==1]} \NC \type{.2.} \NC \NR -\stoptabulate - -In most cases the \type {position} test is more restrictive than the \type -{match} test. - -You can pass your own functions too. Such functions are defined in the \type -{xml.expressions} namespace. We have defined a few shortcuts: - -\starttabulate[|l|l|] -\NC \type {find(str,pattern)} \NC \type{string.find} \NC \NR -\NC \type {contains(str)} \NC \type{string.find} \NC \NR -\NC \type {oneof(str,...)} \NC is \type{str} in list \NC \NR -\NC \type {upper(str)} \NC \type{characters.upper} \NC \NR -\NC \type {lower(str)} \NC \type{characters.lower} \NC \NR -\NC \type {number(str)} \NC \type{tonumber} \NC \NR -\NC \type {boolean(str)} \NC \type{toboolean} \NC \NR -\NC \type {idstring(str)} \NC removes leading hash \NC \NR -\NC \type {name(index)} \NC full tag name \NC \NR -\NC \type {tag(index)} \NC tag name \NC \NR -\NC \type {namespace(index)} \NC namespace of tag \NC \NR -\NC \type {text(index)} \NC content \NC \NR -\NC \type {error(str)} \NC quit and show error \NC \NR -\NC \type {quit()} \NC quit \NC \NR -\NC \type {print()} \NC print message \NC \NR -\NC \type {count(pattern)} \NC number of matches \NC \NR -\NC \type {child(pattern)} \NC take child that matches \NC \NR -\stoptabulate - - -You can also use normal \LUA\ functions as long as you make sure that you pass -the right arguments. There are a few predefined variables available inside such -functions. - -\starttabulate[|Tl|l|p|] -\NC \type{list} \NC table \NC the list of matches \NC \NR -\NC \type{l} \NC number \NC the current index in the list of matches \NC \NR -\NC \type{ll} \NC element \NC the current element that matched \NC \NR -\NC \type{order} \NC number \NC the position of the root of the path \NC \NR -\stoptabulate - -The given expression between \type {[]} is converted to a \LUA\ expression so you -can use the usual operators: - -\starttyping -== ~= <= >= < > not and or () -\stoptyping - -In addition, \type {=} equals \type {==} and \type {!=} is the same as \type -{~=}. If you mess up the expression, you quite likely get a \LUA\ error message. - -\stopsection - -\startsection[title={css selectors}] - -\startbuffer[selector-001] -<?xml version="1.0" ?> - -<a> - <b class="one">b.one</b> - <b class="two">b.two</b> - <b class="one two">b.one.two</b> - <b class="three">b.three</b> - <b id="first">b#first</b> - <c>c</c> - <d>d e</d> - <e>d e</e> - <e>d e e</e> - <d>d f</d> - <f foo="bar">@foo = bar</f> - <f bar="foo">@bar = foo</f> - <f bar="foo1">@bar = foo1</f> - <f bar="foo2">@bar = foo2</f> - <f bar="foo3">@bar = foo3</f> - <f bar="foo+4">@bar = foo+4</f> - <g>g</g> - <g><gg><d>g gg d</d></gg></g> - <g><gg><f>g gg f</f></gg></g> - <g><gg><f class="one">g gg f.one</f></gg></g> - <g>g</g> - <g><gg><f class="two">g gg f.two</f></gg></g> - <g><gg><f class="three">g gg f.three</f></gg></g> - <g><f class="one">g f.one</f></g> - <g><f class="three">g f.three</f></g> - <h whatever="four five six">@whatever = four five six</h> -</a> -\stopbuffer - -\xmlloadbuffer{selector-001}{selector-001} - -\startxmlsetups xml:selector:demo - \advance\scratchcounter\plusone - \inleftmargin{\the\scratchcounter}\ignorespaces\xmlverbatim{#1}\par -\stopxmlsetups - -\unexpanded\def\showCSSdemo#1#2% - {\blank - \textrule{\tttf#2} - \startlines - \dontcomplain - \tttf \obeyspaces - \scratchcounter\zerocount - \xmlcommand{#1}{#2}{xml:selector:demo} - \stoplines - \blank} - -The \CSS\ approach to filtering is a bit different from the path based one and is -supported too. In fact, you can combine both methods. Depending on what you -select, the \CSS\ one can be a little bit faster too. It has the advantage that -one can select more in one go but at the same time looks a bit less attractive. -This method was added just to show that it can be done but might be useful too. A -selector is given between curly braces (after all \CSS\ uses them and they have no -function yet in the parser. - -\starttyping -\xmlall{#1}{{foo bar .whatever, bar foo .whatever}} -\stoptyping - -The following methods are supported: - -\starttabulate[|T||] -\NC element \NC all tags element \NC \NR -\NC element-1 > element-2 \NC all tags element-2 with parent tag element-1 \NC \NR -\NC element-1 + element-2 \NC all tags element-2 preceded by tag element-1 \NC \NR -\NC element-1 ~ element-2 \NC all tags element-2 preceded by tag element-1 \NC \NR -\NC element-1 element-2 \NC all tags element-2 inside tag element-1 \NC \NR -\NC [attribute] \NC has attribute \NC \NR -\NC [attribute=value] \NC attribute equals value\NC \NR -\NC [attribute\lettertilde =value] \NC attribute contains value (space is separator) \NC \NR -\NC [attribute\letterhat ="value"] \NC attribute starts with value \NC \NR -\NC [attribute\letterdollar="value"] \NC attribute ends with value \NC \NR -\NC [attribute*="value"] \NC attribute contains value \NC \NR -\NC .class \NC has class \NC \NR -\NC \letterhash id \NC has id \NC \NR -\NC :nth-child(n) \NC the child at index n \NC \NR -\NC :nth-last-child(n) \NC the child at index n from the end \NC \NR -\NC :first-child \NC the first child \NC \NR -\NC :last-child \NC the last child \NC \NR -\NC :nth-of-type(n) \NC the match at index n \NC \NR -\NC :nth-last-of-type(n) \NC the match at index n from the end \NC \NR -\NC :first-of-type \NC the first match \NC \NR -\NC :last-of-type \NC the last match \NC \NR -\NC :only-of-type \NC the only match or nothing \NC \NR -\NC :only-child \NC the only child or nothing \NC \NR -\NC :empty \NC only when empty \NC \NR -\NC :root \NC the whole tree \NC \NR -\stoptabulate - -The next pages show some examples. For that we use the demo file: - -\typebuffer[selector-001] - -The class and id selectors often only make sense in \HTML\ like documents but they -are supported nevertheless. They are after all just shortcuts for filtering by -attribute. The class filtering is special in the sense that it checks for a class -in a list of classes given in an attribute. - -\showCSSdemo{selector-001}{{.one}} -\showCSSdemo{selector-001}{{.one, .two}} -\showCSSdemo{selector-001}{{.one, .two, \letterhash first}} - -Attributes can be filtered by presence, value, partial value and such. Quotes are -optional but we advice to use them. - -\showCSSdemo{selector-001}{{[foo], [bar=foo]}} -\showCSSdemo{selector-001}{{[bar\lettertilde=foo]}} -\showCSSdemo{selector-001}{{[bar\letterhat="foo"]}} -\showCSSdemo{selector-001}{{[whatever\lettertilde="five"]}} - -You can of course combine the methods as in: - -\showCSSdemo{selector-001}{{g f .one, g f .three}} -\showCSSdemo{selector-001}{{g > f .one, g > f .three}} -\showCSSdemo{selector-001}{{d + e}} -\showCSSdemo{selector-001}{{d ~ e}} -\showCSSdemo{selector-001}{{d ~ e, g f .one, g f .three}} - -You can also negate the result by using \type {:not} on a simple expression: - -\showCSSdemo{selector-001}{{:not([whatever\lettertilde="five"])}} -\showCSSdemo{selector-001}{{:not(d)}} - -The child and match selectors are also supported: - -\showCSSdemo{selector-001}{{a:nth-child(3)}} -\showCSSdemo{selector-001}{{a:nth-last-child(3)}} -\showCSSdemo{selector-001}{{g:nth-of-type(3)}} -\showCSSdemo{selector-001}{{g:nth-last-of-type(3)}} -\showCSSdemo{selector-001}{{a:first-child}} -\showCSSdemo{selector-001}{{a:last-child}} -\showCSSdemo{selector-001}{{e:first-of-type}} -\showCSSdemo{selector-001}{{gg d:only-of-type}} - -Instead of numbers you can also give the \type {an} and \type {an+b} formulas -as well as the \type {odd} and \type {even} keywords: - -\showCSSdemo{selector-001}{{a:nth-child(even)}} -\showCSSdemo{selector-001}{{a:nth-child(odd)}} -\showCSSdemo{selector-001}{{a:nth-child(3n+1)}} -\showCSSdemo{selector-001}{{a:nth-child(2n+3)}} - -There are a few special cases: - -\showCSSdemo{selector-001}{{g:empty}} -\showCSSdemo{selector-001}{{g:root}} -\showCSSdemo{selector-001}{{*}} - -Combining the \CSS\ methods with the regular ones is possible: - -\showCSSdemo{selector-001}{{g gg f .one}} -\showCSSdemo{selector-001}{g/gg/f[@class='one']} -\showCSSdemo{selector-001}{g/{gg f .one}} - -\startbuffer[selector-002] -<?xml version="1.0" ?> - -<document> - <title class="one" >title 1</title> - <title class="two" >title 2</title> - <title class="one" >title 3</title> - <title class="three">title 4</title> -</document> -\stopbuffer - -The next examples we use this file: - -\typebuffer[selector-002] - -\xmlloadbuffer{selector-002}{selector-002} - -When we filter from this (not too well structured) tree we can use both -methods to achieve the same: - -\showCSSdemo{selector-002}{{document title .one, document title .three}} - -\showCSSdemo{selector-002}{/document/title[(@class='one') or (@class='three')]} - -However, imagine this file: - -\startbuffer[selector-003] -<?xml version="1.0" ?> - -<document> - <title class="one">title 1</title> - <subtitle class="sub">title 1.1</subtitle> - <title class="two">title 2</title> - <subtitle class="sub">title 2.1</subtitle> - <title class="one">title 3</title> - <subtitle class="sub">title 3.1</subtitle> - <title class="two">title 4</title> - <subtitle class="sub">title 4.1</subtitle> -</document> -\stopbuffer - -\typebuffer[selector-003] - -\xmlloadbuffer{selector-003}{selector-003} - -The next filter in easier with the \CSS\ selector methods because these accumulate -independent (simple) expressions: - -\showCSSdemo{selector-003}{{document title .one + subtitle, document title .two + subtitle}} - -Watch how we get an output in the document order. Because we render a sequential document -a combined filter will trigger a sorting pass. - -\stopsection - -\startsection[title={functions as filters}] - -At the \LUA\ end a whole \cmdinternal {cd:lpath} expression results in a (set of) node(s) -with its environment, but that is hardly usable in \TEX. Think of code like: - -\starttyping -for e in xml.collected(xml.load('text.xml'),"title") do - -- e = the element that matched -end -\stoptyping - -The older variant is still supported but you can best use the previous variant. - -\starttyping -for r, d, k in xml.elements(xml.load('text.xml'),"title") do - -- r = root of the title element - -- d = data table - -- k = index in data table -end -\stoptyping - -Here \type {d[k]} points to the \type {title} element and in this case all titles -in the tree pass by. In practice this kind of code is encapsulated in function -calls, like those returning elements one by one, or returning the first or last -match. The result is then fed back into \TEX, possibly after being altered by an -associated setup. We've seen the wrappers to such functions already in a previous -chapter. - -In addition to the previously discussed expressions, one can add so called -filters to the expression, for instance: - -\starttyping -a/(b|c)/!d/e/text() -\stoptyping - -In a filter, the last part of the \cmdinternal {cd:lpath} expression is a -function call. The previous example returns the text of each element \type {e} -that results from matching the expression. When running \TEX\ the following -functions are available. Some are also available when using pure \LUA. In \TEX\ -you can often use one of the macros like \type {\xmlfirst} instead of a \type -{\xmlfilter} with finalizer \type {first()}. The filter can be somewhat faster -but that is hardly noticeable. - -\starttabulate[|l|l|p|] -\NC \type {context()} \NC string \NC the serialized text with \TEX\ catcode regime \NC \NR -%NC \type {ctxtext()} \NC string \NC \NC \NR -\NC \type {function()} \NC string \NC depends on the function \NC \NR -% -\NC \type {name()} \NC string \NC the (remapped) namespace \NC \NR -\NC \type {tag()} \NC string \NC the name of the element \NC \NR -\NC \type {tags()} \NC list \NC the names of the element \NC \NR -% -\NC \type {text()} \NC string \NC the serialized text \NC \NR -\NC \type {upper()} \NC string \NC the serialized text uppercased \NC \NR -\NC \type {lower()} \NC string \NC the serialized text lowercased \NC \NR -\NC \type {stripped()} \NC string \NC the serialized text stripped \NC \NR -\NC \type {lettered()} \NC string \NC the serialized text only letters (cf. \UNICODE) \NC \NR -% -\NC \type {count()} \NC number \NC the number of matches \NC \NR -\NC \type {index()} \NC number \NC the matched index in the current path \NC \NR -\NC \type {match()} \NC number \NC the matched index in the preceding path \NC \NR -% -%NC \type {lowerall()} \NC string \NC \NC \NR -%NC \type {upperall()} \NC string \NC \NC \NR -% -\NC \type {attribute(name)} \NC content \NC returns the attribute with the given name \NC \NR -\NC \type {chainattribute(name)} \NC content \NC sidem, but backtracks till one is found \NC \NR -\NC \type {command(name)} \NC content \NC expands the setup with the given name for each found element \NC \NR -\NC \type {position(n)} \NC content \NC processes the \type {n}\high{th} instance of the found element \NC \NR -\NC \type {all()} \NC content \NC processes all instances of the found element \NC \NR -%NC \type {default} \NC content \NC all \NC \NR -\NC \type {reverse()} \NC content \NC idem in reverse order \NC \NR -\NC \type {first()} \NC content \NC processes the first instance of the found element \NC \NR -\NC \type {last()} \NC content \NC processes the last instance of the found element \NC \NR -\NC \type {concat(...)} \NC content \NC concatinates the match \NC \NC \NR -\NC \type {concatrange(from,to,...)} \NC content \NC concatinates a range of matches \NC \NC \NR -\stoptabulate - -The extra arguments of the concatinators are: \type {separator} (string), \type -{lastseparator} (string) and \type {textonly} (a boolean). - -These filters are in fact \LUA\ functions which means that if needed more of them -can be added. Indeed this happens in some of the \XML\ related \MKIV\ modules, -for instance in the \MATHML\ processor. - -\stopsection - -\startsection[title={example}] - -The number of commands is rather large and if you want to avoid them this is -often possible. Take for instance: - -\starttyping -\xmlall{#1}{/a/b[position()>3]} -\stoptyping - -Alternatively you can use: - -\starttyping -\xmlfilter{#1}{/a/b[position()>3]/all()} -\stoptyping - -and actually this is also faster as internally it avoids a function call. Of -course in practice this is hardly measurable. - -In previous examples we've already seen quite some expressions, and it might be -good to point out that the syntax is modelled after \XSLT\ but is not quite the -same. The reason is that we started with a rather minimal system and have already -styles in use that depend on compatibility. - -\starttyping -namespace:// axis node(set) [expr 1]..[expr n] / ... / filter -\stoptyping - -When we are inside a \CONTEXT\ run, the namespace is \type {tex}. Hoewever, if -you want not to print back to \TEX\ you need to be more explicit. Say that we -typeset examns and have a (not that logical) structure like: - -\starttyping -<question> - <text>...</text> - <answer> - <item>one</item> - <item>two</item> - <item>three</item> - </answer> - <alternative> - <condition>true</condition> - <score>1</score> - </alternative> - <alternative> - <condition>false</condition> - <score>0</score> - </alternative> - <alternative> - <condition>true</condition> - <score>2</score> - </alternative> -</question> -\stoptyping - -Say that we typeset the questions with: - -\starttyping -\startxmlsetups question - \blank - score: \xmlfunction{#1}{totalscore} - \blank - \xmlfirst{#1}{text} - \startitemize - \xmlfilter{#1}{/answer/item/command(answer:item)} - \stopitemize - \endgraf - \blank -\stopxmlsetups -\stoptyping - -Each item in the answer results in a call to: - -\starttyping -\startxmlsetups answer:item - \startitem - \xmlflush{#1} - \endgraf - \xmlfilter{#1}{../../alternative[position()=rootposition()]/ - condition/command(answer:condition)} - \stopitem -\stopxmlsetups -\stoptyping - -\starttyping -\startxmlsetups answer:condition - \endgraf - condition: \xmlflush{#1} - \endgraf -\stopxmlsetups -\stoptyping - -Now, there are two rather special filters here. The first one involves -calculating the total score. As we look forward we use a function to deal with -this. - -\starttyping -\startluacode -function xml.functions.totalscore(root) - local score = 0 - for e in xml.collected(root,"/alternative") do - score = score + xml.filter(e,"xml:///score/number()") or 0 - end - tex.write(score) -end -\stopluacode -\stoptyping - -Watch how we use the namespace to keep the results at the \LUA\ end. - -The second special trick shown here is to limit a match using the current -position of the root (\type {#}) match. - -As you can see, a path expression can be more than just filtering a few nodes. At -the end of this manual you will find a bunch of examples. - -\stopsection - -\startsection[title={tables}] - -If you want to know how the internal \XML\ tables look you can print such a -table: - -\starttyping -print(table.serialize(e)) -\stoptyping - -This produces for instance: - -% s = xml.convert("<document><demo label='whatever'>some text</demo></document>") -% print(table.serialize(xml.filter(s,"demo")[1])) - -\starttyping -t={ - ["at"]={ - ["label"]="whatever", - }, - ["dt"]={ "some text" }, - ["ns"]="", - ["rn"]="", - ["tg"]="demo", -} -\stoptyping - -The \type {rn} entry is the renamed namespace (when renaming is applied). If you -see tags like \type {@pi@} this means that we don't have an element, but (in this -case) a processing instruction. - -\starttabulate[|l|p|] -\NC \type {@rt@} \NC the root element \NC \NR -\NC \type {@dd@} \NC document definition \NC \NR -\NC \type {@cm@} \NC comment, like \type {<!-- whatever -->} \NC \NR -\NC \type {@cd@} \NC so called \type {CDATA} \NC \NR -\NC \type {@pi@} \NC processing instruction, like \type {<?whatever we want ?>} \NC \NR -\stoptabulate - -There are many ways to deal with the content, but in the perspective of \TEX\ -only a few matter. - -\starttabulate[|l|p|] -\NC \type {xml.sprint(e)} \NC print the content to \TEX\ and apply setups if needed \NC \NR -\NC \type {xml.tprint(e)} \NC print the content to \TEX\ (serialize elements verbose) \NC \NR -\NC \type {xml.cprint(e)} \NC print the content to \TEX\ (used for special content) \NC \NR -\stoptabulate - -Keep in mind that anything low level that you uncover is not part of the official -interface unless mentioned in this manual. - -\stopsection - -\stopchapter - -\startchapter[title={Tips and tricks}] - -\startsection[title={tracing}] - -It can be hard to debug code as much happens kind of behind the screens. -Therefore we have a couple of tracing options. Of course you can typeset some -status information, using for instance: - -\startxmlcmd {\cmdbasicsetup{xmlshow}} - typeset the tree given by \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlinfo}} - typeset the name in the element given by \cmdinternal {cd:node} -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlpath}} - returns the complete path (including namespace prefix and index) of the - given \cmdinternal {cd:node} -\stopxmlcmd - -\startbuffer[demo] -<?xml version "1.0"?> -<document> - <section> - <content> - <p>first</p> - <p><b>second</b></p> - </content> - </section> - <section> - <content> - <p><b>third</b></p> - <p>fourth</p> - </content> - </section> -</document> -\stopbuffer - -Say that we have the following \XML: - -\typebuffer[demo] - -and the next definitions: - -\startbuffer -\startxmlsetups xml:demo:base - \xmlsetsetup{#1}{p|b}{xml:demo:*} -\stopxmlsetups - -\startxmlsetups xml:demo:p - \xmlflush{#1} - \par -\stopxmlsetups - -\startxmlsetups xml:demo:b - \par - \xmlpath{#1} : \xmlflush{#1} - \par -\stopxmlsetups - -\xmlregisterdocumentsetup{example-10}{xml:demo:base} - -\xmlprocessbuffer{example-10}{demo}{} -\stopbuffer - -\typebuffer - -This will give us: - -\blank \startpacked \getbuffer \stoppacked \blank - -If you use \type {\xmlshow} you will get a complete subtree which can -be handy for tracing but can also lead to large documents. - -We also have a bunch of trackers that can be enabled, like: - -\starttyping -\enabletrackers[xml.show,xml.parse] -\stoptyping - -The full list (currently) is: - -\starttabulate[|lT|p|] -\NC xml.entities \NC show what entities are seen and replaced \NC \NR -\NC xml.path \NC show the result of parsing an lpath expression \NC \NR -\NC xml.parse \NC show stepwise resolving of expressions \NC \NR -\NC xml.profile \NC report all parsed lpath expressions (in the log) \NC \NR -\NC xml.remap \NC show what namespaces are remapped \NC \NR -\NC lxml.access \NC report errors with respect to resolving (symbolic) nodes \NC \NR -\NC lxml.comments \NC show the comments that are encountered (if at all) \NC \NR -\NC lxml.loading \NC show what files are loaded and converted \NC \NR -\NC lxml.setups \NC show what setups are being associated to elements \NC \NR -\stoptabulate - -In one of our workflows we produce books from \XML\ where the (educational) -content is organized in many small files. Each book has about 5~chapters and each -chapter is made of sections that contain text, exercises, resources, etc.\ and so -the document is assembled from thousands of files (don't worry, runtime inclusion -is pretty fast). In order to see where in the sources content resides we can -trace the filename. - -\startxmlcmd {\cmdbasicsetup{xmlinclusion}} - returns the file where the node comes from -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlinclusions}} - returns the list of files where the node comes from -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlbadinclusions}} - returns a list of files that were not included due to some problem -\stopxmlcmd - -Of course you have to make sure that these names end up somewhere visible, for -instance in the margin. - -\stopsection - -\startsection[title={expansion}] - -For novice users the concept of expansion might sound frightening and to some -extend it is. However, it is important enough to spend some words on it here. - -It is good to realize that most setups are sort of immediate. When one setup is -issued, it can call another one and so on. Normally you won't notice that but -there are cases where that can be a problem. In \TEX\ you can define a macro, -take for instance: - -\starttyping -\startxmlsetups xml:foo - \def\foobar{\xmlfirst{#1}{/bar}} -\stopxmlsetups -\stoptyping - -you store the reference top node \type {bar} in \type {\foobar} maybe for later use. In -this case the content is not yet fetched, it will be done when \type {\foobar} is -called. - -\starttyping -\startxmlsetups xml:foo - \edef\foobar{\xmlfirst{#1}{/bar}} -\stopxmlsetups -\stoptyping - -Here the content of \type {bar} becomes the body of the macro. But what if -\type {bar} itself contains elements that also contain elements. When there -is a setup for \type {bar} it will be triggered and so on. - -When that setup looks like: - -\starttyping -\startxmlsetups xml:bar - \def\barfoo{\xmlflush{#1}} -\stopxmlsetups -\stoptyping - -Here we get something like: - -\starttyping -\foobar => {\def\barfoo{...}} -\stoptyping - -When \type {\barfoo} is not defined we get an error and when it is known and expands -to something weird we might also get an error. - -Especially when you don't know what content can show up, this can result in errors -when an expansion fails, for example because some macro being used is not defined. -To prevent this we can define a macro: - -\starttyping -\starttexdefinition unexpanded xml:bar:macro #1 - \def\barfoo{\xmlflush{#1}} -\stoptexdefinition - -\startxmlsetups xml:bar - \texdefinition{xml:bar:macro}{#1} -\stopxmlsetups -\stoptyping - -The setup \type {xml:bar} will still expand but the replacement text now is just the -call to the macro, think of: - -\starttyping -\foobar => {\texdefinition{xml:bar:macro}{#1}} -\stoptyping - -But this is often not needed, most \CONTEXT\ commands can handle the expansions -quite well but it's good to know that there is a way out. So, now to some -examples. Imagine that we have an \XML\ file that looks as follows: - -\starttyping -<?xml version='1.0' ?> -<demo> - <chapter> - <title>Some <em>short</em> title</title> - <content> - zeta - <index> - <key>zeta</key> - <content>zeta again</content> - </index> - alpha - <index> - <key>alpha</key> - <content>alpha <em>again</em></content> - </index> - gamma - <index> - <key>gamma</key> - <content>gamma</content> - </index> - beta - <index> - <key>beta</key> - <content>beta</content> - </index> - delta - <index> - <key>delta</key> - <content>delta</content> - </index> - done! - </content> - </chapter> -</demo> -\stoptyping - -There are a few structure related elements here: a chapter (with its list entry) -and some index entries. Both are multipass related and therefore travel around. -This means that when we let data end up in the auxiliary file, we need to make -sure that we end up with either expanded data (i.e.\ no references to the \XML\ -tree) or with robust forward and backward references to elements in the tree. - -Here we discuss three approaches (and more may show up later): pushing \XML\ into -the auxiliary file and using references to elements either or not with an -associated setup. We control the variants with a switch. - -\starttyping -\newcount\TestMode - -\TestMode=0 % expansion=xml -\TestMode=1 % expansion=yes, index, setup -\TestMode=2 % expansion=yes -\stoptyping - -We apply a couple of setups: - -\starttyping -\startxmlsetups xml:mysetups - \xmlsetsetup{\xmldocument}{demo|index|content|chapter|title|em}{xml:*} -\stopxmlsetups - -\xmlregistersetup{xml:mysetups} -\stoptyping - -The main document is processed with: - -\starttyping -\startxmlsetups xml:demo - \xmlflush{#1} - \subject{contents} - \placelist[chapter][criterium=all] - \subject{index} - \placeregister[index][criterium=all] - \page % else buffer is forgotten when placing header -\stopxmlsetups -\stoptyping - -First we show three alternative ways to deal with the chapter. The first case -expands the \XML\ reference so that we have an \XML\ stream in the auxiliary -file. This stream is processed as a small independent subfile when needed. The -second case registers a reference to the current element (\type {#1}). This means -that we have access to all data of this element, like attributes, title and -content. What happens depends on the given setup. The third variant does the same -but here the setup is part of the reference. - -\starttyping -\startxmlsetups xml:chapter - \ifcase \TestMode - % xml code travels around - \setuphead[chapter][expansion=xml] - \startchapter[title=eh: \xmltext{#1}{title}] - \xmlfirst{#1}{content} - \stopchapter - \or - % index is used for access via setup - \setuphead[chapter][expansion=yes,xmlsetup=xml:title:flush] - \startchapter[title=\xmlgetindex{#1}] - \xmlfirst{#1}{content} - \stopchapter - \or - % tex call to xml using index is used - \setuphead[chapter][expansion=yes] - \startchapter[title=hm: \xmlreference{#1}{xml:title:flush}] - \xmlfirst{#1}{content} - \stopchapter - \fi -\stopxmlsetups - -\startxmlsetups xml:title:flush - \xmltext{#1}{title} -\stopxmlsetups -\stoptyping - -We need to deal with emphasis and the content of the chapter. - -\starttyping -\startxmlsetups xml:em - \begingroup\em\xmlflush{#1}\endgroup -\stopxmlsetups - -\startxmlsetups xml:content - \xmlflush{#1} -\stopxmlsetups -\stoptyping - -A similar approach is followed with the index entries. Watch how we use the -numbered entries variant (in this case we could also have used just \type -{entries} and \type {keys}). - -\starttyping -\startxmlsetups xml:index - \ifcase \TestMode - \setupregister[index][expansion=xml,xmlsetup=] - \setstructurepageregister - [index] - [entries:1=\xmlfirst{#1}{content}, - keys:1=\xmltext{#1}{key}] - \or - \setupregister[index][expansion=yes,xmlsetup=xml:index:flush] - \setstructurepageregister - [index] - [entries:1=\xmlgetindex{#1}, - keys:1=\xmltext{#1}{key}] - \or - \setupregister[index][expansion=yes,xmlsetup=] - \setstructurepageregister - [index] - [entries:1=\xmlreference{#1}{xml:index:flush}, - keys:1=\xmltext{#1}{key}] - \fi -\stopxmlsetups - -\startxmlsetups xml:index:flush - \xmlfirst{#1}{content} -\stopxmlsetups -\stoptyping - -Instead of this flush, you can use the predefined setup \type {xml:flush} -unless it is overloaded by you. - -The file is processed by: - -\starttyping -\starttext - \xmlprocessfile{main}{test.xml}{} -\stoptext -\stoptyping - -We don't show the result here. If you're curious what the output is, you can test -it yourself. In that case it also makes sense to peek into the \type {test.tuc} -file to see how the information travels around. The \type {metadata} fields carry -information about how to process the data. - -The first case, the \XML\ expansion one, is somewhat special in the sense that -internally we use small pseudo files. You can control the rendering by tweaking -the following setups: - -\starttyping -\startxmlsetups xml:ctx:sectionentry - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:ctx:registerentry - \xmlflush{#1} -\stopxmlsetups -\stoptyping - -{\em When these methods work out okay the other structural elements will be -dealt with in a similar way.} - -\stopsection - -\startsection[title={special cases}] - -Normally the content will be flushed under a special (so called) catcode regime. -This means that characters that have a special meaning in \TEX\ will have no such -meaning in an \XML\ file. If you want content to be treated as \TEX\ code, you can -use one of the following: - -\startxmlcmd {\cmdbasicsetup{xmlflushcontext}} - flush the given \cmdinternal {cd:node} using the \TEX\ character - interpretation scheme -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlcontext}} - flush the match of \cmdinternal {cd:lpath} for the given \cmdinternal - {cd:node} using the \TEX\ character interpretation scheme -\stopxmlcmd - -We use this in cases like: - -\starttyping -.... - \xmlsetsetup {#1} { - tm|texformula| - } {xml:*} -.... - -\startxmlsetups xml:tm - \mathematics{\xmlflushcontext{#1}} -\stopxmlsetups - -\startxmlsetups xml:texformula - \placeformula\startformula\xmlflushcontext{#1}\stopformula -\stopxmlsetups -\stoptyping - -\stopsection - -\startsection[title={collecting}] - -Say that your document has - -\starttyping -<table> - <tr> - <td>foo</td> - <td>bar<td> - </tr> -</table> -\stoptyping - -And that you need to convert that to \TEX\ speak like: - -\starttyping -\bTABLE - \bTR - \bTD foo \eTD - \bTD bar \eTD - \eTR -\eTABLE -\stoptyping - -A simple mapping is: - -\starttyping -\startxmlsetups xml:table - \bTABLE \xmlflush{#1} \eTABLE -\stopxmlsetups -\startxmlsetups xml:tr - \bTR \xmlflush{#1} \eTR -\stopxmlsetups -\startxmlsetups xml:td - \bTD \xmlflush{#1} \eTD -\stopxmlsetups -\stoptyping - -The \type {\bTD} command is a so called delimited command which means that it -picks up its argument by looking for an \type {\eTD}. For the simple case here -this works quite well because the flush is inside the pair. This is not the case -in the following variant: - -\starttyping -\startxmlsetups xml:td:start - \bTD -\stopxmlsetups -\startxmlsetups xml:td:stop - \eTD -\stopxmlsetups -\startxmlsetups xml:td - \xmlsetup{#1}{xml:td:start} - \xmlflush{#1} - \xmlsetup{#1}{xml:td:stop} -\stopxmlsetups -\stoptyping - -When for some reason \TEX\ gets confused you can revert to a mechanism that -collects content. - -\starttyping -\startxmlsetups xml:td:start - \startcollect - \bTD - \stopcollect -\stopxmlsetups -\startxmlsetups xml:td:stop - \startcollect - \eTD - \stopcollect -\stopxmlsetups -\startxmlsetups xml:td - \startcollecting - \xmlsetup{#1}{xml:td:start} - \xmlflush{#1} - \xmlsetup{#1}{xml:td:stop} - \stopcollecting -\stopxmlsetups -\stoptyping - -You can even implement solutions that effectively do this: - -\starttyping -\startcollecting - \startcollect \bTABLE \stopcollect - \startcollect \bTR \stopcollect - \startcollect \bTD \stopcollect - \startcollect foo\stopcollect - \startcollect \eTD \stopcollect - \startcollect \bTD \stopcollect - \startcollect bar\stopcollect - \startcollect \eTD \stopcollect - \startcollect \eTR \stopcollect - \startcollect \eTABLE \stopcollect -\stopcollecting -\stoptyping - -Of course you only need to go that complex when the situation demands it. Here is -another weird one: - -\starttyping -\startcollecting - \startcollect \setupsomething[\stopcollect - \startcollect foo=\stopcollect - \startcollect FOO,\stopcollect - \startcollect bar=\stopcollect - \startcollect BAR,\stopcollect - \startcollect ]\stopcollect -\stopcollecting -\stoptyping - -\stopsection - -\startsection[title={selectors and injectors}] - -This section describes a bit special feature, one that we needed for a project -where we could not touch the original content but could add specific sections for -our own purpose. Hopefully the example demonstrates its useability. - -\enabletrackers[lxml.selectors] - -\startbuffer[foo] -<?xml version="1.0" encoding="UTF-8"?> - -<?context-directive message info 1: this is a demo file ?> -<?context-message-directive info 2: this is a demo file ?> - -<one> - <two> - <?context-select begin t1 t2 t3 ?> - <three> - t1 t2 t3 - <?context-directive injector crlf t1 ?> - t1 t2 t3 - </three> - <?context-select end ?> - <?context-select begin t4 ?> - <four> - t4 - </four> - <?context-select end ?> - <?context-select begin t8 ?> - <four> - t8.0 - t8.0 - </four> - <?context-select end ?> - <?context-include begin t4 ?> - <!-- - <three> - t4.t3 - <?context-directive injector crlf t1 ?> - t4.t3 - </three> - --> - <three> - t3 - <?context-directive injector crlf t1 ?> - t3 - </three> - <?context-include end ?> - <?context-select begin t8 ?> - <four> - t8.1 - t8.1 - </four> - <?context-select end ?> - <?context-select begin t8 ?> - <four> - t8.2 - t8.2 - </four> - <?context-select end ?> - <?context-select begin t4 ?> - <four> - t4 - t4 - </four> - <?context-select end ?> - <?context-directive injector page t7 t8 ?> - foo - <?context-directive injector blank t1 ?> - bar - <?context-directive injector page t7 t8 ?> - bar - </two> -</one> -\stopbuffer - -\typebuffer[foo] - -First we show how to plug in a directive. Processing instructions like the -following are normally ignored by an \XML\ processor, unless they make sense -to it. - -\starttyping -<?context-directive message info 1: this is a demo file ?> -<?context-message-directive info 2: this is a demo file ?> -\stoptyping - -We can define a message handler as follows: - -\startbuffer -\def\MyMessage#1#2#3{\writestatus{#1}{#2 #3}} - -\xmlinstalldirective{message}{MyMessage} -\stopbuffer - -\typebuffer \getbuffer - -When this file is processed you will see this on the console: - -\starttyping -info > 1: this is a demo file -info > 2: this is a demo file -\stoptyping - -The file has some sections that can be used or ignored. The recipe for -obeying \type {t1} and \type {t4} is the following: - -\startbuffer -\xmlsetinjectors[t1] -\xmlsetinjectors[t4] - -\startxmlsetups xml:initialize - \xmlapplyselectors{#1} - \xmlsetsetup {#1} { - one|two|three|four - } {xml:*} -\stopxmlsetups - -\xmlregistersetup{xml:initialize} - -\startxmlsetups xml:one - [ONE \xmlflush{#1} ONE] -\stopxmlsetups - -\startxmlsetups xml:two - [TWO \xmlflush{#1} TWO] -\stopxmlsetups - -\startxmlsetups xml:three - [THREE \xmlflush{#1} THREE] -\stopxmlsetups - -\startxmlsetups xml:four - [FOUR \xmlflush{#1} FOUR] -\stopxmlsetups -\stopbuffer - -\typebuffer \getbuffer - -This typesets: - -\startnarrower -\xmlprocessbuffer{main}{foo}{} -\stopnarrower - -The include coding is kind of special: it permits adding content (in a comment) -and ignoring the rest so that we indeed can add something without interfering -with the original. Of course in a normal workflow such messy solutions are -not needed, but alas, often workflows are not that clean, especially when one -has no real control over the source. - -\startxmlcmd {\cmdbasicsetup{xmlsetinjectors}} - enables a list of injectors that will be used -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlresetinjectors}} - resets the list of injectors -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlinjector}} - expands an injection (command); normally this one is only used - (in some setup) or for testing -\stopxmlcmd - -\startxmlcmd {\cmdbasicsetup{xmlapplyselectors}} - analyze the tree \cmdinternal {cd:node} for marked sections that - will be injected -\stopxmlcmd - -We have some injections predefined: - -\starttyping -\startsetups xml:directive:injector:page - \page -\stopsetups - -\startsetups xml:directive:injector:column - \column -\stopsetups - -\startsetups xml:directive:injector:blank - \blank -\stopsetups -\stoptyping - -In the example we see: - -\starttyping -<?context-directive injector page t7 t8 ?> -\stoptyping - -When we set \type {\xmlsetinjector[t7]} a pagebreak will injected in that spot. -Tags like \type {t7}, \type {t8} etc.\ can represent versions. - -\stopsection - -\startsection[title=preprocessing] - -% local match = lpeg.match -% local replacer = lpeg.replacer("BAD TITLE:","<bold>BAD TITLE:</bold>") -% -% function lxml.preprocessor(data,settings) -% return match(replacer,data) -% end - -\startbuffer[pre-code] -\startluacode - function lxml.preprocessor(data,settings) - return string.find(data,"BAD TITLE:") - and string.gsub(data,"BAD TITLE:","<bold>BAD TITLE:</bold>") - or data - end -\stopluacode -\stopbuffer - -\startbuffer[pre-xml] -\startxmlsetups pre:demo:initialize - \xmlsetsetup{#1}{*}{pre:demo:*} -\stopxmlsetups - -\xmlregisterdocumentsetup{pre:demo}{pre:demo:initialize} - -\startxmlsetups pre:demo:root - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups pre:demo:bold - \begingroup\bf\xmlflush{#1}\endgroup -\stopxmlsetups - -\starttext - \xmlprocessbuffer{pre:demo}{demo}{} -\stoptext -\stopbuffer - -Say that you have the following \XML\ setup: - -\typebuffer[pre-xml] - -and that (such things happen) the input looks like this: - -\startbuffer[demo] -<root> -BAD TITLE: crap crap crap ... - -BAD TITLE: crap crap crap ... -</root> -\stopbuffer - -\typebuffer[demo] - -You can then clean up these \type {BAD TITLE}'s as follows: - -\typebuffer[pre-code] - -and get as result: - -\start \getbuffer[pre-code,pre-xml] \stop - -The preprocessor function gets as second argument the current settings, an d -the field \type {currentresource} can be used to limit the actions to -specific resources, in our case it's \type {buffer: demo}. Afterwards you can -reset the proprocessor with: - -\startluacode -lxml.preprocessor = nil -\stopluacode - -Future versions might give some more control over preprocessors. For now consider -it to be a quick hack. - -\stopsection - -\stopchapter - -\startchapter[title={Lookups using lpaths}] - -\startsection[title={introduction}] - -There is not that much system in the following examples. They resulted from tests -with different documents. The current implementation evolved out of the -experimental code. For instance, I decided to add the multiple expressions in row -handling after a few email exchanges with Jean|-|Michel Huffen. - -One of the main differences between the way \XSLT\ resolves a path and our way is -the anchor. Take: - -\starttyping -/something -something -\stoptyping - -The first one anchors in the current (!) element so it will only consider direct -children. The second one does a deep lookup and looks at the descendants as well. -Furthermore we have a few extra shortcuts like \type {**} in \type {a/**/b} which -represents all descendants. - -The expressions (between square brackets) has to be valid \LUA\ and some -preprocessing is done to resolve the built in functions. So, you might use code -like: - -\starttyping -my_lpeg_expression:match(text()) == "whatever" -\stoptyping - -given that \type {my_lpeg_expression} is known. In the examples below we use the -visualizer to show the steps. Some are shown more than once as part of a set. - -\stopsection - -\startsection[title={special cases}] - -\xmllshow{} -\xmllshow{*} -\xmllshow{.} -\xmllshow{/} - -\stopsection - -\startsection[title={wildcards}] - -\xmllshow{*} -\xmllshow{*:*} -\xmllshow{/*} -\xmllshow{/*:*} -\xmllshow{*/*} -\xmllshow{*:*/*:*} - -\xmllshow{a/*} -\xmllshow{a/*:*} -\xmllshow{/a/*} -\xmllshow{/a/*:*} - -\xmllshow{/*} -\xmllshow{/**} -\xmllshow{/***} - -\stopsection - -\startsection[title={multiple steps}] - -\xmllshow{answer} -\xmllshow{answer/test/*} -\xmllshow{answer/test/child::} -\xmllshow{answer/*} -\xmllshow{answer/*[tag()='p' and position()=1 and text()!='']} - -\stopsection - -\startsection[title={pitfals}] - -\xmllshow{[oneof(lower(@encoding),'tex','context','ctx')]} -\xmllshow{.[oneof(lower(@encoding),'tex','context','ctx')]} - -\stopsection - -\startsection[title={more special cases}] - -\xmllshow{**} -\xmllshow{*} -\xmllshow{..} -\xmllshow{.} -\xmllshow{//} -\xmllshow{/} - -\xmllshow{**/} -\xmllshow{**/*} -\xmllshow{**/.} -\xmllshow{**//} - -\xmllshow{*/} -\xmllshow{*/*} -\xmllshow{*/.} -\xmllshow{*//} - -\xmllshow{/**/} -\xmllshow{/**/*} -\xmllshow{/**/.} -\xmllshow{/**//} - -\xmllshow{/*/} -\xmllshow{/*/*} -\xmllshow{/*/.} -\xmllshow{/*//} - -\xmllshow{./} -\xmllshow{./*} -\xmllshow{./.} -\xmllshow{.//} - -\xmllshow{../} -\xmllshow{../*} -\xmllshow{../.} -\xmllshow{..//} - -\stopsection - -\startsection[title={more wildcards}] - -\xmllshow{one//two} -\xmllshow{one/*/two} -\xmllshow{one/**/two} -\xmllshow{one/***/two} -\xmllshow{one/x//two} -\xmllshow{one//x/two} -\xmllshow{//x/two} - -\stopsection - -\startsection[title={special axis}] - -\xmllshow{descendant::whocares/ancestor::whoknows} -\xmllshow{descendant::whocares/ancestor::whoknows/parent::} -\xmllshow{descendant::whocares/ancestor::} -\xmllshow{child::something/child::whatever/child::whocares} -\xmllshow{child::something/child::whatever/child::whocares|whoknows} -\xmllshow{child::something/child::whatever/child::(whocares|whoknows)} -\xmllshow{child::something/child::whatever/child::!(whocares|whoknows)} -\xmllshow{child::something/child::whatever/child::(whocares)} -\xmllshow{child::something/child::whatever/child::(whocares)[position()>2]} -\xmllshow{child::something/child::whatever[position()>2][position()=1]} -\xmllshow{child::something/child::whatever[whocares][whocaresnot]} -\xmllshow{child::something/child::whatever[whocares][not(whocaresnot)]} -\xmllshow{child::something/child::whatever/self::whatever} - -There is also \type {last-match::} that starts with the last found set of nodes. -This can save some run time when you do lots of tests combined with a same check -afterwards. There is however one pitfall: you never know what is done with that -last match in the setup that gets called nested. Take the following example: - -\starttyping -\startbuffer[test] -<something> - <crap> <crapa> <crapb> <crapc> <crapd> - <crape> - done 1 - </crape> - </crapd> </crapc> </crapb> </crapa> - <crap> <crapa> <crapb> <crapc> <crapd> - <crape> - done 2 - </crape> - </crapd> </crapc> </crapb> </crapa> - <crap> <crapa> <crapb> <crapc> <crapd> - <crape> - done 3 - </crape> - </crapd> </crapc> </crapb> </crapa> -</something> -\stopbuffer -\stoptyping - -One way to filter the content is this: - -\starttyping -\xmldoif {#1} {/crap/crapa/crapb/crapc/crapd/crape} { - some action -} -\stoptyping - -It is not unlikely that you will do something like this: - -\starttyping -\xmlfirst {#1} {/crap/crapa/crapb/crapc/crapd/crape} { - \xmlfirst{#1}{/crap/crapa/crapb/crapc/crapd/crape} -} -\stoptyping - -This means that the path is resolved twice but that can be avoided as -follows: - -\starttyping -\xmldoif{#1}{/crap/crapa/crapb/crapc/crapd/crape}{ - \xmlfirst{#1}{last-match::} -} -\stoptyping - -But the next is now guaranteed to work: - -\starttyping -\xmldoif{#1}{/crap/crapa/crapb/crapc/crapd/crape}{ - \xmlfirst{#1}{last-match::} - \xmllast{#1}{last-match::} -} -\stoptyping - -Because the first one can have done some lookup the last match can be replaced -and the second call will give unexpected results. You can overcome this with: - -\starttyping -\xmldoif{#1}{/crap/crapa/crapb/crapc/crapd/crape}{ - \xmlpushmatch - \xmlfirst{#1}{last-match::} - \xmlpopmatch -} -\stoptyping - -Does it pay off? Here are some timings of a 10.000 times text and lookup -like the previous (on a decent January 2016 laptop): - -\starttabulate[|r|l|] -\NC 0.239 \NC \type {\xmldoif {...} {...}} \NC \NR -\NC 0.292 \NC \type {\xmlfirst {...} {...}} \NC \NR -\NC 0.538 \NC \type {\xmldoif {...} {...} + \xmlfirst {...} {...}} \NC \NR -\NC 0.338 \NC \type {\xmldoif {...} {...} + \xmlfirst {...} {last-match::}} \NC \NR -\NC 0.349 \NC \type {+ \xmldoif {...} {...} + \xmlfirst {...} {last-match::}-} \NC \NR -\stoptabulate - -So, pushing and popping (the last row) is a bit slower than not doing that but it -is still much faster than not using \type {last-match::} at all. As a shortcut -you can use \type {=}, as in: - -\starttyping -\xmlfirst{#1}{=} -\stoptyping - -You can even do this: - -\starttyping -\xmlall{#1}{last-match::/text()} -\stoptyping - -or - -\starttyping -\xmlall{#1}{=/text()} -\stoptyping - - -\stopsection - -\startsection[title={some more examples}] - -\xmllshow{/something/whatever} -\xmllshow{something/whatever} -\xmllshow{/**/whocares} -\xmllshow{whoknows/whocares} -\xmllshow{whoknows} -\xmllshow{whocares[contains(text(),'f') or contains(text(),'g')]} -\xmllshow{whocares/first()} -\xmllshow{whocares/last()} -\xmllshow{whatever/all()} -\xmllshow{whocares/position(2)} -\xmllshow{whocares/position(-2)} -\xmllshow{whocares[1]} -\xmllshow{whocares[-1]} -\xmllshow{whocares[2]} -\xmllshow{whocares[-2]} -\xmllshow{whatever[3]/attribute(id)} -\xmllshow{whatever[2]/attribute('id')} -\xmllshow{whatever[3]/text()} -\xmllshow{/whocares/first()} -\xmllshow{/whocares/last()} - -\xmllshow{xml://whatever/all()} -\xmllshow{whatever/all()} -\xmllshow{//whocares} -\xmllshow{..[2]} -\xmllshow{../*[2]} - -\xmllshow{/(whocares|whocaresnot)} -\xmllshow{/!(whocares|whocaresnot)} -\xmllshow{/!whocares} - -\xmllshow{/interface/command/command(xml:setups:register)} -\xmllshow{/interface/command[@name='xxx']/command(xml:setups:typeset)} -\xmllshow{/arguments/*} -\xmllshow{/sequence/first()} -\xmllshow{/arguments/text()} -\xmllshow{/sequence/variable/first()} -\xmllshow{/interface/define[@name='xxx']/first()} -\xmllshow{/parameter/command(xml:setups:parameter:measure)} - -\xmllshow{/(*:library|figurelibrary)/*:figure/*:label} -\xmllshow{/(*:library|figurelibrary)/figure/*:label} -\xmllshow{/(*:library|figurelibrary)/figure/label} -\xmllshow{/(*:library|figurelibrary)/figure:*/label} - -\xmlshow {whatever//br[tag(1)='br']} - -\stopsection - -\stopchapter - -\startchapter[title=Examples] - -\startsection[title=attribute chains] - -In \CSS, when an attribute is not present, the parent element is checked, and when -not found again, the lookup follows the chain till a match is found or the root is -reached. The following example demonstrates how such a chain lookup works. - -\startbuffer[test] -<something mine="1" test="one" more="alpha"> - <whatever mine="2" test="two"> - <whocares mine="3"> - <!-- this is a test --> - </whocares> - </whatever> -</something> -\stopbuffer - -\typebuffer[test] - -We apply the following setups to this tree: - -\startbuffer[setups] -\startxmlsetups xml:common - [ - \xmlchainatt{#1}{mine}, - \xmlchainatt{#1}{test}, - \xmlchainatt{#1}{more}, - \xmlchainatt{#1}{none} - ]\par -\stopxmlsetups - -\startxmlsetups xml:something - something: \xmlsetup{#1}{xml:common} - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:whatever - whatever: \xmlsetup{#1}{xml:common} - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:whocares - whocares: \xmlsetup{#1}{xml:common} - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:mysetups - \xmlsetsetup{#1}{something|whatever|whocares}{xml:*} -\stopxmlsetups - -\xmlregisterdocumentsetup{example-1}{xml:mysetups} - -\xmlprocessbuffer{example-1}{test}{} -\stopbuffer - -\typebuffer[setups] - -This gives: - -\start - \getbuffer[setups] -\stop - -\stopsection - -\startsection[title=conditional setups] - -Say that we have this code: - -\starttyping -\xmldoifelse {#1} {/what[@a='1']} { - \xmlfilter {#1} {/what/command('xml:yes')} -} { - \xmlfilter {#1} {/what/command('xml:nop')} -} -\stoptyping - -Here we first determine if there is a child \type {what} with attribute \type {a} -set to \type {1}. Depending on the outcome again we check the child nodes for -being named \type {what}. A faster solution which also takes less code is this: - -\starttyping -\xmlfilter {#1} {/what[@a='1']/command('xml:yes','xml:nop')} -\stoptyping - -\stopsection - -\startsection[title=manipulating] - -Assume that we have the following \XML\ data: - -\startbuffer[test] -<A> - <B>right</B> - <B>wrong</B> -</A> -\stopbuffer - -\typebuffer[test] - -But, instead of \type {right} we want to see \type {okay}. We can do that with a -finalizer: - -\startbuffer -\startluacode -local rehash = { - ["right"] = "okay", -} - -function xml.finalizers.tex.Okayed(collected,what) - for i=1,#collected do - if what == "all" then - local str = xml.text(collected[i]) - context(rehash[str] or str) - else - context(str) - end - end -end -\stopluacode -\stopbuffer - -\typebuffer \getbuffer - -\startbuffer -\startxmlsetups xml:A - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:B - (It's \xmlfilter{#1}{./Okayed("all")}) -\stopxmlsetups - -\startxmlsetups xml:testsetups - \xmlsetsetup{#1}{A|B}{xml:*} -\stopxmlsetups - -\xmlregisterdocumentsetup{example-2}{xml:testsetups} -\xmlprocessbuffer{example-2}{test}{} -\stopbuffer - -\typebuffer - -The result is: \start \inlinebuffer \stop - -\stopsection - -\startsection[title=cross referencing] - -A rather common way to add cross references to \XML\ files is to borrow the -asymmetrical id's from \HTML. This means that one cannot simply use a value -of (say) \type {href} to locate an \type {id}. The next example came up on -the \CONTEXT\ mailing list. - -\startbuffer[test] -<doc> - <p>Text - <a href="#fn1" class="footnoteref" id="fnref1"><sup>1</sup></a> and - <a href="#fn2" class="footnoteref" id="fnref2"><sup>2</sup></a> - </p> - <div class="footnotes"> - <hr /> - <ol> - <li id="fn1"><p>A footnote.<a href="#fnref1">↩</a></p></li> - <li id="fn2"><p>A second footnote.<a href="#fnref2">↩</a></p></li> - </ol> - </div> -</doc> -\stopbuffer - -\typebuffer[test] - -We give two variants for dealing with such references. The first solution does -lookups and depending on the size of the file can be somewhat inefficient. - -\startbuffer -\startxmlsetups xml:doc - \blank - \xmlflush{#1} - \blank -\stopxmlsetups - -\startxmlsetups xml:p - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:footnote - (variant 1)\footnote - {\xmlfirst - {example-3-1} - {div[@class='footnotes']/ol/li[@id='\xmlrefatt{#1}{href}']}} -\stopxmlsetups - -\startxmlsetups xml:initialize - \xmlsetsetup{#1}{p|doc}{xml:*} - \xmlsetsetup{#1}{a[@class='footnoteref']}{xml:footnote} - \xmlsetsetup{#1}{div[@class='footnotes']}{xml:nothing} -\stopxmlsetups - -\xmlresetdocumentsetups{*} -\xmlregisterdocumentsetup{example-3-1}{xml:initialize} - -\xmlprocessbuffer{example-3-1}{test}{} -\stopbuffer - -\typebuffer - -This will typeset two footnotes. - -\getbuffer - -The second variant collects the references so that the time spend on lookups is -less. - -\startbuffer -\startxmlsetups xml:doc - \blank - \xmlflush{#1} - \blank -\stopxmlsetups - -\startxmlsetups xml:p - \xmlflush{#1} -\stopxmlsetups - -\startluacode - userdata.notes = {} -\stopluacode - -\startxmlsetups xml:collectnotes - \ctxlua{userdata.notes['\xmlrefatt{#1}{id}'] = '#1'} -\stopxmlsetups - -\startxmlsetups xml:footnote - (variant 2)\footnote - {\xmlflush - {\cldcontext{userdata.notes['\xmlrefatt{#1}{href}']}}} -\stopxmlsetups - -\startxmlsetups xml:initialize - \xmlsetsetup{#1}{p|doc}{xml:*} - \xmlsetsetup{#1}{a[@class='footnoteref']}{xml:footnote} - \xmlfilter{#1}{div[@class='footnotes']/ol/li/command(xml:collectnotes)} - \xmlsetsetup{#1}{div[@class='footnotes']}{} -\stopxmlsetups - -\xmlregisterdocumentsetup{example-3-2}{xml:initialize} - -\xmlprocessbuffer{example-3-2}{test}{} -\stopbuffer - -\typebuffer - -This will again typeset two footnotes: - -\getbuffer - -\stopsection - -\startsection[title=mapping values] - -One way to process options \type {frame} in the example below is to map the -values to values known by \CONTEXT. - -\startbuffer[test] -<a> - <nattable frame="on"> - <tr><td>#1</td><td>#2</td><td>#3</td><td>#4</td></tr> - <tr><td>#5</td><td>#6</td><td>#7</td><td>#8</td></tr> - </nattable> - <nattable frame="off"> - <tr><td>#1</td><td>#2</td><td>#3</td><td>#4</td></tr> - <tr><td>#5</td><td>#6</td><td>#7</td><td>#8</td></tr> - </nattable> - <nattable frame="no"> - <tr><td>#1</td><td>#2</td><td>#3</td><td>#4</td></tr> - <tr><td>#5</td><td>#6</td><td>#7</td><td>#8</td></tr> - </nattable> -</a> -\stopbuffer - -\typebuffer[test] - -\startbuffer -\startxmlsetups xml:a - \xmlflush{#1} -\stopxmlsetups - -\xmlmapvalue {nattable:frame} {on} {on} -\xmlmapvalue {nattable:frame} {yes} {on} -\xmlmapvalue {nattable:frame} {off} {off} -\xmlmapvalue {nattable:frame} {no} {off} - -\startxmlsetups xml:nattable - \startplacetable[title=#1] - \setupTABLE[frame=\xmlval{nattable:frame}{\xmlatt{#1}{frame}}{on}]% - \bTABLE - \xmlflush{#1} - \eTABLE - \stopplacetable -\stopxmlsetups - -\startxmlsetups xml:tr - \bTR - \xmlflush{#1} - \eTR -\stopxmlsetups - -\startxmlsetups xml:td - \bTD - \xmlflush{#1} - \eTD -\stopxmlsetups - -\startxmlsetups xml:testsetups - \xmlsetsetup{example-4}{a|nattable|tr|td|}{xml:*} -\stopxmlsetups - -\xmlregisterdocumentsetup{example-4}{xml:testsetups} - -\xmlprocessbuffer{example-4}{test}{} -\stopbuffer - -The \type {\xmlmapvalue} mechanism is rather efficient and involves a minimum -of testing. - -\typebuffer - -We get: - -\getbuffer - -\stopsection - -\startsection[title=using \LUA] - -In this example we demonstrate how you can delegate rendering to \LUA. We -will construct a so called extreme table. The input is: - -\startbuffer[demo] -<?xml version="1.0" encoding="utf-8"?> - -<a> - <b> <c>1</c> <d>Text</d> </b> - <b> <c>2</c> <d>More text</d> </b> - <b> <c>2</c> <d>Even more text</d> </b> - <b> <c>2</c> <d>And more</d> </b> - <b> <c>3</c> <d>And even more</d> </b> - <b> <c>2</c> <d>The last text</d> </b> -</a> -\stopbuffer - -\typebuffer[demo] - -The processor code is: - -\startbuffer[process] -\startxmlsetups xml:test_setups - \xmlsetsetup{#1}{a|b|c|d}{xml:*} -\stopxmlsetups - -\xmlregisterdocumentsetup{example-5}{xml:test_setups} - -\xmlprocessbuffer{example-5}{demo}{} -\stopbuffer - -\typebuffer - -We color a sequence of the same titles (numbers here) differently. The first -solution remembers the last title: - -\startbuffer -\startxmlsetups xml:a - \startembeddedxtable - \xmlflush{#1} - \stopembeddedxtable -\stopxmlsetups - -\startxmlsetups xml:b - \xmlfunction{#1}{test_ba} -\stopxmlsetups - -\startluacode -local lasttitle = nil - -function xml.functions.test_ba(t) - local title = xml.text(t, "/c") - local content = xml.text(t, "/d") - context.startxrow() - context.startxcell { - background = "color", - backgroundcolor = lasttitle == title and "colorone" or "colortwo", - foregroundstyle = "bold", - foregroundcolor = "white", - } - context(title) - lasttitle = title - context.stopxcell() - context.startxcell() - context(content) - context.stopxcell() - context.stopxrow() -end -\stopluacode -\stopbuffer - -\typebuffer \getbuffer - -The \type {embeddedxtable} environment is needed because the table is picked up -as argument. - -\startlinecorrection \getbuffer[process] \stoplinecorrection - -The second implemetation remembers what titles are already processed so here we -can color the last one too. - -\startbuffer -\startxmlsetups xml:a - \ctxlua{xml.functions.reset_bb()} - \startembeddedxtable - \xmlflush{#1} - \stopembeddedxtable -\stopxmlsetups - -\startxmlsetups xml:b - \xmlfunction{#1}{test_bb} -\stopxmlsetups - -\startluacode -local titles - -function xml.functions.reset_bb(t) - titles = { } -end - -function xml.functions.test_bb(t) - local title = xml.text(t, "/c") - local content = xml.text(t, "/d") - context.startxrow() - context.startxcell { - background = "color", - backgroundcolor = titles[title] and "colorone" or "colortwo", - foregroundstyle = "bold", - foregroundcolor = "white", - } - context(title) - titles[title] = true - context.stopxcell() - context.startxcell() - context(content) - context.stopxcell() - context.stopxrow() -end -\stopluacode -\stopbuffer - -\typebuffer \getbuffer - -\startlinecorrection \getbuffer[process] \stoplinecorrection - -A solution without any state variable is given below. - -\startbuffer -\startxmlsetups xml:a - \startembeddedxtable - \xmlflush{#1} - \stopembeddedxtable -\stopxmlsetups - -\startxmlsetups xml:b - \xmlfunction{#1}{test_bc} -\stopxmlsetups - -\startluacode -function xml.functions.test_bc(t) - local title = xml.text(t, "/c") - local content = xml.text(t, "/d") - context.startxrow() - local okay = xml.text(t,"./preceding-sibling::/[-1]") == title - context.startxcell { - background = "color", - backgroundcolor = okay and "colorone" or "colortwo", - foregroundstyle = "bold", - foregroundcolor = "white", - } - context(title) - context.stopxcell() - context.startxcell() - context(content) - context.stopxcell() - context.stopxrow() -end -\stopluacode -\stopbuffer - -\typebuffer \getbuffer - -\startlinecorrection \getbuffer[process] \stoplinecorrection - -Here is a solution that delegates even more to \LUA. The previous variants were -actually not that safe with repect to special characters and didn't handle -nested elements either but the next one does. - -\startbuffer[demo] -<?xml version="1.0" encoding="utf-8"?> - -<a> - <b> <c>#1</c> <d>Text</d> </b> - <b> <c>#2</c> <d>More text</d> </b> - <b> <c>#2</c> <d>Even more text</d> </b> - <b> <c>#2</c> <d>And more</d> </b> - <b> <c>#3</c> <d>And even more</d> </b> - <b> <c>#2</c> <d>Something <i>nested</i> </d> </b> -</a> -\stopbuffer - -\typebuffer[demo] - -We also need to map the \type {i} element. - -\startbuffer -\startxmlsetups xml:a - \starttexcode - \xmlfunction{#1}{test_a} - \stoptexcode -\stopxmlsetups - -\startxmlsetups xml:c - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:d - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:i - {\em\xmlflush{#1}} -\stopxmlsetups - -\startluacode -function xml.functions.test_a(t) - context.startxtable() - local previous = false - for b in xml.collected(lxml.getid(t),"/b") do - context.startxrow() - local current = xml.text(b,"/c") - context.startxcell { - background = "color", - backgroundcolor = (previous == current) and "colorone" or "colortwo", - foregroundstyle = "bold", - foregroundcolor = "white", - } - lxml.first(b,"/c") - context.stopxcell() - context.startxcell() - lxml.first(b,"/d") - context.stopxcell() - previous = current - context.stopxrow() - end - context.stopxtable() -end -\stopluacode - -\startxmlsetups xml:test_setups - \xmlsetsetup{#1}{a|b|c|d|i}{xml:*} -\stopxmlsetups - -\xmlregisterdocumentsetup{example-5}{xml:test_setups} - -\xmlprocessbuffer{example-5}{demo}{} -\stopbuffer - -\typebuffer - -\startlinecorrection \getbuffer \stoplinecorrection - -The question is, do we really need \LUA ? Often we don't, apart maybe from an -occasional special finalizer. A pure \TEX\ solution is given next: - -\startbuffer -\startxmlsetups xml:a - \glet\MyPreviousTitle\empty - \glet\MyCurrentTitle \empty - \startembeddedxtable - \xmlflush{#1} - \stopembeddedxtable -\stopxmlsetups - -\startxmlsetups xml:b - \startxrow - \xmlflush{#1} - \stopxrow -\stopxmlsetups - -\startxmlsetups xml:c - \xdef\MyCurrentTitle{\xmltext{#1}{.}} - \doifelse {\MyPreviousTitle} {\MyCurrentTitle} { - \startxcell - [background=color, - backgroundcolor=colorone, - foregroundstyle=bold, - foregroundcolor=white] - } { - \glet\MyPreviousTitle\MyCurrentTitle - \startxcell - [background=color, - backgroundcolor=colortwo, - foregroundstyle=bold, - foregroundcolor=white] - } - \xmlflush{#1} - \stopxcell -\stopxmlsetups - -\startxmlsetups xml:d - \startxcell - \xmlflush{#1} - \stopxcell -\stopxmlsetups - -\startxmlsetups xml:i - {\em\xmlflush{#1}} -\stopxmlsetups - -\startxmlsetups xml:test_setups - \xmlsetsetup{#1}{*}{xml:*} -\stopxmlsetups - -\xmlregisterdocumentsetup{example-5}{xml:test_setups} - -\xmlprocessbuffer{example-5}{demo}{} -\stopbuffer - -\typebuffer - -\startlinecorrection \getbuffer \stoplinecorrection - -You can even save a few lines of code: - -\starttyping -\startxmlsetups xml:c - \xdef\MyCurrentTitle{\xmltext{#1}{.}} - \startxcell - [background=color, - backgroundcolor=color\ifx\MyPreviousTitle\MyCurrentTitle one\else two\fi, - foregroundstyle=bold, - foregroundcolor=white] - \xmlflush{#1} - \stopxcell - \glet\MyPreviousTitle\MyCurrentTitle -\stopxmlsetups -\stoptyping - -Or if you prefer: - -\starttyping -\startxmlsetups xml:c - \xdef\MyCurrentTitle{\xmltext{#1}{.}} - \doifelse {\MyPreviousTitle} {\MyCurrentTitle} { - \xmlsetup{#1}{xml:c:one} - } { - \xmlsetup{#1}{xml:c:two} - } -\stopxmlsetups - -\startxmlsetups xml:c:one - \startxcell - [background=color, - backgroundcolor=colorone, - foregroundstyle=bold, - foregroundcolor=white] - \xmlflush{#1} - \stopxcell -\stopxmlsetups - -\startxmlsetups xml:c:two - \startxcell - [background=color, - backgroundcolor=colortwo, - foregroundstyle=bold, - foregroundcolor=white] - \xmlflush{#1} - \stopxcell - \global\let\MyPreviousTitle\MyCurrentTitle -\stopxmlsetups -\stoptyping - -These examples demonstrate that it doesn't hurt to know a little bit of \TEX\ -programming: defining macros and basic comparisons can come in handy. There are -examples in the test suite, you can peek in the source code, you can consult -the wiki or you can just ask on the list. - -\stopsection - -\startsection[title=last match] - -For the next example we use the following \XML\ input: - -\startbuffer[demo] -<?xml version "1.0"?> -<document> - <section id="1"> - <content> - <p>first</p> - <p>second</p> - </content> - </section> - <section id="2"> - <content> - <p>third</p> - <p>fourth</p> - </content> - </section> -</document> -\stopbuffer - -\typebuffer[demo] - -If you check if some element is present and then act accordingly, you can -end up with doing the same lookup twice. Although it might sound inefficient, -in practice it's often not measureable. - -\startbuffer -\startxmlsetups xml:demo:document - \type{\xmlall{#1}{/section[@id='2']/content/p}}\par - \xmldoif{#1}{/section[@id='2']/content/p} { - \xmlall{#1}{/section[@id='2']/content/p} - } - \type{\xmllastmatch}\par - \xmldoif{#1}{/section[@id='2']/content/p} { - \xmllastmatch - } - \type{\xmlall{#1}{last-match::}}\par - \xmldoif{#1}{/section[@id='2']/content/p} { - \xmlall{#1}{last-match::} - } - \type{\xmlfilter{#1}{last-match::/command(xml:demo:p)}}\par - \xmldoif{#1}{/section[@id='2']/content/p} { - \xmlfilter{#1}{last-match::/command(xml:demo:p)} - } -\stopxmlsetups - -\startxmlsetups xml:demo:p - \quad\xmlflush{#1}\endgraf -\stopxmlsetups - -\startxmlsetups xml:demo:base - \xmlsetsetup{#1}{document|p}{xml:demo:*} -\stopxmlsetups - -\xmlregisterdocumentsetup{example-6}{xml:demo:base} - -\xmlprocessbuffer{example-6}{demo}{} -\stopbuffer - -\typebuffer - -In the second check we just flush the last match, so effective we do an \type -{\xmlall} here. The third and fourth alternatives demonstrate how we can use -\type {last-match} as axis. The gain is 10\% or more on the lookup but of course -typesetting often takes relatively more time than the lookup. - -\startpacked -\getbuffer -\stoppacked - -\stopsection - -\startsection[title=Finalizers] - -The \XML\ parser is also available outside \TEX. Here is an example of its usage. -We pipe the result to \TEX\ but you can do with \type {t} whatever you like. - -\startbuffer -local x = xml.load("manual-demo-1.xml") -local t = { } - -for c in xml.collected(x,"//*") do - if not c.special and not t[c.tg] then - t[c.tg] = true - end -end - -context.tocontext(table.sortedkeys(t)) -\stopbuffer - -\typebuffer - -This returns: - -\ctxluabuffer - -We can wrap this in a finalizer: - -\startbuffer -xml.finalizers.taglist = function(collected) - local t = { } - for i=1,#collected do - local c = collected[i] - if not c.special then - local tg = c.tg - if tg and not t[tg] then - t[tg] = true - end - end - end - return table.sortedkeys(t) -end -\stopbuffer - -\typebuffer - -Or in a more extensive one: - -\startbuffer -xml.finalizers.taglist = function(collected,parenttoo) - local t = { } - for i=1,#collected do - local c = collected[i] - if not c.special then - local tg = c.tg - if tg and not t[tg] then - t[tg] = true - end - if parenttoo then - local p = c.__p__ - if p and not p.special then - local tg = p.tg .. ":" .. tg - if tg and not t[tg] then - t[tg] = true - end - end - end - end - end - return table.sortedkeys(t) -end -\stopbuffer - -\typebuffer \ctxluabuffer - -Usage is as follows: - -\startbuffer -local x = xml.load("manual-demo-1.xml") -local t = xml.applylpath(x,"//*/taglist()") - -context.tocontext(t) -\stopbuffer - -\typebuffer - -And indeed we get: - -\ctxluabuffer - -But we can also say: - -\startbuffer -local x = xml.load("manual-demo-1.xml") -local t = xml.applylpath(x,"//*/taglist(true)") - -context.tocontext(t) -\stopbuffer - -\typebuffer - -Now we get: - -\ctxluabuffer - -\startsection[title=Pure xml] - -One might wonder how a \TEX\ macro package would look like when backslashes, -dollars and percent signs would have no special meaning. In fact, it would be -rather useless as interpreting commands are triggered by such characters. Any -formatting or coding system needs such characters. Take \XML: angle brackets and -ampersands are really special. So, no matter what system we use, we do have to -deal with the (common) case where these characters need to be seen as they are. -Normally escaping is the solution. - -The \CONTEXT\ interface for \XML\ suffers from this as well. You really don't -want to know how many tricks are used for dealing with special characters and -entities: there are several ways these travel through the system and it is -possible to adapt and cheat. Especially roundtripped data (via tuc file) puts -some demands on the system because when ts \XML\ can become \TEX\ and vise versa. -The next example (derived from a mail on the list) demonstrates this: - -\starttyping -\startbuffer[demo] -<doc> - <pre><code>\ConTeXt\ is great</code></pre> - - <pre><code>but you need to know some tricks</code></pre> -</doc> -\stopbuffer - -\startxmlsetups xml:initialize - \xmlsetsetup{#1}{doc|p|code}{xml:*} - \xmlsetsetup{#1}{pre/code}{xml:pre:code} -\stopxmlsetups - -\xmlregistersetup{xml:initialize} - -\startxmlsetups xml:doc - \xmlflush{#1} -\stopxmlsetups - -\startxmlsetups xml:pre:code - no solution - \comment[symbol=Key, location=inmargin,color=yellow]{\xmlflush{#1}} - \par - solution one \begingroup - \expandUx - \comment[symbol=Key, location=inmargin,color=yellow]{\xmlflush{#1}} - \endgroup - \par - solution two - \comment[symbol=Key, location=inmargin,color=yellow]{\xmlpure{#1}} - \par - \xmlprettyprint{#1}{tex} -\stopxmlsetups - -\xmlprocessbuffer{main}{demo}{} -\stoptyping - -The first comment (an interactive feature of \PDF\ comes out as: - -\starttyping -\Ux {5C}ConTeXt\Ux {5C} is great -\stoptyping - -The second and third comment are okay. It's one of the reasons why we have \type -{\xmlpure}. - -\stopsection - -\stopchapter - + \component xml-mkiv-converter + \component xml-mkiv-filtering + \component xml-mkiv-commands + \component xml-mkiv-expressions + \component xml-mkiv-tricks + \component xml-mkiv-lookups + \component xml-mkiv-examples \stopbodymatter \stoptext diff --git a/metapost/context/base/mpiv/mp-blob.mpiv b/metapost/context/base/mpiv/mp-blob.mpiv index d6773db21..318c78f4f 100644 --- a/metapost/context/base/mpiv/mp-blob.mpiv +++ b/metapost/context/base/mpiv/mp-blob.mpiv @@ -32,13 +32,13 @@ if mfun_use_one_pass : vardef mfun_inject_blob(expr n) = mfun_blob_c := nullpicture ; - mfun_blob_b := lua.mp.blob_dimensions(mfun_blob_n,n) ; + mfun_blob_b := lua.mp.mf_blob_dimensions(mfun_blob_n,n) ; addto mfun_blob_c doublepath unitsquare xscaled redpart mfun_blob_b yscaled (greenpart mfun_blob_b + bluepart mfun_blob_b) shifted (0,- bluepart mfun_blob_b) withprescript "mf_object=texblob" - withprescript "tb_blob=" & decimal lua.mp.blob_index(mfun_blob_n,n) ; + withprescript "tb_blob=" & decimal lua.mp.mf_blob_index(mfun_blob_n,n) ; mfun_blob_c enddef ; @@ -46,14 +46,14 @@ else : vardef mfun_inject_blob(expr n) = mfun_blob_c := nullpicture ; - mfun_blob_b := lua.mp.blob_dimensions(mfun_blob_n,n) ; + mfun_blob_b := lua.mp.mf_blob_dimensions(mfun_blob_n,n) ; addto mfun_blob_c doublepath unitsquare xscaled redpart mfun_blob_b yscaled (greenpart mfun_blob_b + bluepart mfun_blob_b) shifted (0,- bluepart mfun_blob_b) withprescript "mf_object=texblob" withprescript "tb_stage=inject" - withprescript "tb_blob=" & decimal lua.mp.blob_index(mfun_blob_n,n) ; + withprescript "tb_blob=" & decimal lua.mp.mf_blob_index(mfun_blob_n,n) ; mfun_blob_c enddef ; @@ -71,19 +71,19 @@ if mfun_use_one_pass : vardef followtext(expr pth, txt) = image ( mfun_blob_n := mfun_blob_n + 1 ; - lua.mp.InjectBlobB(mfun_blob_n,txt); + lua.mp.mf_inject_blob(mfun_blob_n,txt); save pat, al, at, pl, pc, wid, pos, ap, ad, pic, len, n, sc ; path pat ; pat := pth ; numeric al, at, pl, pc, wid, pos, len[], n, sc ; pair ap, ad ; picture pic[] ; len[0] := 0 ; - n := lua.mp.blob_size(mfun_blob_n) ; + n := lua.mp.mf_blob_size(mfun_blob_n) ; sc := 0 ; for i=1 upto n : pic[i] := mfun_inject_blob(i) ; pic[i] := pic[i] shifted - llcorner pic[i] ; - len[i] := len[i-1] + lua.mp.blob_width(mfun_blob_n,i) ; + len[i] := len[i-1] + lua.mp.mf_blob_width(mfun_blob_n,i) ; endfor ; al := arclength pth ; if al = 0 : @@ -107,7 +107,7 @@ if mfun_use_one_pass : draw pat withpen pencircle scaled 1pt withcolor blue ; fi ; for i=1 upto n : - wid := lua.mp.blob_width(mfun_blob_n,i) ; + wid := lua.mp.mf_blob_width(mfun_blob_n,i) ; pos := len[i]-wid/2 + (i-1)*pl + pc ; at := arctime pos of pat ; ap := point at of pat ; @@ -150,12 +150,12 @@ else : pair ap, ad ; picture pic[] ; len[0] := 0 ; - n := lua.mp.blob_size(mfun_blob_n) ; + n := lua.mp.mf_blob_size(mfun_blob_n) ; sc := 0 ; for i=1 upto n : pic[i] := mfun_inject_blob(i) ; pic[i] := pic[i] shifted - llcorner pic[i] ; - len[i] := len[i-1] + lua.mp.blob_width(mfun_blob_n,i) ; + len[i] := len[i-1] + lua.mp.mf_blob_width(mfun_blob_n,i) ; endfor ; al := arclength pth ; if al = 0 : @@ -179,7 +179,7 @@ else : draw pat withpen pencircle scaled 1pt withcolor blue ; fi ; for i=1 upto n : - wid := lua.mp.blob_width(mfun_blob_n,i) ; + wid := lua.mp.mf_blob_width(mfun_blob_n,i) ; pos := len[i]-wid/2 + (i-1)*pl + pc ; at := arctime pos of pat ; ap := point at of pat ; diff --git a/metapost/context/base/mpiv/mp-grph.mpiv b/metapost/context/base/mpiv/mp-grph.mpiv index a2f710881..2133d0ee5 100644 --- a/metapost/context/base/mpiv/mp-grph.mpiv +++ b/metapost/context/base/mpiv/mp-grph.mpiv @@ -139,7 +139,7 @@ if mfun_use_one_pass : save figurepicture ; picture figurepicture ; figurepicture := currentpicture ; currentpicture := nullpicture ; currentgraphictext := currentgraphictext + 1 ; - lua.mp.GraphicText(currentgraphictext,t) ; + lua.mp.mf_graphic_text(currentgraphictext,t) ; mfun_finish_graphic_text % picks up directives enddef ; diff --git a/metapost/context/base/mpiv/mp-luas.mpiv b/metapost/context/base/mpiv/mp-luas.mpiv index bebe4c0ad..d5aeec158 100644 --- a/metapost/context/base/mpiv/mp-luas.mpiv +++ b/metapost/context/base/mpiv/mp-luas.mpiv @@ -75,32 +75,69 @@ vardef mlib_luas_luacall(text t) = ) enddef ; +% vardef mlib_luas_lualist(expr c)(text t) = +% save b ; boolean b ; b := false ; +% runscript(c & "(" for s = t : +% if b : +% & "," +% else : +% hide(b := true) +% fi +% if string s : +% % & ditto & s & ditto +% & mfun_lua_bs & s & mfun_lua_es +% elseif numeric s : +% & decimal s +% elseif boolean s : +% & if s : "true" else : "false" fi +% elseif pair s : +% & mfun_pair_to_table(s) +% elseif path s : +% & mfun_path_to_table(s) +% elseif rgbcolor s : +% & mfun_rgb_to_table(s) +% elseif cmykcolor s : +% & mfun_cmyk_to_table(s) +% else : +% & ditto & tostring(s) & ditto +% fi endfor & ")" +% ) +% enddef ; + +newinternal mfun_luas_b ; + +def mlib_luas_luadone = + exitif numeric begingroup mfun_luas_b := 1 ; endgroup ; +enddef ; + vardef mlib_luas_lualist(expr c)(text t) = - save b ; boolean b ; b := false ; - runscript(c & "(" for s = t : - if b : - & "," + interim mfun_luas_b := 0 ; + runscript(c & for s = t : + if mfun_luas_b = 0 : + "(" + % hide(mfun_luas_b := 1) + mlib_luas_luadone else : - hide(b := true) + "," fi + & if string s : - % & ditto & s & ditto - & mfun_lua_bs & s & mfun_lua_es + mfun_lua_bs & s & mfun_lua_es elseif numeric s : - & decimal s + decimal s elseif boolean s : - & if s : "true" else : "false" fi + if s : "true" else : "false" fi elseif pair s : - & mfun_pair_to_table(s) + mfun_pair_to_table(s) elseif path s : - & mfun_path_to_table(s) + mfun_path_to_table(s) elseif rgbcolor s : - & mfun_rgb_to_table(s) + mfun_rgb_to_table(s) elseif cmykcolor s : - & mfun_cmyk_to_table(s) + mfun_cmyk_to_table(s) else : - & ditto & tostring(s) & ditto - fi endfor & ")" + ditto & tostring(s) & ditto + fi & endfor if mfun_luas_b = 0 : "()" else : ")" fi ) enddef ; @@ -188,11 +225,11 @@ vardef texstr(expr name) = lua.mp.texstr(name) enddef ; % \stopMPcode def inpath suffix p = - = 1 step 1 until lua.mp.mfun_path_length(str p) + = 1 step 1 until lua.mp.mf_path_length(str p) enddef ; -vardef pointof primary i = lua.mp.mfun_path_point(i) enddef ; -vardef leftof primary i = lua.mp.mfun_path_left (i) enddef ; -vardef rightof primary i = lua.mp.mfun_path_right(i) enddef ; +vardef pointof primary i = lua.mp.mf_path_point(i) enddef ; +vardef leftof primary i = lua.mp.mf_path_left (i) enddef ; +vardef rightof primary i = lua.mp.mf_path_right(i) enddef ; -extra_endfig := extra_endfig & " lua.mp.mfun_path_reset() ; " ; +extra_endfig := extra_endfig & " lua.mp.mf_path_reset() ; " ; diff --git a/metapost/context/base/mpiv/mp-mlib.mpiv b/metapost/context/base/mpiv/mp-mlib.mpiv index 6fcc75d50..019020d82 100644 --- a/metapost/context/base/mpiv/mp-mlib.mpiv +++ b/metapost/context/base/mpiv/mp-mlib.mpiv @@ -202,7 +202,7 @@ if mfun_use_one_pass : mfun_tt_c := nullpicture ; mfun_tt_o := nullpicture ; addto mfun_tt_o doublepath origin _op_ ; % save drawoptions - mfun_tt_r := lua.mp.SomeText(mfun_tt_n,s) ; + mfun_tt_r := lua.mp.mf_some_text(mfun_tt_n,s) ; addto mfun_tt_c doublepath unitsquare xscaled redpart mfun_tt_r yscaled (greenpart mfun_tt_r + bluepart mfun_tt_r) @@ -220,7 +220,7 @@ if mfun_use_one_pass : mfun_tt_c := nullpicture ; mfun_tt_o := nullpicture ; addto mfun_tt_o doublepath origin _op_ ; % save drawoptions - mfun_tt_r := lua.mp.MadeText(mfun_tt_n) ; + mfun_tt_r := lua.mp.mf_made_text(mfun_tt_n) ; addto mfun_tt_c doublepath unitsquare xscaled redpart mfun_tt_r yscaled (greenpart mfun_tt_r + bluepart mfun_tt_r) @@ -255,7 +255,7 @@ else : withprescript "tx_global=yes" ; fi ; else : - mfun_tt_b := lua.mp.tt_dimensions(mfun_tt_n) ; + mfun_tt_b := lua.mp.mf_tt_dimensions(mfun_tt_n) ; addto mfun_tt_c doublepath unitsquare xscaled redpart mfun_tt_b yscaled (greenpart mfun_tt_b + bluepart mfun_tt_b) @@ -286,7 +286,7 @@ enddef ; vardef rawtexbox(expr category, name) = mfun_tt_c := nullpicture ; if validtexbox(category,name) : - mfun_tt_b := lua.mp.tb_dimensions(category, name) ; + mfun_tt_b := lua.mp.mf_tb_dimensions(category, name) ; addto mfun_tt_c doublepath unitsquare xscaled redpart mfun_tt_b yscaled (greenpart mfun_tt_b + bluepart mfun_tt_b) @@ -468,7 +468,7 @@ if mfun_use_one_pass : mfun_tt_c := nullpicture ; mfun_tt_o := nullpicture ; addto mfun_tt_o doublepath origin _op_ ; % save drawoptions - mfun_tt_r := lua.mp.SomeFormattedText(mfun_tt_n,t) ; + mfun_tt_r := lua.mp.mf_formatted_text(mfun_tt_n,t) ; addto mfun_tt_c doublepath unitsquare xscaled redpart mfun_tt_r yscaled (greenpart mfun_tt_r + bluepart mfun_tt_r) @@ -513,7 +513,7 @@ else : withprescript "tx_global=yes" ; fi ; else : - mfun_tt_b := lua.mp.tt_dimensions(mfun_tt_n) ; + mfun_tt_b := lua.mp.mf_tt_dimensions(mfun_tt_n) ; addto mfun_tt_c doublepath unitsquare xscaled redpart mfun_tt_b yscaled (greenpart mfun_tt_b + bluepart mfun_tt_b) @@ -1075,19 +1075,38 @@ def withmask primary filename = withprescript "fg_mask=" & filename enddef ; -def externalfigure primary filename = - if false : - rawtextext("\externalfigure[" & filename & "]") - else : - image ( - addto currentpicture doublepath unitsquare - withprescript "fg_name=" & filename ; - ) -% unitsquare -% withpen pencircle scaled 0 -% withprescript "fg_name=" & filename - fi -enddef ; +if mfun_use_one_pass : + + vardef externalfigure primary filename = + mfun_tt_c := nullpicture ; + mfun_tt_r := lua.mp.mf_external_figure(filename) ; + addto mfun_tt_c doublepath unitsquare + xscaled redpart mfun_tt_r + yscaled greenpart mfun_tt_r + withprescript "mf_object=figure" + withprescript "fg_name=" & filename ; + ; + mfun_tt_c + enddef ; + +else : + + def externalfigure primary filename = + if false : + rawtextext("\externalfigure[" & filename & "]") + else : + image ( + addto currentpicture doublepath unitsquare + withprescript "mf_object=figure" + withprescript "fg_name=" & filename ; + ) + % unitsquare + % withpen pencircle scaled 0 + % withprescript "fg_name=" & filename + fi + enddef ; + +fi ; def figure primary filename = rawtextext("\externalfigure[" & filename & "]") @@ -1247,7 +1266,7 @@ if mfun_use_one_pass : def mfun_do_outline_options_r = enddef ; image ( normaldraw image ( % lua.mp.report("set outline text",currentoutlinetext); - lua.mp.OutlineText(currentoutlinetext,t,kind) ; + lua.mp.mf_outline_text(currentoutlinetext,t,kind) ; % lua.mp.report("get outline text",currentoutlinetext); if kind = "f" : mfun_do_outline_text_set_f rest ; @@ -1264,7 +1283,7 @@ if mfun_use_one_pass : else : mfun_do_outline_text_set_n rest ; fi ; - lua.mp.get_outline_text(currentoutlinetext) ; + lua.mp.mf_get_outline_text(currentoutlinetext) ; ) mfun_do_outline_options_r ; ) enddef ; @@ -1302,7 +1321,7 @@ else : else : mfun_do_outline_text_set_n rest ; fi ; - lua.mp.get_outline_text(currentoutlinetext) ; + lua.mp.mf_get_outline_text(currentoutlinetext) ; fi ; ) mfun_do_outline_options_r ; ) enddef ; @@ -1757,23 +1776,15 @@ def nofill text t = fill t withpostscript "collect" enddef ; % so we can do: withcolor "red" -% vardef resolvedcolor primary s = -% % lua.mp.namedcolor(s) % conflicts with macro namedcolor -% % lua.mp.NamedColor(s) % okay but, can also be -% % lua.mp("NamedColor",s) % which gives expansion mess -% if string s : -% runscript("mp.NamedColor('" & s & "')") % faster anyway -% else : -% s -% fi -% enddef ; +% We do a low level runscript: +% +% lua.mp.namedcolor(s) % conflicts with macro namedcolor +% lua.mp.mf_named_color(s) % okay but, can also be +% lua.mp("mf_named_color",s) % which gives expansion mess def resolvedcolor primary s = % no vardef - % lua.mp.namedcolor(s) % conflicts with macro namedcolor - % lua.mp.NamedColor(s) % okay but, can also be - % lua.mp("NamedColor",s) % which gives expansion mess if string s : - runscript("mp.NamedColor('" & s & "')") % faster anyway + runscript("mp.mf_named_color('" & s & "')") % faster anyway else : s fi diff --git a/metapost/context/base/mpiv/mp-page.mpiv b/metapost/context/base/mpiv/mp-page.mpiv index 6e93bdaae..052bcbb23 100644 --- a/metapost/context/base/mpiv/mp-page.mpiv +++ b/metapost/context/base/mpiv/mp-page.mpiv @@ -188,6 +188,8 @@ fi ; string CurrentLayout ; CurrentLayout := "default" ; +% runscript("mp.PaperHeight()") % way faster of course + vardef PaperHeight = lua.mp.PaperHeight () enddef ; vardef PaperWidth = lua.mp.PaperWidth () enddef ; vardef PrintPaperHeight = lua.mp.PrintPaperHeight () enddef ; diff --git a/metapost/context/base/mpiv/mp-tool.mpiv b/metapost/context/base/mpiv/mp-tool.mpiv index 566f71056..281767522 100644 --- a/metapost/context/base/mpiv/mp-tool.mpiv +++ b/metapost/context/base/mpiv/mp-tool.mpiv @@ -244,19 +244,19 @@ boolean savingdata ; savingdata := false ; boolean savingdatadone ; savingdatadone := false ; def savedata expr txt = - lua.mp.save_data(txt); + lua.mp.mf_save_data(txt); enddef ; def startsavingdata = - lua.mp.start_saving_data(); + lua.mp.mf_start_saving_data(); enddef ; def stopsavingdata = - lua.mp.stop_saving_data() ; + lua.mp.mf_stop_saving_data() ; enddef ; def finishsavingdata = - lua.mp.finish_saving_data() ; + lua.mp.mf_finish_saving_data() ; enddef ; %D Instead of a keystroke eating save and allocation diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index 7e089de90..a28121d0d 100644 --- a/tex/context/base/mkii/cont-new.mkii +++ b/tex/context/base/mkii/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2018.07.06 19:07} +\newcontextversion{2018.07.10 15:52} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii index 09be8b091..6a88fbd1c 100644 --- a/tex/context/base/mkii/context.mkii +++ b/tex/context/base/mkii/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2018.07.06 19:07} +\edef\contextversion{2018.07.10 15:52} %D For those who want to use this: diff --git a/tex/context/base/mkii/mult-de.mkii b/tex/context/base/mkii/mult-de.mkii index 2bd9353d0..6e30e12ad 100644 --- a/tex/context/base/mkii/mult-de.mkii +++ b/tex/context/base/mkii/mult-de.mkii @@ -1027,6 +1027,7 @@ \setinterfaceconstant{otherstext}{otherstext} \setinterfaceconstant{outermargin}{outermargin} \setinterfaceconstant{overprint}{overprint} +\setinterfaceconstant{ownerpassword}{ownerpassword} \setinterfaceconstant{ownnumber}{eigenenummer} \setinterfaceconstant{page}{seite} \setinterfaceconstant{pageboundaries}{seitenbegrenzung} @@ -1268,6 +1269,7 @@ \setinterfaceconstant{up}{up} \setinterfaceconstant{urlalternative}{urlalternative} \setinterfaceconstant{urlspace}{urlspatium} +\setinterfaceconstant{userpassword}{userpassword} \setinterfaceconstant{validate}{validieren} \setinterfaceconstant{values}{values} \setinterfaceconstant{vcommand}{vbefehl} diff --git a/tex/context/base/mkiv/attr-ini.mkiv b/tex/context/base/mkiv/attr-ini.mkiv index e3d328e3d..3792b1c63 100644 --- a/tex/context/base/mkiv/attr-ini.mkiv +++ b/tex/context/base/mkiv/attr-ini.mkiv @@ -24,6 +24,7 @@ \installcorenamespace{attributecount} % the counter representing the attribute (attrdef'd) \installcorenamespace{attributeid} % the internal number \installcorenamespace{attributestack} % the attribute specific stack +\installcorenamespace{attributepickup} \unexpanded\def\pushattribute#1% {\global\advance\csname\??attributestack\string#1\endcsname\plusone @@ -40,12 +41,15 @@ \newtoks \t_attr_list_global \newtoks \t_attr_list_local +\newtoks \t_attr_list_pickup \newtoks \t_attr_list_nomath \ifdefined \s!global \else \def\s!global {global} \fi % for metatex % or hard check later \ifdefined \s!public \else \def\s!public {public} \fi % for metatex % or hard check later \ifdefined \s!private \else \def\s!private {private} \fi % for metatex % or hard check later \ifdefined \s!attribute \else \def\s!attribute{attribute} \fi % for metatex % or hard check later +\ifdefined \s!pickup \else \def\s!pickup {pickup} \fi % for metatex % or hard check later +\ifdefined \s!forget \else \def\s!forget {forget} \fi % for metatex % or hard check later \unexpanded\def\defineattribute {\dodoubleempty\attr_basics_define} \unexpanded\def\definesystemattribute{\dodoubleempty\attr_basics_define_system} @@ -53,6 +57,8 @@ \def\attr_basics_define {\attr_basics_define_indeed\s!public} \def\attr_basics_define_system{\attr_basics_define_indeed\s!private} + % here public means 'visible' so it's not to be confused with 'public' at the lua end + \def\attr_basics_define_indeed#1[#2][#3]% {\ifcsname\??attributecount#2\endcsname\else \scratchcounter\clf_defineattribute{#2}{#1}\relax @@ -66,11 +72,29 @@ {\etoksapp\t_attr_list_local {\csname\??attributecount#2\endcsname\attributeunsetvalue}}% \doifinset\s!nomath{#3}% {\etoksapp\t_attr_list_nomath{\csname\??attributecount#2\endcsname\attributeunsetvalue}}% - % here public means 'visible' so it's not to be confused with 'public' at the lua end \doifinset\s!public{#3}% {\expandafter\let\csname#2\s!attribute\expandafter\endcsname\csname\??attributeid#2\endcsname}% + \doifinset\s!pickup{#3}% + {\expandafter\newconstant\csname\??attributepickup#2\endcsname + \csname\??attributepickup#2\endcsname\attributeunsetvalue + \etoksapp\t_attr_list_pickup{\csname\??attributecount#2\endcsname\csname\??attributepickup#2\endcsname}% + \ifcsname#2\s!attribute\endcsname + \expandafter\edef\csname\s!pickup#2\s!attribute\endcsname + {\csname\??attributepickup#2\endcsname\csname\??attributecount#2\endcsname}% + \expandafter\edef\csname\s!forget#2\s!attribute\endcsname + {\csname\??attributepickup#2\endcsname\attributeunsetvalue}% + \fi}% \fi} +\unexpanded\def\pickupattributes + {\the\t_attr_list_pickup\relax} + +% \unexpanded\def\pickupattribute#1% +% {\csname\??attributecount#1\endcsname\csname\??attributepickup#1\endcsname} + +% \unexpanded\def\pickupattributelater#1% +% {\csname\??attributepickup#1\endcsname\csname\??attributecount#1\endcsname} + \unexpanded\def\newattribute#1% {\attr_basics_define_indeed\s!public[\csstring#1][]% \expandafter\let\expandafter#1\csname\??attributeid\csstring#1\endcsname} diff --git a/tex/context/base/mkiv/buff-ini.lua b/tex/context/base/mkiv/buff-ini.lua index 970042c1b..632565fc7 100644 --- a/tex/context/base/mkiv/buff-ini.lua +++ b/tex/context/base/mkiv/buff-ini.lua @@ -182,7 +182,7 @@ local function collectcontent(name,separator) -- no print end local function loadcontent(name) -- no print - local content = collectcontent(name,"\n") -- tex likes \n + local content = collectcontent(name,"\n") -- tex likes \n hm, elsewhere \r local ok, err = load(content) if ok then return ok() diff --git a/tex/context/base/mkiv/buff-ini.mkiv b/tex/context/base/mkiv/buff-ini.mkiv index e487fc298..145f0f392 100644 --- a/tex/context/base/mkiv/buff-ini.mkiv +++ b/tex/context/base/mkiv/buff-ini.mkiv @@ -179,16 +179,16 @@ {\dosingleempty\buff_get} \unexpanded\def\buff_get[#1]% [name] - {\namedbufferparameter\empty\c!before + {\namedbufferparameter\empty\c!before\relax \doifelsenothing{#1} {\buff_get_stored_indeed\empty} {\processcommalist[#1]\buff_get_stored_indeed}% - \namedbufferparameter\empty\c!after} + \namedbufferparameter\empty\c!after\relax} \unexpanded\def\buff_get_stored#1#2% - {\namedbufferparameter{#1}\c!before + {\namedbufferparameter{#1}\c!before\relax \buff_get_stored_indeed{#2}% - \namedbufferparameter{#1}\c!after} + \namedbufferparameter{#1}\c!after\relax} \unexpanded\def\buff_get_stored_indeed#1% {\clf_getbuffer{#1}} diff --git a/tex/context/base/mkiv/buff-ver.mkiv b/tex/context/base/mkiv/buff-ver.mkiv index 47902ced7..7cf829b74 100644 --- a/tex/context/base/mkiv/buff-ver.mkiv +++ b/tex/context/base/mkiv/buff-ver.mkiv @@ -496,7 +496,7 @@ \def\buff_verbatim_typing_start_nop {\typingparameter\c!before - \startpacked[\v!blank] + \startpacked[\v!blank]% \buff_verbatim_setup_line_numbering \buff_verbatim_initialize_typing_one \buff_verbatim_setup_keep_together @@ -504,7 +504,7 @@ \def\buff_verbatim_typing_start_yes[#1]% {\typingparameter\c!before - \startpacked[\v!blank] + \startpacked[\v!blank]% \doifelseassignment{#1} {\setupcurrenttyping[#1]} {\doif\v!continue{#1}{\lettypingparameter\c!continue\v!yes}}% @@ -540,7 +540,7 @@ \dostoptagged \endofverbatimlines \dostoptagged - \csname#2\endcsname} + \begincsname#2\endcsname} \unexpanded\def\buff_verbatim_typing_stop#1% hm, currenttyping {\stoppacked diff --git a/tex/context/base/mkiv/cldf-ini.lua b/tex/context/base/mkiv/cldf-ini.lua index dabdbb9b0..72f1276d2 100644 --- a/tex/context/base/mkiv/cldf-ini.lua +++ b/tex/context/base/mkiv/cldf-ini.lua @@ -1354,24 +1354,21 @@ do local sentinel = string.char(26) -- ASCII SUB character : endoffileasciicode : ignorecatcode local level = 0 - local function collect(c,...) -- can be optimized - -- snippets - for i=1,select("#",...) do + local function collect(c,a,...) -- can be optimized + if type(c) == "userdata" then nofcollected = nofcollected + 1 - collected[nofcollected] = select(i,...) + -- collected[nofcollected] = userdata(c) + collected[nofcollected] = "\\" .. c.csname + end + if a then + for i=1,select("#",a,...) do + local c = select(i,a,...) + nofcollected = nofcollected + 1 + collected[nofcollected] = type(c) == "userdata" and userdata(c) or c + end end end - -- local function collectdirect(c,...) -- can be optimized - -- -- lines - -- for i=1,select("#",...) do - -- n = n + 1 - -- t[n] = select(i,...) - -- n = n + 1 - -- t[n] = "\r" - -- end - -- end - local collectdirect = collect local permitted = true diff --git a/tex/context/base/mkiv/cldf-ver.lua b/tex/context/base/mkiv/cldf-ver.lua index 3710b2415..7a1c81301 100644 --- a/tex/context/base/mkiv/cldf-ver.lua +++ b/tex/context/base/mkiv/cldf-ver.lua @@ -13,32 +13,69 @@ if not modules then modules = { } end modules ['cldf-ver'] = { local concat, tohandle = table.concat, table.tohandle local splitlines, strip = string.splitlines, string.strip local tostring, type = tostring, type +local assignbuffer = buffers.assign local context = context -local function flush(...) - context(concat{...,"\r"}) -- was \n +context.tobuffer = assignbuffer -- (name,str,catcodes) + +function context.tolines(str,strip) + local lines = type(str) == "string" and splitlines(str) or str + for i=1,#lines do + if strip then + context(strip(lines[i]) .. " ") + else + context(lines[i] .. " ") + end + end end -local function t_tocontext(...) - context.starttyping { "typing" } -- else [1] is intercepted - context.pushcatcodes("verbatim") - tohandle(flush,...) -- ok? - context.stoptyping() - context.popcatcodes() +-- local function flush(...) +-- context(concat { ..., "\r" }) -- was \n +-- end +-- +-- somehow this doesn't work any longer .. i need to figure out why +-- +-- local function t_tocontext(t) +-- context.starttyping { "typing" } -- else [1] is intercepted +-- context.pushcatcodes("verbatim") +-- -- tohandle(flush,...) +-- context(table.serialize(t)) +-- context.stoptyping() +-- context.popcatcodes() +-- end +-- +-- local function s_tocontext(first,second,...) -- we need to catch {\} +-- context.type() +-- context("{") +-- context.pushcatcodes("verbatim") +-- if second then +-- context(concat({ first, second, ... }, " ")) +-- else +-- context(first) -- no need to waste a { } +-- end +-- context.popcatcodes() +-- context("}") +-- end + +local t_buffer = { "t_o_c_o_n_t_e_x_t" } +local t_typing = { "typing" } +local t_type = { "type" } + +local function flush(s,inline) + assignbuffer("t_o_c_o_n_t_e_x_t",s) + context[inline and "typeinlinebuffer" or "typebuffer"](t_buffer) + context.resetbuffer(t_buffer) end -local function s_tocontext(first,...) -- we need to catch {\} - context.type() - context("{") - context.pushcatcodes("verbatim") - if first then - context(first) -- no need to waste a { } - else - context(concat({first,...}," ")) - end - context.popcatcodes() - context("}") +local function t_tocontext(t) + local s = table.serialize(t) + context(function() flush(s,false) end) +end + +local function s_tocontext(first,second,...) -- we need to catch {\} + local s = second and concat({ first, second, ... }, " ") or first + context(function() flush(s,true) end) end local function b_tocontext(b) @@ -74,15 +111,3 @@ end) context.tocontext = tocontext -context.tobuffer = buffers.assign -- (name,str,catcodes) - -function context.tolines(str,strip) - local lines = type(str) == "string" and splitlines(str) or str - for i=1,#lines do - if strip then - context(strip(lines[i]) .. " ") - else - context(lines[i] .. " ") - end - end -end diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 277666af1..e2e0376c8 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2018.07.06 19:07} +\newcontextversion{2018.07.10 15:52} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. @@ -20,8 +20,22 @@ \writestatus\m!system{beware: some patches loaded from cont-new.mkiv} +% math-ini.mkiv + \ifnum\texenginefunctionality<6753\else \mathrulethicknessmode\zerocount \fi +% math-ini.mkiv + +\ifdefined\t \else \unexpanded\def\t{\mathortext\text\mathtext} \fi +\ifdefined\w \else \unexpanded\def\w{\mathortext\word\mathword} \fi + +\appendtoks + \let\t\mathtext + \let\w\mathword +\to \everymathematics + +% done + \protect \endinput diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 523af7cde..5407da02a 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -42,7 +42,7 @@ %D has to match \type {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2018.07.06 19:07} +\edef\contextversion{2018.07.10 15:52} \edef\contextkind {beta} %D For those who want to use this: diff --git a/tex/context/base/mkiv/grph-inc.lua b/tex/context/base/mkiv/grph-inc.lua index ce37c7c62..dd57c9dfa 100644 --- a/tex/context/base/mkiv/grph-inc.lua +++ b/tex/context/base/mkiv/grph-inc.lua @@ -1941,8 +1941,10 @@ function figures.getinfo(name,page) end if name.name then local data = figures.push(name) - figures.identify() - figures.check() + data = figures.identify(data) + if data.status and data.status.status > 0 then + data = figures.check(data) + end figures.pop() return data end diff --git a/tex/context/base/mkiv/meta-blb.lua b/tex/context/base/mkiv/meta-blb.lua index 639e22052..76e9e3362 100644 --- a/tex/context/base/mkiv/meta-blb.lua +++ b/tex/context/base/mkiv/meta-blb.lua @@ -87,20 +87,20 @@ local function blob_raw_wipe(i) allblobs[i] = false end -mp.blob_raw_dimensions = blob_raw_dimensions -mp.blob_raw_content = blob_raw_content -mp.blob_raw_reset = blob_raw_reset -mp.blob_raw_wipe = blob_raw_wipe -mp.blob_raw_toutf = blob_raw_toutf +mp.mf_blob_raw_dimensions = blob_raw_dimensions +mp.mf_blob_raw_content = blob_raw_content +mp.mf_blob_raw_reset = blob_raw_reset +mp.mf_blob_raw_wipe = blob_raw_wipe +mp.mf_blob_raw_toutf = blob_raw_toutf -function mp.blob_new(category,text) +function mp.mf_blob_new(category,text) if trace then report("category %a, text %a",category,text) end texblobs[category].text = text end -function mp.blob_add(category,blob) +function mp.mf_blob_add(category,blob) local tb = texblobs[category].blobs local tn = #allblobs + 1 blob = hpack_nodes(blob) @@ -111,7 +111,7 @@ function mp.blob_add(category,blob) end end -function mp.blob_width(category,i) +function mp.mf_blob_width(category,i) local index = texblobs[category].blobs[i] local blob = allblobs[index] if blob then @@ -121,15 +121,15 @@ function mp.blob_width(category,i) end end -function mp.blob_size(category,i) +function mp.mf_blob_size(category,i) mpprint(#texblobs[category].blobs or 0) end -function mp.blob_index(category,i) +function mp.mf_blob_index(category,i) mpprint(texblobs[category].blobs[i] or 0) end -function mp.blob_dimensions(category,i) +function mp.mf_blob_dimensions(category,i) local index = texblobs[category].blobs[i] local blob = allblobs[index] if blob then @@ -163,7 +163,7 @@ local function injectblob(object,blob) end end -mp.blob_inject = injectblob +-- mp.mf_blob_inject = injectblob local function getblob(box,blob) texsetbox(box,blob_raw_content(blob)) @@ -221,8 +221,8 @@ local flatten_list = node.flatten_discretionaries local remove_node = nodes.remove local flush_node = nodes.flush -local addblob = mp.blob_add -local newblob = mp.blob_new +local addblob = mp.mf_blob_add +local newblob = mp.mf_blob_new local visible_code = { [nodecodes.glyph] = true, @@ -291,7 +291,7 @@ local ft_reset, ft_analyze, ft_process do local mp_category = 0 local mp_str = "" - function mp.InjectBlobB(category,str) + function mp.mf_inject_blob(category,str) newblob(category,str) -- only for tracing mp_category = category mp_str = str diff --git a/tex/context/base/mkiv/meta-ini.lua b/tex/context/base/mkiv/meta-ini.lua index 6c4768671..f320efe20 100644 --- a/tex/context/base/mkiv/meta-ini.lua +++ b/tex/context/base/mkiv/meta-ini.lua @@ -117,23 +117,23 @@ do local data = false - function mp.start_saving_data(n) + function mp.mf_start_saving_data(n) data = { } end - function mp.stop_saving_data() + function mp.mf_stop_saving_data() if data then -- nothing end end - function mp.finish_saving_data() + function mp.mf_finish_saving_data() if data then -- nothing end end - function mp.save_data(str) + function mp.mf_save_data(str) if data then data[#data+1] = str end diff --git a/tex/context/base/mkiv/meta-nod.lua b/tex/context/base/mkiv/meta-nod.lua index 119c276e2..422b4ee14 100644 --- a/tex/context/base/mkiv/meta-nod.lua +++ b/tex/context/base/mkiv/meta-nod.lua @@ -6,24 +6,76 @@ if not modules then modules = { } end modules ['meta-nod'] = { license = "see context related readme files" } +local tonumber = tonumber +local P, R, Cs, lpegmatch = lpeg.P, lpeg.R, lpeg.Cs, lpeg.match + local references = { } +local trace = false +local report = logs.reporter("metapost","nodes") -metapost.nodes = { +local context = context +local implement = interfaces.implement - initialize = function() - references = { } - end, +trackers.register("metapost.nodes", function(v) trace = v end) - register = function(s,r) - references[s] = r - end, +local word = R("AZ","az","__")^1 - resolve = function(s) - context(references[s] or ("\\number " .. (tonumber(s) or 0))) - end, +local pattern = Cs ( + ( + word / function(s) return references[s] or s end + + P("{") / "[" + + P("}") / "]" + + P(1) + )^1 +) + +implement { + name = "grph_nodes_initialize", + actions = function() + references = { } + end +} - reset = function() +implement { + name = "grph_nodes_reset", + actions = function() references = { } - end, + end +} + +implement { + name = "grph_nodes_register", + arguments = { "string", "integer" }, + actions = function(s,r) + if not tonumber(s) then + if trace then + report("register %i as %a",t,s) + end + references[s] = r + end + end +} +implement { + name = "grph_nodes_resolve", + arguments = "string", + actions = function(s) + local r = references[s] + if r then + if trace then + report("resolve %a to %i",s,r) + end + context(r) + return + end + local n = lpegmatch(pattern,s) + if s ~= n then + if trace then + report("resolve '%s' to %s",s,n) + end + context(n) + return + end + context(s) + end } diff --git a/tex/context/base/mkiv/meta-nod.mkiv b/tex/context/base/mkiv/meta-nod.mkiv index bf36e315c..9f966349c 100644 --- a/tex/context/base/mkiv/meta-nod.mkiv +++ b/tex/context/base/mkiv/meta-nod.mkiv @@ -110,6 +110,8 @@ %D Hm, we started out simple but it now quickly becomes the usual mess of %D \TEX, \METAPOST\ and \LUA. Hard to understand. +\newcount\c_meta_nodes_n + \unexpanded\def\startnodes {\dosingleempty\meta_nodes_start} @@ -121,11 +123,12 @@ \edef\p_meta_option{\metanodesparameter\c!option}% \edef\p_meta_alternative{\metanodesparameter\c!alternative}% \the\t_every_meta_nodes + \c_meta_nodes_n\zerocount \t_meta_nodes\emptytoks #2\removeunwantedspaces % for alan, will be commented: \writestatus{metanodes}{\detokenize\expandafter{\the\t_meta_nodes}}% - \ctxlua{metapost.nodes.initialize()}% + \clf_grph_nodes_initialize \startMPcode mfun_node_init(% \the\dimexpr\metanodesparameter\c!dx\relax,% @@ -135,7 +138,7 @@ \the\t_meta_nodes ; mfun_node_flush ; \stopMPcode - \ctxlua{metapost.nodes.reset()}% + \clf_grph_nodes_reset \egroup} \unexpanded\def\grph_nodes_node @@ -149,10 +152,10 @@ \ifsecondargument \setupcurrentmetanodes[#3]% \fi - \edef\p_label {#4}% + \edef\p_label{#4}% \edef\p_reference{\metanodesparameter\c!reference}% \ifx\p_reference\empty\else - \ctxlua{metapost.nodes.register("\p_reference",\number#1)}% + \clf_grph_nodes_register{\p_reference}\c_meta_nodes_n\relax \fi \normalexpanded{\endgroup\noexpand\etoksapp\t_meta_nodes{% mfun_node_make(\number#1,\number#2% @@ -162,7 +165,8 @@ ,"\metanodesparameter\c!command{\p_label}"% \fi );% - }}} + }}% + \advance\c_meta_nodes_n\plusone} \appendtoks \let\placenode\grph_nodes_node @@ -210,7 +214,7 @@ mfun_nodes_fromto\begincsname\??metanodesposition\metanodesparameter\c!position\endcsname(% \metanodesparameter\c!offset,% % \number#1,\number#2% - \ctxlua{metapost.nodes.resolve("#1")},\ctxlua{metapost.nodes.resolve("#2")}% + \clf_grph_nodes_resolve{#1},\clf_grph_nodes_resolve{#2}% \ifx\p_label\empty ,""% \else diff --git a/tex/context/base/mkiv/mlib-lua.lua b/tex/context/base/mkiv/mlib-lua.lua index 5d0ab1ab6..785d3c947 100644 --- a/tex/context/base/mkiv/mlib-lua.lua +++ b/tex/context/base/mkiv/mlib-lua.lua @@ -28,121 +28,16 @@ local trace_enabled = true local be_tolerant = true directives.register("metapost.lua.tolerant", function(v) be_tolerant = v end) -mp = mp or { } -- system namespace -MP = MP or { } -- user namespace +local get, set, aux = { }, { }, { } -local buffer = { } -local n = 0 -local max = 20 -- we reuse upto max -local nesting = 0 - -function mp._f_() - if trace_enabled and trace_luarun then - local result = concat(buffer," ",1,n) - if n > max then - buffer = { } - end - n = 0 - report_luarun("%i: data: %s",nesting,result) - return result - else - if n == 0 then - return "" - end - local result - if n == 1 then - result = buffer[1] - else - result = concat(buffer," ",1,n) - end - if n > max then - buffer = { } - end - n = 0 - return result - end -end - -local f_code = formatters["%s return mp._f_()"] - -local f_integer = formatters["%i"] - --- local f_numeric = formatters["%.16f"] --- local f_pair = formatters["(%.16f,%.16f)"] --- local f_triplet = formatters["(%.16f,%.16f,%.16f)"] --- local f_quadruple = formatters["(%.16f,%.16f,%.16f,%.16f)"] - -local f_numeric = formatters["%n"] -local f_pair = formatters["(%n,%n)"] -local f_ctrl = formatters["(%n,%n) .. controls (%n,%n) and (%n,%n)"] -local f_triplet = formatters["(%n,%n,%n)"] -local f_quadruple = formatters["(%n,%n,%n,%n)"] - -local f_points = formatters["%p"] -local f_pair_pt = formatters["(%p,%p)"] -local f_ctrl_pt = formatters["(%p,%p) .. controls (%p,%p) and (%p,%p)"] -local f_triplet_pt = formatters["(%p,%p,%p)"] -local f_quadruple_pt = formatters["(%p,%p,%p,%p)"] - -local function mpprint(...) -- we can optimize for n=1 - for i=1,select("#",...) do - local value = select(i,...) - if value ~= nil then - n = n + 1 - local t = type(value) - if t == "number" then - buffer[n] = f_numeric(value) - elseif t == "string" then - buffer[n] = value - elseif t == "table" then - buffer[n] = "(" .. concat(value,",") .. ")" - else -- boolean or whatever - buffer[n] = tostring(value) - end - end - end -end - -local r = P('%') / "percent" - + P('"') / "dquote" - + P('\n') / "crlf" - -- + P(' ') / "space" -local a = Cc("&") -local q = Cc('"') -local p = Cs(q * (r * a)^-1 * (a * r * (P(-1) + a) + P(1))^0 * q) - -local function mpvprint(...) -- variable print - for i=1,select("#",...) do - local value = select(i,...) - if value ~= nil then - n = n + 1 - local t = type(value) - if t == "number" then - buffer[n] = f_numeric(value) - elseif t == "string" then - buffer[n] = lpegmatch(p,value) - elseif t == "table" then - local m = #t - if m == 2 then - buffer[n] = f_pair(unpack(t)) - elseif m == 3 then - buffer[n] = f_triplet(unpack(t)) - elseif m == 4 then - buffer[n] = f_quadruple(unpack(t)) - else -- error - buffer[n] = "" - end - else -- boolean or whatever - buffer[n] = tostring(value) - end - end - end -end - -mp.cleaned = function(s) return lpegmatch(p,s) or s end +mp = mp or { -- system namespace + set = set, + get = get, + aux = aux, +} -mp.print = mpprint -mp.vprint = mpvprint +MP = MP or { -- user namespace +} -- We had this: -- @@ -157,238 +52,486 @@ mp.vprint = mpvprint -- lua.mp("somedefdname","foo") table.setmetatablecall(mp,function(t,k,...) return t[k](...) end) +table.setmetatablecall(MP,function(t,k,...) return t[k](...) end) -function mp.boolean(b) - n = n + 1 - buffer[n] = b and "true" or "false" -end - -function mp.numeric(f) - n = n + 1 - buffer[n] = f and f_numeric(f) or "0" -end +do -function mp.integer(i) - n = n + 1 - -- buffer[n] = i and f_integer(i) or "0" - buffer[n] = i or "0" -end + local currentmpx = nil + local stack = { } -function mp.points(i) - n = n + 1 - buffer[n] = i and f_points(i) or "0pt" -end + local get_numeric = mplib.get_numeric + local get_string = mplib.get_string + local get_boolean = mplib.get_boolean + local get_path = mplib.get_path + local set_path = mplib.set_path -function mp.pair(x,y) - n = n + 1 - if type(x) == "table" then - buffer[n] = f_pair(x[1],x[2]) - else - buffer[n] = f_pair(x,y) - end -end + get.numeric = function(s) return get_numeric(currentmpx,s) end + get.string = function(s) return get_string (currentmpx,s) end + get.boolean = function(s) return get_boolean(currentmpx,s) end + get.path = function(s) return get_path (currentmpx,s) end + get.number = function(s) return get_numeric(currentmpx,s) end -function mp.pairpoints(x,y) - n = n + 1 - if type(x) == "table" then - buffer[n] = f_pair_pt(x[1],x[2]) - else - buffer[n] = f_pair_pt(x,y) - end -end + set.path = function(s,t) return set_path(currentmpx,s,t) end -- not working yet -function mp.triplet(x,y,z) - n = n + 1 - if type(x) == "table" then - buffer[n] = f_triplet(x[1],x[2],x[3]) - else - buffer[n] = f_triplet(x,y,z) + function metapost.pushscriptrunner(mpx) + insert(stack,mpx) + currentmpx = mpx end -end -function mp.tripletpoints(x,y,z) - n = n + 1 - if type(x) == "table" then - buffer[n] = f_triplet_pt(x[1],x[2],x[3]) - else - buffer[n] = f_triplet_pt(x,y,z) + function metapost.popscriptrunner() + currentmpx = remove(stack,mpx) end -end -function mp.quadruple(w,x,y,z) - n = n + 1 - if type(w) == "table" then - buffer[n] = f_quadruple(w[1],w[2],w[3],w[4]) - else - buffer[n] = f_quadruple(w,x,y,z) - end end -function mp.quadruplepoints(w,x,y,z) - n = n + 1 - if type(w) == "table" then - buffer[n] = f_quadruple_pt(w[1],w[2],w[3],w[4]) - else - buffer[n] = f_quadruple_pt(w,x,y,z) - end -end +do -local function mppath(f2,f6,t,connector,cycle) - if type(t) == "table" then - local tn = #t - if tn > 0 then - if connector == true then - connector = "--" - cycle = true - elseif not connector then - connector = "--" + local buffer = { } + local n = 0 + local max = 20 -- we reuse upto max + local nesting = 0 + local runs = 0 + + local function _f_() + if trace_enabled and trace_luarun then + local result = concat(buffer," ",1,n) + if n > max then + buffer = { } end - local ti = t[1] - n = n + 1 ; - if #ti == 6 then - local tn = t[2] or t[1] - buffer[n] = f6(ti[1],ti[2],ti[5],ti[6],tn[3],tn[4]) + n = 0 + report_luarun("%i: data: %s",nesting,result) + return result + else + if n == 0 then + return "" + end + local result + if n == 1 then + result = buffer[1] else - buffer[n] = f2(ti[1],ti[2]) + result = concat(buffer," ",1,n) end - for i=2,tn do - local ti = t[i] - n = n + 1 ; buffer[n] = connector - n = n + 1 ; - if #ti == 6 and (i < tn or cycle) then - local tn = t[i+1] or t[1] - buffer[n] = f6(ti[1],ti[2],ti[5],ti[6],tn[3],tn[4]) - else - buffer[n] = f2(ti[1],ti[2]) + if n > max then + buffer = { } + end + n = 0 + return result + end + end + + mp._f_ = _f_ -- convenient to have it in a top module + aux.flush = _f_ + + local f_code = formatters["%s return mp._f_()"] + + local f_integer = formatters["%i"] + -- local f_numeric = formatters["%.16f"] + -- local f_pair = formatters["(%.16f,%.16f)"] + -- local f_triplet = formatters["(%.16f,%.16f,%.16f)"] + -- local f_quadruple = formatters["(%.16f,%.16f,%.16f,%.16f)"] + + -- %N + + local f_numeric = formatters["%n"] + local f_pair = formatters["(%n,%n)"] + local f_ctrl = formatters["(%n,%n) .. controls (%n,%n) and (%n,%n)"] + local f_triplet = formatters["(%n,%n,%n)"] + local f_quadruple = formatters["(%n,%n,%n,%n)"] + + local f_points = formatters["%p"] + local f_pair_pt = formatters["(%p,%p)"] + local f_ctrl_pt = formatters["(%p,%p) .. controls (%p,%p) and (%p,%p)"] + local f_triplet_pt = formatters["(%p,%p,%p)"] + local f_quadruple_pt = formatters["(%p,%p,%p,%p)"] + + local r = P('%') / "percent" + + P('"') / "dquote" + + P('\n') / "crlf" + -- + P(' ') / "space" + local a = Cc("&") + local q = Cc('"') + local p = Cs(q * (r * a)^-1 * (a * r * (P(-1) + a) + P(1))^0 * q) + + mp.cleaned = function(s) return lpegmatch(p,s) or s end + + local function mpprint(...) -- we can optimize for n=1 + for i=1,select("#",...) do + local value = select(i,...) + if value ~= nil then + n = n + 1 + local t = type(value) + if t == "number" then + buffer[n] = f_numeric(value) + elseif t == "string" then + buffer[n] = value + elseif t == "table" then + buffer[n] = "(" .. concat(value,",") .. ")" + else -- boolean or whatever + buffer[n] = tostring(value) end end - if cycle then - n = n + 1 ; buffer[n] = connector - n = n + 1 ; buffer[n] = "cycle" + end + end + + local function mpvprint(...) -- variable print + for i=1,select("#",...) do + local value = select(i,...) + if value ~= nil then + n = n + 1 + local t = type(value) + if t == "number" then + buffer[n] = f_numeric(value) + elseif t == "string" then + buffer[n] = lpegmatch(p,value) + elseif t == "table" then + local m = #t + if m == 2 then + buffer[n] = f_pair(unpack(t)) + elseif m == 3 then + buffer[n] = f_triplet(unpack(t)) + elseif m == 4 then + buffer[n] = f_quadruple(unpack(t)) + else -- error + buffer[n] = "" + end + else -- boolean or whatever + buffer[n] = tostring(value) + end end end end -end -function mp.path(...) - mppath(f_pair,f_ctrl,...) -end + local function mpboolean(b) + n = n + 1 + buffer[n] = b and "true" or "false" + end -function mp.pathpoints(...) - mppath(f_pair_pt,f_ctrl_pt,...) -end + local function mpnumeric(f) + n = n + 1 + buffer[n] = f and f_numeric(f) or "0" + end + local function mpinteger(i) + n = n + 1 + -- buffer[n] = i and f_integer(i) or "0" + buffer[n] = i or "0" + end -function mp.pathpoints(t,connector,cycle) - if type(t) == "table" then - local tn = #t - if tn > 0 then - if connector == true then - connector = "--" - cycle = true - elseif not connector then - connector = "--" - end - local ti = t[1] - n = n + 1 ; - if #ti == 6 then - buffer[n] = f_pair_pt_ctrl(ti[1],ti[2],ti[3],ti[4],ti[5],ti[6]) - else - buffer[n] = f_pair_pt(ti[1],ti[2]) - end - for i=2,tn do - local ti = t[i] - n = n + 1 ; buffer[n] = connector + local function mppoints(i) + n = n + 1 + buffer[n] = i and f_points(i) or "0pt" + end + + local function mppair(x,y) + n = n + 1 + if type(x) == "table" then + buffer[n] = f_pair(x[1],x[2]) + else + buffer[n] = f_pair(x,y) + end + end + + local function mppairpoints(x,y) + n = n + 1 + if type(x) == "table" then + buffer[n] = f_pair_pt(x[1],x[2]) + else + buffer[n] = f_pair_pt(x,y) + end + end + + local function mptriplet(x,y,z) + n = n + 1 + if type(x) == "table" then + buffer[n] = f_triplet(x[1],x[2],x[3]) + else + buffer[n] = f_triplet(x,y,z) + end + end + + local function mptripletpoints(x,y,z) + n = n + 1 + if type(x) == "table" then + buffer[n] = f_triplet_pt(x[1],x[2],x[3]) + else + buffer[n] = f_triplet_pt(x,y,z) + end + end + + local function mpquadruple(w,x,y,z) + n = n + 1 + if type(w) == "table" then + buffer[n] = f_quadruple(w[1],w[2],w[3],w[4]) + else + buffer[n] = f_quadruple(w,x,y,z) + end + end + + local function mpquadruplepoints(w,x,y,z) + n = n + 1 + if type(w) == "table" then + buffer[n] = f_quadruple_pt(w[1],w[2],w[3],w[4]) + else + buffer[n] = f_quadruple_pt(w,x,y,z) + end + end + + -- local function mp_path(f2,f6,t,connector,cycle) + -- if type(t) == "table" then + -- local tn = #t + -- if tn > 0 then + -- if connector == true then + -- connector = "--" + -- cycle = true + -- elseif not connector then + -- connector = "--" + -- end + -- local ti = t[1] + -- n = n + 1 ; + -- if #ti == 6 then + -- local tn = t[2] or t[1] + -- buffer[n] = f6(ti[1],ti[2],ti[5],ti[6],tn[3],tn[4]) + -- else + -- buffer[n] = f2(ti[1],ti[2]) + -- end + -- for i=2,tn do + -- local ti = t[i] + -- n = n + 1 ; buffer[n] = connector + -- n = n + 1 ; + -- if #ti == 6 and (i < tn or cycle) then + -- local tn = t[i+1] or t[1] + -- buffer[n] = f6(ti[1],ti[2],ti[5],ti[6],tn[3],tn[4]) + -- else + -- buffer[n] = f2(ti[1],ti[2]) + -- end + -- end + -- if cycle then + -- n = n + 1 ; buffer[n] = connector + -- n = n + 1 ; buffer[n] = "cycle" + -- end + -- end + -- end + -- end + + local function mp_path(f2,f6,t,connector,cycle) + if type(t) == "table" then + local tn = #t + if tn > 0 then + if connector == true then + connector = "--" + cycle = true + elseif not connector then + connector = "--" + end + local ti = t[1] n = n + 1 ; if #ti == 6 then - buffer[n] = f_pair_pt_ctrl(ti[1],ti[2],ti[3],ti[4],ti[5],ti[6]) + buffer[n] = f6(ti[1],ti[2],ti[3],ti[4],ti[5],ti[6]) else - buffer[n] = f_pair_pt(ti[1],ti[2]) + buffer[n] = f2(ti[1],ti[2]) + end + for i=2,tn do + local ti = t[i] + n = n + 1 ; buffer[n] = connector + n = n + 1 ; + if #ti == 6 then + buffer[n] = f6(ti[1],ti[2],ti[3],ti[4],ti[5],ti[6]) + else + buffer[n] = f2(ti[1],ti[2]) + end + end + if cycle then + n = n + 1 ; buffer[n] = connector + n = n + 1 ; buffer[n] = "cycle" end - end - if cycle then - n = n + 1 ; buffer[n] = connector - n = n + 1 ; buffer[n] = "cycle" end end end -end -function mp.size(t) - n = n + 1 - buffer[n] = type(t) == "table" and f_numeric(#t) or "0" -end + local function mppath(...) + mp_path(f_pair,f_pair_ctrl,...) + end -local mpnamedcolor = attributes.colors.mpnamedcolor + local function mppathpoints(...) + mp_path(f_pair_pt,f_pair_pt_ctrl,...) + end -mp.NamedColor = function(str) - mpprint(mpnamedcolor(str)) -end + local function mpsize(t) + n = n + 1 + buffer[n] = type(t) == "table" and f_numeric(#t) or "0" + end --- experiment: names can change + local replacer = lpeg.replacer("@","%%") + + local function mpfprint(fmt,...) + n = n + 1 + if not find(fmt,"%",1,true) then + fmt = lpegmatch(replacer,fmt) + end + buffer[n] = formatters[fmt](...) + end -local datasets = { } -mp.datasets = datasets + local function mpquoted(fmt,s,...) + n = n + 1 + if s then + if not find(fmt,"%",1,true) then + fmt = lpegmatch(replacer,fmt) + end + -- buffer[n] = '"' .. formatters[fmt](s,...) .. '"' + buffer[n] = lpegmatch(p,formatters[fmt](s,...)) + elseif fmt then + -- buffer[n] = '"' .. fmt .. '"' + buffer[n] = lpegmatch(p,fmt) + else + -- something is wrong + end + end -function datasets.load(tag,filename) - if not filename then - tag, filename = file.basename(tag), tag + aux.print = mpprint + aux.vprint = mpvprint + aux.boolean = mpboolean + aux.numeric = mpnumeric + aux.number = mpnumeric + aux.integer = mpinteger + aux.points = mppoints + aux.pair = mppair + aux.pairpoints = mppairpoints + aux.triplet = mptriplet + aux.tripletpoints = mptripletpoints + aux.quadruple = mpquadruple + aux.quadruplepoints = mpquadruplepoints + aux.path = mppath + aux.pathpoints = mppathpoints + aux.size = mpsize + aux.fprint = mpfprint + aux.quoted = mpquoted + + -- we need access to the variables + + function metapost.nofscriptruns() + return runs + end + + -- there is no gain in: + -- + -- local cache = table.makeweak() + -- + -- f = cache[code] + -- if not f then + -- f = loadstring(f_code(code)) + -- if f then + -- cache[code] = f + -- elseif be_tolerant then + -- f = loadstring(code) + -- if f then + -- cache[code] = f + -- end + -- end + -- end + + function metapost.runscript(code) + nesting = nesting + 1 + local trace = trace_enabled and trace_luarun + if trace then + report_luarun("%i: code: %s",nesting,code) + end + runs = runs + 1 + local f = loadstring(f_code(code)) + if not f and be_tolerant then + f = loadstring(code) + end + if f then + local _buffer_, _n_ = buffer, n + buffer, n = { }, 0 + local result = f() + if result then + local t = type(result) + if t == "number" then + result = f_numeric(result) + elseif t ~= "string" then + result = tostring(result) + end + if trace then + if #result == 0 then + report_luarun("%i: no result",nesting) +-- print(debug.traceback()) + else + report_luarun("%i: result: %s",nesting,result) + end + end + buffer, n = _buffer_, _n_ + nesting = nesting - 1 + return result + elseif trace then + report_luarun("%i: no result",nesting) +-- print(debug.traceback()) + end + buffer, n = _buffer_, _n_ + else + report_luarun("%i: no result, invalid code: %s",nesting,code) + end + nesting = nesting - 1 + return "" end - local data = mp.dataset(io.loaddata(filename) or "") - datasets[tag] = { - Data = data, - Line = function(n) mp.path(data[n or 1]) end, - Size = function() mp.size(data) end, - } -end --- + -- for the moment -local replacer = lpeg.replacer("@","%%") + for k, v in next, aux do mp[k] = v end -function mp.fprint(fmt,...) - n = n + 1 - if not find(fmt,"%",1,true) then - fmt = lpegmatch(replacer,fmt) - end - buffer[n] = formatters[fmt](...) end -local function mpquoted(fmt,s,...) - n = n + 1 - if s then - if not find(fmt,"%",1,true) then - fmt = lpegmatch(replacer,fmt) - end - -- buffer[n] = '"' .. formatters[fmt](s,...) .. '"' - buffer[n] = lpegmatch(p,formatters[fmt](s,...)) - elseif fmt then - -- buffer[n] = '"' .. fmt .. '"' - buffer[n] = lpegmatch(p,fmt) - else - -- something is wrong +do + + local mpnamedcolor = attributes.colors.mpnamedcolor + local mpprint = aux.print + + mp.mf_named_color = function(str) + mpprint(mpnamedcolor(str)) end -end -mp.quoted = mpquoted +end -function mp.n(t) +function mp.n(t) -- used ? return type(t) == "table" and #t or 0 end -local whitespace = lpegpatterns.whitespace -local newline = lpegpatterns.newline -local setsep = newline^2 -local comment = (S("#%") + P("--")) * (1-newline)^0 * (whitespace - setsep)^0 -local value = (1-whitespace)^1 / tonumber -local entry = Ct( value * whitespace * value) -local set = Ct((entry * (whitespace-setsep)^0 * comment^0)^1) -local series = Ct((set * whitespace^0)^1) +do + + -- experiment: names can change + + local mppath = aux.mppath + local mpsize = aux.mpsize -local pattern = whitespace^0 * series + local whitespace = lpegpatterns.whitespace + local newline = lpegpatterns.newline + local setsep = newline^2 + local comment = (S("#%") + P("--")) * (1-newline)^0 * (whitespace - setsep)^0 + local value = (1-whitespace)^1 / tonumber + local entry = Ct( value * whitespace * value) + local set = Ct((entry * (whitespace-setsep)^0 * comment^0)^1) + local series = Ct((set * whitespace^0)^1) + + local pattern = whitespace^0 * series + + local datasets = { } + mp.datasets = datasets + + function mp.dataset(str) + return lpegmatch(pattern,str) + end + + function datasets.load(tag,filename) + if not filename then + tag, filename = file.basename(tag), tag + end + local data = lpegmatch(pattern,io.loaddata(filename) or "") + datasets[tag] = { + Data = data, + Line = function(n) mppath(data[n or 1]) end, + Size = function() mpsize(data) end, + } + end -function mp.dataset(str) - return lpegmatch(pattern,str) end -- \startluacode @@ -420,269 +563,183 @@ end -- endfor ; -- \stopMPpage -local runs = 0 - -function metapost.nofscriptruns() - return runs -end - --- there is no gain in: --- --- local cache = table.makeweak() --- --- f = cache[code] --- if not f then --- f = loadstring(f_code(code)) --- if f then --- cache[code] = f --- elseif be_tolerant then --- f = loadstring(code) --- if f then --- cache[code] = f --- end --- end --- end - -function metapost.runscript(code) - nesting = nesting + 1 - local trace = trace_enabled and trace_luarun - if trace then - report_luarun("%i: code: %s",nesting,code) - end - runs = runs + 1 - local f = loadstring(f_code(code)) - if not f and be_tolerant then - f = loadstring(code) - end - if f then - local _buffer_, _n_ = buffer, n - buffer, n = { }, 0 - local result = f() - if result then - local t = type(result) - if t == "number" then - result = f_numeric(result) - elseif t ~= "string" then - result = tostring(result) - end - if trace then - if #result == 0 then - report_luarun("%i: no result",nesting) - else - report_luarun("%i: result: %s",nesting,result) - end - end - buffer, n = _buffer_, _n_ - nesting = nesting - 1 - return result - elseif trace then - report_luarun("%i: no result",nesting) - end - buffer, n = _buffer_, _n_ - else - report_luarun("%i: no result, invalid code: %s",nesting,code) - end - nesting = nesting - 1 - return "" -end +-- texts: do - local get_numeric = mplib.get_numeric - local get_string = mplib.get_string - local get_boolean = mplib.get_boolean - local get_path = mplib.get_path - local get_number = get_numeric + local mptriplet = mp.triplet - local set_path = mplib.set_path + local bpfactor = number.dimenfactors.bp + local textexts = nil + local mptriplet = mp.triplet + local nbdimensions = nodes.boxes.dimensions - local currentmpx = nil - local stack = { } - local getters = { } - local setters = { } - - getters.numeric = function(s) return get_numeric(currentmpx,s) end - getters.string = function(s) return get_string (currentmpx,s) end - getters.boolean = function(s) return get_boolean(currentmpx,s) end - getters.path = function(s) return get_path (currentmpx,s) end - getters.number = mp.numeric - - setters.path = function(s,t) return set_path(currentmpx,s,t) end + function mp.mf_tt_initialize(tt) + textexts = tt + end - function metapost.pushscriptrunner(mpx) - insert(stack,mpx) - currentmpx = mpx + function mp.mf_tt_dimensions(n) + local box = textexts and textexts[n] + if box then + -- could be made faster with nuts but not critical + mptriplet(box.width*bpfactor,box.height*bpfactor,box.depth*bpfactor) + else + mptriplet(0,0,0) + end end - function metapost.popscriptrunner() - currentmpx = remove(stack,mpx) + function mp.mf_tb_dimensions(category,name) + local w, h, d = nbdimensions(category,name) + mptriplet(w*bpfactor,h*bpfactor,d*bpfactor) end - mp.get = getters - mp.set = setters + function mp.report(a,b) + if b then + report_message("%s : %s",a,b) + elseif a then + report_message("%s : %s","message",a) + end + end end --- texts: +do -local factor = 65536*(7227/7200) -local textexts = nil -local mptriplet = mp.triplet -local nbdimensions = nodes.boxes.dimensions + local mpprint = aux.print + local mpvprint = aux.vprint -function mp.tt_initialize(tt) - textexts = tt -end + local hashes = { } --- function mp.tt_wd(n) --- local box = textexts and textexts[n] --- mpprint(box and box.width/factor or 0) --- end --- function mp.tt_ht(n) --- local box = textexts and textexts[n] --- mpprint(box and box.height/factor or 0) --- end --- function mp.tt_dp(n) --- local box = textexts and textexts[n] --- mpprint(box and box.depth/factor or 0) --- end - -function mp.tt_dimensions(n) - local box = textexts and textexts[n] - if box then - -- could be made faster with nuts but not critical - mptriplet(box.width/factor,box.height/factor,box.depth/factor) - else - mptriplet(0,0,0) + function mp.newhash() + for i=1,#hashes+1 do + if not hashes[i] then + hashes[i] = { } + mpvprint(i) + return + end + end end -end -function mp.tb_dimensions(category,name) - local w, h, d = nbdimensions(category,name) - mptriplet(w/factor,h/factor,d/factor) -end - -function mp.report(a,b) - if b then - report_message("%s : %s",a,b) - elseif a then - report_message("%s : %s","message",a) + function mp.disposehash(n) + hashes[n] = nil end -end - --- -local hashes = { } + function mp.inhash(n,key) + local h = hashes[n] + mpprint(h and h[key] and true or false) + end -function mp.newhash() - for i=1,#hashes+1 do - if not hashes[i] then - hashes[i] = { } - mpprint(i) - return + function mp.tohash(n,key) + local h = hashes[n] + if h then + h[key] = true end end -end -function mp.disposehash(n) - hashes[n] = nil end -function mp.inhash(n,key) - local h = hashes[n] - mpprint(h and h[key] and true or false) -end +do + + local mpprint = aux.print + local modes = tex.modes + local systemmodes = tex.systemmodes -function mp.tohash(n,key) - local h = hashes[n] - if h then - h[key] = true + function mp.mode(s) + mpprint(modes[s] and true or false) end -end -local modes = tex.modes -local systemmodes = tex.systemmodes + function mp.systemmode(s) + mpprint(systemmodes[s] and true or false) + end -function mp.mode(s) - mpprint(modes[s] and true or false) -end + mp.processingmode = mp.mode -function mp.systemmode(s) - mpprint(systemmodes[s] and true or false) end -- for alan's nodes: -function mp.isarray(str) - mpprint(find(str,"%d") and true or false) -end +do -function mp.prefix(str) - mpquoted(match(str,"^(.-)[%d%[]") or str) -end + local mpprint = aux.print + local mpquoted = aux.quoted + + function mp.isarray(str) + mpprint(find(str,"%d") and true or false) + end --- function mp.dimension(str) --- local n = 0 --- for s in gmatch(str,"%[?%-?%d+%]?") do --todo: lpeg --- n = n + 1 --- end --- mpprint(n) --- end + function mp.prefix(str) + mpquoted(match(str,"^(.-)[%d%[]") or str) + end -mp.dimension = lpeg.counter(P("[") * lpegpatterns.integer * P("]") + lpegpatterns.integer,mpprint) + -- function mp.dimension(str) + -- local n = 0 + -- for s in gmatch(str,"%[?%-?%d+%]?") do --todo: lpeg + -- n = n + 1 + -- end + -- mpprint(n) + -- end --- faster and okay as we don't have many variables but probably only --- basename makes sense and even then it's not called that often + mp.dimension = lpeg.counter(P("[") * lpegpatterns.integer * P("]") + lpegpatterns.integer,mpprint) --- local hash = table.setmetatableindex(function(t,k) --- local v = find(k,"%d") and true or false --- t[k] = v --- return v --- end) --- --- function mp.isarray(str) --- mpprint(hash[str]) --- end --- --- local hash = table.setmetatableindex(function(t,k) --- local v = '"' .. (match(k,"^(.-)%d") or k) .. '"' --- t[k] = v --- return v --- end) --- --- function mp.prefix(str) --- mpprint(hash[str]) --- end + -- faster and okay as we don't have many variables but probably only + -- basename makes sense and even then it's not called that often + + -- local hash = table.setmetatableindex(function(t,k) + -- local v = find(k,"%d") and true or false + -- t[k] = v + -- return v + -- end) + -- + -- function mp.isarray(str) + -- mpprint(hash[str]) + -- end + -- + -- local hash = table.setmetatableindex(function(t,k) + -- local v = '"' .. (match(k,"^(.-)%d") or k) .. '"' + -- t[k] = v + -- return v + -- end) + -- + -- function mp.prefix(str) + -- mpprint(hash[str]) + -- end + +end -local getdimen = tex.getdimen -local getcount = tex.getcount -local gettoks = tex.gettoks -local setdimen = tex.setdimen -local setcount = tex.setcount -local settoks = tex.settoks +do + + local getdimen = tex.getdimen + local getcount = tex.getcount + local gettoks = tex.gettoks + local setdimen = tex.setdimen + local setcount = tex.setcount + local settoks = tex.settoks -local mpprint = mp.print -local mpquoted = mp.quoted + local mpprint = mp.print + local mpquoted = mp.quoted -local factor = number.dimenfactors.bp + local bpfactor = number.dimenfactors.bp --- more helpers + -- more helpers -function mp.getdimen(k) mpprint (getdimen(k)*factor) end -function mp.getcount(k) mpprint (getcount(k)) end -function mp.gettoks (k) mpquoted(gettoks (k)) end -function mp.setdimen(k,v) setdimen(k,v/factor) end -function mp.setcount(k,v) setcount(k,v) end -function mp.settoks (k,v) settoks (k,v) end + function mp.getdimen(k) mpprint (getdimen(k)*bpfactor) end + function mp.getcount(k) mpprint (getcount(k)) end + function mp.gettoks (k) mpquoted(gettoks (k)) end --- def foo = lua.mp.foo ... enddef ; % loops due to foo in suffix + function mp.setdimen(k,v) setdimen(k,v/factor) end + function mp.setcount(k,v) setcount(k,v) end + function mp.settoks (k,v) settoks (k,v) end -mp._get_dimen_ = mp.getdimen -mp._get_count_ = mp.getcount -mp._get_toks_ = mp.gettoks -mp._set_dimen_ = mp.setdimen -mp._set_count_ = mp.setcount -mp._set_toks_ = mp.settoks + -- def foo = lua.mp.foo ... enddef ; % loops due to foo in suffix + + mp._get_dimen_ = mp.getdimen + mp._get_count_ = mp.getcount + mp._get_toks_ = mp.gettoks + mp._set_dimen_ = mp.setdimen + mp._set_count_ = mp.setcount + mp._set_toks_ = mp.settoks + +end -- position fun @@ -796,7 +853,7 @@ do local mpvprint = mp.vprint - local stores = { } + local stores = { } function mp.newstore(name) stores[name] = { } @@ -826,59 +883,50 @@ end do - local mpprint = mp.print - local texmodes = tex.modes - - function mp.processingmode(s) - mpprint(tostring(texmodes[s])) - end - -end - -do - -- a bit overkill: just a find(str,"mf_object=") can be enough - local p1 = P("mf_object=") - local p2 = lpeg.patterns.eol * p1 - local pattern = (1-p2)^0 * p2 + p1 + local mpboolean = aux.boolean + + local p1 = P("mf_object=") + local p2 = lpegpatterns.eol * p1 + local pattern = (1-p2)^0 * p2 + p1 function mp.isobject(str) - mp.boolean(pattern and str ~= "" and lpegmatch(p,str)) + mpboolean(pattern and str ~= "" and lpegmatch(p,str)) end end do - local mpnumeric = mp.numeric - local mppair = mp.pair - local mpgetpath = mp.get.path + local mpnumeric = aux.numeric + local mppair = aux.pair + local mpgetpath = get.path local p = nil local n = 0 - function mp.mfun_path_length(name) - p = mp.get.path(name) + local function mf_path_length(name) + p = mpgetpath(name) n = p and #p or 0 mpnumeric(n) end - function mp.mfun_path_point(i) + local function mf_path_point(i) if i > 0 and i <= n then local pi = p[i] mppair(pi[1],pi[2]) end end - function mp.mfun_path_left(i) + local function mf_path_left(i) if i > 0 and i <= n then local pi = p[i] mppair(pi[5],pi[6]) end end - function mp.mfun_path_right(i) + local function mf_path_right(i) if i > 0 and i <= n then local pn if i == 1 then @@ -890,9 +938,15 @@ do end end - function mp.mfun_path_reset() + local function mf_path_reset() p = nil n = 0 end + mp.mf_path_length = mf_path_length mp.pathlength = mf_path_length + mp.mf_path_point = mf_path_point mp.pathpoint = mf_path_point + mp.mf_path_left = mf_path_left mp.pathleft = mf_path_left + mp.mf_path_right = mf_path_right mp.pathright = mf_path_right + mp.mf_path_reset = mf_path_reset mp.pathreset = mf_path_reset + end diff --git a/tex/context/base/mkiv/mlib-pps.lua b/tex/context/base/mkiv/mlib-pps.lua index 237efe901..39b80e344 100644 --- a/tex/context/base/mkiv/mlib-pps.lua +++ b/tex/context/base/mkiv/mlib-pps.lua @@ -101,16 +101,18 @@ local f_f3 = formatters["%.3F"] local f_gray = formatters["%.3F g %.3F G"] local f_rgb = formatters["%.3F %.3F %.3F rg %.3F %.3F %.3F RG"] local f_cmyk = formatters["%.3F %.3F %.3F %.3F k %.3F %.3F %.3F %.3F K"] -local f_cm = formatters["q %F %F %F %F %F %F cm"] +local f_cm_b = formatters["q %F %F %F %F %F %F cm"] local f_shade = formatters["MpSh%s"] +local s_cm_e = "Q" + directives.register("metapost.stripzeros",function() f_f = formatters["%N"] f_f3 = formatters["%.3N"] f_gray = formatters["%.3N g %.3N G"] f_rgb = formatters["%.3N %.3N %.3N rg %.3N %.3N %.3N RG"] f_cmyk = formatters["%.3N %.3N %.3N %.3N k %.3N %.3N %.3N %.3N K"] - f_cm = formatters["q %N %N %N %N %N %N cm"] + f_cm_b = formatters["q %N %N %N %N %N %N cm"] f_shade = formatters["MpSh%s"] end) @@ -606,7 +608,7 @@ function metapost.preparetextextsdata() end end end - mp.tt_initialize(collected) + mp.mf_tt_initialize(collected) end metapost.intermediate = metapost.intermediate or { } @@ -989,7 +991,7 @@ local function cm(object) if op then local first, second, fourth = op[1], op[2], op[4] if fourth then - local tx, ty = first.x_coord , first.y_coord + local tx, ty = first.x_coord, first.y_coord local sx, sy = second.x_coord - tx, fourth.y_coord - ty local rx, ry = second.y_coord - ty, fourth.x_coord - tx if sx == 0 then sx = 0.00001 end @@ -1095,7 +1097,7 @@ local tx_reset, tx_analyze, tx_process do end end - function mp.SomeText(index,str) + function mp.mf_some_text(index,str) mp_target = index mp_index = index mp_c = nil @@ -1111,8 +1113,8 @@ local tx_reset, tx_analyze, tx_process do local madetext = nil - function mp.MadeText(index) - mp.SomeText(index,madetext) + function mp.mf_made_text(index) + mp.mf_some_text(index,madetext) end function metapost.maketext(s,mode) @@ -1129,7 +1131,7 @@ local tx_reset, tx_analyze, tx_process do end end - function mp.SomeFormattedText(index,fmt,...) + function mp.mf_formatted_text(index,fmt,...) local t = { } for i=1,select("#",...) do local ti = select(i,...) @@ -1139,7 +1141,7 @@ local tx_reset, tx_analyze, tx_process do end local f = lpegmatch(cleaner,fmt) local s = formatters[f](unpack(t)) or "" - mp.SomeText(index,s) + mp.mf_some_text(index,s) end interfaces.implement { @@ -1433,7 +1435,7 @@ local gt_reset, gt_analyze, gt_process do function metapost.intermediate.actions.makempy() end - function mp.GraphicText(index,str) + function mp.mf_graphic_text(index,str) if not graphics[index] then mp_index = index mp_str = str @@ -1613,7 +1615,7 @@ end local function bm_process(object,prescript,before,after) local bm_xresolution = prescript.bm_xresolution if bm_xresolution then - before[#before+1] = f_cm(cm(object)) + before[#before+1] = f_cm_b(cm(object)) before[#before+1] = function() figures.bitmapimage { xresolution = tonumber(bm_xresolution), @@ -1623,7 +1625,7 @@ local function bm_process(object,prescript,before,after) data = object.postscript } end - before[#before+1] = "Q" + before[#before+1] = s_cm_e object.path = false object.color = false object.grouped = true @@ -1651,14 +1653,33 @@ end -- figures +-- local sx, rx, ry, sy, tx, ty = cm(object) +-- sxsy(box.width,box.height,box.depth)) + +function mp.mf_external_figure(filename) + local f = figures.getinfo(filename) + local w = 0 + local h = 0 + if f then + local u = f.used + if u and u.fullname then + w = u.width or 0 + h = u.height or 0 + end + else + report_metapost("external figure %a not found",filename) + end + mp.triplet(w/65536,h/65536,0) +end + local function fg_process(object,prescript,before,after) local fg_name = prescript.fg_name if fg_name then - before[#before+1] = f_cm(cm(object)) -- beware: does not use the cm stack + before[#before+1] = f_cm_b(cm(object)) -- beware: does not use the cm stack before[#before+1] = function() context.MPLIBfigure(fg_name,prescript.fg_mask or "") end - before[#before+1] = "Q" + before[#before+1] = s_cm_e object.path = false object.grouped = true end @@ -1835,7 +1856,7 @@ local ot_reset, ot_analyze, ot_process do local mp_kind = "" local mp_str = "" - function mp.OutlineText(index,str,kind) + function mp.mf_outline_text(index,str,kind) if not outlinetexts[index] then mp_index = index mp_kind = kind @@ -1879,7 +1900,7 @@ local ot_reset, ot_analyze, ot_process do end } - function mp.get_outline_text(index) -- maybe we need a more private namespace + function mp.mf_get_outline_text(index) -- maybe we need a more private namespace mp.print(outlinetexts[index] or "draw origin;") end diff --git a/tex/context/base/mkiv/mlib-pps.mkiv b/tex/context/base/mkiv/mlib-pps.mkiv index bc4ce5a04..051130585 100644 --- a/tex/context/base/mkiv/mlib-pps.mkiv +++ b/tex/context/base/mkiv/mlib-pps.mkiv @@ -78,10 +78,15 @@ {\clf_mpgettext\MPtextbox #1% \vpack to \zeropoint{\vss\hpack to \zeropoint{\scale[\c!sx=#2,\c!sy=#3]{\raise\dp\MPtextbox\box\MPtextbox}\forcecolorhack\hss}}} +% \unexpanded\def\MPLIBfigure#1#2% +% {\setbox\scratchbox\hpack{\externalfigure[#1][\c!mask=#2]}% +% \clf_mpsetsxsy\wd\scratchbox\ht\scratchbox\zeropoint +% \vpack to \zeropoint{\vss\hpack to \zeropoint{\scale[\c!sx=\sx,\c!sy=\sy]{\box\scratchbox}\hss}}} + \unexpanded\def\MPLIBfigure#1#2% {\setbox\scratchbox\hpack{\externalfigure[#1][\c!mask=#2]}% \clf_mpsetsxsy\wd\scratchbox\ht\scratchbox\zeropoint - \vpack to \zeropoint{\vss\hpack to \zeropoint{\scale[\c!sx=\sx,\c!sy=\sy]{\box\scratchbox}\hss}}} + \vpack to \zeropoint{\vss\hpack to \zeropoint{\fastsxsy{\sx}{\sy}{\box\scratchbox}\hss}}} % horrible (we could inline scale and matrix code): diff --git a/tex/context/base/mkiv/mult-prm.mkiv b/tex/context/base/mkiv/mult-prm.mkiv index 3480cded5..5ffb84d38 100644 --- a/tex/context/base/mkiv/mult-prm.mkiv +++ b/tex/context/base/mkiv/mult-prm.mkiv @@ -68,7 +68,7 @@ "pdftracingfonts", "pdftrailer", "pdftrailerid", "pdfuniformdeviate", "pdfuniqueresname", "pdfvorigin", "pdfxform", "pdfxformattr", "pdfxformmargin", "pdfxformname", "pdfxformresources", "pdfximage", - "pdfomitcidset", + "pdfomitcidset", "pdfomitcharset", }, aleph = { -- we don't bother "Alephminorversion", "Alephrevision", "Alephversion", diff --git a/tex/context/base/mkiv/mult-sys.mkiv b/tex/context/base/mkiv/mult-sys.mkiv index 7000eed7b..22c14ff9c 100644 --- a/tex/context/base/mkiv/mult-sys.mkiv +++ b/tex/context/base/mkiv/mult-sys.mkiv @@ -240,6 +240,7 @@ \definesystemconstant {next} \definesystemconstant {pickup} +\definesystemconstant {forget} \definesystemconstant {ascii} \definesystemconstant {default} \definesystemconstant {unknown} diff --git a/tex/context/base/mkiv/page-ini.mkiv b/tex/context/base/mkiv/page-ini.mkiv index dc94edf76..1a9968759 100644 --- a/tex/context/base/mkiv/page-ini.mkiv +++ b/tex/context/base/mkiv/page-ini.mkiv @@ -256,7 +256,10 @@ \box\pagebox \egroup \ifconditional\c_page_boxes_save_page_body \copy\b_page_boxes_saved_page_body \fi} -\appendtoks \restoreglobalbodyfont \to \everybeforepagebody +\appendtoks + \restoreglobalbodyfont + \pickupattributes +\to \everybeforepagebody \ifdefined\nestednewbox \else \newbox\nestednextbox \fi % hm, still needed? diff --git a/tex/context/base/mkiv/scrp-ini.mkiv b/tex/context/base/mkiv/scrp-ini.mkiv index 8f28f505d..4567e6791 100644 --- a/tex/context/base/mkiv/scrp-ini.mkiv +++ b/tex/context/base/mkiv/scrp-ini.mkiv @@ -18,9 +18,9 @@ \registerctxluafile{scrp-eth}{} \registerctxluafile{scrp-tha}{} -\definesystemattribute[scriptinjection][public] -\definesystemattribute[scriptsplitting][public] -\definesystemattribute[scriptstatus] [public] +\definesystemattribute[scriptinjection][public,pickup] +\definesystemattribute[scriptsplitting][public,pickup] +\definesystemattribute[scriptstatus] [public,pickup] %D Since scripts need specific \LUA\ code we use hard coded attribute %D values, but we might have more tricks at some time, so we use a @@ -43,10 +43,23 @@ \unexpanded\def\scripts_basics_set {\clf_setscript{\currentscript}{\scriptparameter\c!method}{\scriptparameter\c!preset}} -\unexpanded\def\setscript[#1]% +% \unexpanded\def\setscript[#1]% +% {\edef\currentscript{#1}% +% \scripts_basics_set} + +\unexpanded\def\setglobalscript[#1]% + {\edef\currentscript{#1}% + \scripts_basics_set + \pickupscriptinjectionattribute + \pickupscriptsplittingattribute + \pickupscriptstatusattribute} + +\unexpanded\def\setlocalscript[#1]% {\edef\currentscript{#1}% \scripts_basics_set} +\let\setscript\setlocalscript + \unexpanded\def\resetscript {\clf_resetscript} diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex d94a27382..72d03ba70 100644 --- a/tex/context/base/mkiv/status-files.pdf +++ b/tex/context/base/mkiv/status-files.pdf diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf Binary files differindex 78ada2867..47a682ba6 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/strc-not.mkvi b/tex/context/base/mkiv/strc-not.mkvi index e2c60d1b1..403247b9c 100644 --- a/tex/context/base/mkiv/strc-not.mkvi +++ b/tex/context/base/mkiv/strc-not.mkvi @@ -1057,18 +1057,6 @@ \newskip \s_strc_notes_distance % we need to implement stretch \newcount\c_strc_notes_columns -% \def\strc_notes_set_distance -% {\begingroup -% \setbox\scratchbox\vbox % no reuse as it can mirror -% {\forgetall -% \restoreglobalbodyfont % really needed -% \dontcomplain -% \noteparameter\c!before -% \placenoterule -% \noteparameter\c!after}% -% \expandafter\endgroup\expandafter -% \s_strc_notes_distance\the\htdp\scratchbox\relax} % also dp now - \newskip \s_strc_notes_before \newskip \s_strc_notes_inbetween \newconditional\c_strc_notes_first_flushed @@ -1382,19 +1370,22 @@ \fi} \appendtoks - \strc_notes_set_penalties - \forgetall % again - \strc_notes_set_bodyfont - \redoconvertfont % to undo \undo calls in in headings etc - \splittopskip\strutht % not actually needed here - \splitmaxdepth\strutdp % not actually needed here - % not: -% \leftmargindistance \noteparameter\c!margindistance -% \rightmargindistance\leftmargindistance -% \ifnum\noteparameter\c!n=\zerocount % no ifcase new 31-07-99 ; always ? -% \doifnotinset{\noteparameter\c!width}{\v!fit,\v!broad}\setnotehsize % ? -% \fi - % + \strc_notes_set_penalties + \forgetall % again + \strc_notes_set_bodyfont + \redoconvertfont % to undo \undo calls in in headings etc + \splittopskip\strutht % not actually needed here + \splitmaxdepth\strutdp % not actually needed here + % + % not: + % + % \leftmargindistance \noteparameter\c!margindistance + % \rightmargindistance\leftmargindistance + % \ifnum\noteparameter\c!n=\zerocount % no ifcase new 31-07-99 ; always ? + % \doifnotinset{\noteparameter\c!width}{\v!fit,\v!broad}\setnotehsize % ? + % \fi + % + \pickupattributes \to \everyinsidenoteinsert % maybe but better use [scope=local] here diff --git a/tex/context/base/mkiv/syst-ini.mkiv b/tex/context/base/mkiv/syst-ini.mkiv index 799fccc7a..6e5ced525 100644 --- a/tex/context/base/mkiv/syst-ini.mkiv +++ b/tex/context/base/mkiv/syst-ini.mkiv @@ -605,7 +605,10 @@ %D A few shortcuts: -\normalprotected\def\glet {\global \let } +\ifdefined\glet \else + \normalprotected\def\glet{\global\let} +\fi + \normalprotected\def\udef {\normalprotected\def } \normalprotected\def\ugdef{\normalprotected\gdef} \normalprotected\def\uedef{\normalprotected\edef} @@ -1107,6 +1110,8 @@ \edef\pdfinclusioncopyfonts {\pdfvariable inclusioncopyfonts} \pdfinclusioncopyfonts \plusone \edef\pdfinclusionerrorlevel {\pdfvariable inclusionerrorlevel} \pdfinclusionerrorlevel \zerocount \edef\pdfgentounicode {\pdfvariable gentounicode} \pdfgentounicode \plusone +%edef\pdfomitcidset {\pdfvariable omitcidset } \pdfomitcidset \zerocount +%edef\pdfomitcharset {\pdfvariable omitcharset} \pdfomitcharset \plusone \edef\pdfpagebox {\pdfvariable pagebox} \pdfpagebox \zerocount \edef\pdfmajorversion {\pdfvariable majorversion} % \pdfmajorversion \plusone \edef\pdfminorversion {\pdfvariable minorversion} \pdfminorversion \plusseven diff --git a/tex/context/base/mkiv/typo-dir.mkiv b/tex/context/base/mkiv/typo-dir.mkiv index dd0a03329..9d8d6b968 100644 --- a/tex/context/base/mkiv/typo-dir.mkiv +++ b/tex/context/base/mkiv/typo-dir.mkiv @@ -18,7 +18,7 @@ \unprotect -\registerctxluafile{typo-dir}{} +\registerctxluafile{typo-dir}{optimize} \registerctxluafile{typo-dha}{} \registerctxluafile{typo-dua}{} \registerctxluafile{typo-dub}{} @@ -28,7 +28,7 @@ \registerctxluafile{typo-duc}{} } -\definesystemattribute[directions][public,global] +\definesystemattribute[directions][public,pickup] \installcorenamespace{directions} \installcorenamespace{directionsbidimode} @@ -69,8 +69,9 @@ \expandafter\glet\csname\??directionsbidimode\currentbidistamp\endcsname\currentbidimode} \appendtoks + \edef\p_bidi{\directionsparameter\c!bidi}% \edef\currentbidistamp - {\directionsparameter\c!bidi + {\p_bidi :\directionsparameter\c!method :\directionsparameter\c!fences}% \expandafter\let\expandafter\currentbidimode\csname\??directionsbidimode\currentbidistamp\endcsname @@ -83,6 +84,11 @@ \else \setdirection[\number\directionsbidimode]% \fi + \ifx\p_bidi\v!global + \pickupdirectionsattribute + \else + \forgetdirectionsattribute + \fi \to \everysetupdirections \appendtoks diff --git a/tex/context/base/mkiv/typo-mar.mkiv b/tex/context/base/mkiv/typo-mar.mkiv index f265f173c..10a47e705 100644 --- a/tex/context/base/mkiv/typo-mar.mkiv +++ b/tex/context/base/mkiv/typo-mar.mkiv @@ -155,6 +155,7 @@ \forgetall \tf \resetallattributes % \deactivatecolor % needed, but maybe we should switch to maintextcolor: \onlyinheritmaintextcolor + \pickupattributes \to \everymargindatacontent % trialtypesetting: no need for margin stuff while trialing as diff --git a/tex/context/interface/mkii/keys-de.xml b/tex/context/interface/mkii/keys-de.xml index 9b742d4b1..e5db3a6f4 100644 --- a/tex/context/interface/mkii/keys-de.xml +++ b/tex/context/interface/mkii/keys-de.xml @@ -1033,6 +1033,7 @@ <cd:constant name='otherstext' value='otherstext'/> <cd:constant name='outermargin' value='outermargin'/> <cd:constant name='overprint' value='overprint'/> + <cd:constant name='ownerpassword' value='ownerpassword'/> <cd:constant name='ownnumber' value='eigenenummer'/> <cd:constant name='page' value='seite'/> <cd:constant name='pageboundaries' value='seitenbegrenzung'/> @@ -1274,6 +1275,7 @@ <cd:constant name='up' value='up'/> <cd:constant name='urlalternative' value='urlalternative'/> <cd:constant name='urlspace' value='urlspatium'/> + <cd:constant name='userpassword' value='userpassword'/> <cd:constant name='validate' value='validieren'/> <cd:constant name='values' value='values'/> <cd:constant name='vcommand' value='vbefehl'/> diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf Binary files differindex c92ba194a..e12fb62d5 100644 --- a/tex/context/interface/mkiv/i-context.pdf +++ b/tex/context/interface/mkiv/i-context.pdf diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf Binary files differindex 04f5a960f..0d42c03d2 100644 --- a/tex/context/interface/mkiv/i-readme.pdf +++ b/tex/context/interface/mkiv/i-readme.pdf diff --git a/tex/context/modules/mkiv/x-setups-overview.mkiv b/tex/context/modules/mkiv/x-setups-overview.mkiv index f6dff12f5..512db3bd1 100644 --- a/tex/context/modules/mkiv/x-setups-overview.mkiv +++ b/tex/context/modules/mkiv/x-setups-overview.mkiv @@ -102,8 +102,9 @@ numeric h, w; boolean mapping ; path p, q, r ; color f, d ; pair s ; h := OverlayHeight ; w := 2*OverlayWidth ; r := unitsquare xyscaled (w,h) ; - fill r withcolor \MPcolor{lightgray} ; - mapping := lua.mp.processingmode("setups:mapping") ; + fill r withcolor resolvedcolor("lightgray") ; + % mapping := lua.mp.processingmode("setups:mapping") ; + mapping := lua.mp("processingmode","setups:mapping") ; if mapping : set_grid(w,h,w/8,w/160) ; pickup pensquare yscaled (w/80) ; @@ -114,8 +115,8 @@ forever : s := center r randomized (w,h) ; if new_on_grid(xpart s, ypart s) : - d := .5[\MPcolor{LocalColor},\MPcolor{lightgray}] randomized (.5,.9) ; - f := \MPcolor{lightgray} randomized (.5,.9) ; + d := .5[resolvedcolor("LocalColor"),resolvedcolor("lightgray")] randomized (.5,.9) ; + f := resolvedcolor("lightgray") randomized (.5,.9) ; s := (dx,dy) ; if mapping : p := (-w/4,0) -- (w/4,0) ; diff --git a/tex/generic/context/luatex/luatex-pdf.tex b/tex/generic/context/luatex/luatex-pdf.tex index bd6690860..569f8664f 100644 --- a/tex/generic/context/luatex/luatex-pdf.tex +++ b/tex/generic/context/luatex/luatex-pdf.tex @@ -135,6 +135,8 @@ \xdef\pdfinclusioncopyfonts {\pdfvariable inclusioncopyfonts} \xdef\pdfinclusionerrorlevel {\pdfvariable inclusionerrorlevel} \xdef\pdfgentounicode {\pdfvariable gentounicode} + \xdef\pdfomitcidset {\pdfvariable omitcidset} + \xdef\pdfomitcharset {\pdfvariable omitcharset} \xdef\pdfpagebox {\pdfvariable pagebox} \xdef\pdfmajorversion {\pdfvariable majorversion} \xdef\pdfminorversion {\pdfvariable minorversion} @@ -178,6 +180,8 @@ \global\pdfinclusioncopyfonts 0 \global\pdfinclusionerrorlevel 0 \global\pdfgentounicode 0 + % \global\pdfomitcidset 0 + % \global\pdfomitcharset 0 \global\pdfpagebox 0 % \global\pdfmajorversion 1 \global\pdfminorversion 4 |