xml-mkiv-expressions.tex /size: 22 Kb    last modification: 2021-10-28 13:50
1% language=us runpath=texruns:manuals/xml
2
3\environment xml-mkiv-style
4
5\startcomponent xml-mkiv-expressions
6
7\startchapter[title={Expressions and filters}]
8
9\startsection[title={path expressions}]
10
11In the previous chapters we used \cmdinternal {cd:lpath} expressions, which are a variant
12on \type {xpath} expressions as in \XSLT\ but in this case more geared towards
13usage in \TEX. This mechanisms will be extended when demands are there.
14
15A path is a sequence of matches. A simple path expression is:
16
17\starttyping
18a/b/c/d
19\stoptyping
20
21Here each \type {/} goes one level deeper. We can go backwards in a lookup with
22\type {..}:
23
24\starttyping
25a/b/../d
26\stoptyping
27
28We can also combine lookups, as in:
29
30\starttyping
31a/(b|c)/d
32\stoptyping
33
34A negated lookup is preceded by a \type {!}:
35
36\starttyping
37a/(b|c)/!d
38\stoptyping
39
40A wildcard is specified with a \type {*}:
41
42\starttyping
43a/(b|c)/!d/e/*/f
44\stoptyping
45
46In addition to these tag based lookups we can use attributes:
47
48\starttyping
49a/(b|c)/!d/e/*/f[@type=whatever]
50\stoptyping
51
52An \type {@} as first character means that we are dealing with an attribute.
53Within the square brackets there can be boolean expressions:
54
55\starttyping
56a/(b|c)/!d/e/*/f[@type=whatever and @id>100]
57\stoptyping
58
59You can use functions as in:
60
61\starttyping
62a/(b|c)/!d/e/*/f[something(text()) == "oeps"]
63\stoptyping
64
65There are a couple of predefined functions:
66
67\starttabulate[|l|l|p|]
68\NC \type{rootposition} \type{order} \NC number \NC the index of the matched root element (kind of special) \NC \NR
69\NC \type{position}                  \NC number \NC the current index of the matched element in the match list \NC \NR
70\NC \type{match}                     \NC number \NC the current index of the matched element sub list with the same parent \NC \NR
71\NC \type{first}                     \NC number \NC \NC \NR
72\NC \type{last}                      \NC number \NC \NC \NR
73\NC \type{index}                     \NC number \NC the current index of the matched element in its parent list \NC \NR
74\NC \type{firstindex}                \NC number \NC \NC \NR
75\NC \type{lastindex}                 \NC number \NC \NC \NR
76\NC \type{element}                   \NC number \NC the element's index \NC \NR
77\NC \type{firstelement}              \NC number \NC \NC \NR
78\NC \type{lastelement}               \NC number \NC \NC \NR
79\NC \type{text}                      \NC string \NC the textual representation of the matched element \NC \NR
80\NC \type{content}                   \NC table  \NC the node of the matched element \NC \NR
81\NC \type{name}                      \NC string \NC the full name of the matched element: namespace and tag \NC \NR
82\NC \type{namespace} \type{ns}       \NC string \NC the namespace of the matched element \NC \NR
83\NC \type{tag}                       \NC string \NC the tag of the matched element \NC \NR
84\NC \type{attribute}                 \NC string \NC the value of the attribute with the given name of the matched element \NC \NR
85\stoptabulate
86
87There are fundamental differences between \type {position}, \type {match} and
88\type {index}. Each step results in a new list of matches. The \type {position}
89is the index in this new (possibly intermediate) list. The \type {match} is also
90an index in this list but related to the specific match of element names. The
91\type {index} refers to the location in the parent element.
92
93Say that we have:
94
95\starttyping
96<collection>
97  <resources>
98    <manual>
99      <screen>.1.</screen>
100      <paper>.1.</paper>
101    </manual>
102    <manual>
103      <paper>.2.</paper>
104      <screen>.2.</screen>
105    </manual>
106  <resources>
107  <resources>
108    <manual>
109      <screen>.3.</screen>
110      <paper>.3.</paper>
111    </manual>
112  <resources>
113<collection>
114\stoptyping
115
116The following then applies:
117
118\starttabulate[|l|l|]
119\NC \type {collection/resources/manual[position()==1]/paper} \NC \type{.1.} \NC \NR
120\NC \type {collection/resources/manual[match()==1]/paper}    \NC \type{.1.} \type{.3.} \NC \NR
121\NC \type {collection/resources/manual/paper[index()==1]}    \NC \type{.2.} \NC \NR
122\stoptabulate
123
124In most cases the \type {position} test is more restrictive than the \type
125{match} test.
126
127You can pass your own functions too. Such functions are defined in the \type
128{xml.expressions} namespace. We have defined a few shortcuts:
129
130\starttabulate[|l|l|]
131\NC \type {find(str,pattern)} \NC \type{string.find}      \NC \NR
132\NC \type {contains(str)}     \NC \type{string.find}      \NC \NR
133\NC \type {oneof(str,...)}    \NC is \type{str} in list   \NC \NR
134\NC \type {upper(str)}        \NC \type{characters.upper} \NC \NR
135\NC \type {lower(str)}        \NC \type{characters.lower} \NC \NR
136\NC \type {number(str)}       \NC \type{tonumber}         \NC \NR
137\NC \type {boolean(str)}      \NC \type{toboolean}        \NC \NR
138\NC \type {idstring(str)}     \NC removes leading hash    \NC \NR
139\NC \type {name(index)}       \NC full tag name           \NC \NR
140\NC \type {tag(index)}        \NC tag name                \NC \NR
141\NC \type {namespace(index)}  \NC namespace of tag        \NC \NR
142\NC \type {text(index)}       \NC content                 \NC \NR
143\NC \type {error(str)}        \NC quit and show error     \NC \NR
144\NC \type {quit()}            \NC quit                    \NC \NR
145\NC \type {print()}           \NC print message           \NC \NR
146\NC \type {count(pattern)}    \NC number of matches       \NC \NR
147\NC \type {child(pattern)}    \NC take child that matches \NC \NR
148\stoptabulate
149
150
151You can also use normal \LUA\ functions as long as you make sure that you pass
152the right arguments. There are a few predefined variables available inside such
153functions.
154
155\starttabulate[|Tl|l|p|]
156\NC \type{list}  \NC table   \NC the list of matches \NC \NR
157\NC \type{l}     \NC number  \NC the current index in the list of matches \NC \NR
158\NC \type{ll}    \NC element \NC the current element that matched \NC \NR
159\NC \type{order} \NC number  \NC the position of the root of the path \NC \NR
160\stoptabulate
161
162The given expression between \type {[]} is converted to a \LUA\ expression so you
163can use the usual operators:
164
165\starttyping
166== ~= <= >= < > not and or ()
167\stoptyping
168
169In addition, \type {=} equals \type {==} and \type {!=} is the same as \type
170{~=}. If you mess up the expression, you quite likely get a \LUA\ error message.
171
172\stopsection
173
174\startsection[title={css selectors}]
175
176\startbuffer[selector-001]
177<?xml version="1.0" ?>
178
179<a>
180    <b class="one">b.one</b>
181    <b class="two">b.two</b>
182    <b class="one two">b.one.two</b>
183    <b class="three">b.three</b>
184    <b id="first">b#first</b>
185    <c>c</c>
186    <d>d e</d>
187    <e>d e</e>
188    <e>d e e</e>
189    <d>d f</d>
190    <f foo="bar">@foo = bar</f>
191    <f bar="foo">@bar = foo</f>
192    <f bar="foo1">@bar = foo1</f>
193    <f bar="foo2">@bar = foo2</f>
194    <f bar="foo3">@bar = foo3</f>
195    <f bar="foo+4">@bar = foo+4</f>
196    <g>g</g>
197    <g><gg><d>g gg d</d></gg></g>
198    <g><gg><f>g gg f</f></gg></g>
199    <g><gg><f class="one">g gg f.one</f></gg></g>
200    <g>g</g>
201    <g><gg><f class="two">g gg f.two</f></gg></g>
202    <g><gg><f class="three">g gg f.three</f></gg></g>
203    <g><f class="one">g f.one</f></g>
204    <g><f class="three">g f.three</f></g>
205    <h whatever="four five six">@whatever = four five six</h>
206</a>
207\stopbuffer
208
209\xmlloadbuffer{selector-001}{selector-001}
210
211\startxmlsetups xml:selector:demo
212    \advance\scratchcounter\plusone
213    \inleftmargin{\the\scratchcounter}\ignorespaces\xmlverbatim{#1}\par
214\stopxmlsetups
215
216\unexpanded\def\showCSSdemo#1#2%
217  {\blank
218   \textrule{\tttf#2}
219   \startlines
220   \dontcomplain
221   \tttf \obeyspaces
222   \scratchcounter\zerocount
223   \xmlcommand{#1}{#2}{xml:selector:demo}
224   \stoplines
225   \blank}
226
227The \CSS\ approach to filtering is a bit different from the path based one and is
228supported too. In fact, you can combine both methods. Depending on what you
229select, the \CSS\ one can be a little bit faster too. It has the advantage that
230one can select more in one go but at the same time looks a bit less attractive.
231This method was added just to show that it can be done but might be useful too. A
232selector is given between curly braces (after all \CSS\ uses them and they have no
233function yet in the parser.
234
235\starttyping
236\xmlall{#1}{{foo bar .whatever, bar foo .whatever}}
237\stoptyping
238
239The following methods are supported:
240
241\starttabulate[|T||]
242\NC element                          \NC all tags element \NC \NR
243\NC element-1 > element-2            \NC all tags element-2 with parent tag element-1 \NC \NR
244\NC element-1 + element-2            \NC all tags element-2 preceded by tag element-1 \NC \NR
245\NC element-1 ~ element-2            \NC all tags element-2 preceded by tag element-1 \NC \NR
246\NC element-1 element-2              \NC all tags element-2 inside tag element-1 \NC \NR
247\NC [attribute]                      \NC has attribute \NC \NR
248\NC [attribute=value]                \NC attribute equals value\NC \NR
249\NC [attribute\lettertilde =value]   \NC attribute contains value (space is separator) \NC \NR
250\NC [attribute\letterhat   ="value"] \NC attribute starts with value \NC \NR
251\NC [attribute\letterdollar="value"] \NC attribute ends with value \NC \NR
252\NC [attribute*="value"]             \NC attribute contains value \NC \NR
253\NC .class                           \NC has class \NC \NR
254\NC \letterhash id                   \NC has id \NC \NR
255\NC :nth-child(n)                    \NC the child at index n \NC \NR
256\NC :nth-last-child(n)               \NC the child at index n from the end \NC \NR
257\NC :first-child                     \NC the first child \NC \NR
258\NC :last-child                      \NC the last child \NC \NR
259\NC :nth-of-type(n)                  \NC the match at index n \NC \NR
260\NC :nth-last-of-type(n)             \NC the match at index n from the end \NC \NR
261\NC :first-of-type                   \NC the first match \NC \NR
262\NC :last-of-type                    \NC the last match \NC \NR
263\NC :only-of-type                    \NC the only match or nothing \NC \NR
264\NC :only-child                      \NC the only child or nothing \NC \NR
265\NC :empty                           \NC only when empty \NC \NR
266\NC :root                            \NC the whole tree \NC \NR
267\stoptabulate
268
269The next pages show some examples. For that we use the demo file:
270
271\typebuffer[selector-001]
272
273The class and id selectors often only make sense in \HTML\ like documents but they
274are supported nevertheless. They are after all just shortcuts for filtering by
275attribute. The class filtering is special in the sense that it checks for a class
276in a list of classes given in an attribute.
277
278\showCSSdemo{selector-001}{{.one}}
279\showCSSdemo{selector-001}{{.one, .two}}
280\showCSSdemo{selector-001}{{.one, .two, \letterhash first}}
281
282Attributes can be filtered by presence, value, partial value and such. Quotes are
283optional but we advice to use them.
284
285\showCSSdemo{selector-001}{{[foo], [bar=foo]}}
286\showCSSdemo{selector-001}{{[bar\lettertilde=foo]}}
287\showCSSdemo{selector-001}{{[bar\letterhat="foo"]}}
288\showCSSdemo{selector-001}{{[whatever\lettertilde="five"]}}
289
290You can of course combine the methods as in:
291
292\showCSSdemo{selector-001}{{g f .one, g f .three}}
293\showCSSdemo{selector-001}{{g > f .one, g > f .three}}
294\showCSSdemo{selector-001}{{d + e}}
295\showCSSdemo{selector-001}{{d ~ e}}
296\showCSSdemo{selector-001}{{d ~ e, g f .one, g f .three}}
297
298You can also negate the result by using \type {:not} on a simple expression:
299
300\showCSSdemo{selector-001}{{:not([whatever\lettertilde="five"])}}
301\showCSSdemo{selector-001}{{:not(d)}}
302
303The child and match selectors are also supported:
304
305\showCSSdemo{selector-001}{{a:nth-child(3)}}
306\showCSSdemo{selector-001}{{a:nth-last-child(3)}}
307\showCSSdemo{selector-001}{{g:nth-of-type(3)}}
308\showCSSdemo{selector-001}{{g:nth-last-of-type(3)}}
309\showCSSdemo{selector-001}{{a:first-child}}
310\showCSSdemo{selector-001}{{a:last-child}}
311\showCSSdemo{selector-001}{{e:first-of-type}}
312\showCSSdemo{selector-001}{{gg d:only-of-type}}
313
314Instead of numbers you can also give the \type {an} and \type {an+b} formulas
315as well as the \type {odd} and \type {even} keywords:
316
317\showCSSdemo{selector-001}{{a:nth-child(even)}}
318\showCSSdemo{selector-001}{{a:nth-child(odd)}}
319\showCSSdemo{selector-001}{{a:nth-child(3n+1)}}
320\showCSSdemo{selector-001}{{a:nth-child(2n+3)}}
321
322There are a few special cases:
323
324\showCSSdemo{selector-001}{{g:empty}}
325\showCSSdemo{selector-001}{{g:root}}
326\showCSSdemo{selector-001}{{*}}
327
328Combining the \CSS\ methods with the regular ones is possible:
329
330\showCSSdemo{selector-001}{{g gg f .one}}
331\showCSSdemo{selector-001}{g/gg/f[@class='one']}
332\showCSSdemo{selector-001}{g/{gg f .one}}
333
334\startbuffer[selector-002]
335<?xml version="1.0" ?>
336
337<document>
338    <title class="one"  >title 1</title>
339    <title class="two"  >title 2</title>
340    <title class="one"  >title 3</title>
341    <title class="three">title 4</title>
342</document>
343\stopbuffer
344
345The next examples we use this file:
346
347\typebuffer[selector-002]
348
349\xmlloadbuffer{selector-002}{selector-002}
350
351When we filter from this (not too well structured) tree we can use both
352methods to achieve the same:
353
354\showCSSdemo{selector-002}{{document title .one, document title .three}}
355
356\showCSSdemo{selector-002}{/document/title[(@class='one') or (@class='three')]}
357
358However, imagine this file:
359
360\startbuffer[selector-003]
361<?xml version="1.0" ?>
362
363<document>
364    <title    class="one">title 1</title>
365    <subtitle class="sub">title 1.1</subtitle>
366    <title    class="two">title 2</title>
367    <subtitle class="sub">title 2.1</subtitle>
368    <title    class="one">title 3</title>
369    <subtitle class="sub">title 3.1</subtitle>
370    <title    class="two">title 4</title>
371    <subtitle class="sub">title 4.1</subtitle>
372</document>
373\stopbuffer
374
375\typebuffer[selector-003]
376
377\xmlloadbuffer{selector-003}{selector-003}
378
379The next filter in easier with the \CSS\ selector methods because these accumulate
380independent (simple) expressions:
381
382\showCSSdemo{selector-003}{{document title .one + subtitle, document title .two + subtitle}}
383
384Watch how we get an output in the document order. Because we render a sequential document
385a combined filter will trigger a sorting pass.
386
387\stopsection
388
389\startsection[title={functions as filters}]
390
391At the \LUA\ end a whole \cmdinternal {cd:lpath} expression results in a (set of) node(s)
392with its environment, but that is hardly usable in \TEX. Think of code like:
393
394\starttyping
395for e in xml.collected(xml.load('text.xml'),"title") do
396  -- e = the element that matched
397end
398\stoptyping
399
400The older variant is still supported but you can best use the previous variant.
401
402\starttyping
403for r, d, k in xml.elements(xml.load('text.xml'),"title") do
404  -- r = root of the title element
405  -- d = data table
406  -- k = index in data table
407end
408\stoptyping
409
410Here \type {d[k]} points to the \type {title} element and in this case all titles
411in the tree pass by. In practice this kind of code is encapsulated in function
412calls, like those returning elements one by one, or returning the first or last
413match. The result is then fed back into \TEX, possibly after being altered by an
414associated setup. We've seen the wrappers to such functions already in a previous
415chapter.
416
417In addition to the previously discussed expressions, one can add so called
418filters to the expression, for instance:
419
420\starttyping
421a/(b|c)/!d/e/text()
422\stoptyping
423
424In a filter, the last part of the \cmdinternal {cd:lpath} expression is a
425function call. The previous example returns the text of each element \type {e}
426that results from matching the expression. When running \TEX\ the following
427functions are available. Some are also available when using pure \LUA. In \TEX\
428you can often use one of the macros like \type {\xmlfirst} instead of a \type
429{\xmlfilter} with finalizer \type {first()}. The filter can be somewhat faster
430but that is hardly noticeable.
431
432\starttabulate[|l|l|p|]
433\NC \type {context()}                \NC string  \NC the serialized text with \TEX\ catcode regime \NC \NR
434%NC \type {ctxtext()}                \NC string  \NC \NC \NR
435\NC \type {function()}               \NC string  \NC depends on the function \NC \NR
436%
437\NC \type {name()}                   \NC string  \NC the (remapped) namespace \NC \NR
438\NC \type {tag()}                    \NC string  \NC the name of the element \NC \NR
439\NC \type {tags()}                   \NC list    \NC the names of the element \NC \NR
440%
441\NC \type {text()}                   \NC string  \NC the serialized text \NC \NR
442\NC \type {upper()}                  \NC string  \NC the serialized text uppercased \NC \NR
443\NC \type {lower()}                  \NC string  \NC the serialized text lowercased \NC \NR
444\NC \type {stripped()}               \NC string  \NC the serialized text stripped \NC \NR
445\NC \type {lettered()}               \NC string  \NC the serialized text only letters (cf. \UNICODE) \NC \NR
446%
447\NC \type {count()}                  \NC number  \NC the number of matches \NC \NR
448\NC \type {index()}                  \NC number  \NC the matched index in the current path \NC \NR
449\NC \type {match()}                  \NC number  \NC the matched index in the preceding path \NC \NR
450%
451%NC \type {lowerall()}               \NC string  \NC \NC \NR
452%NC \type {upperall()}               \NC string  \NC \NC \NR
453%
454\NC \type {attribute(name)}          \NC content \NC returns the attribute with the given name \NC \NR
455\NC \type {chainattribute(name)}     \NC content \NC sidem, but backtracks till one is found \NC \NR
456\NC \type {command(name)}            \NC content \NC expands the setup with the given name for each found element \NC \NR
457\NC \type {position(n)}              \NC content \NC processes the \type {n}\high{th} instance of the found element \NC \NR
458\NC \type {all()}                    \NC content \NC processes all instances of the found element \NC \NR
459%NC \type {default}                  \NC content \NC all \NC \NR
460\NC \type {reverse()}                \NC content \NC idem in reverse order \NC \NR
461\NC \type {first()}                  \NC content \NC processes the first instance of the found element \NC \NR
462\NC \type {last()}                   \NC content \NC processes the last instance of the found element \NC \NR
463\NC \type {concat(...)}              \NC content \NC concatinates the match \NC \NC \NR
464\NC \type {concatrange(from,to,...)} \NC content \NC concatinates a range of matches \NC \NC \NR
465\NC \type {depth()}                  \NC number  \NC the depth in the tree of the found element \NC \NC \NR
466\stoptabulate
467
468The extra arguments of the concatinators are: \type {separator} (string), \type
469{lastseparator} (string) and \type {textonly} (a boolean).
470
471These filters are in fact \LUA\ functions which means that if needed more of them
472can be added. Indeed this happens in some of the \XML\ related \MKIV\ modules,
473for instance in the \MATHML\ processor.
474
475\stopsection
476
477\startsection[title={example}]
478
479The number of commands is rather large and if you want to avoid them this is
480often possible. Take for instance:
481
482\starttyping
483\xmlall{#1}{/a/b[position()>3]}
484\stoptyping
485
486Alternatively you can use:
487
488\starttyping
489\xmlfilter{#1}{/a/b[position()>3]/all()}
490\stoptyping
491
492and actually this is also faster as internally it avoids a function call. Of
493course in practice this is hardly measurable.
494
495In previous examples we've already seen quite some expressions, and it might be
496good to point out that the syntax is modelled after \XSLT\ but is not quite the
497same. The reason is that we started with a rather minimal system and have already
498styles in use that depend on compatibility.
499
500\starttyping
501namespace:// axis node(set) [expr 1]..[expr n] / ... / filter
502\stoptyping
503
504When we are inside a \CONTEXT\ run, the namespace is \type {tex}. Hoewever, if
505you want not to print back to \TEX\ you need to be more explicit. Say that we
506typeset examns and have a (not that logical) structure like:
507
508\starttyping
509<question>
510  <text>...</text>
511  <answer>
512    <item>one</item>
513    <item>two</item>
514    <item>three</item>
515  </answer>
516  <alternative>
517    <condition>true</condition>
518    <score>1</score>
519  </alternative>
520  <alternative>
521    <condition>false</condition>
522    <score>0</score>
523  </alternative>
524  <alternative>
525    <condition>true</condition>
526    <score>2</score>
527  </alternative>
528</question>
529\stoptyping
530
531Say that we typeset the questions with:
532
533\starttyping
534\startxmlsetups question
535  \blank
536  score: \xmlfunction{#1}{totalscore}
537  \blank
538  \xmlfirst{#1}{text}
539  \startitemize
540      \xmlfilter{#1}{/answer/item/command(answer:item)}
541  \stopitemize
542  \endgraf
543  \blank
544\stopxmlsetups
545\stoptyping
546
547Each item in the answer results in a call to:
548
549\starttyping
550\startxmlsetups answer:item
551  \startitem
552    \xmlflush{#1}
553    \endgraf
554    \xmlfilter{#1}{../../alternative[position()=rootposition()]/
555      condition/command(answer:condition)}
556  \stopitem
557\stopxmlsetups
558\stoptyping
559
560\starttyping
561\startxmlsetups answer:condition
562  \endgraf
563  condition: \xmlflush{#1}
564  \endgraf
565\stopxmlsetups
566\stoptyping
567
568Now, there are two rather special filters here. The first one involves
569calculating the total score. As we look forward we use a function to deal with
570this.
571
572\starttyping
573\startluacode
574function xml.functions.totalscore(root)
575  local score = 0
576  for e in xml.collected(root,"/alternative") do
577    score = score + xml.filter(e,"xml:///score/number()") or 0
578  end
579  tex.write(score)
580end
581\stopluacode
582\stoptyping
583
584Watch how we use the namespace to keep the results at the \LUA\ end.
585
586The second special trick shown here is to limit a match using the current
587position of the root (\type {#}) match.
588
589As you can see, a path expression can be more than just filtering a few nodes. At
590the end of this manual you will find a bunch of examples.
591
592\stopsection
593
594\startsection[title={tables}]
595
596If you want to know how the internal \XML\ tables look you can print such a
597table:
598
599\starttyping
600print(table.serialize(e))
601\stoptyping
602
603This produces for instance:
604
605% s = xml.convert("<document><demo label='whatever'>some text</demo></document>")
606% print(table.serialize(xml.filter(s,"demo")[1]))
607
608\starttyping
609t={
610 ["at"]={
611  ["label"]="whatever",
612 },
613 ["dt"]={ "some text" },
614 ["ns"]="",
615 ["rn"]="",
616 ["tg"]="demo",
617}
618\stoptyping
619
620The \type {rn} entry is the renamed namespace (when renaming is applied). If you
621see tags like \type {@pi@} this means that we don't have an element, but (in this
622case) a processing instruction.
623
624\starttabulate[|l|p|]
625\NC \type {@rt@} \NC the root element \NC \NR
626\NC \type {@dd@} \NC document definition \NC \NR
627\NC \type {@cm@} \NC comment, like \type {<!-- whatever -->} \NC \NR
628\NC \type {@cd@} \NC so called \type {CDATA} \NC \NR
629\NC \type {@pi@} \NC processing instruction, like \type {<?whatever we want ?>} \NC \NR
630\stoptabulate
631
632There are many ways to deal with the content, but in the perspective of \TEX\
633only a few matter.
634
635\starttabulate[|l|p|]
636\NC \type {xml.sprint(e)} \NC print the content to \TEX\ and apply setups if needed \NC \NR
637\NC \type {xml.tprint(e)} \NC print the content to \TEX\ (serialize elements verbose) \NC \NR
638\NC \type {xml.cprint(e)} \NC print the content to \TEX\ (used for special content) \NC \NR
639\stoptabulate
640
641Keep in mind that anything low level that you uncover is not part of the official
642interface unless mentioned in this manual.
643
644\stopsection
645
646\stopchapter
647
648\stopcomponent
649