45

The title is pretty self-explanatory. I need something similar to Add new field to biblatex entries, but for completely new entry types. (IIUC, the linked just shuffles one type onto another.)

I'm trying to define a @stackexchange type where I can cite StackExchange questions:

@stackexchange{se:l3help,
  sitekey = {tex},
  % sitetopic = {\TeX, \LaTeX, Con\TeX t, and related typesetting systems},
  askid   = {45838},
  title   = {What can \textit{I} do to help the \LaTeX3 Project},
  askdate = {2012/02/26}
}

where id must match the regexp [0-9]+, asked is a date, and sitekey provides a hard-coded mapping to the appropriate sitetopic when available. If sitekey isn't available, then sitetopic is required. If sitetopic is supplied, then it overwrites the mapping from sitekey. id, title, and asked are all required.

If there are any other fields you think should be included, feel free; I tried to pare down the data type only to the 'special' ones. I would hope that this Q can cover most of the bases for different ways fields can act.

MWE (Adapted per comments)

\begin{filecontents}{references.bib}
@stackexchange{se:l3help,
    sitetopic = {tex},
    title   = {What can \textit{I} do to help the \LaTeX3 Project},
    askdate = {2012/02/26},
    askid   = {45838},
    askp    = {Brent Longorough},
    askerid = 344,
    ansp    = {Frank Mittelbach},
    anspid  = 10109,
    ansdate = {2012/03/01},
    ansid   = 46427
  }
\end{filecontents}
\begin{filecontents}{stackexchange.dbx}
\DeclareDatamodelEntrytypes{stackexchange}
\DeclareDatamodelFields{
  sitekey,
  sitetopic,
  askdate,
  askedit,
  askid,
  askp,
  askpid,
  ansp,
  anspid,
  ansid,
  ansdate,
  ansedit}
\DeclareDatamodelEntryfields[stackexchange]{
  sitekey,
  sitetopic,
  askdate,
  askedit,
  askid,
  askp,
  askpid,
  ansp,
  anspid,
  ansid,
  ansdate,
  ansedit,
  title}
\end{filecontents}
\documentclass{article}

\usepackage{csquotes}
\usepackage[datamodel=stackexchange,backend=biber]{biblatex}
\addbibresource{references.bib}

\newbibmacro*{stackexchangequestion}{%
  \mkbibquote{\printfield{title}}
  \mkbibparens{\printfield{askid}}
  \addperiod
}

\newbibmacro*{stackexchangeask}{%
  Asked \mkbibdatelong{\printfield{askdate}}%
    \iffieldundef{askedit}{}{ \mkbibparens{edited \mkbibdatelong{\printfield{askedit}}}}%
  by
  \printfield{askp} \mkbibparens{\printfield{askpid}}
  \addperiod
}

\newbibmacro*{stackexchangeans}{%
  Answered \mkbibdatelong{\printfield{ansdate}}%
    \iffieldundef{ansedit}{}{ \mkbibparens{edited \mkbibdatelong{\printfield{ansedit}}}}%
  by
  \printfield{ansp} \mkbibparens{\printfield{anspid}}
  \addperiod
}

\newbibmacro*{stackexchangesite}{%
  \printfield{sitetopic}}

\DeclareBibliographyDriver{stackexchange}{%
  \usebibmacro{bibindex}%
  \usebibmacro{begentry}%
  \usebibmacro{stackexchangequestion}%
  \usebibmacro{stackexchangeask}%
  \usebibmacro{stackexchangeans}%
  \usebibmacro{stackexchangesite}%
  \usebibmacro{finentry}}

\begin{document}

\cite{se:l3help}

\printbibliography
\end{document}

Throws a Missing \endcsname error, likely caused by misuse of \usebibmacro.

Sean Allred
  • 27,421

1 Answers1

66

The answer is now updated for the date handling in newer biblatex versions >= 3.6, lots of what had to be done manually before will now be done automatically. Check the edit history for earlier versions.

