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

View File

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