# ConTeXt XML: Configureable Titleblock

I am trying out XML processing with ConTeXt. The basics are working fine for me. Now I am trying to make the titleblock layout independent of where the data appears in the XML file. Let's consider this example:

\startbuffer[test]
<?xml version='1.0' standalone='yes?>
<document>
<title>The Title</title>
<author>The author</author>
<p>This is a first sentence</p>
</document>
\stopbuffer

\startxmlsetups xml:setup
\xmlsetsetup{\xmldocument}{*}{-}
\xmlsetsetup{\xmldocument}{document|author|title|p}{xml:*}
\stopxmlsetups

\xmlregistersetup{xml:setup}

\startxmlsetups xml:document
\startdocument
\xmlflush{#1}
\stopdocument
\stopxmlsetups

\startxmlsetups xml:title
{\ss\bfa\setupinterlinespace
\xmlflush{#1}\par}
\stopxmlsetups

\startxmlsetups xml:author
\xmlflush{#1}\blank[big]
\stopxmlsetups

\startxmlsetups xml:p
\xmlflush{#1}\par
\stopxmlsetups

\xmlprocessbuffer{test}{test}{}


This works fine for simple cases, but this breaks if the author appears before the title in the source file. Also, designing the titleblock is rather complicated with this approach.

I have thought about using something like this:

\startxmlsetups xml:title
\def\thetitle{\xmlflush{#1}}
\stopxmlsetups

\startxmlsetups xml:author
\def\theauthor{\xmlflush{#1}}
\stopxmlsetups


With this I could define a command like \placetitle, and use this to output the author and title in arbitrary order. However, this would entail that I (or the users) must manually call this command in the XML file, which is something I would like to avoid.

I think something like this would probably the best way to go, but I have no idea how I could make this work with XML. (I am processing my XML files with context --environment=environment file.xml)

If the document has only one title and one author, you can use xmlfilter to filter out that information before flushing the rest of the content. For example:

\startbuffer[test]
<?xml version='1.0' standalone='yes?>
<document>
<title>The Title</title>
<author>The author</author>
<p>This is a first sentence</p>
</document>
\stopbuffer

\startxmlsetups xml:setup
\xmlsetsetup{\xmldocument}{*}{-}
\xmlsetsetup{\xmldocument}{document|p}{xml:*}
\stopxmlsetups

\xmlregistersetup{xml:setup}

\startxmlsetups xml:document
\xmlfilter{#1}{/title/command(xml:title)}
\xmlfilter{#1}{/author/command(xml:author)}
\startdocument
\xmlflush{#1}
\stopdocument
\stopxmlsetups

\startxmlsetups xml:title
\setupdocument[title={\xmlflush{#1}}]
\stopxmlsetups

\startxmlsetups xml:author
\setupdocument[author={\xmlflush{#1}}]
\stopxmlsetups

\startxmlsetups xml:p
\xmlflush{#1}\par
\stopxmlsetups

\startsetups document:start
\startalignment[middle]
{\ssbfa\setupinterlinespace
\documentvariable{title}\endgraf}
\blank[medium]
\documentvariable{author}
\stopalignment
\blank[big]
\stopsetups

\xmlprocessbuffer{main}{test}{}


which gives

With this approach, it doesn't matter where the <title> and <author> block appear. For example, the following will also work:

\startbuffer[test]
<?xml version='1.0' standalone='yes?>
<document>
<p>This is a first sentence</p>
<title>The Title</title>
<author>The author</author>
</document>
\stopbuffer

• Wow. One title sounds reasonable. But sometimes there might be more than one author. Can this be incorporated? – Denis Jan 21 at 18:33
• Depends on how the XML is structured and how you want it to be translated to ConTeXt. If you have a structure in mind, please add that to your question; else I can just cook up something reasonable. – Aditya Jan 21 at 18:45
• I've managed to combine your solution with your answer to this question. If you have suggestions for improvements, feel free to edit... – Denis Jan 21 at 21:34

Ok, based on Aditya's answer here and on his answer to this question I can now come up with this:

\startbuffer[test]
<?xml version='1.0' standalone='yes?>
<document>
<title>The Title</title>
<author>First Author</author>
<author>Second Author</author>
<p>This is a first sentence</p>
</document>
\stopbuffer

\startxmlsetups xml:setup
\xmlsetsetup{\xmldocument}{*}{-}
\xmlsetsetup{\xmldocument}{document|p}{xml:*}
\stopxmlsetups

\xmlregistersetup{xml:setup}

\startxmlsetups xml:document
\xmlfilter{#1}{/title/command(xml:title)}
\xmlfilter{#1}{/author/command(xml:author)}
\startdocument
\xmlflush{#1}
\stopdocument
\stopxmlsetups

\startxmlsetups xml:title
\setupdocument[title={\xmlflush{#1}},author={\AuthorList}]
\stopxmlsetups

\startxmlsetups xml:author
\defineauthor[\xmlflush{#1}][name={\xmlflush{#1}}]
\stopxmlsetups

\startxmlsetups xml:p
\xmlflush{#1}\par
\stopxmlsetups

\definenamespace
[documentauthor] % name of internal varialbles
[type=module,
name=author,
command=yes, % Create \defineauthor
style=yes, % Create \useauthorstyleandcolor
setup=list, % Create \setupauthor
parent=documentauthor,
]

\def\AuthorList{}

\define[1]\useauthor
{\edef\currentauthor{#1}%
{\useauthorstyleandcolor{style}{color}
\authorparameter{name}}%
\par
\mono{\authorparameter{email}}
\blank[small]
}

\startsetups document:start
\startalignment[middle]
{\ssbfc\setupinterlinespace
\documentvariable{title}
\endgraf}
\blank[medium]
\processcommacommand[\documentvariable{author}]\useauthor
\blank[big]
\stopalignment
\stopsetups

\setupauthor[style=sansbold]

\xmlprocessbuffer{main}{test}{}


What we do here is:

1. Define a \defineauthorcommand.

2. Define an empty list for the authors: \def\AuthorList{}

3. Let <author> define a new author and add this author to the list of authors.

4. Make sure the author list is added to the document metadata:

\startxmlsetups xml:title
\setupdocument[title={\xmlflush{#1}},author={\AuthorList}]
\stopxmlsetups


Edit: A more complete version that also accomodates the author's email could look like this:

\startbuffer[test]
<?xml version='1.0' standalone='yes?>
<document>
<title>The Title</title>
<author>
<name>First Author</name>
<email>author@gmail.com</email>
</author>
<author>
<name>Second Author</name>
<email>author@gmail.com</email>
</author>
<p>This is a first sentence</p>
</document>
\stopbuffer

\startxmlsetups xml:setup
\xmlsetsetup{\xmldocument}{*}{-}
\xmlsetsetup{\xmldocument}{document|author|name|email|p}{xml:*}
\stopxmlsetups

\xmlregistersetup{xml:setup}

\startxmlsetups xml:document
\xmlfilter{#1}{/title/command(xml:title)}
\xmlfilter{#1}{/author/command(xml:author)}
\startdocument
\xmlflush{#1}
\stopdocument
\stopxmlsetups

\startxmlsetups xml:title
\setupdocument[title={\xmlflush{#1}},author={\AuthorList}]
\stopxmlsetups

\startxmlsetups xml:author
\defineauthor[\xmlfirst{#1}{/name}][name={\xmlfirst{#1}{/name}},email={\xmlfirst{#1}{/email}}]
\stopxmlsetups

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

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

\startxmlsetups xml:p
\xmlflush{#1}\par
\stopxmlsetups

\definenamespace
[documentauthor] % name of internal varialbles
[type=module,
name=author,
command=yes, % Create \defineauthor
style=yes, % Create \useauthorstyleandcolor
setup=list, % Create \setupauthor
parent=documentauthor,
]

\def\AuthorList{}

\define[1]\useauthor
{\edef\currentauthor{#1}%
{\useauthorstyleandcolor{style}{color}
\authorparameter{name}}%
\par
\mono{\authorparameter{email}}
\blank[small]
}

\startsetups document:start
\startalignment[middle]
{\ssbfc\setupinterlinespace
\documentvariable{title}
\endgraf}
\blank[medium]
\processcommacommand[\documentvariable{author}]\useauthor
\blank[big]
\stopalignment
\stopsetups

\setupauthor[style=sansbold]

\xmlprocessbuffer{main}{test}{}


I am not really sure if I haven't introduced new problems, so I'd be happy about comments/edits wherever necessary. (For example, I don't understand why I had to introduce author|name|email to \xmlsetsetup, whereas Aditya's solution didn't have authorin \xmlsetsetup. Also, it is not entirely clear to me how \xmlflush works. Sometimes I had to use this although a certain XML node is only used by another XML setup, for example email.)

• This is quite similar to what I had in mind. – Aditya Jan 22 at 17:00
• @Aditya: Great. Thanks for your feedback. Just a quick thought: Would it be possible to let \defineauthor automatically add an author to the author list? – Denis Jan 24 at 9:35