This is quite a full-on question, but I will try to answer it anyway. This answer mainly deals with the bibliography output. For citations additional modifications and configurations might be necessary, but what needs to be done strongly depends on the used style, there is no universal answer. For numeric citation styles the example below will of course work without further modification.

Declare new fields, and the new entry types and their fields

First, when declaring the data model, we need to make sure biblatex actually knows the type of the fields/lists we declare (this is done via the optional argument to \DeclareDatamodelFields). You can read much more about this in §4.5.4 Data Model Specification, p. 212 of the biblatex documentation.

There are two main types for entry field: field and list. fields usually hold one value, while lists can hold more items separated by an and in the .bib file (see also §2.2.1 Data Types, p. 15).

I declared the sitekey and sitetopic to be literal fields (such as the title field). askp and ansp are clearly name lists (even though in this context the list will probably only ever hold one item). A lot of the fields you are asking for seem to revolve about dates, so there are askdate, ansdate, askeditdate, anseditdate and their dateparts (which will be created automatically, but they still need to be added to \DeclareDatamodelEntryfields manually). Finally, I decided the ids should be verbatim fields.

\begin{filecontents}{stackexchange.dbx}
\DeclareDatamodelEntrytypes{stackexchange}
\DeclareDatamodelFields[type=field,datatype=literal]{
  sitekey,
  sitetopic,
}
\DeclareDatamodelFields[type=list,datatype=name]{
  askp,
  ansp,
}
\DeclareDatamodelFields[type=field, datatype=date, skipout]{
  askdate,
  ansdate,
  askeditdate,
  anseditdate}
\DeclareDatamodelFields[type=field, datatype=verbatim]{
  askid,
  askpid,
  anspid,
  ansid,
}
\DeclareDatamodelEntryfields[stackexchange]{
  sitekey,
  sitetopic,
  askid,
  askp,
  askpid,
  ansp,
  anspid,
  ansid,
  askyear,
  askmonth,
  askday,
  ansyear,
  ansmonth,
  ansday,
  askedityear,
  askeditmonth,
  askeditday,
  ansedityear,
  anseditmonth,
  anseditday,
  title}
\end{filecontents}

The \DeclareDatamodelEntryfields just makes those fields relevant to @stackexchange known to that entry type.

Declare new bibliography strings (if necessary)

We also want to display words like 'asked' and 'answered', instead of hard-coding them, localisation with .lbx files is the way to go. This is only necessary if you wish to include strings in the output. It is not necessary to include a string for each field you define. The fact that the name of some bibstrings coincides with the name of some fields is purely accidental. There is no requirement to define bibstrings for certain field types.

The most complete way to define new strings is by means of an .lbx file, because that method allows you to define long and short forms of the strings. You can also define new strings directly in the preamble, but then you can only give one form that is used as short and long version.

Our new localisation file english-stack.lbx inherits everything from english.lbx but adds asked, answered and edited as bibstrings.

\begin{filecontents*}{english-stack.lbx}
  \ProvidesFile{english-stack.lbx}[2014/05/07 english with additions for stackexchange]
  \InheritBibliographyExtras{english}
  \NewBibliographyString{asked,answered,edited}
  \DeclareBibliographyStrings{%
    inherit   = {english},
    asked     = {{asked}{asked}},
    answered  = {{answered}{answered}},
    edited    = {{edited}{edited}},
  }
\end{filecontents*}

We have to tell biblatex to use that language definition

\DeclareLanguageMapping{english}{english-stack}

Defining the bibliography output

Then finally, we can go on to define the bibliography driver. The bibliography driver is the main definition that decides how the entry is printed in the bibliography. A bibliography driver typically consists of calls to several bibliography macros as well as calls to punctuation and printing commands.

Field formats

Field formats define the formatting of each printed field. We avoid hard-coding anything and use the macros provided by biblatex.

So instead of wrapping \printfield{title} in \mkbibquote, we define the field format to do so. We use \setunit for punctuation and \bibstrings in lieu of hard-coded words.

