# \DeclareSourceMap does not work

I have the following MWE:

\documentclass{article}
\usepackage{polyglossia}
\setmainlanguage{english}

% Bibliography
\usepackage[backend=biber]{biblatex}

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldset=keywords, fieldvalue=hit]
}
}
}

\begin{document}

\printbibliography[keyword=hit]

\end{document}


Which as I understand it should add the keyword hit to all entries from an author named "Muster" which then can be printed with \printbibliography[keyword=hit] (as I have found it here: https://tex.stackexchange.com/a/65145/11820)

I compile the document with xelatex, biber, xelatex, xelatex but I get the warning:

Package biblatex Warning: Keyword 'hit' not found on input line 21.


and nothing is printed in the bibliography.

Are there any other specific pre-requirements for \DeclareSourcemap to work or am I understanding it completely wrong?

The custom.bib file is as follows:

@book{key,
author = {Max Muster},
maintitle = {Der Werktitel},
title = {Titel des zweiten Bandes},
volume = {2},
location = {Ort},
year = {2002},
keywords = {muster, etwas}
}

@book{other,
author = {Michael Karomann},
maintitle = {Etwas},
title = {Nichts},
volume = {3},
location = {Ort},
year = {2002},
keywords = {test, etwas}
}


There are two issues here.

1. Non-empty fields are not overwritten unless overwrite is explicitly specified. (Empty fields are fine, though, this'll come in handy soon.)
2. You probably do not want to overwrite the existing keywords, instead you want to append hit to the keywords. If you do that, you also need to add a comma.

To catch both the cases with an undefined and non-empty keyword field, use

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldsource=keywords, match=\regexp{\A.+\Z}, final]
\step[fieldset=keywords, fieldvalue={,hit}, append]
}
\map{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldset=keywords, fieldvalue={hit}]
}
}
}


The first \map only matches non-empty keywords field and adds ,hit so hit does not meld into the last keyword as keywords = {muster, etwashit}. The second \map does not overwrite existing fields, so it only applies if no keyword field is defined. It simply makes the keywords field read hit.

MWE (This MWE uses filecontents. It therefore overwrites an existing .bib file with the same name as the .tex without advance warning. To be on the safe side test this in an empty folder.)

\documentclass{article}
\usepackage[backend=biber]{biblatex}

\usepackage{filecontents}
\begin{filecontents}{\jobname.bib}
@book{key,
author = {Max Muster},
maintitle = {Der Werktitel},
title = {Titel des zweiten Bandes},
volume = {2},
location = {Ort},
year = {2002},
keywords = {muster, etwas},
}
@book{keya,
author = {Max Muster},
maintitle = {Der Werktitel},
title = {Titel des Dritten Bandes},
volume = {3},
location = {Ort},
year = {2002},
}
@book{other,
author = {Michael Karomann},
maintitle = {Etwas},
title = {Nichts},
volume = {3},
location = {Ort},
year = {2002},
keywords = {test, etwas},
}
\end{filecontents}

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldsource=keywords, match=\regexp{\A.+\Z}, final]
\step[fieldset=keywords, fieldvalue={,hit}, append]
}
\map{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldset=keywords, fieldvalue={hit}]
}
}
}

\begin{document}
\nocite{*}
\printbibliography[keyword=hit]
\end{document}


Naturally

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldset=keywords, fieldvalue={,hit}, append]
}
}
}


would have been shorter, but that leaves an "empty keyword" in the .bbl if the keywords field was empty (\keyw{,hit}). This should not cause problems, but I consider this bad form.

If you are one of those people who are into the perverse habit of leaving fields empty as in keywords = {}, you need one further \map

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldsource=keywords, match=\regexp{\A.+\Z}, final]
\step[fieldset=keywords, fieldvalue={,hit}, append]
}
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldsource=keywords, notmatch=\regexp{.+}, final]
\step[fieldset=keywords, fieldvalue={hit}]
}
\map{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldset=keywords, fieldvalue={hit}]
}
}
}

