XML Setup Commands

From Wiki
Jump to navigation Jump to search

TODO: this page is WIP

before being finished it will be a mess (See: To-Do List)


Introduction

From the introductory explanation to XML formatting, a more detailed description of the setup commands is required.

The setup commands help formatting as far as they provide the XML selections to be formatted with standard ConTeXt commands.

A very basic setup configuration would be:

\startxmlsetups xml:emphasis
  \bgroup\em\xmltext{#1}{.}\egroup
\stopxmlsetups

The only XML setup command above is \xmltext. Both \em and \bgroup … \egroup are standard ConTeXt commands.

This page describes only setup commands for XML in ConTeXt.

Flushing Text and Elements

\xmlflush

\xmlflush is the most basic setup command, since it includes all XML from the current node (text and children elements with their attributes).

Imagine the following XML sample:

<text>
  <paragraph class="first">
    <sentence>This is the first sentence.</sentence>
    <sentence>This is the second sentence.</sentence>
  </paragraph>
  <paragraph class="second">
    <sentence>This is the third sentence.</sentence>
    <sentence>This is the fourth sentence.</sentence>
  </paragraph>
</text>

Given the following environment:

\startxmlsetups xml:sample
  \xmlsetsetup{#1}{*}{xml:*}
  \xmlsetsetup{#1}
    {paragraph[@class='second']}
    {xml:second:paragraph}
\stopxmlsetups

\xmlregistersetup{xml:sample}

\startxmlsetups xml:text
  \xmlflush{#1}
\stopxmlsetups

\startxmlsetups xml:paragraph
  \xmlflush{#1}
\stopxmlsetups

\startxmlsetups xml:sentence
  \xmlflush{#1}
\stopxmlsetups

\startxmlsetups xml:second:paragraph
   % this is empty (no flush for children)
\stopxmlsetups

The result would be:

You might wonder Why the third and fourth sentences are missing.

They are not typeset because the path for the second paragraph is missing a flushing that would reach the <sentence> elements that element contains.

Replacing the comment with \xmlflush{#1} would typeset the second paragraph.

\xmlflushcontext

\xmlflushcontext also flushes text and children elements, but it also interprets ConTeXt commands.

Sample code:

<text>
  <paragraph>\ConTeXt\ is awesome.</paragraph>
  <paragraph class="second">\ConTeXt\ is also a command.</paragraph>
</text>

Sample environment that shows the difference:

\startxmlsetups xml:text
  \xmlflush{#1}
\stopxmlsetups

\startxmlsetups xml:paragraph
  \startparagraph
    \xmlflush{#1}
  \stopparagraph
\stopxmlsetups

\startxmlsetups xml:second:paragraph
  \startparagraph
    \xmlflushcontext{#1}
  \stopparagraph
\stopxmlsetups

Only the second paragraph has ConTeXt typeset following the command:

\xmlflushtext

\xmlflushtext flushes all text from the current node.

This includes

Taking the sample code above and only replacing the xml:text setup command such as in:

\startxmlsetups xml:text
  \xmlflushtext{#1}
\stopxmlsetups

This is the output:

No ConTeXt command interpretation, as expected.

Also no paragraph, since \xmlflushtext includes text from all children elements, but not the children themselves.

In that way, the setup commands xml:paragraph and xml:second:paragraph in the sample have nothing to deal with.

\xmlpure

\xmlpure is needed to pass pure text (without extra codes) to PDF comments or similar.

Here is the XML sample:

<text>
  <sentence>Code may be tricky.</sentence>
  <code>\ConTeXt\ code.</code>
</text>

The relevant setup command that shows the difference:

\startxmlsetups xml:code
\xmlflushcontext{#1}\par
standard flushing\comment{\xmlflush{#1}}\\
pure flushing\comment{\xmlpure{#1}}
\stopxmlsetups

Being a PDF interactive feature, the result cannot be displayed on the wiki:[1]


Standard flushing (with \xmlflush) gives the text from the PDF comment: \Ux {5C}ConTeXt\Ux {5C} code.

Pure flushing (with \xmlpure) gives the text from that comment: \ConTeXt\ code.

\xmlpure accepts a path as an optional second argument.

This would make \xmlpure{#1} and \xmlpure{#1}{.} (or even \xmlpure{#1}{../code} in that sample) synonymous commands.

Attributes

\xmlatt

\xmlatt gives the value of a given attribute.

A minimal sample:

<text>
  <element class="single">text</element>
</text>

The setup to output the attribute value would read:

\startxmlsetups xml:element
  \xmlatt{#1}{class}
\stopxmlsetups

So the output would read:

\xmlrefatt

\xmlrefatt gives the value of an attribute, but it removes leading # from its value.

A minimal sample with destination:

<text>
  <section id="section-1">Section 1
    <p>Irrelevant text.</p>
  </section>
  <section id="section-2">Section 2
    <p>As said in <a href="#section-1">previous section</a></p>
  </section>
</text>

The setup to read the output as a destination for a ConTeXt reference:

\startxmlsetups xml:a
  \in{section}[\xmlrefatt{#1}{href}]
\stopxmlsetups

So the output would read (link interaction enabled to see the difference):

\xmlattdef

\xmlattdef gives the value of a given attribute or a text if the attribute doesn’t exist.

Taking the first XML sample from Attributes, the following setup will warn about the not available attribute:

\startxmlsetups xml:element
  \xmlattdef{#1}{id}{no defined id attribute}
\stopxmlsetups

This setup would output:

There is no way to format the warning string (no defined id attribute in this case). Conditionals would be needed for that.

Verbatim Text

There are four basic commands to get verbatim text: \xmlverbatim, \inlinexmlverbatim, \xmlprettyprint and \xmlinlineprettyprint.

The inline versions display inline code and the pretty versions highlight the displayed code.

All verbatim cannot specify paths (they are limited to the contents of the current element).

Let’s take XML and enviroment samples from \xmlflush.

Only the setup for xml:text is replaced with:

\startxmlsetups xml:text
  block: \xmlverbatim{#1}\blank
  inline: \xmlinlineverbatim{#1}\blank
  block: \xmlprettyprint{#1}{xml}\blank
  inline: \xmlinlineprettyprint{#1}{xml}\blank
\stopxmlsetups

The output would be:[2]

Setups for xml:paragraph and xml:sentence haven’t been removed.

But they don’t have anything to deal with, as none of the verbatim commands flushes elements.

Conditionals

There are four basic XML conditional commands:

  1. \xmldoif
  2. \xmldoiftext
  3. \xmldoifempty
  4. \xmldoifatt

All four have the ifnot and ifelse variants. Only the main if commands are explained (and variants shown in results).

\xmldoif

\xmldoif checks if a given element exists (as defined by a path). It only requires that a path that can be selected.

Taking the XML sample from \xmlflush and replacing the xml:element setup configuration with:

\startxmlsetups xml:text
  paragraph: \xmldoif{#1}{paragraph}{exists}\\
  sentence: \xmldoifelse{#1}{paragraph/sentence}{exists}{not available}\\
  sentence: \xmldoifnot{#1}{/sentence}{not available}
\stopxmlsetups

This is the result from that configuration setup:

Please, keep in mind the following considerations from this sample:

  1. There is no flushing at all, only a requirement checking and consequent code when any defined criterion is met.
  2. <paragraph> is child (or direct descendant) from <text>, but <sentence> is only indirect descendant.
  3. The path selection /sentence was written as a child purposefully to get a negative conditional.
  4. It would be pointless to set . (the current node) as path. If the node has already been reached, the condition will always be true.

\xmldoiftext

\xmldoiftext checks if a given element (as selected by a path) contains text.

Text is understood here as text content in XML element and not what gives width (such as in ConTeXt command \doiftextelse{\hskip0pt}{text}{no text}).

A very basic XML sample:

<text>
  <paragraph>
    <sentence>Just a sentence.</sentence>
    <sentence> </sentence>
    <sentence>#113826;</sentence>
    <sentence></sentence>
  </paragraph>
</text>

These are the conditionals for the setup of xml:text:

\startxmlsetups xml:text
  paragraph: \xmldoiftext{#1}{paragraph}{text given}\\
  sentence: \xmldoifelsetext{#1}{sentence}{text given}{no text}\\
  first sentence: \xmldoifelsetext{#1}{sentence[position()==1]}{text given}{no text}\\
  sentence 2: \xmldoifelsetext{#1}{sentence[position()==2]}{text given}{no text}\\
  sentence 3: \xmldoifelsetext{#1}{sentence[position()==3]}{text given}{no text}\\
  last sentence: \xmldoifelsetext{#1}{sentence[position()==last()]}{text given}{no text}
\stopxmlsetups

The results would be:

You have to keep in mind:

  1. Spaces count as text for conditionals (no matter its width [&#113826; is zero–width space]).
  2. If not specified, conditional is performed with the first match.
  3. Elements have text when their descendants have it.

\xmldoifempty

\xmldoifempty gives the opposite results from \xmldoiftext.

Having the previous XML sample and replacing the setup for xml:text with:

\startxmlsetups xml:text
  paragraph: \xmldoifelseempty{#1}{paragraph}{empty}{full}\\
  sentence: \xmldoifelseempty{#1}{sentence}{empty}{full}\\
  first sentence: \xmldoifelseempty{#1}{sentence[position()==1]}{empty}{full}\\
  sentence 2: \xmldoifelseempty{#1}{sentence[position()==2]}{empty}{full}\\
  sentence 3: \xmldoifelseempty{#1}{sentence[position()==3]}{empty}{full}\\
  last sentence: \xmldoifelseempty{#1}{sentence[position()==last()]}{empty}{full}
\stopxmlsetups

Results are:

\xmldoifselfempty

There is a self version of \xmldoifempty, named \xmldoifselfempty (provided with ifnot and ifelse variants, as well).

It checks from emptiness in current node (no path selection). \xmldoifselfempty{#1}{empty} is the same as \xmldoifempty{#1}{.}{empty}.

It may be just me, but code readability is problematic \xmldoifselfelseempty (instead of just \xmldoifelseempty).

\xmldoifatt

\xmldoifatt

  1. You need to compile the sources and inspect the PDF output. The wiki only displays images taken from the PDF output.
    \setupinteraction[state=start]
    \startbuffer[demo]
    <text>
      <sentence>Code may be tricky.</sentence>
      <code>\ConTeXt\ code.</code>
    </text>
    \stopbuffer
    
    \startxmlsetups xml:sample
      \xmlsetsetup{#1}{*}{xml:*}
    \stopxmlsetups
    
    \xmlregistersetup{xml:sample}
    
    \startxmlsetups xml:text
      \xmlflush{#1}
    \stopxmlsetups
    
    \startxmlsetups xml:sentence
      \startparagraph
        \xmlflush{#1}
      \stopparagraph
    \stopxmlsetups
    
    \startxmlsetups xml:code
    \xmlflushcontext{#1}\par
    standard flushing\comment{\xmlflush{#1}}\\
    pure flushing\comment{\xmlpure{#1}}
    \stopxmlsetups
    
    \setupbodyfont[24pt]
    
    \startTEXpage[offset=1ex]
    \xmlprocessbuffer{main}{demo}{}
    \stopTEXpage
    
  2. \xmlinlineverbatim seems to have a bug (in both the wiki and latest from 2024.06.14 09:18).
    \xmlinlineprettyprint{#1}{none} achieves the same result (no code highlighting).