\DeclareFieldFormat[stackexchange]{title}{\mkbibquote{#1\isdot}}
\DeclareFieldFormat{askpid}{%
  \mkbibparens{\ifhyperref
    {\href{http://tex.stackexchange.com/users/#1}{\nolinkurl{#1}}}
    {\nolinkurl{#1}}}}

\DeclareFieldFormat{anspid}{% \mkbibparens{\ifhyperref {\href{http://tex.stackexchange.com/users/#1}{\nolinkurl{#1}}} {\nolinkurl{#1}}}}

\DeclareFieldFormat{askid}{% \mkbibparens{\ifhyperref {\href{http://tex.stackexchange.com/q/#1}{\nolinkurl{#1}}} {\nolinkurl{#1}}}}

\DeclareFieldFormat{ansid}{% \mkbibparens{\ifhyperref {\href{http://tex.stackexchange.com/a/#1}{\nolinkurl{#1}}} {\nolinkurl{#1}}}}

As an added bonus, the id fields now link to the proper stackexchange site.

\newbibmacro*{stackexchangequestion}{%
  \printfield{title}%
  \setunit{\addspace}%
  \printfield{askid}%
}

Bibliography macros

Bibliography macros can be used to compartmentalise the output definitions.

No formatting should be applied to the \printfield commands, formatting is dealt with by \DeclareFieldFormat.

\newbibmacro*{stackexchangeask}{%
  \bibstring{asked}%
  \setunit{\addspace}%
  \printaskdate%
  \iffieldundef{askedityear}%
    {}
    {\printtext[parens]{%
       \bibstring{edited}%
       \setunit{\addspace}%
       \printaskeditdate}}%
  \setunit{\addspace}%
  \bibstring{byauthor}%
  \setunit{\addspace}%
  \printnames{askp}%
  \setunit{\addspace}%
  \printfield{askpid}%
}

\newbibmacro*{stackexchangeans}{% \bibstring{answered}% \setunit{\addspace}% \printansdate% \iffieldundef{ansedityear} {} {\printtext[parens]{% \bibstring{edited}% \setunit{\addspace}% \printanseditdate}}% \setunit{\addspace}% \bibstring{byauthor}% \setunit{\addspace}% \printnames{ansp}% \setunit{\addspace}% \printfield{anspid}% }

\newbibmacro*{stackexchangesite}{% \printfield{sitetopic}}

Bibliography driver

The driver defines the final output structure. Usually a driver makes heavy use of bibmacros, but it need not do that.

\DeclareBibliographyDriver{stackexchange}{%
  \usebibmacro{bibindex}%
  \usebibmacro{begentry}%
  \usebibmacro{stackexchangequestion}%
  \newunit\newblock
  \usebibmacro{stackexchangeask}%
  \newunit\newblock
  \usebibmacro{stackexchangeans}%
  \newunit\newblock
  \usebibmacro{stackexchangesite}%
  \newunit\newblock
  \usebibmacro{finentry}}

MWE

\RequirePackage{filecontents}
\begin{filecontents*}{\jobname.bib}
@stackexchange{se:l3help,
  sitetopic = {tex},
  title   = {What can \textit{I} do to help the \LaTeX3 Project},
  askdate = {2012-02-26},
  askid   = {45838},
  askp    = {Brent Longorough},
  askpid  = {344},
  ansp    = {Frank Mittelbach},
  anspid  = {10109},
  ansdate = {2012-03-01},
  ansid   = {46427},
}
\end{filecontents*}
\begin{filecontents}{stackexchange.dbx}
\DeclareDatamodelEntrytypes{stackexchange}
\DeclareDatamodelFields[type=field,datatype=literal]{
  sitekey,
  sitetopic,
}
\DeclareDatamodelFields[type=list,datatype=name]{
  askp,
  ansp,
}
\DeclareDatamodelFields[type=field, datatype=date, skipout]{
  askdate,
  ansdate,
  askeditdate,
  anseditdate}
\DeclareDatamodelFields[type=field, datatype=verbatim]{
  askid,
  askpid,
  anspid,
  ansid,
}
\DeclareDatamodelEntryfields[stackexchange]{
  sitekey,
  sitetopic,
  askid,
  askp,
  askpid,
  ansp,
  anspid,
  ansid,
  askyear,
  askmonth,
  askday,
  ansyear,
  ansmonth,
  ansday,
  askedityear,
  askeditmonth,
  askeditday,
  ansedityear,
  anseditmonth,
  anseditday,
  title}
\end{filecontents}
\documentclass[english]{article}
\usepackage{babel}
\usepackage{csquotes}
\usepackage[datamodel=stackexchange,backend=biber]{biblatex}
\usepackage{hyperref}
\addbibresource{\jobname.bib}

\begin{filecontents}{english-stack.lbx} \ProvidesFile{english-stack.lbx}[2014/05/07 english with additions for stackexchange] \InheritBibliographyExtras{english} \NewBibliographyString{asked,answered,edited} \DeclareBibliographyStrings{% inherit = {english}, asked = {{asked}{asked}}, answered = {{answered}{answered}}, edited = {{edited}{edited}}, } \end{filecontents} \DeclareLanguageMapping{english}{english-stack}

\DeclareFieldFormat[stackexchange]{title}{\mkbibquote{#1\isdot}} \DeclareFieldFormat{askpid}{% \mkbibparens{\ifhyperref {\href{http://tex.stackexchange.com/users/#1}{\nolinkurl{#1}}} {\nolinkurl{#1}}}}

\DeclareFieldFormat{anspid}{% \mkbibparens{\ifhyperref {\href{http://tex.stackexchange.com/users/#1}{\nolinkurl{#1}}} {\nolinkurl{#1}}}}

\DeclareFieldFormat{askid}{% \mkbibparens{\ifhyperref {\href{http://tex.stackexchange.com/q/#1}{\nolinkurl{#1}}} {\nolinkurl{#1}}}}

\DeclareFieldFormat{ansid}{% \mkbibparens{\ifhyperref {\href{http://tex.stackexchange.com/a/#1}{\nolinkurl{#1}}} {\nolinkurl{#1}}}}

\newbibmacro*{stackexchangequestion}{% \printfield{title}% \setunit{\addspace}% \printfield{askid}% }

\newbibmacro*{stackexchangeask}{% \bibstring{asked}% \setunit{\addspace}% \printaskdate% \iffieldundef{askedityear}% {} {\printtext[parens]{% \bibstring{edited}% \setunit{\addspace}% \printaskeditdate}}% \setunit{\addspace}% \bibstring{byauthor}% \setunit{\addspace}% \printnames{askp}% \setunit{\addspace}% \printfield{askpid}% }

\newbibmacro*{stackexchangeans}{% \bibstring{answered}% \setunit{\addspace}% \printansdate% \iffieldundef{ansedityear} {} {\printtext[parens]{% \bibstring{edited}% \setunit{\addspace}% \printanseditdate}}% \setunit{\addspace}% \bibstring{byauthor}% \setunit{\addspace}% \printnames{ansp}% \setunit{\addspace}% \printfield{anspid}% }

\newbibmacro*{stackexchangesite}{% \printfield{sitetopic}}

\DeclareBibliographyDriver{stackexchange}{% \usebibmacro{bibindex}% \usebibmacro{begentry}% \usebibmacro{stackexchangequestion}% \newunit\newblock \usebibmacro{stackexchangeask}% \newunit\newblock \usebibmacro{stackexchangeans}% \newunit\newblock \usebibmacro{stackexchangesite}% \newunit\newblock \usebibmacro{finentry}}

\begin{document} \nocite{*} \cite{se:l3help}

\printbibliography \end{document}

enter image description here


To allow the use of askdate as labeldate, so the authoryear style (and other similar ones) does not print 'n.d.', we can use \DeclareLabeldate (§4.5.11 Special Fields, p. 238) as follows

\DeclareLabeldate{%
  \field{date}
  \field{eventdate}
  \field{origdate}
  \field{askdate}
  \field{urldate}
  \literal{nodate}
}

There also is \DeclareLabelname (p. 238) with a similar syntax, if you want to see either askp or ansp as the author in authoryear/authortitle styles.

Stewart
  • 703
moewe
  • 175,683
  • 9
    Very nice, and very complete answer (I knew I should refrain). I would've had to steal the code too; but it probably would've taken me much longer to get everything in place. – jon May 07 '14 at 18:18
  • 8
    This is an absolutely fantastic answer, so first and foremost I want to thank you. That said, when using an authoryear style, the citation engine determines that there is no date: ... Project n.d.. Is there a way to map the askdate onto this field (which I'm presuming would be date)? – Sean Allred May 08 '14 at 03:08
  • @SeanAllred Have a look at the edited answer. With biblatex we can explicitly choose which date fields are considered for the labeldate with \DeclareLabeldate. – moewe May 08 '14 at 05:15
  • Naive question: could this be packaged and put on CTAN? (There are some explicitly tex.s in there; on purpose?) – Raphael Sep 18 '15 at 06:56
  • 1
    @Raphael There is precedence of a package on CTAN that just enables use of certain entry types: biblatex-bookinarticle. Maïeul Rouquette has also brought other packages to CTAN that only enable certain additional features and do not constitute a style in their own right. If you are talking about the tex.s in the URLs then they were on purpose, but that could probably be automated using the sitetopic field. – moewe Sep 18 '15 at 07:04
  • @PLK Am I right in thinking that one still has to define the dateparts separately? (See Biblatex: Custom date fields) – moewe Mar 09 '16 at 07:52
  • Currently yes, but I think I'll automate that too shortly. – PLK Mar 09 '16 at 16:29
  • @moewe Can you tell me if–apart from a minimized .bbl file–there is an advantage using skipout? – Thorsten Apr 03 '16 at 09:37
  • @Thorsten That is the standard way, date fields are defined in biblatex. I don't think it would do any harm not to skipout the date entries (I didn't actually check), but it won't do biblatex any good either since all the necessary information is already in the .bbl. Note that the date field handling will be made easier in the upcoming biblatex 3.4 (see PLK's comments above). Is there any specific reason you ask? Do you want to not skipout the date fields in the .bbl? – moewe Apr 03 '16 at 10:04
  • @Thorsten I suppose (I can't be certain) that that is done because the date is read from the datepart fields year, month, day from the .bbl and that it would only introduce redundancy to write an additional date to the .bbl. The date as written to the .bib is parsed by Biber and passed on to the .bbl in a form that is easy to digest. – moewe Apr 03 '16 at 14:36
  • Impressive but I guess it is not worth adapting and taking so much work for my use case. Sadly I think it is faster to just rename my custom field to @misc entries. – Caleb Stanford Feb 05 '20 at 20:48
  • This is a great answer and just goes to show that vote count is no guide to quality: this deserves to have garnered far more votes in the years it has been here. May I ask if there is any advantage to using custom fields for things like dates and names? It's evident from existing entry types that different entries can share fields, so I'm wondering why askdate rather than date? Or askp rather than author (but maybe that's just because we have askp and ansp?) – cfr Dec 18 '23 at 05:37
  • 1
    @cfr I think I used askdate/ansdate and askp/ansp because the example in the question used them. But I also think that if you want question and answer in one entry it makes sense to avoid something as generic as author or date, because it's not entirely clear if the field refers to the question or the answer. You can definitely use existing fields and depending on the use case that may be more sensible than defining a new field with a new name. (For more usual bibliography entries I'd expect you can actually reuse a lot of fields and one define a couple of new ones.) – moewe Dec 18 '23 at 06:39