26 #include <QtCore/QSet>
27 #include <QtCore/QDir>
28 #include <QtCore/QFile>
29 #include <QtCore/QDateTime>
30 #include <QtCore/QMutexLocker>
32 #include <Soprano/Node>
33 #include <Soprano/LiteralValue>
34 #include <Soprano/QueryResultIterator>
35 #include <Soprano/Model>
36 #include <Soprano/Vocabulary/RDF>
37 #include <Soprano/Vocabulary/RDFS>
38 #include <Soprano/Vocabulary/NAO>
39 #include <Soprano/Vocabulary/NRL>
40 #include <Soprano/Vocabulary/XMLSchema>
44 using namespace Soprano;
45 using namespace Soprano::Vocabulary;
49 class Nepomuk2::ClassAndPropertyTree::ClassOrProperty
56 hasRdfsLiteralRange(false) {
66 QSet<QUrl> directParents;
69 QSet<QUrl> allParents;
82 QVariant::Type literalType;
83 bool hasRdfsLiteralRange;
88 m_mutex(QMutex::Recursive)
90 Q_ASSERT(s_self == 0);
102 QMutexLocker lock(&m_mutex);
103 if(
const ClassOrProperty* cop = findClassOrProperty(uri))
104 return !cop->isProperty;
111 QMutexLocker lock(&m_mutex);
112 if(
const ClassOrProperty* cop = findClassOrProperty(uri))
113 return cop->allParents;
121 foreach(
const QUrl& uri, types) {
122 all.unite( allParents(uri) );
132 if( type == superClass )
135 QMutexLocker lock(&m_mutex);
136 if(
const ClassOrProperty* cop = findClassOrProperty(type))
137 return cop->allParents.contains(superClass);
144 if(superClass == RDFS::Resource()) {
148 foreach(
const QUrl & type, types ) {
149 if( isChildOf( type, superClass ) )
157 QMutexLocker lock(&m_mutex);
158 if(
const ClassOrProperty* cop = findClassOrProperty(type))
159 return cop->maxCardinality;
166 QMutexLocker lock(&m_mutex);
167 if(
const ClassOrProperty* cop = findClassOrProperty(uri))
175 QMutexLocker lock(&m_mutex);
176 if(
const ClassOrProperty* cop = findClassOrProperty(uri))
185 QMutexLocker lock(&m_mutex);
186 if(
const ClassOrProperty* cop = findClassOrProperty(uri))
187 return (cop->range.toString().startsWith(XMLSchema::xsdNamespace().toString() ) ||
188 cop->range == RDFS::Literal());
195 QMutexLocker lock(&m_mutex);
196 if(
const ClassOrProperty* cop = findClassOrProperty(uri))
197 return cop->defining == 1;
204 QSet<Soprano::Node> nodes = variantListToNodeSet(QVariantList() << value, property);
206 return Soprano::Node();
208 return *nodes.begin();
215 QSet<Soprano::Node> nodes;
216 nodes.reserve( vl.size() );
219 QVariant::Type literalType;
220 bool hasRdfsLiteralRange =
false;
224 QMutexLocker lock(&m_mutex);
225 const ClassOrProperty* propertyNode = findClassOrProperty( property );
226 if( !propertyNode ) {
227 setError( QString::fromLatin1(
"Cannot set values for abstract property '%1'.")
228 .arg( Soprano::Node::resourceToN3( property ) ) );
229 return QSet<Soprano::Node>();
232 range = propertyNode->range;
233 literalType = propertyNode->literalType;
234 hasRdfsLiteralRange = propertyNode->hasRdfsLiteralRange;
240 if(range.isEmpty()) {
241 setError(QString::fromLatin1(
"Cannot set values for abstract property '%1'.").arg(property.toString()), Soprano::Error::ErrorInvalidArgument);
242 return QSet<Soprano::Node>();
248 if( hasRdfsLiteralRange ) {
249 Q_FOREACH(
const QVariant& value, vl) {
250 nodes.insert(Soprano::LiteralValue::createPlainLiteral(value.toString()));
258 if(literalType == QVariant::Invalid) {
259 Q_FOREACH(
const QVariant& value, vl) {
261 if(value.type() == QVariant::Url) {
262 QUrl url = value.toUrl();
263 if( url.scheme().isEmpty() && !url.toString().startsWith(
"_:") )
264 url.setScheme(
"file");
267 else if(value.type() == QVariant::String) {
268 QString s = value.toString();
271 if(s[0] == QDir::separator() && QFile::exists(s)) {
272 nodes.insert(QUrl::fromLocalFile(s));
276 nodes.insert(QUrl(s));
281 setError(QString::fromLatin1(
"Encountered an empty string where a resource URI was expected."), Soprano::Error::ErrorInvalidArgument);
282 return QSet<Soprano::Node>();
287 setError(QString::fromLatin1(
"Encountered '%1' where a resource URI was expected.").arg(value.toString()), Soprano::Error::ErrorInvalidArgument);
288 return QSet<Soprano::Node>();
298 Q_FOREACH(
const QVariant& value, vl) {
302 if((range == XMLSchema::xsdFloat() || range == XMLSchema::xsdDouble())
303 && value.type() == QVariant::String) {
306 if ( sscanf( value.toString().toLatin1().data(),
"%d/%d", &x, &y ) == 2 && y != 0 ) {
307 const double v = double( x )/double( y );
308 nodes.insert(LiteralValue::fromVariant(v, range));
317 else if(range == XMLSchema::dateTime()
318 && value.canConvert(QVariant::UInt)) {
320 const int t = value.toInt(&ok);
321 if(ok && t > 0 && t <= 9999) {
322 nodes.insert(LiteralValue(QDateTime(QDate(t, 1, 1), QTime(0, 0), Qt::UTC)));
327 Soprano::LiteralValue v = Soprano::LiteralValue::fromVariant(value, range);
333 setError(QString::fromLatin1(
"Failed to convert '%1' to literal of type '%2'.").arg(value.toString(), range.toString()), Soprano::Error::ErrorInvalidArgument);
334 return QSet<Soprano::Node>();
343 namespace Vocabulary {
344 namespace XMLSchema {
346 return QUrl( Soprano::Vocabulary::XMLSchema::xsdNamespace().toString() +
347 QLatin1String(
"duration") );
355 QMutexLocker lock(&m_mutex);
361 = QString::fromLatin1(
"select distinct ?r ?p ?v ?mc ?c ?domain ?range ?ct ?pt "
363 "{ ?r a ?ct . FILTER(?ct=rdfs:Class) . "
364 "OPTIONAL { ?r rdfs:subClassOf ?p . ?p a rdfs:Class . } . } "
366 "{ ?r a ?pt . FILTER(?pt=rdf:Property) . "
367 "OPTIONAL { ?r rdfs:subPropertyOf ?p . ?p a rdf:Property . } . } "
368 "OPTIONAL { ?r %1 ?mc . } . "
369 "OPTIONAL { ?r %2 ?c . } . "
370 "OPTIONAL { ?r %3 ?domain . } . "
371 "OPTIONAL { ?r %4 ?range . } . "
374 .arg(Soprano::Node::resourceToN3(NRL::maxCardinality()),
375 Soprano::Node::resourceToN3(NRL::cardinality()),
376 Soprano::Node::resourceToN3(RDFS::domain()),
377 Soprano::Node::resourceToN3(RDFS::range()),
378 Soprano::Node::resourceToN3(RDFS::Resource()));
380 Soprano::QueryResultIterator it
381 = model->executeQuery( query, Soprano::Query::QueryLanguageSparql );
383 const QUrl r = it[
"r"].uri();
384 const Soprano::Node p = it[
"p"];
385 const Soprano::Node v = it[
"v"];
386 int mc = it[
"mc"].literal().toInt();
387 int c = it[
"c"].literal().toInt();
388 const QUrl domain = it[
"domain"].uri();
389 const QUrl range = it[
"range"].uri();
391 ClassOrProperty* r_cop = 0;
393 if(copIt != m_tree.end()) {
394 r_cop = copIt.value();
397 r_cop =
new ClassOrProperty;
399 m_tree.insert( r, r_cop );
402 r_cop->isProperty = it[
"pt"].isValid();
404 if(mc > 0 || c > 0) {
405 r_cop->maxCardinality = qMax(mc, c);
408 if(!domain.isEmpty()) {
409 r_cop->domain = domain;
412 if(!range.isEmpty()) {
413 r_cop->range = range;
417 r_cop->literalType = QVariant::UInt;
418 else if( range == RDFS::Literal() ) {
419 r_cop->literalType = QVariant::UserType;
420 r_cop->hasRdfsLiteralRange =
true;
423 r_cop->literalType = Soprano::LiteralValue::typeFromDataTypeUri( range );
427 r_cop->defining = -1;
430 if ( p.isResource() &&
432 p.uri() != RDFS::Resource() ) {
433 ClassOrProperty* p_cop = 0;
434 if ( !m_tree.contains( p.uri() ) ) {
435 p_cop =
new ClassOrProperty;
436 p_cop->uri = p.uri();
437 m_tree.insert( p.uri(), p_cop );
439 r_cop->directParents.insert(p.uri());
446 if(m_tree.contains(NAO::identifier())) {
447 ClassOrProperty* cop = m_tree[NAO::identifier()];
448 cop->range = XMLSchema::string();
449 cop->literalType = QVariant::String;
453 ClassOrProperty* rdfsResourceNode = 0;
455 if( rdfsResourceIt == m_tree.end() ) {
456 rdfsResourceNode =
new ClassOrProperty;
457 rdfsResourceNode->uri = RDFS::Resource();
458 m_tree.insert( RDFS::Resource(), rdfsResourceNode );
461 rdfsResourceNode = rdfsResourceIt.value();
464 it != m_tree.end(); ++it ) {
465 if( it.value() != rdfsResourceNode && it.value()->directParents.isEmpty() ) {
466 it.value()->directParents.insert( RDFS::Resource() );
472 it != m_tree.end(); ++it ) {
473 QSet<QUrl> visitedNodes;
474 getAllParents( it.value(), visitedNodes );
480 query = QString::fromLatin1(
"select ?p ?t where { "
481 "?p a rdf:Property . "
482 "?p a ?t . FILTER(?t!=rdf:Property) . }");
483 it = model->executeQuery( query, Soprano::Query::QueryLanguageSparql );
485 const QUrl p = it[
"p"].uri();
486 const QUrl t = it[
"t"].uri();
488 if(t == NRL::DefiningProperty()) {
489 m_tree[p]->defining = 1;
491 else if(t == NRL::NonDefiningProperty()) {
492 m_tree[p]->defining = -1;
497 if(m_tree.contains(RDF::type()))
498 m_tree[RDF::type()]->defining = 1;
501 if(m_tree.contains(NAO::hasSubResource()))
502 m_tree[NAO::hasSubResource()]->defining = 1;
505 it != m_tree.end(); ++it ) {
506 if(it.value()->isProperty) {
507 QSet<QUrl> visitedNodes;
508 updateDefining( it.value(), visitedNodes );
513 const Nepomuk2::ClassAndPropertyTree::ClassOrProperty * Nepomuk2::ClassAndPropertyTree::findClassOrProperty(
const QUrl &uri)
const
516 if(it == m_tree.constEnd())
524 return m_tree.contains(uri);
532 int Nepomuk2::ClassAndPropertyTree::updateDefining( ClassOrProperty* cop, QSet<QUrl>& definingNodes )
534 if ( cop->defining != 0 ) {
535 return cop->defining;
538 for ( QSet<QUrl>::iterator it = cop->directParents.begin();
539 it != cop->directParents.end(); ++it ) {
541 if( definingNodes.contains(*it) )
543 definingNodes.insert(*it);
544 if ( updateDefining( m_tree[*it], definingNodes ) == 1 ) {
549 if ( cop->defining == 0 ) {
551 cop->defining = hasLiteralRange(cop->uri) ? 1 : -1;
554 return cop->defining;
558 QSet<QUrl> Nepomuk2::ClassAndPropertyTree::getAllParents(ClassOrProperty* cop, QSet<QUrl>& visitedNodes)
560 if(cop->allParents.isEmpty()) {
561 for ( QSet<QUrl>::iterator it = cop->directParents.begin();
562 it != cop->directParents.end(); ++it ) {
564 if( visitedNodes.contains(*it) )
566 visitedNodes.insert( *it );
567 cop->allParents += getAllParents(m_tree[*it], visitedNodes);
569 cop->allParents += cop->directParents;
572 cop->allParents << RDFS::Resource();
573 cop->allParents.remove(cop->uri);
575 return cop->allParents;
580 Soprano::Node convertIfBlankNode(
const Soprano::Node & n ) {
581 if( n.isResource() ) {
582 const QString uriString = n.uri().toString();
583 if( uriString.startsWith(
"_:") ) {
584 return Soprano::Node( uriString.mid(2) );
596 #include "classandpropertytree.moc"
bool hasLiteralRange(const QUrl &uri) const
QUrl propertyDomain(const QUrl &uri) const
bool contains(const QUrl &uri) const
Returns true if the uri is a Class or a Property.
QUrl propertyRange(const QUrl &uri) const
static ClassAndPropertyTree * self()
bool isChildOf(const QUrl &type, const QUrl &superClass) const
void rebuildTree(Soprano::Model *model)
QSet< QUrl > allParents(const QUrl &uri) const
Soprano::Node variantToNode(const QVariant &value, const QUrl &property) const
will try very hard to convert a variant into a node. Supports literal XML types and QUrl ...
bool isDefiningProperty(const QUrl &uri) const
ClassAndPropertyTree(QObject *parent=0)
QSet< Soprano::Node > variantListToNodeSet(const QVariantList &vl, const QUrl &property) const
int maxCardinality(const QUrl &type) const
bool isKnownClass(const QUrl &uri) const