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> 
                   {
  • A sequence cannot be used for the V argument. – egreg Dec 23 '14 at 11:49
  • @egreg But it seems to work as soon as the sequence is not \c_empty_tl. – Denis Bitouzé Dec 23 '14 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 Dec 23 '14 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 Dec 23 '14 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 Dec 23 '14 at 12:03
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

  • Perfect, as usual! I certainly won't be able to involve tricks such as \tl_to_str :) – Denis Bitouzé Dec 23 '14 at 15:10
  • 1
    @DenisBitouzé That's to avoid problems with special characters in the name. – egreg Dec 23 '14 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)? – Denis Bitouzé Dec 23 '14 at 15:33
  • @DenisBitouzé The row counter might change from the moment the database is created to when it's used. – egreg Dec 23 '14 at 15:58

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.