我想扩展条目类型set
以biblatex
容纳更多字段 - 但到目前为止我还没有让它发挥作用。
考虑一下:您有一系列书籍,所有书籍的作者和主标题相同,每卷都有单独的标题,并且应以集合的方式引用它们(例如 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 文件中的定义将其放在整个列表的前面,以获得如下内容:
以下是我的基本问题:
- 我如何获取 bibers 条目输出的附加信息
set
? - 如何删除集合条目中的作者和标题,但不删除其他书籍中的作者和标题?
- 我如何按数量对子条目进行排序?
谢谢...
梅威瑟:
\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.sty
。standard.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}