To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

root / utilities / composer / composer.cpp @ 53:bcea875d8d2f

History | View | Annotate | Download (11.5 KB)

1
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2

    
3
#include "Objects.h"
4
#include "TypeRegistrar.h"
5

    
6
#include <dataquay/BasicStore.h>
7
#include <dataquay/TransactionalStore.h>
8
#include <dataquay/RDFException.h>
9
#include <dataquay/objectmapper/ObjectLoader.h>
10
#include <dataquay/objectmapper/ObjectStorer.h>
11
#include <dataquay/objectmapper/ObjectMapper.h>
12
#include <dataquay/objectmapper/TypeMapping.h>
13

    
14
#include <QMultiMap>
15
#include <QFileInfo>
16

    
17
#include <iostream>
18

    
19
using namespace Dataquay;
20
using namespace ClassicalData;
21
using namespace std;
22

    
23
/*
24
ostream &operator<<(ostream &target, const QString &str)
25
{
26
    return target << str.toLocal8Bit().data();
27
}
28

29
ostream &operator<<(ostream &target, const QUrl &u)
30
{
31
    return target << "<" << u.toString() << ">";
32
}
33
*/
34

    
35
bool
36
load(BasicStore *store, QString fileName)
37
{
38
    QUrl url = QUrl::fromLocalFile(fileName);
39

    
40
    cerr << "Importing from URL " << url << " ...";
41
    try {
42
        store->import(url, BasicStore::ImportPermitDuplicates);
43
    } catch (RDFException e) {
44
        cerr << " retrying with explicit ntriples type...";
45
        try {
46
            store->import(url, BasicStore::ImportPermitDuplicates, "ntriples");
47
        } catch (RDFException e) {
48
            cerr << "failed" << endl;
49
            cerr << "Import failed: " << e.what() << endl;
50
            return false;
51
        }
52
    }
53

    
54
    cerr << " done" << endl;
55
    return true;
56
}
57

    
58
void
59
usage(char *name)
60
{
61
    int s = 0;
62
    for (int i = 0; name[i]; ++i) if (name[i] == '/') s = i + 1;
63
    name = name + s;
64
    cerr << "Usage:" << endl;
65
    cerr << "  " << name << " <input-rdf-file> list" << endl;
66
    cerr << "  " << name << " <input-rdf-file> list-uris" << endl;
67
    cerr << "  " << name << " <input-rdf-file> show <uri> [<uri> ...]" << endl;
68
    cerr << "  " << name << " <input-rdf-file> search <text>" << endl;
69
    cerr << "  " << name << " <input-rdf-file> match <text>" << endl;
70
    cerr << "  " << name << " <input-rdf-file> merge <target-uri> <dup> [<dup> ...]" << endl;
71
    cerr << "  " << name << " <input-rdf-file> write" << endl;
72
    exit(-1);
73
}
74

    
75
static QList<Composer *> allComposers;
76
static QMap<Composer *, QSet<Work *> > worksMap;
77

    
78
void
79
show(Composer *c)
80
{
81
    cout << c->property("uri").value<Uri>() << endl;
82
    cout << c->getSortName(true);
83
    QString d = c->getDisplayDates();
84
    if (d != "") cout << " (" << d << ")";
85
    if (!c->nationality().empty() || c->period() != "") {
86
        cout << " [";
87
        bool first = true;
88
        foreach (QString n, c->nationality()) {
89
            if (!first) cout << "/";
90
            cout << n;
91
            first = false;
92
        }
93
        if (c->period() != "") {
94
            if (!first) cout << ", ";
95
            cout << c->period();
96
        }
97
        cout << "]";
98
    }
99
    if (c->gender() != "") {
100
        cout << " *" << c->gender();
101
    }
102
    if (!worksMap[c].empty()) {
103
        cout << " [" << worksMap[c].size() << " work(s)]";
104
    }
105
    cout << endl;
106
    foreach (QString a, c->aliases()) {
107
        cout << " - " << a << endl;
108
    }
109
    if (c->remarks() != "") {
110
        cout << " " << c->remarks() << endl;
111
    }
112
    foreach (Document *d, c->pages()) {
113
        cout << d->siteName() << " -> " << d->uri() << endl;
114
    }
115
    foreach (Uri u, c->otherURIs()) {
116
        cout << "Same as " << u << endl;
117
    }
118
}
119

    
120
void
121
showBrief(Composer *c)
122
{
123
    cout << c->property("uri").value<Uri>() << endl;
124
    cout << c->getSortName(false);
125
    QString d = c->getDisplayDates();
126
    if (d != "") cout << " (" << d << ")";
127
    if (!c->nationality().empty() || c->period() != "") {
128
        cout << " [";
129
        bool first = true;
130
        foreach (QString n, c->nationality()) {
131
            if (!first) cout << "/";
132
            cout << n;
133
            first = false;
134
        }
135
        if (c->period() != "") {
136
            if (!first) cout << " ";
137
            cout << c->period();
138
        }
139
        cout << "]";
140
    }
141
    if (c->gender() != "") {
142
        cout << " *" << c->gender();
143
    }
144
    if (!worksMap[c].empty()) {
145
        cout << " [" << worksMap[c].size() << " work(s)]";
146
    }
147
    cout << endl;
148
}
149

    
150
void
151
listBrief(QList<Composer *> composers)
152
{
153
    QMultiMap<QString, Composer *> sorted;
154
    foreach (Composer *c, composers) {
155
        sorted.insert(c->getSortName(false), c);
156
    }
157
    foreach (Composer *c, sorted) {
158
        showBrief(c);
159
    }
160
}
161

    
162
void
163
listUris(QList<Composer *> composers)
164
{
165
    QMultiMap<Uri, Composer *> sorted;
166
    foreach (Composer *c, composers) {
167
        sorted.insert(c->property("uri").value<Uri>(), c);
168
    }
169
    foreach (Uri uri, sorted.keys()) {
170
        cout << uri << endl;
171
    }
172
}
173

    
174
void
175
showSearchResults(QMultiMap<float, Composer *> matches, int count)
176
{
177
    int n = 0;
178
    for (QMultiMap<float, Composer *>::const_iterator i = matches.end();
179
         i != matches.begin(); ) {
180
        --i;
181
        if (i.key() <= 0) continue;
182
        cout << endl;
183
        if (n == 0) {
184
            cout << "Best match:" << endl;
185
        } else if (n == 1) {
186
            cout << "Other candidate(s):" << endl;
187
        }
188
        cout << "[" << i.key() << "] ";
189
        if (n == 0) show(i.value());
190
        else showBrief(i.value());
191
        if (++n > count) break;
192
    }
193
    if (n == 0) cout << "No matches" << endl;
194
    cout << endl;
195
}
196

    
197
void
198
search(QString typing)
199
{
200
    cout << "Searching (quick) for: " << typing << endl;
201
    QMultiMap<float, Composer *> matches;
202
    foreach (Composer *c, allComposers) {
203
        float value = c->matchTypingQuick(typing);
204
        matches.insert(value, c);
205
    }
206
    showSearchResults(matches, 5);
207

    
208
    cout << "Searching (slow) for: " << typing << endl;
209
    matches.clear();
210
    foreach (Composer *c, allComposers) {
211
        float value = c->matchTyping(typing);
212
        matches.insert(value, c);
213
    }
214
    showSearchResults(matches, 5);
215
}
216

    
217
void
218
match(QString text)
219
{
220
    cout << "Matching: " << text << endl;
221
    QMultiMap<float, Composer *> matches;
222
    QRegExp sre("[\\., -]+");
223
    QStringList elements = text.toLower().split(sre, QString::SkipEmptyParts);
224
    foreach (Composer *c, allComposers) {
225
        float value = c->matchFuzzyName(elements);
226
        matches.insert(value, c);
227
    }
228
    showSearchResults(matches, 5);
229
}
230

    
231
QList<Composer *>
232
matchWildcard(QString text)
233
{
234
    if (!text.contains('/') && !text.contains('*')) {
235
        text = "*" + text + "*";
236
    }
237
    QRegExp re(text, Qt::CaseInsensitive, QRegExp::Wildcard);
238
    QList<Composer *> results;
239
    foreach (Composer *c, allComposers) {
240
        if (re.exactMatch(c->property("uri").value<Uri>().toString())) {
241
            results.push_back(c);
242
        }
243
    }
244
    return results;
245
}    
246

    
247
Composer *
248
matchSingle(QString text)
249
{
250
    QList<Composer *> matches = matchWildcard(text);
251
    if (matches.empty()) {
252
        cerr << "matchSingle: No matches for " << text << endl;
253
        return 0;
254
    } else if (matches.size() > 1) {
255
        cerr << "matchSingle: Multiple matches for " << text << endl;
256
        return 0;
257
    }
258
    return matches[0];
259
}
260

    
261
void
262
showWildcard(QString text)
263
{
264
    cout << "Showing URI or wildcard: " << text << endl;
265
    cout << endl;
266
    foreach (Composer *c, matchWildcard(text)) {
267
        show(c);
268
        cout << endl;
269
    }
270
}
271

    
272
void
273
merge(Composer *target, QList<Composer *> sources, BasicStore *store)
274
{
275
    cout << "Merging into this composer record:" << endl << endl;
276
    show(target);
277
    cout << endl << "... the following composer record(s):" << endl;
278
    foreach (Composer *c, sources) {
279
        cout << endl;
280
        show(c);
281
        target->mergeFrom(c);
282

    
283
        QSet<Work *> works = worksMap[c];
284
        foreach (Work *w, works) {
285
            w->composition()->setComposer(target);
286
        }
287
        worksMap[target].unite(works);
288
        worksMap.remove(c);
289

    
290
        delete c->birth();
291
        delete c->death();
292
        delete c;
293

    
294
        //!!! and composition events!
295
    }
296
    cout << endl << "Result after merging:" << endl << endl;;
297
    show(target);
298
    cout << endl;
299
}
300

    
301
int
302
main(int argc, char **argv)
303
{
304
    if (argc < 3) usage(argv[0]);
305
    QString inFileName = argv[1];
306
    QString command = argv[2];
307
    QStringList args;
308
    for (int i = 3; i < argc; ++i) {
309
        args.push_back(argv[i]);
310
    }
311

    
312
    BasicStore *store = new BasicStore();
313
    store->setBaseUri(Uri("http://dbtune.org/classical/resource/"));
314
    ObjectLoader *loader = new ObjectLoader(store);
315
//    loader->setFollowPolicy(ObjectLoader::FollowObjectProperties);
316

    
317
    TypeMapping tm;
318

    
319
    TypeRegistrar::registerTypes();
320
    TypeRegistrar::addMappings(store, &tm);
321

    
322
    loader->setTypeMapping(tm);
323

    
324
    if (!load(store, inFileName)) {
325
        cerr << "Failed to load data source" << endl;
326
        return 1;
327
    }
328

    
329
    cerr << "Imported RDF data, mapping to objects...";
330
    QObjectList objects = loader->loadAll();
331
    cerr << " done" << endl;
332

    
333
    delete loader;
334

    
335
    bool write = false, writeFull = false;
336
    if (command == "merge") {
337
        write = true;
338
    } else if (command == "write") {
339
        writeFull = true;
340
    }
341

    
342
    TransactionalStore *ts = 0;
343
    ObjectMapper *mapper = 0;
344

    
345
    if (write) {
346
        cerr << "Managing objects...";
347
        ts = new TransactionalStore(store);
348
        mapper = new ObjectMapper(ts);
349
        mapper->setTypeMapping(tm);
350
        mapper->manage(objects);
351
        cerr << " done" << endl;
352
    }
353
    
354
    foreach (QObject *o, objects) {
355
        Composer *c = qobject_cast<Composer *>(o);
356
        if (c) allComposers.push_back(c);
357
    }
358
    
359
    QList<Work *> works;
360
    foreach (QObject *o, objects) {
361
        Work *w = qobject_cast<Work *>(o);
362
        if (w) works.push_back(w);
363
    }
364

    
365
    foreach (Work *w, works) {
366
        Composition *c = w->composition();
367
        if (c) {
368
            Composer *cp = c->composer();
369
            if (cp) worksMap[cp].insert(w);
370
        }
371
    }
372

    
373
    if (command == "write") {
374
        if (!args.empty()) usage(argv[0]);
375
    } else if (command == "list") {
376
        if (!args.empty()) usage(argv[0]);
377
        listBrief(allComposers);
378
    } else if (command == "list-uris") {
379
        if (!args.empty()) usage(argv[0]);
380
        listUris(allComposers);
381
    } else {
382
        if (args.empty()) usage(argv[0]);
383
        if (command == "show") {
384
            foreach (QString s, args) {
385
                showWildcard(s);
386
            }
387
        } else if (command == "search") {
388
            foreach (QString s, args) {
389
                search(s);
390
            }
391
        } else if (command == "match") {
392
            foreach (QString s, args) {
393
                match(s);
394
            }
395
        } else if (command == "merge") {
396
            if (args.size() < 2) usage(argv[0]);
397
            Composer *target = matchSingle(args[0]);
398
            if (!target) return 1;
399
            QList<Composer *> sources;
400
            for (int i = 1; i < args.size(); ++i) {
401
                Composer *c = matchSingle(args[i]);
402
                if (!c) return 1;
403
                sources.push_back(c);
404
            }
405
            merge(target, sources, store);
406
        }
407
    }
408
        
409
    if (write) {
410

    
411
        cerr << "Committing changes...";
412
        mapper->commit();
413
        cerr << " done" << endl;
414

    
415
        cerr << "Saving to file out.ttl...";
416
        store->save("out.ttl");
417
        cerr << " done" << endl;
418

    
419
    } else if (writeFull) {
420

    
421
        ObjectStorer *storer = new ObjectStorer(store);
422

    
423
        storer->setTypeMapping(tm);
424

    
425
        storer->setPropertyStorePolicy(ObjectStorer::StoreIfChanged);
426
        storer->setBlankNodePolicy(Dataquay::NeverUseBlankNodes);
427

    
428
        cerr << "Mapping results back to store...";
429
        storer->setFollowPolicy(ObjectStorer::FollowObjectProperties);
430
        storer->store(objects);
431
        cerr << " done" << endl;
432
 
433
        cerr << "Saving to file out.ttl...";
434
        store->save("out.ttl");
435
        cerr << " done" << endl;
436

    
437
        delete storer;
438
    }
439

    
440
    delete mapper;
441
    delete ts;
442

    
443
    delete store;
444
}
445