0

I have a large database of bibtex items. Often authors do not care for series and number information, but I want to have the complete information. I am looking for a clever way to check the database for missing information and record the result. I am using biber/biblatex. I could declare series and number obligatory fields, but some publishers do not have series and/or number. So, I would like to have a field optnumber, which could have the value "none", and optseries which could also have the value none. Or serieschecked or numberchecked, or something similar. biber should then test whether series or optseries/serieschecked is present and if it is not throw a warning.

I already know how to make the fields obligatory, but there should be one of two fields mandatory, so that I can see that somebody already checked the item under consideration and either added a series or the information that there is no series.

\DeclareDatamodelConstraints[book,mvbook,mvcollection,mvreference]{
  \constraint[type=mandatory]{
    \constraintfield{title}
    \constraintfield{series}
    \constraintfield{number}
  }
}

Can this be done? Thanks.

1 Answer 1

1

You can add an XOR constraint to the datamodel, which means that exactly one of series or optseries needs to be present.

Since we don't need optseries except for datamodel validation we can declare it skipout, so it does not appear in the .bbl file.

\documentclass{article}

\begin{filecontents}{seriescheck.dbx}
\DeclareDatamodelFields[type=field, datatype=literal, skipout]{optseries}

\DeclareDatamodelEntryfields[
  book,mvbook,inbook,
  collection,mvcollection,incollection
]{optseries}
\DeclareDatamodelConstraints[
  book,mvbook,inbook,
  collection,mvcollection,incollection]
  {
    \constraint[type=mandatory]{
      \constraintfieldsxor{
        \constraintfield{series}
        \constraintfield{optseries}
      }
    }
  }
\end{filecontents}

\usepackage[
  backend=biber,
  datamodel=seriescheck,
]{biblatex}

