Improve info display for biblatex databases, part II

In addition to the classic crossref, biblatex introduces xdata
references in order to source-out common data of entries. Entries
that have "xdata = {somekey}" just inherit all fields from the
respective @xdata entry, if the field is not already defined in
the entry itself (just like crossref, with the exception that @xdata
entries themselves are _never_ output on their own). @xdata entries can
themselves inherit to other @xdata entries (ad infinitum). So you can,
for instance, setup an xdata entry for a book series with series name
that inherits an xdata entry with information of the publisher
(publisher, address). Any book of that series would just need to refer
to the series xdata and add the number.

BiblioInfo now checks, in addition to crossrefs, for such xdata
references and inherits missing fields.

Nte that biblatex also introduces an "xref" field as an alternative to
crossref. We must not care about that, since the point of xref is that
it does not inherit fields from the target (just cites that one if a
given number of refs to it exist)
This commit is contained in:
Juergen Spitzmueller 2016-09-18 12:44:12 +02:00
parent ba17193067
commit 2c4673af58
2 changed files with 105 additions and 58 deletions

View File

@ -352,14 +352,6 @@ docstring const BibTeXInfo::getYear() const
}
docstring const BibTeXInfo::getXRef() const
{
if (!is_bibtex_)
return docstring();
return operator[]("crossref");
}
namespace {
docstring parseOptions(docstring const & format, string & optkey,
@ -485,7 +477,7 @@ I can tell, but it still feels like a hack. Fixing this would require quite a
bit of work, however.
*/
docstring BibTeXInfo::expandFormat(docstring const & format,
BibTeXInfo const * const xref, int & counter, Buffer const & buf,
BibTeXInfoList const xrefs, int & counter, Buffer const & buf,
docstring before, docstring after, docstring dialog, bool next) const
{
// incorrect use of macros could put us in an infinite loop
@ -534,7 +526,7 @@ docstring BibTeXInfo::expandFormat(docstring const & format,
ret << trans;
} else {
docstring const val =
getValueForKey(key, buf, before, after, dialog, xref, max_keysize);
getValueForKey(key, buf, before, after, dialog, xrefs, max_keysize);
if (!scanning_rich)
ret << from_ascii("{!<span class=\"bib-" + key + "\">!}");
ret << val;
@ -565,16 +557,16 @@ docstring BibTeXInfo::expandFormat(docstring const & format,
return _("ERROR!");
fmt = newfmt;
docstring const val =
getValueForKey(optkey, buf, before, after, dialog, xref);
getValueForKey(optkey, buf, before, after, dialog, xrefs);
if (optkey == "next" && next)
ret << ifpart; // without expansion
else if (!val.empty()) {
int newcounter = 0;
ret << expandFormat(ifpart, xref, newcounter, buf,
ret << expandFormat(ifpart, xrefs, newcounter, buf,
before, after, dialog, next);
} else if (!elsepart.empty()) {
int newcounter = 0;
ret << expandFormat(elsepart, xref, newcounter, buf,
ret << expandFormat(elsepart, xrefs, newcounter, buf,
before, after, dialog, next);
}
// fmt will have been shortened for us already
@ -623,7 +615,7 @@ docstring BibTeXInfo::expandFormat(docstring const & format,
}
docstring const & BibTeXInfo::getInfo(BibTeXInfo const * const xref,
docstring const & BibTeXInfo::getInfo(BibTeXInfoList const xrefs,
Buffer const & buf, bool richtext) const
{
if (!richtext && !info_.empty())
@ -642,7 +634,7 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfo const * const xref,
docstring const & format =
from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_)));
int counter = 0;
info_ = expandFormat(format, xref, counter, buf,
info_ = expandFormat(format, xrefs, counter, buf,
docstring(), docstring(), docstring(), false);
if (info_.empty()) {
@ -660,7 +652,7 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfo const * const xref,
}
docstring const BibTeXInfo::getLabel(BibTeXInfo const * const xref,
docstring const BibTeXInfo::getLabel(BibTeXInfoList const xrefs,
Buffer const & buf, docstring const & format, bool richtext,
docstring const & before, docstring const & after,
docstring const & dialog, bool next) const
@ -668,7 +660,7 @@ docstring const BibTeXInfo::getLabel(BibTeXInfo const * const xref,
docstring loclabel;
int counter = 0;
loclabel = expandFormat(format, xref, counter, buf,
loclabel = expandFormat(format, xrefs, counter, buf,
before, after, dialog, next);
if (!loclabel.empty() && !next) {
@ -698,7 +690,7 @@ docstring const & BibTeXInfo::operator[](string const & field) const
docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
docstring const & before, docstring const & after, docstring const & dialog,
BibTeXInfo const * const xref, size_t maxsize) const
BibTeXInfoList const xrefs, size_t maxsize) const
{
// anything less is pointless
LASSERT(maxsize >= 16, maxsize = 16);
@ -710,8 +702,16 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
}
docstring ret = operator[](key);
if (ret.empty() && xref)
ret = (*xref)[key];
if (ret.empty() && !xrefs.empty()) {
vector<BibTeXInfo const *>::const_iterator it = xrefs.begin();
vector<BibTeXInfo const *>::const_iterator en = xrefs.end();
for (; it != en; ++it) {
if (*it && !(**it)[key].empty()) {
ret = (**it)[key];
break;
}
}
}
if (ret.empty()) {
// some special keys
// FIXME: dialog, textbefore and textafter have nothing to do with this
@ -751,7 +751,7 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
docstring const & format =
from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_)));
int counter = 0;
ret = expandFormat(format, xref, counter, buf,
ret = expandFormat(format, xrefs, counter, buf,
docstring(), docstring(), docstring(), false);
} else if (key == "textbefore")
ret = before;
@ -790,6 +790,30 @@ public:
} // namespace anon
vector<docstring> const BiblioInfo::getXRefs(BibTeXInfo const & data, bool const nested) const
{
vector<docstring> result;
if (!data.isBibTeX())
return result;
// Legacy crossref field. This is not nestable.
if (!nested && !data["crossref"].empty())
result.push_back(data["crossref"]);
// Biblatex's xdata field. Infinitely nestable.
docstring const xdatakey = data["xdata"];
if (!xdatakey.empty()) {
result.push_back(xdatakey);
BiblioInfo::const_iterator it = find(xdatakey);
if (it != end()) {
BibTeXInfo const & xdata = it->second;
vector<docstring> const nxdata = getXRefs(xdata, true);
if (!nxdata.empty())
result.insert(result.end(), nxdata.begin(), nxdata.end());
}
}
return result;
}
vector<docstring> const BiblioInfo::getKeys() const
{
vector<docstring> bibkeys;
@ -853,17 +877,23 @@ docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) co
BibTeXInfo const & data = it->second;
docstring year = data.getYear();
if (year.empty()) {
// let's try the crossref
docstring const xref = data.getXRef();
if (xref.empty())
// let's try the crossrefs
vector<docstring> const xrefs = getXRefs(data);
if (xrefs.empty())
// no luck
return docstring();
BiblioInfo::const_iterator const xrefit = find(xref);
vector<docstring>::const_iterator it = xrefs.begin();
vector<docstring>::const_iterator en = xrefs.end();
for (; it != en; ++it) {
BiblioInfo::const_iterator const xrefit = find(*it);
if (xrefit == end())
// no luck again
return docstring();
continue;
BibTeXInfo const & xref_data = xrefit->second;
year = xref_data.getYear();
if (!year.empty())
// success!
break;
}
}
if (use_modifier && data.modifier() != 0)
year += data.modifier();
@ -887,14 +917,18 @@ docstring const BiblioInfo::getInfo(docstring const & key,
if (it == end())
return docstring(_("Bibliography entry not found!"));
BibTeXInfo const & data = it->second;
BibTeXInfo const * xrefptr = 0;
docstring const xref = data.getXRef();
if (!xref.empty()) {
BiblioInfo::const_iterator const xrefit = find(xref);
BibTeXInfoList xrefptrs;
vector<docstring> const xrefs = getXRefs(data);
if (!xrefs.empty()) {
vector<docstring>::const_iterator it = xrefs.begin();
vector<docstring>::const_iterator en = xrefs.end();
for (; it != en; ++it) {
BiblioInfo::const_iterator const xrefit = find(*it);
if (xrefit != end())
xrefptr = &(xrefit->second);
xrefptrs.push_back(&(xrefit->second));
}
return data.getInfo(xrefptr, buf, richtext);
}
return data.getInfo(xrefptrs, buf, richtext);
}
@ -922,17 +956,21 @@ docstring const BiblioInfo::getLabel(vector<docstring> keys,
BibTeXInfo empty_data;
empty_data.key(*key);
BibTeXInfo & data = empty_data;
BibTeXInfo const * xrefptr = 0;
vector<BibTeXInfo const *> xrefptrs;
if (it != end()) {
data = it->second;
docstring const xref = data.getXRef();
if (!xref.empty()) {
BiblioInfo::const_iterator const xrefit = find(xref);
vector<docstring> const xrefs = getXRefs(data);
if (!xrefs.empty()) {
vector<docstring>::const_iterator it = xrefs.begin();
vector<docstring>::const_iterator en = xrefs.end();
for (; it != en; ++it) {
BiblioInfo::const_iterator const xrefit = find(*it);
if (xrefit != end())
xrefptr = &(xrefit->second);
xrefptrs.push_back(&(xrefit->second));
}
}
ret = data.getLabel(xrefptr, buf, ret, for_xhtml,
}
ret = data.getLabel(xrefptrs, buf, ret, for_xhtml,
before, after, dialog, key + 1 != ken);
}

View File

@ -45,6 +45,8 @@ public:
/// and the values are the associated field values.
typedef std::map<docstring, docstring>::const_iterator const_iterator;
///
typedef std::vector<BibTeXInfo const *> const BibTeXInfoList;
///
BibTeXInfo() : is_bibtex_(true), modifier_(0) {}
/// argument sets isBibTeX_, so should be false only if it's coming
/// from a bibliography environment
@ -58,14 +60,12 @@ public:
Buffer const * buf = 0, bool jurabib_style = false) const;
///
docstring const getYear() const;
///
docstring const getXRef() const;
/// \return formatted BibTeX data suitable for framing.
/// \param pointer to crossref information
docstring const & getInfo(BibTeXInfo const * const xref,
/// \param vector of pointers to crossref/xdata information
docstring const & getInfo(BibTeXInfoList const xrefs,
Buffer const & buf, bool richtext) const;
/// \return formatted BibTeX data for a citation label
docstring const getLabel(BibTeXInfo const * const xref,
docstring const getLabel(BibTeXInfoList const xrefs,
Buffer const & buf, docstring const & format, bool richtext,
const docstring & before, const docstring & after,
const docstring & dialog, bool next = false) const;
@ -111,11 +111,11 @@ public:
bool isBibTeX() const { return is_bibtex_; }
private:
/// like operator[], except, if the field is empty, it will attempt
/// to get the data from xref BibTeXInfo object, which would normally
/// be the one referenced in the crossref field.
/// to get the data from xref BibTeXInfo objects, which would normally
/// be the one referenced in the crossref or xdata field.
docstring getValueForKey(std::string const & key, Buffer const & buf,
docstring const & before, docstring const & after, docstring const & dialog,
BibTeXInfo const * const xref, size_t maxsize = 4096) const;
BibTeXInfoList const xrefs, size_t maxsize = 4096) const;
/// replace %keys% in a format string with their values
/// called from getInfo()
/// format strings may contain:
@ -133,7 +133,7 @@ private:
/// moreover, keys that look like "%_key%" are treated as translatable
/// so that things like "pp." and "vol." can be translated.
docstring expandFormat(docstring const & fmt,
BibTeXInfo const * const xref, int & counter,
BibTeXInfoList const xrefs, int & counter,
Buffer const & buf, docstring before = docstring(),
docstring after = docstring(), docstring dialog = docstring(),
bool next = false) const;
@ -166,8 +166,13 @@ private:
/// from BibTeX or from bibliography environments.
class BiblioInfo {
public:
///
typedef std::vector<BibTeXInfo const *> BibTeXInfoList;
/// bibliography key --> data for that key
typedef std::map<docstring, BibTeXInfo>::const_iterator const_iterator;
/// Get a vector with all external data (crossref, xdata)
std::vector<docstring> const getXRefs(BibTeXInfo const & data,
bool const nested = false) const;
/// \return a sorted vector of bibliography keys
std::vector<docstring> const getKeys() const;
/// \return a sorted vector of present BibTeX fields
@ -179,15 +184,19 @@ public:
/// \return the year from the bibtex data record for \param key
/// if \param use_modifier is true, then we will also append any
/// modifier for this entry (e.g., 1998b).
/// Note that this will get the year from the crossref if it's
/// not present in the record itself.
/// If no legacy year field is present, check for date (common in
/// biblatex) and extract the year from there.
/// Note further that this will get the year from the crossref or xdata
/// if it's not present in the record itself.
docstring const getYear(docstring const & key,
bool use_modifier = false) const;
/// \return the year from the bibtex data record for \param key
/// if \param use_modifier is true, then we will also append any
/// modifier for this entry (e.g., 1998b).
/// Note that this will get the year from the crossref if it's
/// not present in the record itself.
/// If no legacy year field is present, check for date (common in
/// biblatex) and extract the year from there.
/// Note further that this will get the year from the crossref or xdata
/// if it's not present in the record itself.
/// If no year is found, \return "No year" translated to the buffer
/// language.
docstring const getYear(docstring const & key, Buffer const & buf,
@ -196,7 +205,7 @@ public:
docstring const getCiteNumber(docstring const & key) const;
/// \return formatted BibTeX data associated with a given key.
/// Empty if no info exists.
/// Note that this will retrieve data from the crossref as needed.
/// Note that this will retrieve data from the crossref or xdata as needed.
/// If \param richtext is true, then it will output any richtext tags
/// marked in the citation format and escape < and > elsewhere.
docstring const getInfo(docstring const & key, Buffer const & buf,