• Ah, that's a more elegant way to add a keyword to a list! (+1) I used to append comma, append keyword, remove comma in first position. Worked, but not pretty. By the way, would you care to expand on the use of final in the source maps' steps? Even though I do not consider myself "uninitiated", the documentation on Source Maps eludes me to a large extent. And this is one of the pieces I lack. – gusbrs Mar 15 '18 at 14:31
• @gusbrs final stops execution of the entire "parent" \map (i.e. the \map the \step lives in) if the conditions for the current \step are not met. Otherwise the next step would be executed. Check out what happens in the MWE if final were not set in \step[fieldsource=author, match=\regexp{Muster}]. In particular final aborts the \step if a fieldsource is not defined or if no match is found. – moewe Mar 15 '18 at 14:40
• @gusbrs Mhhh, actually I quite like your idea of appending with a comma and then removing the leading comma. Do you want to make that an answer? – moewe Mar 15 '18 at 14:44
• If I get it correctly, if final was not present in \step[fieldsource=author, match=\regexp{Muster}] the keyword would be added to all entries. Is this correct? – gusbrs Mar 15 '18 at 14:47
• @gusbrs Exactly. Often you'll want final if you do sequential steps. But leaving away final allows you to put several unrelated \steps into the same \map. – moewe Mar 15 '18 at 14:52

This is a complement to moewe's answer, just providing an alternative method to add a keyword without overwriting existing ones. It is done by appending ,keyword to all entries of interest, irrespective of them being empty or not, and then removing and eventual leading comma, as the case may be.

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldset=keywords, fieldvalue={,hit}, append]
\step[fieldsource=keywords, match=\regexp{\A,}, replace={}]
}
}
}


A full MWE:

\documentclass{article}
\usepackage[backend=biber]{biblatex}

\usepackage{filecontents}
\begin{filecontents}{\jobname.bib}
@book{key,
author = {Max Muster},
maintitle = {Der Werktitel},
title = {Titel des zweiten Bandes},
volume = {2},
location = {Ort},
year = {2002},
keywords = {muster, etwas},
}
@book{keya,
author = {Max Muster},
maintitle = {Der Werktitel},
title = {Titel des Dritten Bandes},
volume = {3},
location = {Ort},
year = {2002},
}
@book{other,
author = {Michael Karomann},
maintitle = {Etwas},
title = {Nichts},
volume = {3},
location = {Ort},
year = {2002},
keywords = {test, etwas},
}
\end{filecontents}

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldset=keywords, fieldvalue={,hit}, append]
\step[fieldsource=keywords, match=\regexp{\A,}, replace={}]
}
}
}

\begin{document}
\nocite{*}
\printbibliography[keyword=hit]
\end{document}


Update: Still another method. If keyword field is not empty, append a comma. Then append keyword. (I tried to fit it in a single map, but couldn't, perhaps there's a way).

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldsource=keywords, match=\regexp{\A.+\Z}, final]
\step[fieldset=keywords, fieldvalue={,}, append]
}
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldset=keywords, fieldvalue={hit}, append]
}
}
}


Or shorter (by moewe):

\DeclareSourcemap{
\maps[datatype=bibtex]{
\map[overwrite]{
\step[fieldsource=author, match=\regexp{Muster}, final]
\step[fieldsource=keywords, match=\regexp{\A(.+)\Z}, replace=\regexp{$1,}] %$
\step[fieldset=keywords, fieldvalue={hit}, append]
}
}
}

• @moewe, added yet another method. – gusbrs Mar 16 '18 at 0:07
• AFAIK you can't get your second version into one map because you need the final in \step[fieldsource=keywords, match=\regexp{\A.+\Z}, final] you could try \step[fieldsource=keywords, match=\regexp{\A(.+)\Z}, replace=\regexp{,$1}] instead. I.e. only one \map with \step[fieldsource=author, match=\regexp{Muster}, final]\step[fieldsource=keywords, match=\regexp{\A(.+)\Z}, replace=\regexp{,$1}]\step[fieldset=keywords, fieldvalue={hit}, append] haven't tested that, though. – moewe Mar 16 '18 at 7:14
• @moewe, that does work! Incorporated it to the answer as well. Thanks! – gusbrs Mar 16 '18 at 10:02
• I must add, I like this last one specially. – gusbrs Mar 16 '18 at 10:26