additional fields for biblatex/biber "set"

Thanks to moewe in his first comment I tried it again digging through biblatex.sty and standard.bbx.

Here is the solution:

1) biber assigns the command \inset{<setkey>} to every enty that's part of the set. biblatex uses this to define the field \abx@field@entrykey which is made available with:

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

2) Since \abx@field@entrykey holds the citekey of the @set we can read the fields from the subentries (if the key naming convention is consistent) and use them in the @set driver:

\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) Redefine the bibliography driver for book to print name and titles only if the entry is not part of a @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}%
  [...]

Result:

enter image description here

Adapting this to other bibliography drivers should be no big deal...

And here's the complete code:

\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}

Once more my own answer to my own question since I think it's an improvement and has quite some potential...

After playing around a bit I came up with this solution that reads data from the first entryset id, adds missing data from other set members and does some integrity checks. After collecting data (what's collected actually is up to the user) it prints the following bibliography:

enter image description here

I must admit it looks pretty the same compared with the first answer - but changing just one line of code (line 291) from

\DeclareXsetOptions{ ontop = {url} }

to

\DeclareXsetOptions{ nottop = {maintitle} }

results in

enter image description here

compared to biblatex' default output which is

enter image description here

In the MWE the set driver is patched to represent the common data in biblatex books; a useful expansion would be to decide what to print depending on what types of entries are combined within the set (\strfield{entrytype}). Here's the code:

\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}

It should be easy to implement new fields/lists with standard or special treatment. One thing I still have not managed to get solved is collecting names and the absolutely annoying additional space between the 'a)' and the 'Asterix'... :-(

But at least - maybe this is going to help someone to deal with the really basic implementation of sets in biblatex...

You could also think about collecting namefields (that one might break biblatex' sorting routines)...


Following my suggestion to use the related feature in biblatex: why does @mvbook not work as a containter (like @set)?, here is a solution that tries to implement the thing missing there, namely set citations of the form "[1a]" instead of \volcite's "[1, Bd. 1]".

As mentioned in the other answer, some of the @set stuff is implemented (hard-coded) on the Biber side, but it is sort of possible to come up with biblatex-side emulations for many things.

\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}

Citations "[1, Bd. 1] [1a] [1d] [1a, 1d] [1, 2]". The bibliography shows as desired, i.e. with a common section for the <code>@mvbook</code> bit and new lines for the separate bits.

Tags:

Biblatex

Biber