# HG changeset patch # User Chris Cannam # Date 1259854930 0 # Node ID 29ca5974905dbef1fd89d0b67e65bbbdd0737d7a # Parent e8f4c2b55fd8317bc8104fc6d1f64f3af7eabf2b * More work on a nice tidy import; get some sensible URIs etc diff -r e8f4c2b55fd8 -r 29ca5974905d common/Objects.cpp --- a/common/Objects.cpp Tue Dec 01 17:50:41 2009 +0000 +++ b/common/Objects.cpp Thu Dec 03 15:42:10 2009 +0000 @@ -12,6 +12,39 @@ QMap Form::m_map; QMutex Form::m_mutex; +bool +Composer::datesMatch(const Composer *b) const +{ + const Composer *a = this; + + if (a->birth() && b->birth()) { + int ay = a->birth()->year(), by = b->birth()->year(); + if (ay < 1800 || // birth dates before 1700 tend to be vague! + a->birth()->approximate() || + b->birth()->approximate()) { + if (abs(ay - by) > 25) return false; + } else { + if (abs(ay - by) > 1) { + return false; + } + } + } + if (a->death() && b->death()) { + int ay = a->death()->year(), by = b->death()->year(); + if (a->death()->approximate() || b->death()->approximate()) { + if (abs(ay - by) > 10) return false; + } else if (ay < 1700) { + if (abs(ay - by) > 25) return false; + } else if (ay < 1800) { + // cut a bit of slack, but not as much as for birth date + if (abs(ay - by) > 10) return false; + } else { + if (abs(ay - by) > 1) return false; + } + } + return true; +} + QString Composer::getSortName(bool caps) const { diff -r e8f4c2b55fd8 -r 29ca5974905d common/Objects.h --- a/common/Objects.h Tue Dec 01 17:50:41 2009 +0000 +++ b/common/Objects.h Thu Dec 03 15:42:10 2009 +0000 @@ -291,6 +291,7 @@ const Death *death() const { return m_death; } void setDeath(Death *d) { m_death = d; } + bool datesMatch(const Composer *other) const; // "well enough" QString getSortName(bool caps) const; QString getDisplayDates() const; diff -r e8f4c2b55fd8 -r 29ca5974905d import/Import.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/import/Import.cpp Thu Dec 03 15:42:10 2009 +0000 @@ -0,0 +1,862 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +#include "Objects.h" + +#include +#include +#include +#include +#include + +#include "ImportClassicalComposersOrg.h" +#include "ImportClassicalDotNet.h" +#include "ImportWikipediaComposers.h" +#include "ImportWikipediaWorks.h" +#include "ImportWikipediaWorksK.h" +#include "ImportWikipediaWorksList.h" +#include "ImportHoboken.h" + +#include + +using namespace ClassicalData; +using namespace Dataquay; + +#include +#include + +typedef QMap > ComposerMap; // name -> composers + +void +addMiscExpansions(Composer *c) +{ + QString n = c->name(); + + DEBUG << "addMiscExpansions: n = " << n << endl; + + // lovely hard-coded special cases go here! some of these are + // needed for works->composer assignments + if (n == "Balakirev, Milii") { + c->addAlias("Mily Balakirev"); + } + if (n.startsWith("Cui, C")) { + c->addAlias(QString::fromUtf8("C\303\251sar Cui")); + } + if (n == "Handel, George Frideric") { + c->addAlias("Handel, Georg Friedrich"); + c->addAlias("Handel"); + } + if (n == "Prokofiev, Sergey") { + c->addAlias("Prokofieff, Sergei"); + c->addAlias("Sergei Prokofieff"); + } + if (n == "Rossini, Gioacchino") { + c->addAlias("Rossini, Gioachino"); + c->addAlias("Gioachino Rossini"); + } + if (n == "Edwards, Richard") { + c->addAlias("Edwardes, Richard"); + c->addAlias("Richard Edwardes"); + c->addAlias("Richard Edwards"); + } + if (n == "Rimsky-Korsakov, Nikolay Andreyevich") { + c->addAlias("Nikolai Rimsky-Korsakov"); + } + if (n.startsWith("Piccinni, Nico")) { + c->addAlias(n); + c->setName(QString::fromUtf8("Piccinni, Niccol\303\262")); + } + if (n == "Tchaikovsky, Pyotr Ilyich") { + c->addAlias("Tchaikovsky, Piotr Ilyitch"); + } + if (n == "Wilhelm Stenhammar") { + c->addAlias("Stenhammar, Vilhelm Eugene"); + c->setName("Stenhammar, Wilhelm"); + c->addAlias(n); + } + if (n == "Mercadante, Saverio Rafaele") { + c->addAlias("Mercadante, Giuseppe"); + } + if (n == "Johann Wenzel Anton Stamitz") { + c->addAlias(n); + c->setName("Stamitz, Johann Wenzel Anton"); + c->addAlias("Stamitz, Jan Vaclav"); + } + if (n == "Mario Castelnuovo-Tedesco") { + c->addAlias("Castelnuovo Tedesco, Mario"); + } + if (n == "Mayr, Simon") { + c->addAlias("Mayr"); + } + + n.replace(", Sr.", " Sr."); + n.replace(", Jr.", " Jr."); + + int comma = n.indexOf(", "); + if (comma > 0 && comma + 2 < n.length()) { + + QString left = n.left(comma); + QString right = n.right(n.length() - comma - 2); + + QRegExp jrsr("( (Sr\\.|Jr\\.|I|II))$"); + if (jrsr.indexIn(right) >= 0) { + left = left + jrsr.cap(1); + right = right.left(right.length()-jrsr.matchedLength()); + } + n = right + " " + left; + } + + if (n != c->name()) c->addAlias(n); + + if (n.contains("Sergey")) { + QString nn(n); + nn.replace("Sergey", "Sergei"); + c->addAlias(nn); + } else if (n.contains("Sergei")) { + QString nn(n); + nn.replace("Sergei", "Sergey"); + c->addAlias(nn); + } + + QRegExp sr("((, )?Sr\\.|Senior|\\(?the elder\\)?)", Qt::CaseInsensitive); + if (sr.indexIn(n) >= 0) { + QString nr = n; + nr.replace(sr.pos(0), sr.matchedLength(), " I"); + nr.replace(" ", " "); + DEBUG << "addMiscExpansions: trying " << nr << " for " << n << endl; + c->addAlias(nr); + } + QRegExp jr("((, )?Jr\\.|Junior|\\(?the younger\\)?)", Qt::CaseInsensitive); + if (jr.indexIn(n) >= 0) { + QString nr = n; + nr.replace(jr.pos(0), jr.matchedLength(), " II"); + nr.replace(" ", " "); + DEBUG << "addMiscExpansions: trying " << nr << " for " << n << endl; + c->addAlias(nr); + } + QString nr = n; + nr.replace("(I)", "I"); + nr.replace("(II)", "II"); + nr.replace("(III)", "III"); + c->addAlias(nr); +} + +bool namesFuzzyMatch(QString an, Composer *b) +{ + // ew! + + QString bn = b->name(); + if (bn == an) return true; + if (b->aliases().contains(an)) return true; + int aSurnameIndex = 0, bSurnameIndex = 0; + if (an.contains(",")) { + an.replace(",", ""); + } else { + aSurnameIndex = -1; + } + if (bn.contains(",")) { + bn.replace(",", ""); + } else { + bSurnameIndex = -1; + } + QStringList nl = an.split(QRegExp("[ -]")); + QStringList bnl = bn.split(QRegExp("[ -]")); + int matchCount = 0; + QString surnameMatch = ""; + if (aSurnameIndex == -1) aSurnameIndex = nl.size()-1; + if (bSurnameIndex == -1) bSurnameIndex = bnl.size()-1; + if (nl[aSurnameIndex][0].isUpper() && + nl[aSurnameIndex] != "Della" && + nl[aSurnameIndex] == bnl[bSurnameIndex]) { + surnameMatch = nl[aSurnameIndex]; + } + foreach (QString elt, nl) { + if (!elt[0].isUpper() || elt == "Della") continue; + if (bnl.contains(elt)) { + ++matchCount; + continue; + } + } + if (matchCount > 1 && surnameMatch != "") { + DEBUG << "namesFuzzyMatch: note: surnameMatch = " << surnameMatch << endl; + return true; + } + return false; +} + +bool +hasBetterName(Composer *c, Composer *other) +{ + if (c->name() == other->name()) return false; + + // Try to guess which of c and other is more likely to have a good + // "canonical form" of the composer's name + + if (c->name().startsWith("van ")) { + return false; // wrong choice of sort for e.g. LvB; should be + // Beethoven, Ludwig van, not van Beethoven, Ludwig + } + if (other->name().startsWith("van ")) { + return true; + } + + if (c->aliases().size() != other->aliases().size()) { + // a rather weak heuristic + return c->aliases().size() > other->aliases().size(); + } + + if (c->name().contains(',') && !other->name().contains(',')) { + // another rather weak heuristic + return true; + } + + return false; +} + +void mergeComposer(Composer *c, ComposerMap &composers) +{ + QString name = c->name(); + + QSet allNames = c->aliases(); + allNames.insert(name); + + QString dates; + if (c->birth()) { + if (c->death()) { + dates = QString("%1-%2").arg(c->birth()->year()).arg(c->death()->year()); + } else { + dates = QString("%1-").arg(c->birth()->year()); + } + } + if (dates != "") { + allNames.insert(dates); + } + + QSet matches; + + foreach (QString candidateName, allNames) { + QString key = candidateName.toLower(); + if (composers.contains(key)) { + foreach (Composer *candidate, composers[key]) { + if (candidateName == dates) { + if (!namesFuzzyMatch(c->name(), candidate) && + !namesFuzzyMatch(candidate->name(), c)) { + DEBUG << "mergeComposer: Names differ for " << c->name() << " and " << candidate->name() << " (having matched date(s) " << dates << ")" << endl; + continue; + } else { + DEBUG << "mergeComposer: Note: Fuzzy name match for " << c->name() << " and " << candidate->name() << " with date(s) " << dates << endl; + } + } else { + if (!c->datesMatch(candidate)) { + DEBUG << "mergeComposer: Dates differ for " << c->name() << " and " << candidate->name() << endl; + continue; + } + } + matches.insert(candidate); + } + } + } + + if (matches.empty()) { + DEBUG << "mergeComposer: No existing composer with alias matching any alias of " << c->name() << ", adding" << endl; + + if (!c->birth() && !c->death()) { + // laboriously look for fuzzy match across _all_ composers + for (ComposerMap::iterator i = composers.begin(); + i != composers.end(); ++i) { + foreach (Composer *candidate, *i) { + if (namesFuzzyMatch(c->name(), candidate)) { + DEBUG << "mergeComposer: Found fuzzy match for undated composer " << c->name() << " as " << candidate->name() << ", daringly merging" << endl; + matches.insert(candidate); + break; + } + } + if (!matches.empty()) break; + } + } + + if (matches.empty()) { + foreach (QString candidateName, allNames) { + composers[candidateName.toLower()].insert(c); + DEBUG << "added for alias or date " << candidateName << endl; + } + return; + } + } + + if (matches.size() > 1) { + DEBUG << "mergeComposer: More than one composer matches name and date(s) for " << c->name() << " -- something fishy here" << endl; + } + + Composer *other = *matches.begin(); + + DEBUG << "mergeComposer: Merging " << c->name() << " with " << other->name() << endl; + + if (hasBetterName(c, other)) { + other->addAlias(other->name()); + other->setName(c->name()); + } else { + other->addAlias(c->name()); + } + composers[c->name().toLower()].insert(other); + DEBUG << "linking from alias " << c->name() << endl; + + foreach (QString alias, c->aliases()) { + if (alias != other->name() && + !other->aliases().contains(alias)) { + other->addAlias(alias); + composers[alias.toLower()].insert(other); + DEBUG << "linking from alias " << alias << endl; + } + } + + foreach (Document *d, c->pages()) { + bool found = false; + foreach (Document *dd, other->pages()) { + if (d->uri() == dd->uri()) { + found = true; + break; + } + } + if (!found) { + d->setTopic(other); + other->addPage(d); + } + } + + //!!! actually the "approximate" bits of the following are bogus; + // a source reporting birth or death date as approx is probably + // more accurate than one reporting an exact date + + if (c->birth()) { + if (!other->birth() || other->birth()->approximate()) { + other->setBirth(c->birth()); + } + } + + if (c->death()) { + if (!other->death() || other->death()->approximate()) { + other->setDeath(c->death()); + } + } + + if (c->gender() != "") other->setGender(c->gender()); + if (c->nationality() != "") other->setNationality(c->nationality()); + if (c->remarks() != "") other->setRemarks(c->remarks()); + if (c->period() != "") other->setPeriod(c->period()); + +} + +QString +asciify(QString field) +{ + // accented characters etc -- add "ascii version" for dumb search purposes + QString ascii; + for (int i = 0; i < field.length(); ++i) { + QString dc = field[i].decomposition(); + if (dc != "") ascii += dc[0]; + else if (field[i] == QChar(0x00DF)) { + ascii += "ss"; + } else { + ascii += field[i]; + } + } + ascii.replace(QString::fromUtf8("\342\200\231"), "'"); // apostrophe + ascii.replace(QString::fromUtf8("\342\200\222"), "-"); + ascii.replace(QString::fromUtf8("\342\200\223"), "-"); + ascii.replace(QString::fromUtf8("\342\200\224"), "-"); + ascii.replace(QString::fromUtf8("\342\200\225"), "-"); + return ascii; +} + +void +asciify(Composer *c) +{ + QString n = c->name(); + QString asc = asciify(n); + if (asc != n && !c->aliases().contains(asc)) c->addAlias(asc); + foreach (QString alias, c->aliases()) { + asc = asciify(alias); + if (asc != alias && !c->aliases().contains(asc)) c->addAlias(asc); + } +} + +void +asciify(Work *w) +{ + QString n = w->name(); + QString asc = asciify(n); + if (asc != n && !w->aliases().contains(asc)) w->addAlias(asc); + foreach (QString alias, w->aliases()) { + asc = asciify(alias); + if (asc != alias && !w->aliases().contains(asc)) w->addAlias(asc); + } +} + +void +assignUri(Store *s, Composer *c) +{ + static QSet convSet; + QString conv = c->name(); + if (!conv.contains(",")) { + QStringList sl = conv.split(" "); + if (!sl.empty()) { + sl.push_front(sl[sl.size()-1]); + sl.removeLast(); + conv = sl.join(" "); + DEBUG << "assignUri: " << c->name() << " -> " << conv << endl; + } + } + conv = asciify(conv); + conv.replace(" ", "_"); + conv.replace("-", "_"); + conv.replace(QRegExp("[^a-zA-Z0-9_-]"), ""); + conv = conv.toLower(); + QString initial = conv; + int i = 2; + while (convSet.contains(conv)) { + conv = QString("%1__%2").arg(initial).arg(i); + i++; + } + convSet.insert(conv); + c->setProperty("uri", s->expand(":composer/" + conv)); +} + +void +assignUri(Store *s, Work *w, Composer *c) +{ + QString pfx = c->property("uri").toUrl().toString(); + DEBUG << "pfx = " << pfx << endl; + if (!pfx.contains("composer/")) pfx = ""; + + static QSet convSet; + + QString conv = w->catalogue(); + if (conv == "") conv = w->opus(); + conv = conv.replace(".", ""); + bool hasOpus = (conv != ""); + if (conv == "") conv = w->name().toLower(); + if (w->number() != "") conv = conv + "_no" + w->number(); + conv = asciify(conv); + conv.replace(" ", "_"); + conv.replace("-", "_"); + conv.replace(":", "_"); + conv.replace(QRegExp("[^a-zA-Z0-9_-]"), ""); + + if (pfx != "") conv = pfx + "/work/" + conv; + + // I think actually for works we want to merge duplicates rather than + // assign them separate URIs, _unless_ they lack a viable opus number + if (!hasOpus) { + QString initial = conv; + int i = 2; + while (convSet.contains(conv)) { + conv = QString("%1__%2").arg(initial).arg(i); + i++; + } + } + convSet.insert(conv); + + w->setProperty("uri", conv); +} + +void +addDbpediaResource(Store *store, QObject *o, QString s) +{ + QUrl u = o->property("uri").toUrl(); + if (u == QUrl()) return; + if (s.startsWith("http://en.wikipedia.org/wiki/")) { + store->add(Triple(u, + "mo:wikipedia", + QUrl(s))); + s.replace("http://en.wikipedia.org/wiki/", + "http://dbpedia.org/resource/"); + store->add(Triple(u, + "owl:sameAs", + QUrl(s))); + } +} + +int main(int argc, char **argv) +{ + qRegisterMetaType + ("ClassicalData::HistoricalEvent*"); + qRegisterMetaType + ("ClassicalData::Birth*"); + qRegisterMetaType + ("ClassicalData::Death*"); + qRegisterMetaType + ("ClassicalData::Composition*"); + qRegisterMetaType + ("ClassicalData::Work*"); + qRegisterMetaType + ("ClassicalData::Movement*"); + qRegisterMetaType + ("ClassicalData::Composer*"); + qRegisterMetaType + ("ClassicalData::Document*"); + qRegisterMetaType
+ ("ClassicalData::Form*"); + qRegisterMetaType > + ("QSet"); + qRegisterMetaType > + ("QSet"); + qRegisterMetaType > + ("QSet"); + qRegisterMetaType > + ("QSet"); + qRegisterMetaType > + ("QSet"); + + qRegisterMetaType + ("ClassicalData::ClassicalComposersOrgImporter*"); + qRegisterMetaType + ("ClassicalData::ClassicalDotNetImporter*"); + qRegisterMetaType + ("ClassicalData::WikipediaComposersImporter*"); + qRegisterMetaType + ("ClassicalData::WikipediaWorksImporter*"); + qRegisterMetaType + ("ClassicalData::WikipediaWorksKImporter*"); + qRegisterMetaType + ("ClassicalData::WikipediaWorksListImporter*"); + qRegisterMetaType + ("ClassicalData::HobokenImporter*"); + + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::HistoricalEvent*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::Birth*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::Death*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::Composition*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::Work*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::Movement*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::Composer*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::Document*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::Form*"); + + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::ClassicalComposersOrgImporter*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::ClassicalDotNetImporter*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::WikipediaComposersImporter*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::WikipediaWorksImporter*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::WikipediaWorksKImporter*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::WikipediaWorksListImporter*"); + ObjectBuilder::getInstance()->registerClass + ("ClassicalData::HobokenImporter*"); + + ContainerBuilder::getInstance()->registerContainer + > + ("QString", "QSet", ContainerBuilder::SetKind); + + ContainerBuilder::getInstance()->registerContainer + > + ("ClassicalData::Work*", "QSet", + ContainerBuilder::SetKind); + + ContainerBuilder::getInstance()->registerContainer + > + ("ClassicalData::Movement*", "QSet", + ContainerBuilder::SetKind); + + ContainerBuilder::getInstance()->registerContainer + > + ("ClassicalData::Document*", "QSet", + ContainerBuilder::SetKind); + + ContainerBuilder::getInstance()->registerContainer + > + ("ClassicalData::Form*", "QSet", + ContainerBuilder::SetKind); + + BasicStore *store = BasicStore::load("file:importers.ttl"); + ObjectMapper mapper(store); + QObject *parentObject = mapper.loadAllObjects(new QObject()); + + BasicStore *outstore = new BasicStore(); + outstore->setBaseUri("http://dbtune.org/classical/resource/"); + ObjectMapper outmapper(outstore); + + outmapper.setPropertyStorePolicy(ObjectMapper::StoreIfChanged); + + outmapper.setObjectTypePrefix("http://dbtune.org/classical/resource/"); + outmapper.setPropertyPrefix("http://dbtune.org/classical/resource/vocab/"); + outmapper.setRelationshipPrefix("http://dbtune.org/classical/resource/vocab/relationship/"); + + outstore->addPrefix("type", outmapper.getObjectTypePrefix()); + outstore->addPrefix("classical", outmapper.getObjectTypePrefix() + "type/"); + outstore->addPrefix("property", outmapper.getPropertyPrefix()); + outstore->addPrefix("rel", outmapper.getRelationshipPrefix()); + + outstore->addPrefix("foaf", "http://xmlns.com/foaf/0.1/"); + outstore->addPrefix("mo", "http://purl.org/ontology/mo/"); + outstore->addPrefix("dc", "http://purl.org/dc/elements/1.1/"); + outstore->addPrefix("bio", "http://purl.org/vocab/bio/0.1/"); + outstore->addPrefix("owl", "http://www.w3.org/2002/07/owl#"); + outstore->addPrefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#"); + outstore->addPrefix("db", "http://dbtune.org/musicbrainz/resource/"); + outstore->addPrefix("dbv", "http://dbtune.org/musicbrainz/resource/vocab/"); + + outmapper.addTypeMapping("ClassicalData::Composer", "classical:Composer"); + outmapper.addPropertyMapping("ClassicalData::Composer", "pages", "foaf:page"); + outmapper.addPropertyMapping("ClassicalData::Composer", "name", "foaf:name"); + outmapper.addPropertyMapping("ClassicalData::Composer", "aliases", "dbv:alias"); + outmapper.addPropertyMapping("ClassicalData::Composer", "birth", "property:birth"); + outmapper.addPropertyMapping("ClassicalData::Composer", "death", "property:death"); + + outmapper.addTypeMapping("ClassicalData::Birth", "bio:Birth"); + outmapper.addTypeMapping("ClassicalData::Death", "bio:Death"); + outmapper.addPropertyMapping("ClassicalData::Birth", "year", "bio:date"); + outmapper.addPropertyMapping("ClassicalData::Death", "year", "bio:date"); + outmapper.addPropertyMapping("ClassicalData::Birth", "place", "bio:place"); + outmapper.addPropertyMapping("ClassicalData::Death", "place", "bio:place"); + + outmapper.addTypeMapping("ClassicalData::Document", "foaf:Document"); + outmapper.addPropertyMapping("ClassicalData::Document", "topic", "foaf:primaryTopic"); + + outmapper.addTypeMapping("ClassicalData::Work", "mo:MusicalWork"); + + outmapper.addPropertyMapping("ClassicalData::Work", "composition", "mo:composed_in"); + outmapper.addPropertyMapping("ClassicalData::Work", "opus", "mo:opus"); + outmapper.addPropertyMapping("ClassicalData::Work", "catalogue", "mo:catalogue"); + outmapper.addPropertyMapping("ClassicalData::Work", "number", "mo:number"); + outmapper.addPropertyMapping("ClassicalData::Work", "partOf", "dc:isPartOf"); + outmapper.addPropertyMapping("ClassicalData::Work", "parts", "dc:hasPart"); + outmapper.addPropertyMapping("ClassicalData::Work", "pages", "foaf:page"); + outmapper.addPropertyMapping("ClassicalData::Work", "forms", "property:form"); + outmapper.addPropertyMapping("ClassicalData::Work", "key", "mo:key"); + outmapper.addPropertyMapping("ClassicalData::Work", "aliases", "dbv:alias"); + outmapper.addPropertyMapping("ClassicalData::Work", "name", "dc:title"); + + outmapper.addTypeMapping("ClassicalData::Composition", "mo:Composition"); + outmapper.addPropertyMapping("ClassicalData::Composition", "composer", "mo:composer"); + outmapper.addPropertyMapping("ClassicalData::Composition", "works", "mo:produced_work"); + + outstore->add(Triple("classical:Composer", "a", outstore->expand("owl:Class"))); + outstore->add(Triple("classical:Composer", "rdfs:subClassOf", outstore->expand("mo:MusicArtist"))); + + outstore->add(Triple("property:birth", "a", outstore->expand("owl:ObjectProperty"))); + outstore->add(Triple("property:birth", "rdfs:subPropertyOf", outstore->expand("bio:event"))); + + outstore->add(Triple("property:death", "a", outstore->expand("owl:ObjectProperty"))); + outstore->add(Triple("property:death", "rdfs:subPropertyOf", outstore->expand("bio:event"))); + + QList importers = parentObject->findChildren(); + std::cerr << "have " << importers.size() << " importers" << std::endl; + + ComposerMap composers; + + QList dated; + QList undated; + + QList works; + QList compositions; + QList other; + + foreach (Importer *importer, importers) { + QObjectList objects = importer->getImportedObjects(); + foreach (QObject *o, objects) { + Composer *c; + if ((c = qobject_cast(o))) { + addMiscExpansions(c); + asciify(c); + if (c->birth() || c->death()) dated.push_back(c); + else undated.push_back(c); + continue; + } + Work *w; + if ((w = qobject_cast(o))) { + asciify(w); + works.push_back(w); + continue; + } + Composition *cn; + if ((cn = qobject_cast(o))) { + compositions.push_back(cn); + continue; + } + } + } + + // get all the dated composers merged before attempting to match + // the undated ones + foreach (Composer *c, dated) { + mergeComposer(c, composers); + } + foreach (Composer *c, undated) { + mergeComposer(c, composers); + } + + QObjectList toStore; + + QSet cset; + for (ComposerMap::iterator i = composers.begin(); i != composers.end(); ++i) { + foreach (Composer *c, i.value()) { + if (!cset.contains(c)) { + assignUri(outstore, c); + toStore.push_back(c); + cset.insert(c); + } + foreach (Document *d, c->pages()) { + QString s = d->uri().toString(); + addDbpediaResource(outstore, c, s); + } + } + } + + QSet storedUris; + + foreach (Work *w, works) { + Composition *cn = w->composition(); + if (!cn) continue; + if (!cn->composer()) { + QString cname = cn->composerName(); + if (cname != "") { + if (!composers.contains(cname.toLower())) { + DEBUG << "Failed to assign Composition to composer: no composer matches name " << cname << endl; + } else { + QSet cs = composers[cname.toLower()]; + if (cs.empty()) { + DEBUG << "Failed to assign Composition to composer: no composer matches name " << cname << endl; + } else if (cs.size() > 1) { + DEBUG << "Failed to assign Composition to composer: " + << cs.size() << " composers match name " << cname << endl; + } else { + cn->setComposer(*cs.begin()); + } + } + } else { + DEBUG << "Failed to assign Composition to composer: composer name is empty" << endl; + } + } + + if (cn->composer()) { + assignUri(outstore, w, cn->composer()); + } + + foreach (Document *d, w->pages()) { + QString s = d->uri().toString(); + addDbpediaResource(outstore, w, s); + if (!storedUris.contains(s)) { + toStore.push_back(d); + storedUris.insert(s); + } + } + + QString u = w->property("uri").toUrl().toString(); + if (u == "" || !storedUris.contains(u)) { + toStore.push_back(w); + if (u != "") storedUris.insert(u); + } + } + + try { + outmapper.storeAllObjects(toStore); + + } catch (RDFException e) { + std::cerr << "Caught RDF exception: " << e.what() << std::endl; + } + + DEBUG << "Stored, now saving" << endl; + + outstore->save("test-out.ttl"); + + DEBUG << "Saved" << endl; + + + QMultiMap cmap; + foreach (Composer *c, cset) { + QString n = c->getSortName(true); + cmap.insert(n, c); + } + + std::cout << "Composers: " << cmap.size() << std::endl; + + for (QMultiMap::iterator i = cmap.begin(); + i != cmap.end(); ++i) { + + QString n = i.key(); + Composer *c = i.value(); + + std::cout << n.toStdString(); + + QString d = c->getDisplayDates(); + if (d != "") std::cout << " (" << d.toStdString() << ")"; + std::cout << std::endl; + } + + std::cout << std::endl; + + std::cout << "Works by composer:" << std::endl; + + for (QMultiMap::iterator i = cmap.begin(); + i != cmap.end(); ++i) { + + QString n = i.key(); + Composer *c = i.value(); + + std::set wmap; + foreach (Work *w, works) { + Composition *cn = w->composition(); + if (!cn) continue; + if (cn->composer() != c) continue; + if (w->partOf()) continue; + wmap.insert(w); + } + + if (wmap.empty()) continue; + + std::cout << n.toStdString() << std::endl; + + foreach (Work *w, wmap) { + std::cout << " * "; + std::cout << w->name().toStdString(); + if (w->catalogue() != "") { + std::cout << " [" << w->catalogue().toStdString() << "]"; + } + if (w->opus() != "") { + std::cout << " [op. " << w->opus().toStdString() << "]"; + } + std::cout << std::endl; + std::set orderedParts; + foreach (Work *ww, w->parts()) { + orderedParts.insert(ww); + } + foreach (Work *ww, orderedParts) { + std::cout << " "; + if (ww->number() != "") { + std::cout << ww->number().toStdString() << ". "; + } + std::cout << ww->name().toStdString(); + if (ww->catalogue() != "" && ww->catalogue() != w->catalogue()) { + std::cout << " [" << ww->catalogue().toStdString() << "]"; + } + if (ww->opus() != "" && ww->opus() != w->opus()) { + std::cout << " [op. " << ww->opus().toStdString() << "]"; + } + std::cout << std::endl; + } + } + + std::cout << std::endl; + } + + delete outstore; + + DEBUG << "Done" << endl; + + +} + + diff -r e8f4c2b55fd8 -r 29ca5974905d import/ImportClassicalComposersOrg.cpp --- a/import/ImportClassicalComposersOrg.cpp Tue Dec 01 17:50:41 2009 +0000 +++ b/import/ImportClassicalComposersOrg.cpp Thu Dec 03 15:42:10 2009 +0000 @@ -262,7 +262,7 @@ all.replace(QRegExp("^.*
"), ""); QRegExp matcher - ("
  • ([^<]+)(([^<]*))? \\((\\*?)([0-9]+)[^0-9)]*([0-9]+)?\\)\\s*([^\\s])?
  • "); + (QString::fromUtf8("
  • ([^<]+)(([^<]*))? \\((\\*?)([0-9]+)([^0-9)]*)([0-9]+)?\\)\\s*([^\\s])?
  • ")); int pos = 0, count = 0; while ((pos = matcher.indexIn(all, pos)) != -1) { @@ -272,9 +272,11 @@ QString page = matcher.cap(1); QString name = matcher.cap(2); + QString star = matcher.cap(5); QString birth = matcher.cap(6); - QString death = matcher.cap(7); - QString female = matcher.cap(8); + QString dagger = matcher.cap(7); + QString death = matcher.cap(8); + QString female = matcher.cap(9); DEBUG << "Item " << count << ": page = " << page @@ -314,6 +316,25 @@ d->setSiteName("Classical Composers Database"); composer->addPage(d); } + + if (birth != "" && death == "") { + if (star == "" && dagger != QString::fromUtf8("\342\200\240")) { + DEBUG << "Unexpected \"dagger\" character" << dagger << endl; + birth = ""; + } + if (star == "" && dagger == "") { + DEBUG << "Only one date in date range (" << birth << "), but no star or dagger -- ignoring" << endl; + birth = ""; + } else if (star != "" && dagger != "") { + DEBUG << "Date range features both star and dagger -- ignoring" << endl; + birth = ""; + } else if (dagger != "") { + DEBUG << "dagger found: setting death to " << birth << endl; + death = birth; + birth = ""; + } + } + if (birth != "") { Birth *e = new Birth(birth.toInt()); composer->setBirth(e); diff -r e8f4c2b55fd8 -r 29ca5974905d import/Test.cpp --- a/import/Test.cpp Tue Dec 01 17:50:41 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,831 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -#include "Objects.h" - -#include -#include -#include -#include -#include - -#include "ImportClassicalComposersOrg.h" -#include "ImportClassicalDotNet.h" -#include "ImportWikipediaComposers.h" -#include "ImportWikipediaWorks.h" -#include "ImportWikipediaWorksK.h" -#include "ImportWikipediaWorksList.h" -#include "ImportHoboken.h" - -#include - -using namespace ClassicalData; -using namespace Dataquay; - -#include -#include - -typedef QMap > ComposerMap; // name -> composers - -bool datesMatch(Composer *a, Composer *b) -{ - if (a->birth() && b->birth()) { - if (abs(a->birth()->year() - b->birth()->year()) > 1) { - if ((!a->birth()->approximate() && !b->birth()->approximate()) || - (abs(a->birth()->year() - b->birth()->year()) > 10)) { - return false; - } - } - } - if (a->death() && b->death()) { - if (abs(a->death()->year() - b->death()->year()) > 1) { - if ((!a->death()->approximate() && !b->death()->approximate()) || - (abs(a->death()->year() - b->death()->year()) > 10)) { - return false; - } - } - } - return true; -} - -void -addMiscExpansions(Composer *c) -{ - QString n = c->name(); - - DEBUG << "addMiscExpansions: n = " << n << endl; - - // lovely hard-coded special cases go here! some of these are - // needed for works->composer assignments - if (n == "Balakirev, Milii") { - c->addAlias("Mily Balakirev"); - } - if (n.startsWith("Cui, C")) { - c->addAlias(QString::fromUtf8("C\303\251sar Cui")); - } - if (n == "Handel, George Frideric") { - c->addAlias("Handel, Georg Friedrich"); - c->addAlias("Handel"); - } - if (n == "Mayr, Simon") { - c->addAlias("Mayr"); - } - - n.replace(", Sr.", " Sr."); - n.replace(", Jr.", " Jr."); - - int comma = n.indexOf(", "); - if (comma > 0 && comma + 2 < n.length()) { - - QString left = n.left(comma); - QString right = n.right(n.length() - comma - 2); - - QRegExp jrsr("( (Sr\\.|Jr\\.|I|II))$"); - if (jrsr.indexIn(right) >= 0) { - left = left + jrsr.cap(1); - right = right.left(right.length()-jrsr.matchedLength()); - } - n = right + " " + left; - } - - if (n != c->name()) c->addAlias(n); - - if (n.contains("Sergey")) { - QString nn(n); - nn.replace("Sergey", "Sergei"); - c->addAlias(nn); - } - - QRegExp sr("((, )?Sr\\.|Senior|\\(?the elder\\)?)", Qt::CaseInsensitive); - if (sr.indexIn(n) >= 0) { - QString nr = n; - nr.replace(sr.pos(0), sr.matchedLength(), " I"); - nr.replace(" ", " "); - DEBUG << "addMiscExpansions: trying " << nr << " for " << n << endl; - c->addAlias(nr); - } - QRegExp jr("((, )?Jr\\.|Junior|\\(?the younger\\)?)", Qt::CaseInsensitive); - if (jr.indexIn(n) >= 0) { - QString nr = n; - nr.replace(jr.pos(0), jr.matchedLength(), " II"); - nr.replace(" ", " "); - DEBUG << "addMiscExpansions: trying " << nr << " for " << n << endl; - c->addAlias(nr); - } - QString nr = n; - nr.replace("(I)", "I"); - nr.replace("(II)", "II"); - nr.replace("(III)", "III"); - c->addAlias(nr); -} - -bool namesFuzzyMatch(QString an, Composer *b) -{ - // ew! - - QString bn = b->name(); - if (bn == an) return true; - if (b->aliases().contains(an)) return true; - int aSurnameIndex = 0, bSurnameIndex = 0; - if (an.contains(",")) { - an.replace(",", ""); - } else { - aSurnameIndex = -1; - } - if (bn.contains(",")) { - bn.replace(",", ""); - } else { - bSurnameIndex = -1; - } - QStringList nl = an.split(QRegExp("[ -]")); - QStringList bnl = bn.split(QRegExp("[ -]")); - int matchCount = 0; - QString surnameMatch = ""; - if (aSurnameIndex == -1) aSurnameIndex = nl.size()-1; - if (bSurnameIndex == -1) bSurnameIndex = bnl.size()-1; - if (nl[aSurnameIndex][0].isUpper() && - nl[aSurnameIndex] != "Della" && - nl[aSurnameIndex] == bnl[bSurnameIndex]) { - surnameMatch = nl[aSurnameIndex]; - } - foreach (QString elt, nl) { - if (!elt[0].isUpper() || elt == "Della") continue; - if (bnl.contains(elt)) { - ++matchCount; - continue; - } - } - if (matchCount > 1 && surnameMatch != "") { - DEBUG << "namesFuzzyMatch: note: surnameMatch = " << surnameMatch << endl; - return true; - } - return false; -} - -bool -hasBetterName(Composer *c, Composer *other) -{ - if (c->name() == other->name()) return false; - - // Try to guess which of c and other is more likely to have a good - // "canonical form" of the composer's name - - if (c->name().startsWith("van ")) { - return false; // wrong choice of sort for e.g. LvB; should be - // Beethoven, Ludwig van, not van Beethoven, Ludwig - } - if (other->name().startsWith("van ")) { - return true; - } - - if (c->aliases().size() != other->aliases().size()) { - // a rather weak heuristic - return c->aliases().size() > other->aliases().size(); - } - - if (c->name().contains(',') && !other->name().contains(',')) { - // another rather weak heuristic - return true; - } - - return false; -} - -void mergeComposer(Composer *c, ComposerMap &composers) -{ - QString name = c->name(); - - QSet allNames = c->aliases(); - allNames.insert(name); - - QString dates; - if (c->birth()) { - if (c->death()) { - dates = QString("%1-%2").arg(c->birth()->year()).arg(c->death()->year()); - } else { - dates = QString("%1-").arg(c->birth()->year()); - } - } - if (dates != "") { - allNames.insert(dates); - } - - QSet matches; - - foreach (QString candidateName, allNames) { - QString key = candidateName.toLower(); - if (composers.contains(key)) { - foreach (Composer *candidate, composers[key]) { - if (candidateName == dates) { - if (!namesFuzzyMatch(c->name(), candidate) && - !namesFuzzyMatch(candidate->name(), c)) { - DEBUG << "mergeComposer: Names differ for " << c->name() << " and " << candidate->name() << " (having matched date(s) " << dates << ")" << endl; - continue; - } else { - DEBUG << "mergeComposer: Note: Fuzzy name match for " << c->name() << " and " << candidate->name() << " with date(s) " << dates << endl; - } - } else { - if (!datesMatch(c, candidate)) { - DEBUG << "mergeComposer: Dates differ for " << c->name() << " and " << candidate->name() << endl; - continue; - } - } - matches.insert(candidate); - } - } - } - - if (matches.empty()) { - DEBUG << "mergeComposer: No existing composer with alias matching any alias of " << c->name() << ", adding" << endl; - - if (!c->birth() && !c->death()) { - // laboriously look for fuzzy match across _all_ composers - for (ComposerMap::iterator i = composers.begin(); - i != composers.end(); ++i) { - foreach (Composer *candidate, *i) { - if (namesFuzzyMatch(c->name(), candidate)) { - DEBUG << "mergeComposer: Found fuzzy match for undated composer " << c->name() << " as " << candidate->name() << ", daringly merging" << endl; - matches.insert(candidate); - break; - } - } - if (!matches.empty()) break; - } - } - - if (matches.empty()) { - foreach (QString candidateName, allNames) { - composers[candidateName.toLower()].insert(c); - DEBUG << "added for alias or date " << candidateName << endl; - } - return; - } - } - - if (matches.size() > 1) { - DEBUG << "mergeComposer: More than one composer matches name and date(s) for " << c->name() << " -- something fishy here" << endl; - } - - Composer *other = *matches.begin(); - - DEBUG << "mergeComposer: Merging " << c->name() << " with " << other->name() << endl; - - if (hasBetterName(c, other)) { - other->addAlias(other->name()); - other->setName(c->name()); - } else { - other->addAlias(c->name()); - } - composers[c->name().toLower()].insert(other); - DEBUG << "linking from alias " << c->name() << endl; - - foreach (QString alias, c->aliases()) { - if (alias != other->name() && - !other->aliases().contains(alias)) { - other->addAlias(alias); - composers[alias.toLower()].insert(other); - DEBUG << "linking from alias " << alias << endl; - } - } - - foreach (Document *d, c->pages()) { - bool found = false; - foreach (Document *dd, other->pages()) { - if (d->uri() == dd->uri()) { - found = true; - break; - } - } - if (!found) { - d->setTopic(other); - other->addPage(d); - } - } - - //!!! actually the "approximate" bits of the following are bogus; - // a source reporting birth or death date as approx is probably - // more accurate than one reporting an exact date - - if (c->birth()) { - if (!other->birth() || other->birth()->approximate()) { - other->setBirth(c->birth()); - } - } - - if (c->death()) { - if (!other->death() || other->death()->approximate()) { - other->setDeath(c->death()); - } - } - - if (c->gender() != "") other->setGender(c->gender()); - if (c->nationality() != "") other->setNationality(c->nationality()); - if (c->remarks() != "") other->setRemarks(c->remarks()); - if (c->period() != "") other->setPeriod(c->period()); - -} - -QString -asciify(QString field) -{ - // accented characters etc -- add "ascii version" for dumb search purposes - QString ascii; - for (int i = 0; i < field.length(); ++i) { - QString dc = field[i].decomposition(); - if (dc != "") ascii += dc[0]; - else if (field[i] == QChar(0x00DF)) { - ascii += "ss"; - } else { - ascii += field[i]; - } - } - ascii.replace(QString::fromUtf8("\342\200\231"), "'"); // apostrophe - ascii.replace(QString::fromUtf8("\342\200\222"), "-"); - ascii.replace(QString::fromUtf8("\342\200\223"), "-"); - ascii.replace(QString::fromUtf8("\342\200\224"), "-"); - ascii.replace(QString::fromUtf8("\342\200\225"), "-"); - return ascii; -} - -void -asciify(Composer *c) -{ - QString n = c->name(); - QString asc = asciify(n); - if (asc != n && !c->aliases().contains(asc)) c->addAlias(asc); - foreach (QString alias, c->aliases()) { - asc = asciify(alias); - if (asc != alias && !c->aliases().contains(asc)) c->addAlias(asc); - } -} - -void -asciify(Work *w) -{ - QString n = w->name(); - QString asc = asciify(n); - if (asc != n && !w->aliases().contains(asc)) w->addAlias(asc); - foreach (QString alias, w->aliases()) { - asc = asciify(alias); - if (asc != alias && !w->aliases().contains(asc)) w->addAlias(asc); - } -} - -void -assignUri(Store *s, Composer *c) -{ - static QSet convSet; - QString conv = c->name(); - if (!conv.contains(",")) { - QStringList sl = conv.split(" "); - if (!sl.empty()) { - sl.push_front(sl[sl.size()-1]); - sl.removeLast(); - conv = sl.join(" "); - DEBUG << "assignUri: " << c->name() << " -> " << conv << endl; - } - } - conv = asciify(conv); - conv.replace(" ", "_"); - conv.replace("-", "_"); - conv.replace(QRegExp("[^a-zA-Z0-9_-]"), ""); - conv = conv.toLower(); - QString initial = conv; - int i = 1; - while (convSet.contains(conv)) { - conv = QString("%1__%2").arg(initial).arg(i); - i++; - } - convSet.insert(conv); - c->setProperty("uri", s->expand(":composer_" + conv)); -} - -void -assignUri(Store *s, Work *w, Composer *c) -{ - QString pfx = c->property("uri").toUrl().toString(); - DEBUG << "pfx = " << pfx << endl; - if (!pfx.contains("composer_")) pfx = ""; - else pfx.replace(QRegExp("^.*composer_"), ""); - - static QSet convSet; - QString conv = w->catalogue(); - if (conv == "") conv = w->opus(); - conv = conv.replace(".", ""); - bool hasOpus = (conv != ""); - if (conv == "") conv = w->name(); - if (w->number() != "") conv = conv + "_no" + w->number(); - if (pfx != "") conv = pfx + "_" + conv; - conv = asciify(conv); - conv.replace(" ", "_"); - conv.replace("-", "_"); - conv.replace(":", "_"); - conv.replace(QRegExp("[^a-zA-Z0-9_-]"), ""); - conv = conv.toLower(); - // I think actually for works we want to merge duplicates rather than - // assign them separate URIs, _unless_ they lack a viable opus number - if (!hasOpus) { - QString initial = conv; - int i = 1; - while (convSet.contains(conv)) { - conv = QString("%1__%2").arg(initial).arg(i); - i++; - } - } - convSet.insert(conv); - w->setProperty("uri", s->expand(":work_" + conv)); -} - -void -addDbpediaResource(Store *store, QObject *o, QString s) -{ - QUrl u = o->property("uri").toUrl(); - if (u == QUrl()) return; - if (s.startsWith("http://en.wikipedia.org/wiki/")) { - store->add(Triple(u, - "mo:wikipedia", - QUrl(s))); - s.replace("http://en.wikipedia.org/wiki/", - "http://dbpedia.org/resource/"); - store->add(Triple(u, - "owl:sameAs", - QUrl(s))); - } -} - -int main(int argc, char **argv) -{ - qRegisterMetaType - ("ClassicalData::HistoricalEvent*"); - qRegisterMetaType - ("ClassicalData::Birth*"); - qRegisterMetaType - ("ClassicalData::Death*"); - qRegisterMetaType - ("ClassicalData::Composition*"); - qRegisterMetaType - ("ClassicalData::Work*"); - qRegisterMetaType - ("ClassicalData::Movement*"); - qRegisterMetaType - ("ClassicalData::Composer*"); - qRegisterMetaType - ("ClassicalData::Document*"); - qRegisterMetaType - ("ClassicalData::Form*"); - qRegisterMetaType > - ("QSet"); - qRegisterMetaType > - ("QSet"); - qRegisterMetaType > - ("QSet"); - qRegisterMetaType > - ("QSet"); - qRegisterMetaType > - ("QSet"); - - qRegisterMetaType - ("ClassicalData::ClassicalComposersOrgImporter*"); - qRegisterMetaType - ("ClassicalData::ClassicalDotNetImporter*"); - qRegisterMetaType - ("ClassicalData::WikipediaComposersImporter*"); - qRegisterMetaType - ("ClassicalData::WikipediaWorksImporter*"); - qRegisterMetaType - ("ClassicalData::WikipediaWorksKImporter*"); - qRegisterMetaType - ("ClassicalData::WikipediaWorksListImporter*"); - qRegisterMetaType - ("ClassicalData::HobokenImporter*"); - - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::HistoricalEvent*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::Birth*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::Death*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::Composition*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::Work*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::Movement*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::Composer*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::Document*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::Form*"); - - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::ClassicalComposersOrgImporter*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::ClassicalDotNetImporter*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::WikipediaComposersImporter*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::WikipediaWorksImporter*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::WikipediaWorksKImporter*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::WikipediaWorksListImporter*"); - ObjectBuilder::getInstance()->registerClass - ("ClassicalData::HobokenImporter*"); - - ContainerBuilder::getInstance()->registerContainer - > - ("QString", "QSet", ContainerBuilder::SetKind); - - ContainerBuilder::getInstance()->registerContainer - > - ("ClassicalData::Work*", "QSet", - ContainerBuilder::SetKind); - - ContainerBuilder::getInstance()->registerContainer - > - ("ClassicalData::Movement*", "QSet", - ContainerBuilder::SetKind); - - ContainerBuilder::getInstance()->registerContainer - > - ("ClassicalData::Document*", "QSet", - ContainerBuilder::SetKind); - - ContainerBuilder::getInstance()->registerContainer - > - ("ClassicalData::Form*", "QSet", - ContainerBuilder::SetKind); - - BasicStore *store = BasicStore::load("file:importers.ttl"); - ObjectMapper mapper(store); - QObject *parentObject = mapper.loadAllObjects(new QObject()); - - BasicStore *outstore = new BasicStore(); - ObjectMapper outmapper(outstore); - - outmapper.setPropertyStorePolicy(ObjectMapper::StoreIfChanged); - - outstore->addPrefix("type", outmapper.getObjectTypePrefix()); - outstore->addPrefix("classical", outmapper.getObjectTypePrefix() + "ClassicalData/"); - outstore->addPrefix("property", outmapper.getPropertyPrefix()); - outstore->addPrefix("rel", outmapper.getRelationshipPrefix()); - outstore->addPrefix("foaf", "http://xmlns.com/foaf/0.1/"); - outstore->addPrefix("mo", "http://purl.org/ontology/mo/"); - outstore->addPrefix("dc", "http://purl.org/dc/elements/1.1/"); - outstore->addPrefix("bio", "http://purl.org/vocab/bio/0.1/"); - outstore->addPrefix("owl", "http://www.w3.org/2002/07/owl#"); - outstore->addPrefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#"); - - outmapper.addPropertyMapping("ClassicalData::Composer", "pages", - outstore->expand("foaf:page")); - outmapper.addPropertyMapping("ClassicalData::Composer", "name", - outstore->expand("foaf:name")); - outmapper.addPropertyMapping("ClassicalData::Composer", "aliases", - outstore->expand("property:also_known_as")); - outmapper.addPropertyMapping("ClassicalData::Document", "topic", - outstore->expand("foaf:primaryTopic")); - - outmapper.addTypeMapping("ClassicalData::Work", - outstore->expand("mo:MusicalWork")); - outmapper.addPropertyMapping("ClassicalData::Work", "composition", - outstore->expand("mo:composed_in")); - outmapper.addPropertyMapping("ClassicalData::Work", "opus", - outstore->expand("mo:opus")); - outmapper.addPropertyMapping("ClassicalData::Work", "k6", - outstore->expand("mo:k6")); - outmapper.addPropertyMapping("ClassicalData::Work", "bwv", - outstore->expand("mo:bwv")); - outmapper.addPropertyMapping("ClassicalData::Work", "number", - outstore->expand("mo:number")); - outmapper.addPropertyMapping("ClassicalData::Work", "partOf", - outstore->expand("dc:isPartOf")); - outmapper.addPropertyMapping("ClassicalData::Work", "parts", - outstore->expand("dc:hasPart")); - outmapper.addPropertyMapping("ClassicalData::Work", "pages", - outstore->expand("foaf:page")); - outmapper.addPropertyMapping("ClassicalData::Work", "forms", - outstore->expand("property:form")); - outmapper.addPropertyMapping("ClassicalData::Work", "key", - outstore->expand("mo:key")); - outmapper.addPropertyMapping("ClassicalData::Work", "aliases", - outstore->expand("property:also_known_as")); - outmapper.addPropertyMapping("ClassicalData::Work", "name", - outstore->expand("dc:title")); - - outmapper.addTypeMapping("ClassicalData::Composition", - outstore->expand("mo:Composition")); - outmapper.addPropertyMapping("ClassicalData::Composition", "composer", - outstore->expand("mo:composer")); - outmapper.addPropertyMapping("ClassicalData::Composition", "works", - outstore->expand("mo:produced_work")); - - outstore->add(Triple("classical:Composer", "a", - outstore->expand("owl:Class"))); - outstore->add(Triple("classical:Composer", "rdfs:subClassOf", - outstore->expand("mo:MusicArtist"))); - - QList importers = parentObject->findChildren(); - std::cerr << "have " << importers.size() << " importers" << std::endl; - - ComposerMap composers; - - QList dated; - QList undated; - - QList works; - QList compositions; - QList other; - - foreach (Importer *importer, importers) { - QObjectList objects = importer->getImportedObjects(); - foreach (QObject *o, objects) { - Composer *c; - if ((c = qobject_cast(o))) { - addMiscExpansions(c); - asciify(c); - if (c->birth() || c->death()) dated.push_back(c); - else undated.push_back(c); - continue; - } - Work *w; - if ((w = qobject_cast(o))) { - asciify(w); - works.push_back(w); - continue; - } - Composition *cn; - if ((cn = qobject_cast(o))) { - compositions.push_back(cn); - continue; - } - } - } - - // get all the dated composers merged before attempting to match - // the undated ones - foreach (Composer *c, dated) { - mergeComposer(c, composers); - } - foreach (Composer *c, undated) { - mergeComposer(c, composers); - } - - QObjectList toStore; - - QSet cset; - for (ComposerMap::iterator i = composers.begin(); i != composers.end(); ++i) { - foreach (Composer *c, i.value()) { - if (!cset.contains(c)) { - assignUri(outstore, c); - toStore.push_back(c); - cset.insert(c); - } - foreach (Document *d, c->pages()) { - QString s = d->uri().toString(); - addDbpediaResource(outstore, c, s); - } - } - } - - QSet storedUris; - - foreach (Work *w, works) { - Composition *cn = w->composition(); - if (!cn) continue; - if (!cn->composer()) { - QString cname = cn->composerName(); - if (cname != "") { - if (!composers.contains(cname.toLower())) { - DEBUG << "Failed to assign Composition to composer: no composer matches name " << cname << endl; - } else { - QSet cs = composers[cname.toLower()]; - if (cs.empty()) { - DEBUG << "Failed to assign Composition to composer: no composer matches name " << cname << endl; - } else if (cs.size() > 1) { - DEBUG << "Failed to assign Composition to composer: " - << cs.size() << " composers match name " << cname << endl; - } else { - cn->setComposer(*cs.begin()); - } - } - } else { - DEBUG << "Failed to assign Composition to composer: composer name is empty" << endl; - } - } - - if (cn->composer()) { - assignUri(outstore, w, cn->composer()); - } - - foreach (Document *d, w->pages()) { - QString s = d->uri().toString(); - addDbpediaResource(outstore, w, s); - toStore.push_back(d); - } - - QString u = w->property("uri").toUrl().toString(); - if (u == "" || !storedUris.contains(u)) { - toStore.push_back(w); - if (u != "") storedUris.insert(u); - } - } - - try { - outmapper.storeAllObjects(toStore); - - } catch (RDFException e) { - std::cerr << "Caught RDF exception: " << e.what() << std::endl; - } - - DEBUG << "Stored, now saving" << endl; - - outstore->save("test-out.ttl"); - - DEBUG << "Saved" << endl; - - - QMultiMap cmap; - foreach (Composer *c, cset) { - QString n = c->getSortName(true); - cmap.insert(n, c); - } - - std::cout << "Composers: " << cmap.size() << std::endl; - - for (QMultiMap::iterator i = cmap.begin(); - i != cmap.end(); ++i) { - - QString n = i.key(); - Composer *c = i.value(); - - std::cout << n.toStdString(); - - QString d = c->getDisplayDates(); - if (d != "") std::cout << " (" << d.toStdString() << ")"; - std::cout << std::endl; - } - - std::cout << std::endl; - - std::cout << "Works by composer:" << std::endl; - - for (QMultiMap::iterator i = cmap.begin(); - i != cmap.end(); ++i) { - - QString n = i.key(); - Composer *c = i.value(); - - std::set wmap; - foreach (Work *w, works) { - Composition *cn = w->composition(); - if (!cn) continue; - if (cn->composer() != c) continue; - if (w->partOf()) continue; - wmap.insert(w); - } - - if (wmap.empty()) continue; - - std::cout << n.toStdString() << std::endl; - - foreach (Work *w, wmap) { - std::cout << " * "; - std::cout << w->name().toStdString(); - if (w->catalogue() != "") { - std::cout << " [" << w->catalogue().toStdString() << "]"; - } - if (w->opus() != "") { - std::cout << " [op. " << w->opus().toStdString() << "]"; - } - std::cout << std::endl; - std::set orderedParts; - foreach (Work *ww, w->parts()) { - orderedParts.insert(ww); - } - foreach (Work *ww, orderedParts) { - std::cout << " "; - if (ww->number() != "") { - std::cout << ww->number().toStdString() << ". "; - } - std::cout << ww->name().toStdString(); - if (ww->catalogue() != "" && ww->catalogue() != w->catalogue()) { - std::cout << " [" << ww->catalogue().toStdString() << "]"; - } - if (ww->opus() != "" && ww->opus() != w->opus()) { - std::cout << " [op. " << ww->opus().toStdString() << "]"; - } - std::cout << std::endl; - } - } - - std::cout << std::endl; - } - - delete outstore; - - DEBUG << "Done" << endl; - - -} - - diff -r e8f4c2b55fd8 -r 29ca5974905d import/importers.ttl --- a/import/importers.ttl Tue Dec 01 17:50:41 2009 +0000 +++ b/import/importers.ttl Thu Dec 03 15:42:10 2009 +0000 @@ -6,704 +6,704 @@ :cdn a classical:ClassicalDotNetImporter ; - property:source . + property:source . :wkiA a classical:WikipediaComposersImporter ; - property:source . + property:source . :wkiM a classical:WikipediaComposersImporter ; - property:source . + property:source . :wkiB a classical:WikipediaComposersImporter ; - property:source . + property:source . :wkiC a classical:WikipediaComposersImporter ; - property:source . + property:source . :wkiD a classical:WikipediaComposersImporter ; - property:source . + property:source . :wkiE a classical:WikipediaComposersImporter ; - property:source . + property:source . :wkiF a classical:WikipediaComposersImporter ; - property:source . + property:source . :cciA a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciB a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciC a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciD a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciE a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciF a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciG a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciH a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciI a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciJ a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciK a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciL a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciM a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciN a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciO a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciP a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciQ a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciR a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciS a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciT a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciU a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciV a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciW a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciX a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciY a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . :cciZ a classical:ClassicalComposersOrgImporter ; - property:source . + property:source . # These ones need more work: #:wki_216 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . # mangling of Mazeppa #:wki_345 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . # classification levels all wrong (many works listed at ** level) #:wki_354 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . # tabular form #:wki_201 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :hob a classical:HobokenImporter ; - property:source . + property:source . :wki_198 a classical:WikipediaWorksKImporter ; - property:source . + property:source . ## metapage only ##:wki_199 a classical:WikipediaWorksListImporter ; -## property:source . +## property:source . :wki_200 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_202 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_203 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_204 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_205 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_206 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_207 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_208 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_209 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . # tabular #:wki_210 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_211 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_212 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_213 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_214 a classical:WikipediaWorksListImporter ; - property:source . + property:source . # messy, doesn't work -- do we care? :wki_215 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_217 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_218 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_219 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_220 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_221 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_222 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_223 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_224 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_225 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_226 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_227 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_228 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_229 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_230 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_231 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_232 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_233 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_234 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_235 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_236 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_237 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_238 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_239 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_240 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_241 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_242 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_243 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_244 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_245 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_246 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_247 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_248 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_249 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_250 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_251 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_252 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_253 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_254 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_255 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_256 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_257 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_258 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_259 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_260 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_261 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_262 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_263 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_264 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_265 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_266 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_267 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_268 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_269 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_270 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_271 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_272 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_273 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_274 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_275 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_276 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_277 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_278 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_279 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_280 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_281 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_282 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_283 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_284 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_285 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_286 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_287 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_288 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_289 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_290 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_291 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_292 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_293 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_294 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_295 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_296 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_297 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_298 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_299 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_300 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_301 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_302 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_303 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_304 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_305 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_306 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_307 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_308 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_309 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_310 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_311 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_312 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_313 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_314 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_315 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_316 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_317 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_318 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_319 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_320 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_321 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_322 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_323 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_324 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_325 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_326 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_327 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_328 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_329 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_330 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_331 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_332 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_333 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_334 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_335 a classical:WikipediaWorksListImporter ; -# property:source . # who? +# property:source . # who? :wki_336 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_337 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_338 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_339 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_340 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_341 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_342 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_343 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_344 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_346 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_347 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_348 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_349 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_350 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_351 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_352 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_353 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_355 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_356 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_357 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_358 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_359 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_360 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_361 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_362 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_363 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_364 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_365 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_366 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_367 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_368 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_369 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_370 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_371 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_372 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_373 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_374 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_375 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_376 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_377 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_378 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_379 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_380 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_381 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_382 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_383 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_384 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_386 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_387 a classical:WikipediaWorksListImporter ; - property:source . + property:source . #:wki_388 a classical:WikipediaWorksListImporter ; -# property:source . +# property:source . :wki_389 a classical:WikipediaWorksListImporter ; - property:source . + property:source . :wki_390 a classical:WikipediaWorksListImporter ; - property:source . + property:source .