1

In a document, I need to add many links via a biblatex entry with something like:

\NewDocumentCommand{\addLink}{O{}mm}{\href{#2}{#3}}

\addLink{https://en.wikipedia.org/}{Wikipedia}\cite{Wiki}

where the bib contains:

@online{Wiki,
    title        = {Wikipedia},
    author       = {Wikipedia},
    year         = 2024,
    url          = {https://en.wikipedia.org/},
}

But manually maintaining these two lists is quite expensive, and adding a bib entry for a simple link is quite annoying and hard to maintain. Would it be possible, somehow, to avoid this by creating automatically the entry in the \NewDocumentCommand? The year can be fixed to 2024 and the author could be equal to the title unless specified otherwise in the optional argument.

MWE:

\documentclass[]{article}

\begin{filecontents}[noheader,overwrite]{main.bib} @online{Wiki, title = {Wikipedia}, author = {Wikipedia}, year = 2024, url = {https://en.wikipedia.org/}, } \end{filecontents}

\usepackage[ style=alphabetic,% also minalphanames=3,maxalphanames=4, % [Foo+99] -> [FBB+99]. maxnames=99, % Do not put "et al". Sets maxbibnames, maxcitenames and maxsortnames. sortcites=true, %sorting=none, doi=false, url=false, giveninits=true, % Bob Foo --> B. Foo isbn=false, url=false, eprint=false, sortcites=false, % \cite{B,A,C}: [A,B,C] --> [B,A,C] %backref=true, % [1] Title, blabla --> [1] Title, blabla (pages 1, 45, 56) %% TODO: customize using https://tex.stackexchange.com/questions/36307/formatting-back-references-in-bibliography ]{biblatex} \addbibresource{main.bib}%

\NewDocumentCommand{\addLink}{O{}mm}{ \href{#2}{#3} } \usepackage{hyperref}

\begin{document}

You can go to \addLink{https://en.wikipedia.org/}{Wikipedia}\cite{Wiki}.

\printbibliography

\end{document}

EDIT I guess I can think of a solution that writes to a temporary file all entries, and that (maybe rename?) and loads this file at startup… but seems like quite a quite dirty solution. Is there a better one?

tobiasBora
  • 8,684
  • Not really related, but O{}mm means that you're allowing \addLink[first]{second}{third}. What's the point of first if you don't do anything with it? – Teepeemm Jan 22 '24 at 13:32
  • @Teepeemm sure, that is a placeholder for people answering, as I was saying "The year can be fixed to 2024 and the author could be equal to the title unless specified otherwise in the optional argument" – tobiasBora Jan 22 '24 at 15:37

2 Answers2

2

I don't think there is a fair chance of "injecting" the entry into biblatex's internals purely on the LaTeX side of things, not least because sorting has to be done by Biber.

So I think your best chance is to write to a temporary .bib file and \addbibresource that file. This can all be hidden from the user in helper macros as shown in my answer to Make specific author bold using biblatex.

For example you could try

\documentclass[]{article}

\usepackage[ style=alphabetic,% also minalphanames=3,maxalphanames=4, % [Foo+99] -> [FBB+99]. maxnames=99, % Do not put "et al". Sets maxbibnames, maxcitenames and maxsortnames. sortcites=true, %sorting=none, doi=false, url=false, giveninits=true, % Bob Foo --> B. Foo isbn=false, url=false, eprint=false, sortcites=false, % \cite{B,A,C}: [A,B,C] --> [B,A,C] ]{biblatex} \usepackage{hyperref}

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

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

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

\newcommand*{\tbblx@citeandwritetobib}[3]{% \stepcounter{tbblx@name}% \edef\tbblx@tmp@cite{% \noexpand\autocite{tbblx@name@\the\value{tbblx@name}}}% \tbblx@tmp@cite \immediate\write\tbblx@bibfile{% @online{tbblx@name@\the\value{tbblx@name}, author = {\unexpanded{#1}}, % title = {\unexpanded{#2}}, year = {2024}, url = {\unexpanded{#3}},}% }% }

\AtEndDocument{% \closeout\tbblx@bibfile}

\addbibresource{\tbblx@bibfile@name}

\NewDocumentCommand{\addLink}{O{#3}mm}{% \href{#2}{#3} \tbblx@citeandwritetobib{#1}{#3}{#2}% } \makeatother

\addbibresource{biblatex-examples.bib}

\begin{document}

You can go to \addLink{https://en.wikipedia.org/}{Wikipedia}. \cite{sigfridsson}

\printbibliography

\end{document}

This generates a helper file <jobname>-tblx.bib to which we write all .bib entries on the fly (via \tbblx@citeandwritetobib). In this example all entries are given entry key tbblx@name@<counter>, but you could of course change the code so that you could supply a useful entry key for later re-use. (At the moment you can't easily retrieve the entry key for a specific entry, because the specification said nothing about the entry key you want to use and arbitrary text like author, title or url are unsafe as and shouldn't be used for the entry key. That's also why at the moment \tbblx@citeandwritetobib issues an \autocite to the entry. If you make the entry key predictable, you can separate that out.) Apart from that we just need the usual bookkeeping of opening and closing the output file. (We need to close \AtEndDocument to ensure we can write at any time in the document.)

moewe
  • 175,683
  • Thanks a lot. I was hoping to be able to do it without, but seems like it is the only option. For reference, I managed to create dynamically an entry, but this only works inside the preamble… I created an issue here https://github.com/plk/biblatex/issues/1336 – tobiasBora Jan 24 '24 at 20:46
  • 1
    @tobiasBora I don't think the temporary .bib file is that dirty a solution. If sourcemaps could be used anywhere (as suggested in your feature request) that could be avoided, but it wouldn't result in anything that is more efficient in terms of LaTeX/Biber runs. If you didn't need sorting (and the other Biber features) you could try and inject the raw data of the entry only on the LaTeX side, but if you don't need all that, you might as well not use citations/the bibliography at all and just use end notes or some other much simpler construction. – moewe Jan 25 '24 at 07:07
  • I see. Actually, thanks for showing me the trick O{#3}, I wasn't aware that it was possible! – tobiasBora Jan 25 '24 at 09:13
  • Actually, I realized that I was getting weird behaviors when using only the counter (e.g. if you remove one entry, all entries are shifted without producing any error if you forget to rerun pdflatex). So I removed the counter, and generate the key using only the hash of the entries, as explained in my answer. Feel free to add it to yours if you want. – tobiasBora Feb 05 '24 at 13:21
0

Just to add to the answer of moewe, I realized that just using the counter was quite error prone (e.g. if I just remove one element, all entries will be shifted without any error if I forget to re-run biblatex).

So I'm using instead:

\usepackage{pdftexcmds}
\makeatletter
\def\tbblx@bibfile@name{\jobname -tblx.bib}
\newwrite\tbblx@bibfile
\immediate\openout\tbblx@bibfile=\tbblx@bibfile@name

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

\usepackage{pdftexcmds} \newcommand*{\tbblx@citeandwritetobib}[5]{% \edef\tbblx@name@entry{\pdf@mdfivesum{\detokenize{#1#2#3#4#5}}}%just the counter is not enough, as we might forget to run latexmk to regenerate the entries if one changes. Also, not adding the counter is better as it allows exactly identical entries to share the same line in the bibliography. \edef\tbblx@tmp@cite{% \noexpand\cite{tbblx@name@\tbblx@name@entry}}% \tbblx@tmp@cite \immediate\write\tbblx@bibfile{% @online{tbblx@name@\tbblx@name@entry, author = {\unexpanded{#1}}, % title = {\unexpanded{#2}}, year = {#4}, url = {\unexpanded{#3}} }% }% }

\AtEndDocument{% \closeout\tbblx@bibfile}

\addbibresource{\tbblx@bibfile@name}

\NewDocumentCommand{\mylinkCite}{O{{#3}}mO{#4}mO{2024}}{% \href{#2}{#4} \tbblx@citeandwritetobib{#1}{#3}{#2}{#5}{}% }

\makeatother

And I use it like: \mylinkCite[author, default to text]{link}[title, default to text]{text to write in pdf}[year (default 2024)]

Note also that biblatex does not plan to support this feature out of the box as it is too complicated to implement internally Biblatex: create a bib entry automatically from \addCitation{http://myurl}

tobiasBora
  • 8,684