1

I can't get the \iffieldequalstr conditional test in Biblatex to work. Here's an example where I'm intending to remove all notes except notes attached to a specific author (there are extraneous notes in my Zotero database that were automatically downloaded and I typically want not to show, but for one author I do need a note) - but that author gets their notes deleted too:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[backend=biber,bibstyle=authoryear,citestyle=authoryear-icomp,url=true,isbn=false,doi=false]{biblatex}

\usepackage{filecontents} \begin{filecontents}{bibfile.bib} @book{smith_2010, location = {London}, title = {An Interesting Book}, publisher = {Big Publishing Company}, author = {Smith, John}, date = {2010-01-01}, note = {Note I do want included} }

@book{evans_2011, location = {New York}, title = {Another Interesting Book}, publisher = {Small Publishing Company}, author = {Evans, Joe}, date = {2011-01-01}, note = {Note I don't want included} }

\end{filecontents}

\addbibresource{bibfile.bib}

\AtEveryBibitem{ \iffieldequalstr{author}{Smith, John} {} {\clearfield{note}}}

\begin{document} \textcite{smith_2010} \textcite{evans_2011} \printbibliography \end{document}

As output, I get both notes included, though the intention is to remove the note attached to Evans. Where am I going wrong?

McDuffin
  • 133
  • Name fields are special and can't be tested for equality with a simple \iffieldequalstr (which only works for literal fields such as title or note). For name equality testing one's best bet is name hashes. See https://tex.stackexchange.com/q/73136/35864. (Note that there is a difference between testing the whole field and testing a single item in the field.) – moewe Jun 23 '20 at 16:48
  • I'm assuming this isn't the real-world application of \iffieldequalstr you have in mind. If you can explain what you need the test for we might be able to come up with a better alternative. – moewe Jun 23 '20 at 16:49
  • Thanks, I've edited the question to be a MWE of my actual use case – McDuffin Jun 23 '20 at 17:02
  • Mhhh, I had hoped your actual question would be more different than that. Do you want to display the note in smith_2010 (1) because John Smith is the sole author of the work, (2) because John Smith is one author of the work or (3) because of some other property of smith_2010 not directly related to the author. To ask differently, suppose you had another work written only by John Smith would you also want to see the note there? Suppose you had work written jointly by John Smith and Jane Smoth would you want to show the note there? – moewe Jun 23 '20 at 17:06
  • I want all notes on works by John Smith to be outputted (I don't have any works with John Smith as a coauthor, but I'd want notes on them to be outputted to - the note is due to John Smith having changed their name/gender (and I'm following John Smith's reccomendation in adding the note)) – McDuffin Jun 23 '20 at 17:08
  • I see, that is possible, but a bit tricker. Essentially the idea would be to loop through the author list for every entry and set a flag whether or not to print the note if the name is encountered. It should be possible to piece this together from code shown in https://tex.stackexchange.com/q/73136/35864. Unfortunately, I have to go now, but I'll have a look at this later (which may well mean tomorrow or the day after tomorrow) if no one else has had a shot at answering with the method I have in mind. – moewe Jun 23 '20 at 17:12

1 Answers1

2

\iffieldequalstr only works for literal fields, but author is a name list, which has a complex internal structure that can not easily be compared to a simple string.

In my opinion the best way to compare names is via name hashes. See also my answer to Make specific author bold using biblatex. Name hashes can be a bit unwieldy (cf. Highlight an author in bibliography using biblatex allowing bibliography style to format it), so the linked answer uses a more complex method to extract the relevant name hash automatically from Biber.

With the definitions from the linked answer we can now compare names with \xifinlist{\thefield{hash}}{\nhblx@notehashes}. Now we need a way to reliably detect whether a name is present in an entry. A very clever way to do that is presented in Audrey's answer to biblatex: filter out publications from a specific author in the references dynamically: We abuse name indexing to loop over all name items.

Putting that together we get

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[backend=biber,
  style=authoryear-icomp,
  doi=false, url=true, isbn=false,
]{biblatex}

\makeatletter \def\nhblx@bibfile@name{\jobname -nhblx.bib} \newwrite\nhblx@bibfile \immediate\openout\nhblx@bibfile=\nhblx@bibfile@name

\immediate\write\nhblx@bibfile{% @comment{Auto-generated file}\blx@nl}

\newcounter{nhblx@name} \setcounter{nhblx@name}{0}

\newcommand*{\nhblx@writenametobib}[1]{% \stepcounter{nhblx@name}% \edef\nhblx@tmp@nocite{% \noexpand\AfterPreamble{% \noexpand\setbox0\noexpand\vbox{% \noexpand\nhblx@getmethehash{nhblx@name@\the\value{nhblx@name}}}}% }% \nhblx@tmp@nocite \immediate\write\nhblx@bibfile{% @misc{nhblx@name@\the\value{nhblx@name}, author = {\unexpanded{#1}}, % options = {dataonly=true},}% }% }

\AtEndDocument{% \closeout\nhblx@bibfile}

\addbibresource{\nhblx@bibfile@name}

\newcommand*{\nhblx@notehashes}{} \DeclareNameFormat{nhblx@hashextract}{% \xifinlist{\thefield{hash}}{\nhblx@notehashes} {} {\listxadd{\nhblx@notehashes}{\thefield{fullhash}}}}

\DeclareCiteCommand{\nhblx@getmethehash} {} {\printnames[nhblx@hashextract][1-999]{author}} {} {}

\newcommand{\addnotenames}{\forcsvlist\nhblx@writenametobib} \newcommand{\resetnotenames}{\def\nhblx@notehashes{}}

\newtoggle{notename} \DeclareIndexNameFormat{notename}{% \xifinlist{\thefield{hash}}{\nhblx@notehashes} {\global\toggletrue{notename}} {}}

\AtEveryBibitem{% \togglefalse{notename}% \indexnames[notename]{labelname}% \iftoggle{notename} {} {\clearfield{note}}} \makeatother

\addnotenames{John Smith}

\begin{filecontents}{\jobname.bib} @book{smith_2010, location = {London}, title = {An Interesting Book}, publisher = {Big Publishing Company}, author = {Smith, John}, date = {2010-01-01}, note = {Note I want included}, } @book{evans_2011, location = {New York}, title = {Another Interesting Book}, publisher = {Small Publishing Company}, author = {Evans, Joe}, date = {2011-01-01}, note = {Note I don't want included}, } \end{filecontents} \addbibresource{\jobname.bib}

\begin{document} \textcite{smith_2010} \textcite{evans_2011} \printbibliography \end{document}

Evans, Joe (Jan. 1, 2011). Another Interesting Book. New York: Small Publishing Company.//Smith, John (Jan. 1, 2010). An Interesting Book. Note I want included. London: Big Publishing Company.


Given our discussions in the comments about the purpose of that note, something like this might be more convenient.

Here you don't give the note for the author in the as note in the .bib file, instead you give it directly as note for the specific author in the document. The note is automatically added after the author name in the bibliography.

The underlying idea to identify the name is the same as above, though. We still use name hashes. But this time we also associate a note to the relevant hash that we can easily print.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[backend=biber,
  style=authoryear-icomp,
  doi=false, url=true, isbn=false,
]{biblatex}

\makeatletter \def\nhblx@bibfile@name{\jobname -nhblx.bib} \newwrite\nhblx@bibfile \immediate\openout\nhblx@bibfile=\nhblx@bibfile@name

\immediate\write\nhblx@bibfile{% @comment{Auto-generated file}\blx@nl}

\newcounter{nhblx@name} \setcounter{nhblx@name}{0}

\newcommand*{\nhblx@writenameandnotetobib}[2]{% \stepcounter{nhblx@name}% \edef\nhblx@tmp@nocite{% \noexpand\AfterPreamble{% \noexpand\setbox0\noexpand\vbox{% \noexpand\nhblx@hashnoteextract{nhblx@name@\the\value{nhblx@name}}}}% }% \nhblx@tmp@nocite \immediate\write\nhblx@bibfile{% @misc{nhblx@name@\the\value{nhblx@name},\blx@nl \space\space author = {\unexpanded{#2}},\blx@nl \space\space note = {\unexpanded{#1}},\blx@nl \space\space options = {dataonly=true},\blx@nl }% }% }

\AtEndDocument{% \closeout\nhblx@bibfile}

\addbibresource{\nhblx@bibfile@name}

\newcommand*{\nhblx@notehashes}{} \DeclareNameFormat{nhblx@hashnoteextract}{% \global\csletcs{hashnotemap@\thefield{hash}}{abx@field@note}}

\DeclareCiteCommand{\nhblx@hashnoteextract} {} {\printnames[nhblx@hashnoteextract][1-999]{author}} {} {}

\newcommand*{\addnotenames}[2]{\forcsvlist{\nhblx@writenameandnotetobib{#2}}{#1}} \makeatother

\newrobustcmd*{\mknotename}[1]{% \ifcsundef{hashnotemap@\thefield{hash}} {#1} {#1 (\csuse{hashnotemap@\thefield{hash}})}% }

\DeclareNameWrapperFormat{notenames}{% \renewcommand*{\mkbibcompletename}{\mknotename}% #1}

\DeclareNameWrapperAlias{sortname}{notenames}

\addnotenames{John Smith}{A note for John Smith}

\begin{filecontents}{\jobname.bib} @book{smith_2010, location = {London}, title = {An Interesting Book}, publisher = {Big Publishing Company}, author = {Smith, John}, date = {2010-01-01}, } @book{evans_2011, location = {New York}, title = {Another Interesting Book}, publisher = {Small Publishing Company}, author = {Evans, Joe}, date = {2011-01-01}, } \end{filecontents} \addbibresource{\jobname.bib}

\begin{document} \textcite{smith_2010} \textcite{evans_2011} \printbibliography \end{document}


A less automatic version of this idea uses literal field annotations that are given directly in the .bib file and can attach to a particular item in a name list.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[backend=biber,
  style=authoryear-icomp,
  doi=false, url=true, isbn=false,
]{biblatex}

\newrobustcmd*{\mknotename}[1]{% \hasitemannotation {#1 (\getitemannotation)} {#1}% }

\DeclareNameWrapperFormat{notenames}{% \renewcommand*{\mkbibcompletename}{\mknotename}% #1}

\DeclareNameWrapperAlias{sortname}{notenames}

\begin{filecontents}{\jobname.bib} @book{smith_2010, location = {London}, title = {An Interesting Book}, publisher = {Big Publishing Company}, author = {Smith, John}, author+an = {1="Some note"}, date = {2010-01-01}, } @book{evans_2011, location = {New York}, title = {Another Interesting Book}, publisher = {Small Publishing Company}, author = {Evans, Joe}, date = {2011-01-01}, } \end{filecontents} \addbibresource{\jobname.bib}

\begin{document} \textcite{smith_2010} \textcite{evans_2011} \printbibliography \end{document}

moewe
  • 175,683