0

I want a portable way to prepend/append text to any field of any item in the bibliography, which means that it has to go in biblatex.cfg which is a special file that is automatically read when using biblatex package.

biblatex.cfg (can't be generated with filecontents):

\ExecuteBibliographyOptions{sorting=nyt}
\DeclareSourcemap{
  \maps{
    \map[overwrite]{
      \step[fieldsource=url, final]
      % \step[fieldset=author, fieldvalue={|prepend|}, prepend]
      \step[fieldset=author, fieldvalue={|append|}, append] % That actually works
    }
  }
}

MWE (for lualatex):

\documentclass{article}

\begin{filecontents*}{example.bib}
@book{sometag,
  author = {author},
  title = {title},
  year = {year},
  url = {url},
}
\end{filecontents*}

\usepackage{biblatex}

\addbibresource{example.bib}

% I don't understand why it doesn't work but it's not portable anyway.
% \usepackage{xpatch}
% \xpretofieldformat{author}{|prepend|}{}{}
% \xapptofieldformat{author}{|append|}{}{}

\nocite{*}

\begin{document}
\printbibliography{}
\end{document}

Output:

output

Desired output:

desired output

4
  • Can you explain your use case in more detail? While the append in your example will work on a technical level, a prepend feature does not exist. But then author is a name list, which is parsed according to very specific rules, which means that appending text via a sourcemap may or may not have the desired effect.
    – moewe
    Commented Apr 6, 2023 at 16:12
  • My use case is a bit more complicated, but the main goal is to write text to the left of an author (i.e., whole cite text) but after the index. Because modifying the rules is probably very messy (I haven't done that yet). Although, I would also like to know how to append text so that I can do both (but right now I don't have to have this information).
    – Andrew15_5
    Commented Apr 6, 2023 at 16:25
  • What kind of text is that, though? On which "level" does it come in? I'm assuming it is not something that makes sense in the author field? In that case prepending or appending to the author field does not seem to be the most idiomatic solution. Most biblatex styles support a begentry bibmacro that is executed at the entry head. In theory you could redefine that to print some text. \renewbibmacro{begentry}{\printtext{Foo}}.
    – moewe
    Commented Apr 6, 2023 at 16:30
  • It's not a math mode text, just a normal text with no macros. \renewbibmacro indeed does work, thanks. But I need something that can be used in biblatex.cfg file (1). The condition should be checked too (2) (as in example). It would be nice to see a solution that can prepend & append text to any field, but yes, the author field just so happen to be at the beginning. Right now I just need a solution like \renewbibmacro but which also meets above criteria (1) and (2).
    – Andrew15_5
    Commented Apr 6, 2023 at 17:14

2 Answers 2

2

I don't think there is a general way to prepend and append to arbitrary fields in biblatex.

A sourcemap not dissimilar to the one shown in the question is the first thing I would think of as the most universal solution. While append exists (and will work as shown in your example*), there is no prepend, but such a feature could be emulated with regexp matching.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{biblatex}

\DeclareSourcemap{
  \maps{
    \map[overwrite]{
      \step[fieldsource=title,
            match=\regexp{\A(.*)\Z},
            replace=|pre text|$1|post text|]
    }
  }
}

\begin{filecontents*}{\jobname.bib}
@book{sometag,
  author = {author},
  title  = {title},
  year   = {2023},
  url    = {url},
}
\end{filecontents*}
\addbibresource{\jobname.bib}

\nocite{*}

\begin{document}
\printbibliography
\end{document}

author. |pre text|title|post text|. 2023. url: url.

For simple text like pre text and post text you can just use

replace=|pre text|$1|post text|

if you have more complex macros in there that are not expandable (or want to use some RegEx features), you are better off wrapping the text in \regexp, but then spaces are eaten by the normalisation, so you have to use \x{20} instead and the regex meaning of characters is active, which means you need to escape \ and the like

replace=\regexp{|pre\x{20}\\textbf{text}|$1|post\x{20}text|}

will produce

author. |pre text|title|post text|. 2023. url: url.

in the above example.

A sourcemap solution comes with drawbacks, however.

  • The text is added to the field when the .bib file is read. That means it influences sorting and all other .bib-data-based operations.

  • The text becomes part of the field, which means it will be formatted like the field. In the example the "pre" and "post" are also italicised.

  • For name list fields like author, the added text is parsed as part of the name. This may lead to extremely odd results as in

    \documentclass{article}
    \usepackage[T1]{fontenc}
    \usepackage{biblatex}
    
    \DeclareSourcemap{
      \maps{
        \map[overwrite]{
          \step[fieldsource=author,
                match=\regexp{\A(.*)\Z},
                replace=|pre|$1|post|]
        }
      }
    }
    
    \begin{filecontents*}{\jobname.bib}
    @book{sometag,
      author = {Jane Doe and Elk, Anne},
      title  = {title},
      year   = {2023},
      url    = {url},
    }
    \end{filecontents*}
    \addbibresource{\jobname.bib}
    
    \nocite{*}
    
    \begin{document}
    \printbibliography
    \end{document}
    

    |pre|Jane Doe and Anne|post| Elk. title. 2023. url: url.

    This is not something you can counter easily because you don't know how the names are formatted.

So for most intents and purposes the sourcemap is probably not going to cut it.

All other solutions, however, will be style-dependent to some degree.

  • All biblatex standard styles and almost all well-written third-party styles have a begentry and finentry bibmacro that is executed at the beginning and end of the entry, respectively. They can be redefined to print arbitrary text at that point. An example of begentry can be found in How to print shortauthor in the references as well?.

  • There are usually two ways a style can take to print text before or after a field. Depending on whether or not that text should be considered "part of the field output" one of these solutions might be more appropriate than the other.

    • Find out which bibmacro prints the field and insert the text before or after the relevant \printfield, \printlist or \printnames call. Obviously that is highly style-dependent.

    • Use field formats to add the text, e.g. \DeclareFieldFormat{title}{pre-#1-post}. This will overwrite what the style does and may only half-work as expected due to type-specific formatting (cf. Remove Quotation Marks from Style).

Everything discussed here can be used in biblatex.cfg, but obviously not all of the solutions work the same for all possible styles you would want to use.


In the end I think we can only give you a useful answer if you can describe your actual use case (or at least the motivation for asking this question) in more detail. The point of biblatex is to display your .bib data in format defined in the style you use. It's not to insert arbitrary text in there - unless that's what the style wants (but then you need to customise the specific style you want to use).


* The example does not work on my machine, because filecontents refuses to write out biblatex.cfg, since a global biblatex.cfg already exists. Apparently LaTeX thinks it would overwrite that file. If I generate the file with the shown contents manually, I get an error about prepend, but when I delete that line, the append works as expected.

2
  • Yeah, sorry about the example, the "prepend" & "append" lines are just out of my head (but append is working). And yes, biblatex.cfg can't be generated, unfortunately (that's why my screenshot isn't correct). I will correct my post. Thank you for your answer, a lot of useful information. But I have 2 problems: I can't add space inside \regexp{} when replacing (maybe there is a special macro for it?); if instead of biblatex.cfg \begentry is used then how to add the condition (e.g., field url is present)?
    – Andrew15_5
    Commented Apr 6, 2023 at 21:04
  • 1
    @Andrew15_5 Space can be added with \x{20}. On the biblatex side you can check if the URL is present with \iffieldundef{url}{<URL not present>}{<URL present>}, see tex.stackexchange.com/a/154872/35864.
    – moewe
    Commented Apr 7, 2023 at 4:43
0

I want to share my solution in case someone will have a similar problem.

In reality, I only need to prepend to the beginning of the item some text if the url field is present. But the selected answer apparently didn't fit my case. This is because some of my sources don't have an author field, and therefore the solution becomes much harder/bigger. Well, that is, if the solution isn't this one:

% Solution 1
\def\prepend{prepend} % Any text goes here

\renewbibmacro{begentry}{\iffieldundef{url}{}{\prepend\addspace}}

But, for example, this one:

I've found the definition of \newbibmacro*{author} and \newbibmacro*{title} in texlive/20*/texmf-dist/tex/latex/biblatex/biblatex.def (which appeared in logs):

\newbibmacro*{author}{%
  \ifboolexpr{
    test \ifuseauthor
    and
    not test {\ifnameundef{author}}
  }
    {\printnames{author}%
     \iffieldundef{authortype}
       {}
       {\setunit{\printdelim{authortypedelim}}%
        \usebibmacro{authorstrg}}}
    {}}
\newbibmacro*{title}{%
  \ifboolexpr{
    test {\iffieldundef{title}}
    and
    test {\iffieldundef{subtitle}}
  }
    {}
    {\printtext[title]{%
       \printfield[titlecase]{title}%
       \setunit{\subtitlepunct}%
       \printfield[titlecase]{subtitle}}%
     \newunit}%
  \printfield{titleaddon}}

Then I redefined (and reformatted) them like this:

% Solution 2
\def\prepend{prepend} % Any text goes here

\renewbibmacro*{author}{%
  \ifboolexpr{
    test \ifuseauthor
    and
    not test {\ifnameundef{author}}
  }{%
    \iffieldundef{url}{}{\prepend\addspace}%
    \printnames{author}%
    \iffieldundef{authortype}{}{%
      \setunit{\printdelim{authortypedelim}}%
      \usebibmacro{authorstrg}%
    }%
  }{}%
}

\renewbibmacro*{title}{%
  \ifboolexpr{
    test {\iffieldundef{title}}
    and
    test {\iffieldundef{subtitle}}
  }
  {}
  {%
    \ifboolexpr{% Simple \iffieldundef{author}{}{} didn't work in some cases
      test \ifuseauthor
      and
      not test {\ifnameundef{author}}
    }{}{%
      \iffieldundef{url}{}{\prepend\addspace}%
    }%
    \printtext[title]{%
      \printfield[titlecase]{title}%
      \setunit{\subtitlepunct}%
      \printfield[titlecase]{subtitle}%
    }%
    \newunit%
  }%
  \printfield{titleaddon}%
}

Now, even if author does not exist (but title does) then the \prepend text is added to the left.

@book{sometag1,
  author = {author1},
  title = {title1},
  year = {year1},
}
@book{sometag2,
  author = {author2},
  title = {title2},
  year = {year2},
  url = {url2},
}
@book{sometag3,
  author = {author3},
  title = {title3},
  year = {year3},
}
@book{sometag4,
  title = {title4},
  year = {year4},
}
@book{sometag5,
  title = {title5},
  year = {year5},
  url = {url5},
}

correct output

You must log in to answer this question.

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