6

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)

2 Answers 2

6

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
3
  • Wow. One title sounds reasonable. But sometimes there might be more than one author. Can this be incorporated?
    – Denis
    Commented Jan 21, 2019 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
    Commented Jan 21, 2019 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
    Commented Jan 21, 2019 at 21:34
2

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>[email protected]</email>
</author>
<author>
<name>Second Author</name>
<email>[email protected]</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.)

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .