biblatex/biber“设置”的附加字段

biblatex/biber“设置”的附加字段

我想扩展条目类型setbiblatex容纳更多字段 - 但到目前为止我还没有让它发挥作用。

考虑一下:您有一系列书籍,所有书籍的作者和主标题相同,每卷都有单独的标题,并且应以集合的方式引用它们(例如 1a、1b、...)。标准biblatex/biber设置导致

在此处输入图片描述

这不是期望的结果。

因此添加一个新字段,mastertitle例如

\DeclareDatamodelFields[type=field, datatype=literal]{mastertitle}
\DeclareDatamodelEntryfields{mastertitle}

\DeclareSourcemap{
  \maps[datatype=bibtex]{
    \map{
      \pertype{set}
      \step[fieldsource=maintitle]
    }
    \map{
      \step[fieldsource=mastertitle]
    }
  }
}

没什么大不了的 - 除了它没有出现在 bibers 的集合输出中:

\entry{A}{set}{}
  \set{A1,A2,A3}
  \field{sortinit}{G}
  \field{sortinithash}{5e8d2bf9d38de41b1528bd307546008f}
\endentry

我想删除每个集合条目的作者和主标题,并通过 bib 文件中的定义将其放在整个列表的前面,以获得如下内容:

在此处输入图片描述

以下是我的基本问题:

  1. 我如何获取 bibers 条目输出的附加信息set
  2. 如何删除集合条目中的作者和标题,但不删除其他书籍中的作者和标题?
  3. 我如何按数量对子条目进行排序?

谢谢...

梅威瑟:

\documentclass{article}
\usepackage[ansinew]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[babel,german=quotes]{csquotes}
% ... with hq fonts...
\usepackage[T1]{fontenc}
\usepackage{lmodern}

\begin{filecontents*}{\jobname.bib}
@Set{A,
  entryset    = {A1,A2,A3},
  author      = {René Goscinny and Albert Uderzo},
  title       = {Asterix und Obelix},
  maintitle   = {Asterix und Obelix},
  mastertitle = {-0-},
}

@Book{A1,
  author      = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  title       = {Asterix der Gallier},
  year        = {1959},
  volume      = {1},
  isbn        = {9783770400010},
}

@Book{A2,
  author      = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  title       = {Asterix und Kleopatra},
  year        = {1968},
  volume      = {2},
  isbn        = {9783770400027},
}

@Book{A3,
  author      = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  title       = {Asterix als Gladiator},
  year        = {1969},
  volume      = {3},
  isbn        = {9783770436033},
}

@Book{A4,
  author      = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  title       = {Der Kampf der Häuptlinge},
  year        = {1969},
  volume      = {4},
  isbn        = {9783770436040},
}
\end{filecontents*}
% write dbx
\begin{filecontents*}{xset.dbx}
  \DeclareDatamodelFields[type=field, datatype=literal]{mastertitle}
  \DeclareDatamodelEntryfields{mastertitle}
\end{filecontents*}
% load biblatex

\usepackage[doi=false,defernumbers=true,backend=biber,subentry,sorting=nyt,sortsets=true,style=numeric-comp,datamodel=xset]{biblatex}
\usepackage{xpatch}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% add maintitle to set type
\DeclareSourcemap{
  \maps[datatype=bibtex]{
    \map{
      \pertype{set}
      \step[fieldsource=maintitle]
    }
    \map{
      \step[fieldsource=mastertitle]
    }
  }
}
% newline per set entry
\renewcommand{\entrysetpunct}{\par\nobreak}
% patch entryset
\xpatchbibdriver{set}
  {\entryset}
  {\iffieldundef{author}{}{\printfield{author}}%
   \iffieldundef{maintitle}{\iffieldundef{mastertitle}{}{\printfield{mastertitle}\par}}{\printfield{maintitle}\par}\entryset}
  {}{\errmessage{failed to add maintitle to set driver}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% bib data
\addbibresource{\jobname.bib}
%
\begin{document}
Asterix\supercite{A1,A2} und Obelix\supercite{A3,A4} und Idefix\supercite{A}.
\printbibliography
\end{document}

答案1

感谢 moewe 在他的第一条评论中,我再次尝试深入挖掘biblatex.stystandard.bbx

解决方案如下:

1)biber将命令分配\inset{<setkey>}给集合中的每个条目。使用它来定义可用的biblatex字段:\abx@field@entrykey

\makeatletter
\def\thisentrykey{\abx@field@entrykey}
\makeatother

2) 由于\abx@field@entrykey保存了 citekey,@set我们可以从子条目中读取字段(如果键命名约定一致)并在@set驱动程序中使用它们:

\xpatchbibdriver{set}
  {\entryset} % https://tex.stackexchange.com/a/387849/118739
  {\citeauthorfirstlast{\thisentrykey\subkeydelim}. \textit{\citefield{\thisentrykey\subkeydelim}{maintitle}.}\par\entryset}
  {}{\errmessage{failed to add maintitle to set driver}}

3)重新定义书籍的书目驱动程序,仅当条目不属于以下内容时才打印名称和标题@set

\DeclareBibliographyDriver{book}{%
  \usebibmacro{bibindex}%
  \usebibmacro{begentry}%
    \iffieldundef{entrysetcount}% modification start
      {%\errmessage{book not in set}
        \usebibmacro{author/editor+others/translator+others}%
     \setunit{\printdelim{nametitledelim}}\newblock
     \usebibmacro{maintitle+title}}
      {%\errmessage{book only in set}
        \iffieldundef{volume}{}{\printfield{volume}}
     \usebibmacro{title}}%      moodification end
  \newunit
  \printlist{language}%
  [...]

结果:

在此处输入图片描述

将其适应于其他书目驱动程序应该不是什么大问题......

完整代码如下:

\documentclass{article}
\usepackage[ansinew]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[babel,german=quotes]{csquotes}
% ... with hq fonts...
\usepackage[T1]{fontenc}
\usepackage{lmodern}

\begin{filecontents*}{\jobname.bib}
@Set{A,
  entryset    = {A:V1,A:V2,A:V3},
  author      = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix der Gallier},
}

@Book{A:V1,
  author      = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  title       = {Asterix der Gallier},
  sorttitle   = {Asterix und Obelix 01},
  year        = {1959},
  volume      = {1},
  isbn        = {9783770400010},
}

@Book{A:V2,
  author      = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  title       = {Asterix und Kleopatra},
  sorttitle   = {Asterix und Obelix 02},
  year        = {1968},
  volume      = {2},
  isbn        = {9783770400027},
}

@Book{A:V3,
  author      = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  title       = {Asterix als Gladiator},
  sorttitle   = {Asterix und Obelix 03},
  year        = {1969},
  volume      = {3},
  isbn        = {9783770436033},
}

@Book{A:V4,
  author      = {René Goscinny and Albert Uderzo},
  maintitle   = {Asterix und Obelix},
  title       = {Der Kampf der Häuptlinge},
  year        = {1969},
  volume      = {4},
  isbn        = {9783770436040},
}

@Set{B,
  entryset    = {B:V1,B:V2,B:V3},
  author      = {Max Muster und Theresa Test},
  maintitle   = {Der Gallier Asterix},
}

@Book{B:V1,
  author      = {Max Muster und Theresa Test},
  maintitle   = {Der Gallier Asterix},
  title       = {Asterix der Gallier},
  sorttitle   = {Asterix und Obelix 01},
  year        = {1989},
  volume      = {1},
  isbn        = {9783770400010},
}

@Book{B:V2,
  author      = {Max Muster und Theresa Test},
  maintitle   = {Der Gallier Asterix},
  title       = {Asterix und Kleopatra},
  sorttitle   = {Asterix und Obelix 02},
  year        = {1998},
  volume      = {2},
  isbn        = {9783770400027},
}

@Book{B:V3,
  author      = {Max Muster und Theresa Test},
  maintitle   = {Der Gallier Asterix},
  title       = {Asterix als Gladiator},
  sorttitle   = {Asterix und Obelix 03},
  year        = {1999},
  volume      = {3},
  isbn        = {9783770436033},
}

@Book{B:V4,
  author      = {Max Muster und Theresa Test},
  maintitle   = {Der Gallier Asterix},
  title       = {Der Kampf der Häuptlinge},
  year        = {1999},
  volume      = {4},
  isbn        = {9783770436040},
}
\end{filecontents*}
% load biblatex
\usepackage[doi=false,defernumbers=true,backend=biber,subentry,sorting=nyt,sortsets=true,style=numeric-comp]{biblatex}
\usepackage{xpatch}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\DeclareBibliographyDriver{book}{%
  \usebibmacro{bibindex}%
  \usebibmacro{begentry}%
    \iffieldundef{entrysetcount}% modification start
      {%\errmessage{book not in set}
        \usebibmacro{author/editor+others/translator+others}%
     \setunit{\printdelim{nametitledelim}}\newblock
     \usebibmacro{maintitle+title}}
      {%\errmessage{book only in set}
        \iffieldundef{volume}{}{\printfield{volume}}
        \usebibmacro{title}}%      moodification end
  \newunit
  \printlist{language}%
  \newunit\newblock
  \usebibmacro{byauthor}%
  \newunit\newblock
  \usebibmacro{byeditor+others}%
  \newunit\newblock
  \printfield{edition}%
  \newunit
  \iffieldundef{maintitle}
    {\printfield{volume}%
     \printfield{part}}
    {}%
  \newunit
  \printfield{volumes}%
  \newunit\newblock
  \usebibmacro{series+number}%
  \newunit\newblock
  \printfield{note}%
  \newunit\newblock
  \usebibmacro{publisher+location+date}%
  \newunit\newblock
  \usebibmacro{chapter+pages}%
  \newunit
  \printfield{pagetotal}%
  \newunit\newblock
  \iftoggle{bbx:isbn}
    {\printfield{isbn}}
    {}%
  \newunit\newblock
  \usebibmacro{doi+eprint+url}%
  \newunit\newblock
  \usebibmacro{addendum+pubstate}%
  \setunit{\bibpagerefpunct}\newblock
  \usebibmacro{pageref}%
  \newunit\newblock
    \iftoggle{bbx:related}
    {\usebibmacro{related:init}%
     \usebibmacro{related}}
    {}%
  \usebibmacro{finentry}}
%
% newline per set entry
\renewcommand{\entrysetpunct}{\par\nobreak}
%
% subentry naming convention
\def\subkeydelim{:V1}
%
% https://tex.stackexchange.com/a/73819/118739
\DeclareCiteCommand{\citeauthorfirstlast}
  {\boolfalse{citetracker}%
   \boolfalse{pagetracker}%
   \DeclareNameAlias{labelname}{first-last}%
   \usebibmacro{prenote}}
  {\ifciteindex
     {\indexnames{labelname}}
     {}%
   \printnames{labelname}}
  {\multicitedelim}
  {\usebibmacro{postnote}}
%
% access to own key and key delimiter
\makeatletter
\def\thisentrykey{\abx@field@entrykey}
\makeatother
%
% patch entryset
\xpatchbibdriver{set}
  {\entryset} % https://tex.stackexchange.com/a/387849/118739
  {\citeauthorfirstlast{\thisentrykey\subkeydelim}. \textit{\citefield{\thisentrykey\subkeydelim}{maintitle}.}\par\entryset}
  {}{\errmessage{failed to add maintitle to set driver}}
\DeclareFieldFormat{bibentrysetcount}{\makebox[15pt][l]{\mknumalph{#1})}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% bib data
\addbibresource{\jobname.bib}
%
\begin{document}
Asterix\supercite{A:V1,A:V2} und Obelix\supercite{A:V3,A:V4} und Idefix\supercite{A}.

Asterix\supercite{B:V1,B:V2} und Obelix\supercite{B:V3,B:V4} und Idefix\supercite{B}.
\printbibliography
\end{document}

答案2

我再次回答我自己的问题,因为我认为这是一个进步并且具有相当大的潜力......

经过一番尝试,我想出了一个解决方案,它从第一个条目集 ID 读取数据,从其他集合成员中添加缺失数据并进行一些完整性检查。收集数据后(收集什么数据实际上取决于用户),它会打印以下参考书目:

在此处输入图片描述

我必须承认,与第一个答案相比,它看起来非常相似 - 但只更改了一行代码(第 291 行)

\DeclareXsetOptions{ ontop = {url} }

\DeclareXsetOptions{ nottop = {maintitle} }

结果是

在此处输入图片描述

与 biblatex 的默认输出相比

在此处输入图片描述

在 MWE 中,set 驱动程序被修补以表示 biblatex 书籍中的公共数据;一个有用的扩展是根据集合内组合的条目类型来决定打印什么(\strfield{entrytype})。这是代码:

\documentclass{article}
\usepackage[ansinew]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[babel,german=quotes]{csquotes}
\usepackage[doi=false,defernumbers=true,backend=biber,subentry,sorting=nyt,sortsets=true,style=numeric-comp,datamodel=xset]{biblatex}
\usepackage{xpatch}

\newlinechar=`\^^J

\makeatletter
%%% test bib file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{filecontents}{\jobname.bib}
@Set{A,
  entryset    = {A:V1,A:V2,A:V3,A:V4,A:V5},
}

@Book{A:V1,
  author      = {René Goscinny and Albert Uderzo},  title       = {Asterix der Gallier},
  maintitle   = {Asterix und Obelix},               sorttitle   = {Asterix und Obelix 01},
  year        = {1959},                             isbn        = {1234567890123},
  publisher   = {Dargaud},                          location    = {Paris},
  volume      = {1},
}

@Book{A:V2,
  author      = {René Goscinny and Albert Uderzo},  title       = {Asterix und Kleopatra},
  maintitle   = {Asterix und Obelix},               sorttitle   = {Asterix und Obelix 02},
  year        = {1968},                             isbn        = {2345678901234},
  publisher   = {Dargaud},                          location    = {Paris},
  volume      = {2},
}

@Book{A:V3,
  author      = {René Goscinny and Albert Uderzo},  title       = {Asterix als Gladiator},
  maintitle   = {Asterix und Obelix},               sorttitle   = {Asterix und Obelix 03},
  year        = {1969},                             isbn        = {3456789012345},
  publisher   = {Dargaud},                          location    = {Paris},
  volume      = {3},
}

@Book{A:V4,
  author      = {René Goscinny and Albert Uderzo},  title       = {Der Kampf der Häuptlinge},
  maintitle   = {Asterix und Obelix},               sorttitle   = {Asterix und Obelix 04},
  year        = {1969},                             isbn        = {4567890123456},
  publisher   = {Dargaud},                          location    = {Paris},
  volume      = {4},
}

@Book{A:V5,
  author      = {René Goscinny and Albert Uderzo},  title       = {Die goldene Sichel},
  maintitle   = {Asterix und Obelix},               sorttitle   = {Asterix und Obelix 05},
  year        = {1970},                             isbn        = {5678901234567},
  publisher   = {Ehapa-Verlag},                     location    = {Berlin},
  volume      = {5},
}

@Book{A:VX,
  author      = {René Goscinny and Albert Uderzo},  title       = {Tour de France},
  maintitle   = {Asterix und Obelix},               sorttitle   = {Asterix und Obelix 06},
  year        = {1970},                             isbn        = {6789012345678},
  publisher   = {Ehapa-Verlag},                     location    = {Berlin},
  volume      = {6},
}

@Book{DHS:nik,
  editor    = {{Deutsche Hauptstelle für Suchtfragen e.~V.}},
  title     = {Tabakabhängigkeit},
  year      = {2017},
  url       = {www.dhs.de},
  urldate   = {2018-04-30},
  isbn      = {978-3-937587-00-4},
  maintitle = {Suchtmedizinische Reihe},
  sorttitle = {Suchtmedizinische Reihe 01},
  volume    = {1},
}

@Book{DHS:alk,
  editor    = {{Deutsche Hauptstelle für Suchtfragen e.~V.}},
  title     = {Alkoholabhängigkeit},
  year      = {2017},
  url       = {www.dhs.de},
  urldate   = {2018-04-30},
  isbn      = {978-3-937587-01-1},
  maintitle = {Suchtmedizinische Reihe},
  sorttitle = {Suchtmedizinische Reihe 02},
  volume    = {2},
}

@Book{DHS:drogen,
  editor    = {{Deutsche Hauptstelle für Suchtfragen e.~V.}},
  title     = {Drogenabhängigkeit},
  year      = {2017},
  url       = {www.dhs.de},
  urldate   = {2018-11-11},
  isbn      = {978-3-937587-03-5},
  maintitle = {Suchtmedizinische Reihe},
  sorttitle = {Suchtmedizinische Reihe 04},
  volume    = {4},
}

@Set{DHS:SMR,
  entryset  = {DHS:alk,DHS:nik,DHS:drogen},
}
\end{filecontents}

%%% tools part - tools & gimmiks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\xset@killfirst}[1]{}
\long\def\@noneofthree#1#2#3{}
\long\def\@firstofthree#1#2#3{#1}
\long\def\@secondofthree#1#2#3{#2}
\long\def\@thirdofthree#1#2#3{#3}% Is defined in `latex.ltx` already as \@threeofthree
\global\let\xset@message\message% message handler

% missing biblatex macros:
% {<field>}{<csname>}
\protected\def\blx@imc@restorefieldcs#1{\csletcs{abx@field@#1}}
% {<name>}{<csname>}
\protected\def\blx@imc@restorenamecs#1{\csletcs{abx@name@#1}}
% {<list>}{<csname>}
\protected\def\blx@imc@restorelistcs#1{\csletcs{abx@list@#1}}
% update biblatex
\blx@regimcs{\restorefieldcs \restorenamecs \restorelistcs}

% missing etoolbox macros:
\def\iftoggleexists#1{\ifcsdef{etb@tgl@#1}{\@firstoftwo}{\@secondoftwo}}
%\def\removetoggle#1{\iftoggleexists{#1}{\cslet{etb@tgl@#1}{\undefined}{}}}

%%% keyval part - the options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% register given field|names|lists denotifier in a etoolbox-list
\newcommand{\xset@savetolist}[2]{% <list> {<item>,...,<item>}
  \renewcommand{\do}[1]{\ifinlist{##1}{#1}%
    {\xset@message{^^Jxset Warning: Option value ##1 already in dataname list - skipping^^J}}%
    {\listadd{#1}{##1}}}\docsvlist{#2}}
% remove given field|names|lists denotifier from a etoolbox-list
\newcommand{\xset@removefromlist}[2]{% <list> {<item>,...,<item>}
  \renewcommand{\do}[1]{\ifinlist{##1}{#1}%
    {\listremove{#1}{##1}}%
    {\xset@message{^^Jxset Warning: Option value ##1 not found in dataname list - skipping^^J}}}\docsvlist{#2}}

% userside
\newcommand{\DeclareXsetOptions}[1]{\setkeys{xset@opt}{#1}}

% keys
\define@key{xset@opt}{ontop}{\xset@savetolist{\xset@opt@ontop}{#1}}
\define@key{xset@opt}{nottop}{\xset@removefromlist{\xset@opt@ontop}{#1}}
\define@key{xset@opt}{unhide}{\xset@savetolist{\xset@opt@unhide}{#1}}
\define@key{xset@opt}{info}{\ifstrequal{#1}{silent}{\let\xset@message\xset@killfirst\message{^^Jxset Info: Running in silent mode.^^J}}%
                           {\ifstrequal{#1}{warning}{\let\xset@message\message}%
                             {\let\xset@message\message\xset@message{^^Jxset Warning: Unknon option for info. Use 'silent' or 'warning', not '#1'.}}}}

% basic lists empty
\def\xset@opt@ontop{}
\def\xset@opt@unhide{}

% defaults
\DeclareXsetOptions{  info =  warning,
                     ontop = {author,editor,maintitle,year},
                     ontop = {yearmin,yearmax},% administraional - don't remove
                    unhide =  year }

\providetoggle{xset@patcherror}% safetybreak
\providetoggle{xset@hide@@year}% yearspan hack

%%% bibliography part - manipulating sets %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% step 1: patch the new set driver
% patch entryset
\xpatchbibdriver{set}
  {\entryset}% https://tex.stackexchange.com/a/387849/118739
  {\xsetParseSet%
     \usebibmacro{author/editor+others/translator+others}%
     \iffieldundef{maintitle}{}%
       {\setunit{\printdelim{nametitledelim}}\newblock%
        \usebibmacro{maintitle+title}}%
     \iffieldundef{yearmin}{}%
       {\newunit\newblock\ifnum\numexpr\strfield{yearmin}<\numexpr\strfield{yearmax}%
          \printfield{yearmin}--\printfield{yearmax}\global\togglefalse{xset@hide@@year}\else%
          \printfield{yearmin}\global\toggletrue{xset@hide@@year}\fi% all same year - hide
          \global\undef{\xset@savedmin@year}\global\undef{\xset@savedmax@year}% make cleanup a bit quicker...
       }%
     \iffieldundef{url}{}{\newunit\newblock\printfield{url}}%
     \par\entryset}%
  {}{\errmessage{xset error: unable to apply entryset-patch to set driver}\toggletrue{xset@patcherror}}% can not be overwritten: major error

% patch finentry
\xpatchbibdriver{set}
  {\finentry}% https://tex.stackexchange.com/a/387849/118739
  {\xset@cleanup\finentry}%
  {}{\errmessage{xset error: unable to apply finentry-patch to set driver}\toggletrue{xset@patcherror}}% can not be overwritten: major error

\newcommand{\xset@usehideflags@i}[2]{% execute toggle based data deletion
  \iftoggleexists{#1}{\iftoggle{#1}{\clearfield{#2}\clearname{#2}\clearlist{#2}}{}}{}}% brute force
\newcommand{\xset@usehideflags}{%
  \renewcommand{\do}[1]{\edef\xset@tempa{xset@hide@\strfield{entrykey}@##1}%
    \expandafter\xset@usehideflags@i\expandafter{\xset@tempa}{##1}}%
  \dolistloop{\xset@opt@ontop}%
  \xset@usehideflags@i{xset@hide@@year}{year}% don't forget the manipulated year toggle
  }

\newcommand{\xset@modifyusebibmacros}{%
\renewbibmacro*{maintitle+title}{%
  \iffieldundef{maintitle}%
    {\iffieldundef{volume}%
       {}%
       {\printfield{volume}%
        \printfield{part}%
        \setunit{\addcolon\space}}%
    }%
    {\usebibmacro{maintitle}%
     \newunit\newblock%
     \iffieldundef{volume}%
       {}%
       {\printfield{volume}%
        \printfield{part}%
        \setunit{\addcolon\space}}}%
  \usebibmacro{title}\newunit%
  \clearfield{volume}\clearfield{part}}%
}

% step 2: patch the entry drivers
\renewcommand{\do}[1]{\xpatchbibdriver{#1}%
  {\usebibmacro{begentry}}%
  {\usebibmacro{begentry}\xset@usehideflags\xset@modifyusebibmacros}%
  {}{\errmessage{xset error: unable to patch #1 driver}\toggletrue{xset@patcherror}}}%
\docsvlist{book,booklet}% <- names of subentry drivers to patch, add what is needed here

%%% xset part - collecting and manipulating data %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% <set id> <entry id> <data name>
\newcommand{\xset@checkfield}[3]{% treat special fields different
% a) year: save min and max for <min>-<max> todo: convert to biberlike notation <low year>/<high year> and drop all min/max garbage
  \ifstrequal{#3}{year}{\ifcsvoid{xset@savedmin@#3}{\savefieldcs{#3}{xset@savedmin@#3}\savefieldcs{#3}{xset@savedmax@#3}}%
    {\ifnum\numexpr\strfield{#3}>\numexpr\csuse{xset@savedmax@#3}%
       \savefieldcs{#3}{xset@savedmax@#3}\else\ifnum\numexpr\strfield{#3}<\numexpr\csuse{xset@savedmin@#3}%
       \savefieldcs{#3}{xset@savedmin@#3}\fi\fi}}{\ifcsvoid{xset@savedf@#3}{\savefieldcs{#3}{xset@savedf@#3}%
         \ifinlist{#3}{\xset@opt@unhide}{}{\global\providetoggle{xset@hide@#2@#3}\global\toggletrue{xset@hide@#2@#3}}}{%
         \ifinlist{#3}{\xset@opt@unhide}{}{\iffieldequalcs{#3}{xset@savedf@#3}{%
           \global\providetoggle{xset@hide@#2@#3}\global\toggletrue{xset@hide@#2@#3}}{% data mismatch! might be an error?
           \xset@message{^^Jxset Warning: Name mismatch in #3 (set #1 / entry #2) - check result!^^J}}}}}}

% <set id> <entry id> <data name>
\newcommand{\xset@checknames}[3]{\ifcsvoid{xset@savedn@#3}{\savenamecs{#3}{xset@savedn@#3}\csxdef{xset@savedc@#3}{\arabic{#3}}% save
% removed set id from toggle name (was: xset@hide@#1@#2@#3)
  \ifinlist{#3}{\xset@opt@unhide}{}{\global\providetoggle{xset@hide@#2@#3}\global\toggletrue{xset@hide@#2@#3}}}{%
  % remember to hide later
  \ifinlist{#3}{\xset@opt@unhide}{}{\ifnameequalcs{#3}{xset@savedn@#3}{% name already saved and equal - remember to hide later
    \global\providetoggle{xset@hide@#2@#3}\global\toggletrue{xset@hide@#2@#3}}{% data mismatch! might be an error?
    \xset@message{^^Jxset Warning: Name mismatch in #3 (set #1 / entry #2) - check result!^^J}}}}}

\newcommand{\xset@checklists}[3]{\ifcsvoid{xset@savedl@#3}{\savelistcs{#3}{xset@savedl@#3}\csxdef{xset@savedc@#3}{\arabic{#3}}}{}}

% <set id> <set children id list> <field name>
\newcommand{\xset@dataparser}[3]{\edef\xset@setid{#1}% remember set ID
  \bgroup\renewcommand{\do}[1]{%
    \ifentryinbib{##1}{\entrydata{##1}%
         {\iffieldundef{#3}{\iflistundef{#3}{\ifnameundef{#3}{}{%
            \xset@checknames{\xset@setid}{##1}{#3}}}{\xset@checklists{\xset@setid}{##1}{#3}}}{\xset@checkfield{\xset@setid}{##1}{#3}}}%
      }{\xset@message{^^Jxset Warning: Entry ##1 of set #1 not found...^^J}}}%
  \edef\xset@tempa{#2}\expandafter\docsvlist\expandafter{\xset@tempa}%
  \egroup}

\newcommand{\xsetParseSet}{%
  \renewcommand{\do}[1]{\xset@dataparser{\thefield{entrykey}}{\thefield{entryset}}{##1}%
    \ifcsvoid{xset@savedf@##1}{% now the trick: restore all collected data
    \ifcsvoid{xset@savedn@##1}{% but now we are in the set scope...
    \ifcsvoid{xset@savedl@##1}{}{\restorelistcs{##1}{xset@savedl@##1}\setcounter{##1}{\csuse{xset@savedc@##1}}}}%
                                {\restorenamecs{##1}{xset@savedn@##1}\setcounter{##1}{\csuse{xset@savedc@##1}}}}%
                                {\restorefieldcs{##1}{xset@savedf@##1}}%
    \ifcsvoid{xset@savedmin@##1}{}{\ifstrequal{##1}{year}{\restorefieldcs{##1min}{xset@savedmin@##1}% year is different
                                                          \restorefieldcs{##1max}{xset@savedmax@##1}}{}}}%
  \dolistloop{\xset@opt@ontop}}%

\newcommand{\xset@cleanup}{% cleanup after set
  \renewcommand{\do}[1]{%
    \global\csundef{xset@savedf@##1}\global\csundef{xset@savedn@##1}\global\csundef{xset@savedl@##1}}% absolut brute force - no checks
  \dolistloop{\xset@opt@ontop}%
  \global\togglefalse{xset@hide@@year}% reset special global toggles
  }
\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% this is the user-level part %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% include bib data
\addbibresource{\jobname.bib}

% a little bit of design
\renewcommand{\entrysetpunct}{\par\nobreak}
\DeclareFieldFormat{bibentrysetcount}{\makebox[1em][l]{\smash{\mknumalph{#1})}}\ignorespaces}
\DeclareFieldFormat[set]{editortype}{\mkbibparens{#1}}

% control xset behaviour
\DeclareXsetOptions{ ontop = {url,publisher} }% tell xset what to put on top...

% create output
\begin{document}\nocite{*}
\printbibliography
\end{document}

应该很容易通过标准或特殊处理实现新的字段/列表。我仍未解决的一件事是收集名称以及“a)”和“Asterix”之间绝对令人讨厌的额外空格... :-(

但至少 - 也许这将帮助某人处理 biblatex 中集合的真正基本实现......

您还可以考虑收集名称字段(这可能会破坏 biblatex 的排序程序)......

答案3

related根据我的建议使用biblatex:为什么@mvbook 不能作为容器工作(像@set 一样)?,这里有一个解决方案,试图实现那里缺少的东西,即设置形式为“[1a]”的引用,而不是\volcite“[1, Bd. 1]”。

正如在另一个答案中提到的那样,有些内容是在 Biber 端实现的(硬编码),但对于许多事情来说,提出端模拟@set是可能的。biblatex

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[babel,german=quotes]{csquotes}
\usepackage[doi=false,backend=biber,subentry,sorting=nyt,style=numeric-comp,sortsets=true]{biblatex}
\usepackage{hyperref}

\makeatletter
\newcommand*{\begrelateddelimmultivolumeset}{\newunitpunct\par\nobreak}
\newbibmacro*{related:multivolumeset}[1]{%
  \entrydata*{#1}{%
    \printfield[bibentrysetcount]{entrysetcount}%
    \blx@anchor % this is to get the link right, everything else is
                % a straightforward extension of related:multivolume
    \setunit{\addspace}%
    \printtext{%
      \printfield{volume}%
      \printfield{part}}%
    \setunit*{\addcolon\space}%
    \usebibmacro{title}%
    \ifboolexpr{
      test {\ifnamesequal{author}{savedauthor}}
      or
      test {\ifnameundef{author}}
    }
      {}
      {\usebibmacro{bytypestrg}{author}{author}%
       \setunit{\addspace}%
       \printnames[byauthor]{author}
       \newunit\newblock}%
    \ifboolexpr{
      test {\ifnamesequal{editor}{savededitor}}
      or
      test {\ifnameundef{editor}}
    }
      {}
      {\usebibmacro{byeditor+others}%
       \newunit\newblock}%
    \ifboolexpr{
      test {\iflistsequal{location}{savedlocation}}
      or
      test {\iflistundef{location}}
    }
      {}
      {\printlist{location}}%<- typo
    \ifboolexpr{
      test {\iflistsequal{publisher}{savedpublisher}}
      or
      test {\iflistundef{publisher}}
    }
      {\setunit*{\addcomma\space}}
      {\setunit*{\addcolon\space}%
       \printlist{publisher}%
       \setunit*{\addcomma\space}}%
  \printdate%
  \newunit\newblock
  \ifboolexpr{
    test {\iffieldsequal{isbn}{savedisbn}}
    or
    not togl {bbx:isbn}
  }
    {}
    {\printfield{isbn}}}}

% {<entrykey>}
% get the hash-keys of all related 'children'
\newcommand*{\blx@fakeset@gethashkey}[1]{%
  \listcsxadd{blx@fakeset@hashkeys@toprocess@\the\c@refsection}{%
    \detokenize{#1}}%
  % save fakeset parent of hash-key
  \csxdef{blx@fakeset@setp@\the\c@refsection @#1}{\strfield{entrykey}}%
  \ifcsundef{blx@fakeset@plist@\the\c@refsection}
    {\global\cslet{blx@fakeset@plist@\the\c@refsection}\@empty}
    {}%
  \xifinlistcs{\strfield{entrykey}}{blx@fakeset@plist@\the\c@refsection}
    {}
    {\listcsxadd{blx@fakeset@plist@\the\c@refsection}{\strfield{entrykey}}}%
  \advance\blx@tempcnta\@ne
  \csxdef{blx@fakeset@seti@\the\c@refsection @#1}{\the\blx@tempcnta}%
}

% {<cmd>}{<csv field>}
% execute <cmd> for each item in the csv field
% there should be a way to avoid the \def here ...
\newrobustcmd*{\blx@fakeset@forcsvfield}[2]{%
  \def\blx@fakeset@forcsvfield@handler{#1}
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter
  \forcsvlist
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter
  \blx@fakeset@forcsvfield@handler
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
  \expandafter
  {\thefield{#2}}}

\AtDataInput{%
  \blx@tempcnta\z@
  \iffieldequalstr{relatedtype}{multivolumeset}
    {\iffieldundef{related}
       {}
       {\blx@fakeset@forcsvfield{\blx@fakeset@gethashkey}{related}}}
    {}%
  % sorted list of *all* entries in the .bbl including cloned entries
  \listcsxadd{blx@fakeset@dlist@aentry@\the\c@refsection
    @\blx@dlist@name}{\strfield{entrykey}}%
}

% resolve hash-key to bib-key and other usable stuff
% {<hash-key>}
\newcommand*{\blx@fakeset@resolvekeys}[1]{%
  % get the entrykey from the bib, not the cloned hash
  \entrydata{#1}{\xdef\blx@fakeset@temp@bibkey{\strfield{clonesourcekey}}}%
  % map hash-key to bib-key
  \csxdef{blx@fakeset@bibkey@\the\c@refsection @#1}{\blx@fakeset@temp@bibkey}%
  % map fakeset parent to list of its children
  \ifcsundef{blx@fakeset@setc@\the\c@refsection @%
             \csuse{blx@fakeset@setp@\the\c@refsection @#1}}
    {\global\cslet{blx@fakeset@setc@\the\c@refsection
                   @\csuse{blx@fakeset@setp@\the\c@refsection @#1}}
       \@empty
     \blx@tempcnta\z@}
    {}%
  \advance\blx@tempcnta\@ne
  \listcsxadd{blx@fakeset@setc@\the\c@refsection
              @\csuse{blx@fakeset@setp@\the\c@refsection @#1}}
    {\blx@fakeset@temp@bibkey}%
  % map bib-key to fakeset parent
  \csxdef{blx@setc@\the\c@refsection @\blx@fakeset@temp@bibkey}{%
    \csuse{blx@fakeset@setp@\the\c@refsection @#1}}%
  % copy data from hash-key to bib-key
  \global\csletcs{blx@data@\the\c@refsection @\blx@refcontext@context
                  @\blx@fakeset@temp@bibkey}%
    {blx@data@\the\c@refsection @\blx@refcontext@context @#1}%
  % fakeset count
  \iftoggle{blx@sortsets}
    {\csnumgdef{blx@fakeset@seti@\the\c@refsection @#1}{\blx@tempcnta}}
    {}%
  \global\csletcs{blx@seti@\the\c@refsection @\blx@fakeset@temp@bibkey}
    {blx@fakeset@seti@\the\c@refsection @#1}%
  \global\csletcs{blx@seti@\the\c@refsection @#1}
    {blx@fakeset@seti@\the\c@refsection @#1}%
}

\newcommand*{\blxfset@addrealkey}[2]{%
  \listgadd{#1}{#2}%
  \ifcsundef{blx@fakeset@setc@\the\c@refsection @#2}
    {}
    {\forlistcsloop{\listadd{#1}}{blx@fakeset@setc@\the\c@refsection @#2}}}

% {<list_1>}{<list_2>}{<item>}
% worker macro to sort:
% add <item> to <list_2> if it exists in <list_1>
\newcommand*{\blx@fakeset@sortbycsinto@i}[3]{%
  \xifinlist{\detokenize{#3}}{#1}
    {\listeadd{#2}{\detokenize{#3}}}
    {}}

% {<list_1>}{<cs list_2>}{<list_3>}
% sorts all entries in <list_2> in the order given by <cs list_2> into <list_3>
\newcommand*{\blx@fakeset@sortbycsinto}[3]{%
  \forlistcsloop{\blx@fakeset@sortbycsinto@i{#1}{#3}}{#2}}

\newcommand*{\blx@fakeset@csvstrtolist@i}[2]{%
  \listeadd{#1}{\detokenize{#2}}}

\newcommand*{\blx@fakeset@listtocsvstr@i}[2]{%
  \appto{#1}{#2,}}

\newcommand*{\blx@fakeset@listtocsvstr}[2]{%
  \forlistloop{\blx@fakeset@listtocsvstr@i{#1}}{#2}}

\newcommand*{\blx@fakeset@sortrelatedfield}[1]{%
  \begingroup
  \blx@getdata{#1}%
  \let\blx@fakeset@tempa\@empty
  \let\blx@fakeset@tempb\@empty
  \blx@fakeset@forcsvfield
    {\blx@fakeset@csvstrtolist@i{\blx@fakeset@tempa}}
    {related}%
  \blx@fakeset@sortbycsinto
    {\blx@fakeset@tempa}
    {blx@fakeset@dlist@aentry@\the\c@refsection @\blx@refcontext@context}
    {\blx@fakeset@tempb}
  \let\blx@fakeset@tempa\@empty
  \blx@fakeset@listtocsvstr{\blx@fakeset@tempa}{\blx@fakeset@tempb}%
  \blx@bbl@addentryfield{#1}{\the\c@refsection}{related}%
    {\blx@refcontext@context}{\blx@fakeset@tempa}%
  \endgroup
}

% we can only resolve our fakeset entries once all entries have been read
\preto{\blx@bbl@endrefsection}{%
  \letcs\blx@fakeset@tempa{blx@fakeset@hashkeys@toprocess@\the\c@refsection}%
  \ifundef\blx@fakeset@tempa
    {\let\blx@fakeset@tempa\@empty}
    {}%
  \iftoggle{blx@sortsets}
    {\letcs\blx@fakeset@tempb{blx@fakeset@dlist@aentry@\the\c@refsection
       @\blx@refcontext@context}%
     \blx@filtercitesort\blx@fakeset@tempb{blx@fakeset@tempa}%
     \let\blx@fakeset@tempa\blx@fakeset@tempb}
    {}%
  \forlistloop{\blx@fakeset@resolvekeys}\blx@fakeset@tempa
  \let\blx@fakeset@tempa\@empty
  \forlistcsloop
    {\blxfset@addrealkey{\blx@fakeset@tempa}}
    {blx@dlist@centry@\the\c@refsection @\blx@refcontext@context}%
  \global\cslet{blx@dlist@centry@\the\c@refsection @\blx@refcontext@context}%
    \blx@fakeset@tempa
  \iftoggle{blx@sortsets}
    {\ifcsundef{blx@fakeset@plist@\the\c@refsection}
       {}
       {\forlistcsloop
          {\blx@fakeset@sortrelatedfield}
          {blx@fakeset@plist@\the\c@refsection}}}
    {}%
}%
\makeatother

\usepackage{filecontents}
\begin{filecontents}{\jobname.bib}
@mvbook{A,
  author      = {René Goscinny and Albert Uderzo},
  sorttitle   = {Asterix und Obelix 00},
  sortyear    = {1959},
  maintitle   = {Asterix und Obelix},
  location    = {Paris},
  related     = {A:V2,A:V5,A:V3,A:V1,A:V4},
  relatedtype = {multivolumeset},
}
@Book{A:V1,
  crossref    = {A},
  volume      = {1},
  title       = {Asterix der Gallier},
  sorttitle   = {Asterix und Obelix 01},
  year        = {1959},
  publisher   = {Dargaud},
  options     = {dataonly},
}
@Book{A:V2,
  crossref    = {A},
  title       = {Asterix und Kleopatra},
  volume      = {2},
  sorttitle   = {Asterix und Obelix 02},
  year        = {1968},
  publisher   = {Dargaud},
  options     = {dataonly},
}
@Book{A:V3,
  crossref    = {A},
  title       = {Asterix als Gladiator},
  volume      = {3},
  sorttitle   = {Asterix und Obelix 03},
  year        = {1969},
  publisher   = {Dargaud},
  options     = {dataonly},
}
@Book{A:V4,
  crossref    = {A},
  title       = {Der Kampf der Häuptlinge},
  volume      = {4},
  sorttitle  = {Asterix und Obelix 04},
  year        = {1969},
  publisher   = {Dargaud},
  options     = {dataonly},
}
@Book{A:V5,
  crossref    = {A},
  title       = {Die goldene Sichel},
  volume      = {5},
  sorttitle   = {Asterix und Obelix 05},
  year        = {1970},
  publisher   = {Ehapa-Verlag},
  options     = {dataonly},
}
@Book{A:VX,
  crossref    = {A},
  title       = {Tour de France},
  volume      = {6},
  sorttitle   = {Asterix und Obelix 06},
  year        = {1970},
  publisher   = {Ehapa-Verlag},
  location    = {Berlin},
}
\end{filecontents}

\addbibresource[label=asterix]{\jobname.bib}
\addbibresource[label=blxex]{biblatex-examples.bib}

\begin{document}
\volcite{1}{A}

\cite{A:V1}

\cite{A:V4}

\cite{A:V1,A:V4}

\cite{A,A:VX}
\printbibliography

\clearpage
\section{Don't cite the other one}
\newrefsection[asterix]
\cite{A:V1}

\cite{A:V4}

\cite{A:V1,A:V4}

\cite{A}
\printbibliography

\clearpage
\section{Nocite}
\newrefsection[asterix]
\nocite{*}

\cite{A:V1}

\cite{A:V4}

\cite{A:V1,A:V4}

\cite{A}
\printbibliography

\clearpage
\section{sigfridsson}
\newrefsection[asterix,blxex]
\cite{sigfridsson}
\printbibliography

\clearpage
\section{sigfridsson with set}
\newrefsection[asterix,blxex]
\cite{sigfridsson,A:V4,A}
\printbibliography
\end{document}

引文“[1, Bd. 1] [1a] [1d] [1a, 1d] [1, 2]”。参考书目按需要显示,即 <code>@mvbook</code> 位的公共部分和单独位的新行。

相关内容