3

I'm trying to use expl3 sequences in order to stored 0, 1 or more affiliations to 1 or more authors stored in a datatool database. The following MWE works nicely:

\documentclass{article}
\usepackage{xparse}
\usepackage{datatool}

\ExplSyntaxOn

\DTLnewdb{_mymodule_authors}

\seq_new:N \g_mymodule_author_affiliations_seq

\keys_define:nn { mymodule/authors }
{
  affiliation .code:n = \seq_gput_right:Nn \g_mymodule_author_affiliations_seq {#1}
}

\cs_new_protected:Nn \_mymodule_authors:nn
{
  \DTLnewrow{_mymodule_authors}
  \DTLnewdbentry{_mymodule_authors}{name}{#1}
  \DTLnewdbentry{_mymodule_authors}{affiliations}{#2}
}

\cs_generate_variant:Nn \_mymodule_authors:nn { nV }

\RenewDocumentCommand \author { o m } {
  \IfValueTF {#1}
  {
    \keys_set:nn { mymodule/authors } { #1 }
    \_mymodule_authors:nV {#2}{\g_mymodule_author_affiliations_seq}
  }
  {
    \_mymodule_authors:nV {#2}{\c_empty_tl}
  }
  \seq_gclear:N \g_mymodule_author_affiliations_seq
}

\NewDocumentCommand \showauthors {  } {
  \DTLforeach*{_mymodule_authors}{
    \l_tmpa_tl=name,
    \l_tmpa_seq=affiliations
  }{
    \mymodule_display_author:nn {\l_tmpa_tl}{\l_tmpa_seq}
    \DTLiflastrow{
    }{
      \DTLpar
    }
  }
}

\cs_new_protected:Nn \mymodule_display_author:nn
{
  #1
  \seq_if_empty:NF {\l_tmpa_seq}
  {
    \space(\seq_use:Nn \l_tmpa_seq { ,~ })
  }
}

\ExplSyntaxOff

\begin{document}
%\author{Foo, Bar 0}
\author[affiliation=Blah]{Foo, Bar 1}
\author[affiliation=Bleh,affiliation=Blih]{Foo, Bar 2}
\author[affiliation=Bloh,affiliation=Bluh,affiliation=Blyh]{Foo, Bar 3}
%
\showauthors
\end{document}

But, as soon as I comment out \author{Foo, Bar 0}, the author with 0 affiliation, I'm facing the following error I don't understand:

! Missing = inserted for \ifnum.
<to be read again> 
                   {
7
  • A sequence cannot be used for the V argument.
    – egreg
    Commented Dec 23, 2014 at 11:49
  • @egreg But it seems to work as soon as the sequence is not \c_empty_tl. Commented Dec 23, 2014 at 11:51
  • 1
    It seems to work. Page 28 of interface3 says “The V type returns the value of a register, which can be one of tl, num, int, skip, dim, toks, or built-in TeX registers.”
    – egreg
    Commented Dec 23, 2014 at 11:55
  • 1
    The list should be updated, but as far as I know, using sequences for V is unpredictable. I tried using \c_empty_seq rather than \c_empty_tl, but errors are thrown nonetheless.
    – egreg
    Commented Dec 23, 2014 at 12:02
  • 2
    Indeed, the V type can only be used where there is some logical 'value' concept. That simply isn't the case for a sequence.
    – Joseph Wright
    Commented Dec 23, 2014 at 12:03

1 Answer 1

3

A sequence cannot be used as argument to a V specifier, because it hasn't a single unique value.

So, instead of storing a sequence in the database, you can store a pointer to a sequence. As pointer, I use the “stringified” version of the author's name.

\documentclass{article}
\usepackage{xparse}
\usepackage{datatool}

\ExplSyntaxOn

\DTLnewdb{_mymodule_authors}

\seq_new:N \l_mymodule_author_affiliations_seq

\keys_define:nn { mymodule/authors }
 {
  affiliation .code:n = \seq_put_right:Nn \l_mymodule_author_affiliations_seq {#1}
 }

\cs_new_protected:Nn \_mymodule_authors:n
 {
  \DTLnewrow{_mymodule_authors}
  \DTLnewdbentry{_mymodule_authors}{name}{#1}
  \DTLnewdbentry{_mymodule_authors}{affiliations}{\tl_to_str:n{#1}}
 }

\RenewDocumentCommand \author { O{} m }
 {
  \seq_clear:N \l_mymodule_author_affiliations_seq
  \keys_set:nn { mymodule/authors } { #1 }
  \_mymodule_authors:n {#2}
  \seq_new:c { g_mymodule_affiliation_ \tl_to_str:n{#2} _seq }
  \seq_gset_eq:cN { g_mymodule_affiliation_ \tl_to_str:n{#2} _seq } \l_mymodule_author_affiliations_seq
 }

\NewDocumentCommand \showauthors {  }
 {
  \DTLforeach*{_mymodule_authors}
   {
    \l_tmpa_tl=name,
    \l_tmpb_tl=affiliations
   }
   {
    \mymodule_display_author:VV \l_tmpa_tl \l_tmpb_tl
    \DTLiflastrow { }{ \DTLpar }
   }
 }

\cs_new_protected:Nn \mymodule_display_author:nn
 {
  #1
  \seq_if_empty:cF { g_mymodule_affiliation_#2_seq }
  {
   \c_space_tl(\seq_use:cn { g_mymodule_affiliation_#2_seq } { ,~ })
  }
 }

\cs_generate_variant:Nn \mymodule_display_author:nn { VV }

\ExplSyntaxOff

\begin{document}
\author{Foo, Bar 0}
\author[affiliation=Blah]{Foo, Bar 1}
\author[affiliation=Bleh,affiliation=Blih]{Foo, Bar 2}
\author[affiliation=Bloh,affiliation=Bluh,affiliation=Blyh]{Foo, Bar 3}

\showauthors
\end{document}

enter image description here

4
  • Perfect, as usual! I certainly won't be able to involve tricks such as \tl_to_str :) Commented Dec 23, 2014 at 15:10
  • 1
    @DenisBitouzé That's to avoid problems with special characters in the name.
    – egreg
    Commented Dec 23, 2014 at 15:13
  • Your comment makes me think that your solution would fail in case of homonym authors (highly unlikely, for sure). Wouldn't it be possible to disambiguate the pointers, for instance with the help of datatool's \DTLcurrentindex (arabic value of the current row counter)? Commented Dec 23, 2014 at 15:33
  • @DenisBitouzé The row counter might change from the moment the database is created to when it's used.
    – egreg
    Commented Dec 23, 2014 at 15:58

You must log in to answer this question.

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