\begin{filecontents}{\jobname.bib}
@book{nussbaum,
  author       = {Nussbaum, Martha},
  title        = {Aristotle's \mkbibquote{De Motu Animalium}},
  date         = 1978,
  publisher    = {Princeton University Press},
  location     = {Princeton},
  optseries    = {none},
}
@book{worman,
  author       = {Worman, Nancy},
  title        = {The Cast of Character},
  date         = 2002,
  publisher    = {University of Texas Press},
  location     = {Austin},
}
@collection{omeara,
  editor       = {O'Meara, Dominic J.},
  title        = {Studies in {Aristotle}},
  date         = 1981,
  series       = {Studies in Philosophy and the History of Philosophy},
  number       = 9,
  publisher    = {The Catholic University of America Press},
  location     = {Washington, D.C.},
  pages        = {161-191},
}
@book{aristotle:poetics,
  author       = {Aristotle},
  title        = {Poetics},
  date         = 1968,
  editor       = {Lucas, D. W.},
  series       = {Clarendon {Aristotle}},
  publisher    = {Clarendon Press},
  location     = {Oxford},
  optseries    = {none},
}
\end{filecontents}
\addbibresource{\jobname.bib}

\begin{document}
\nocite{*}

\printbibliography
\end{document}

When run with biber -V generates

[437] Biber.pm:1641> INFO - Datamodel validation starting
[438] Utils.pm:395> WARN - Datamodel: Entry 'worman' (Namenddfdfdsflos-21.bib): Missing mandatory field - one of 'series, optseries' must be defined
[443] Utils.pm:395> WARN - Datamodel: Entry 'aristotle:poetics' (Namenddfdfdsflos-21.bib): Mandatory fields - only one of 'series, optseries' must be defined - ignoring field 'optseries'
[443] Biber.pm:1690> INFO - Datamodel validation complete

I don't think I am a big fan of a fake field just for data model verification. Maybe it would be more suitable to use a null value for series instead. Then you would only need to verify if series is present and later filter out the null value (this can be done via \DeclareFieldInputHandler).

\documentclass{article}

\begin{filecontents}{seriescheck.dbx}
\DeclareDatamodelFields[type=field, datatype=literal, skipout]{optseries}

\DeclareDatamodelEntryfields[
  book,mvbook,inbook,
  collection,mvcollection,incollection
]{optseries}
\DeclareDatamodelConstraints[
  book,mvbook,inbook,
  collection,mvcollection,incollection]
  {
    \constraint[type=mandatory]{
      \constraintfield{series}
    }
  }
\end{filecontents}

\usepackage[
  backend=biber,
  datamodel=seriescheck,
]{biblatex}

\DeclareFieldInputHandler{series}{%
  \ifdefstring{\NewValue}{none}
    {\def\NewValue{}}
    {}}

\begin{filecontents}{\jobname.bib}
@book{nussbaum,
  author       = {Nussbaum, Martha},
  title        = {Aristotle's \mkbibquote{De Motu Animalium}},
  date         = 1978,
  publisher    = {Princeton University Press},
  location     = {Princeton},
  series       = {none},
}
@book{worman,
  author       = {Worman, Nancy},
  title        = {The Cast of Character},
  date         = 2002,
  publisher    = {University of Texas Press},
  location     = {Austin},
}
@collection{omeara,
  editor       = {O'Meara, Dominic J.},
  title        = {Studies in {Aristotle}},
  date         = 1981,
  series       = {Studies in Philosophy and the History of Philosophy},
  number       = 9,
  publisher    = {The Catholic University of America Press},
  location     = {Washington, D.C.},
  pages        = {161-191},
}
@book{aristotle:poetics,
  author       = {Aristotle},
  title        = {Poetics},
  date         = 1968,
  editor       = {Lucas, D. W.},
  series       = {Clarendon {Aristotle}},
  publisher    = {Clarendon Press},
  location     = {Oxford},
}
\end{filecontents}
\addbibresource{\jobname.bib}

\begin{document}
\nocite{*}

\printbibliography
\end{document}
[442] Biber.pm:1641> INFO - Datamodel validation starting
[443] Utils.pm:395> WARN - Datamodel: Entry 'worman' (Namenddfdfdsflos-21.bib): Missing mandatory field 'series'
[444] Biber.pm:1690> INFO - Datamodel validation complete

If you also want to verify whether you have a number for your series you can try the following. It isn't quite as elegant as I would have liked it to be because the data model verification cannot branch on field values, so we have to fake that with a source map

\documentclass{article}

\begin{filecontents}{seriescheck.dbx}
\DeclareDatamodelFields[type=field, datatype=literal, skipout]{optseries}

\DeclareDatamodelEntryfields[
  book,mvbook,inbook,
  collection,mvcollection,incollection
]{optseries}
\DeclareDatamodelConstraints[
  book,mvbook,inbook,
  collection,mvcollection,incollection]
{
  \constraint[type=mandatory]{
    \constraintfield{series}
  }
  \constraint[type=conditional]{
    \antecedent[quantifier=all]{
      \constraintfield{series}
    }
    \consequent[quantifier=all]{
      \constraintfield{number}
    }
  }
}
\end{filecontents}

\usepackage[
  backend=biber,
  datamodel=seriescheck,
]{biblatex}

\DeclareSourcemap{
  \maps[datatype=bibtex]{
    \map{
       \step[fieldsource=series, match=\regexp{\Anone\Z}, final]
       \step[fieldset=number, fieldvalue=none]
    }
  }
}

\DeclareFieldInputHandler{series}{%
  \ifdefstring{\NewValue}{none}
    {\def\NewValue{}}
    {}}
    
\DeclareFieldInputHandler{number}{%
  \ifdefstring{\NewValue}{none}
    {\def\NewValue{}}
    {}}

\begin{filecontents}{\jobname.bib}
@book{nussbaum,
  author       = {Nussbaum, Martha},
  title        = {Aristotle's \mkbibquote{De Motu Animalium}},
  date         = 1978,
  publisher    = {Princeton University Press},
  location     = {Princeton},
  series       = {none},
}
@book{worman,
  author       = {Worman, Nancy},
  title        = {The Cast of Character},
  date         = 2002,
  publisher    = {University of Texas Press},
  location     = {Austin},
}
@collection{omeara,
  editor       = {O'Meara, Dominic J.},
  title        = {Studies in {Aristotle}},
  date         = 1981,
  series       = {Studies in Philosophy and the History of Philosophy},
  number       = 9,
  publisher    = {The Catholic University of America Press},
  location     = {Washington, D.C.},
  pages        = {161-191},
}
@book{aristotle:poetics,
  author       = {Aristotle},
  title        = {Poetics},
  date         = 1968,
  editor       = {Lucas, D. W.},
  series       = {Clarendon {Aristotle}},
  publisher    = {Clarendon Press},
  location     = {Oxford},
}
\end{filecontents}
\addbibresource{\jobname.bib}

\begin{document}
\nocite{*}

\printbibliography
\end{document}
[396] Biber.pm:1641> INFO - Datamodel validation starting
[396] Utils.pm:395> WARN - Datamodel: Entry 'worman' (Namenddfdfdsflos-21.bib): Missing mandatory field 'series'
[398] Utils.pm:395> WARN - Datamodel: Entry 'aristotle:poetics' (Namenddfdfdsflos-21.bib): Constraint violation - all of fields (number) must exist when all of fields (series) exist
[401] Biber.pm:1690> INFO - Datamodel validation complete
4
  • Perfect! Thank you very much! This is also good for using a gui, since the series field is already there. On top of all this, would there by a way to throw a warning if series is not "none" and there is no number? Feb 11, 2021 at 20:10
  • 1
    @StefanMüller That's a bit trickier, see the edit, please.
    – moewe
    Feb 11, 2021 at 20:37
  • I tried to extend this to the editor and publisher fields, but this doesn't seem to work. It just types out "none"m even though I added \def\NewValue{}. Apr 23, 2021 at 19:41
  • 1
    @StefanMüller editor is a name field and publisher is a list field. So you need \DeclareNameInputHandler and \DeclareListInputHandler, respectively, instead of \DeclareFieldInputHandler. But often name and list fields are trickier than normal fields, so it is possible that additional work is necessary. If you can't get this to work I suggest you ask a new question.
    – moewe
    Apr 24, 2021 at 9:46

You must log in to answer this question.

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