5

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)

5

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

enter image description here

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
1

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}}]
  \addtocommalist {\xmlflush{#1}} \AuthorList
\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}}]
  \addtocommalist {\xmlfirst{#1}{/name}} \AuthorList
\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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.