UNPKG

sparnatural

Version:

Visual client-side SPARQL query builder and knowledge graph exploration tool

267 lines (266 loc) 13 kB
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _OWLSpecificationProvider_parser, _OWLSpecificationProvider_generator; import { DataFactory } from 'rdf-data-factory'; import { Config } from "../../ontologies/SparnaturalConfig"; import { Parser, Generator } from "sparqljs"; import { OWLSpecificationEntity } from "./OWLSpecificationEntity"; import { OWLSpecificationProperty } from "./OWLSpecificationProperty"; import { Dag } from '../../dag/Dag'; import { BaseRDFReader } from '../BaseRDFReader'; import { RDFS } from '../../../rdf/vocabularies/RDFS'; const factory = new DataFactory(); const OWL_NAMESPACE = "http://www.w3.org/2002/07/owl#"; export const OWL = { THING: factory.namedNode(OWL_NAMESPACE + "Thing"), EQUIVALENT_PROPERTY: factory.namedNode(OWL_NAMESPACE + "equivalentProperty"), EQUIVALENT_CLASS: factory.namedNode(OWL_NAMESPACE + "equivalentClass"), UNION_OF: factory.namedNode(OWL_NAMESPACE + "unionOf") }; export class OWLSpecificationProvider extends BaseRDFReader { constructor(n3store, lang) { super(n3store, lang); _OWLSpecificationProvider_parser.set(this, void 0); _OWLSpecificationProvider_generator.set(this, void 0); // init SPARQL parser and generator once __classPrivateFieldSet(this, _OWLSpecificationProvider_parser, new Parser(), "f"); __classPrivateFieldSet(this, _OWLSpecificationProvider_generator, new Generator(), "f"); /* var sparql = ` SELECT ?o2 WHERE { { OPTIONAL {?x ?p1 ?var_1 } OPTIONAL {?x ?p2 ?var_2 } BIND(COALESCE(?var_1, ?var_2) AS ?var) } ?x ?p2 ?o2 . } `; var query = this.#parser.parse(sparql); console.dir(query) */ } getLanguages() { let languages = this.store .getQuads(null, RDFS.LABEL, null, null) .map((quad) => quad.object.language); // deduplicate the list of languages return [...new Set(languages)]; } getEntity(entityUri) { return new OWLSpecificationEntity(entityUri, this, this.store, this.lang); } getProperty(property) { return new OWLSpecificationProperty(property, this, this.store, this.lang); } getAllSparnaturalEntities() { var classes = this.getEntitiesInDomainOfAnyProperty(); // copy initial array // create a set to avoid duplicates var result = new Set(classes.slice()); // now look for all classes we can reach from this class list for (const aClass of classes) { var connectedClasses = this.getEntity(aClass).getConnectedEntities(); for (const aConnectedClass of connectedClasses) { result.add(aConnectedClass); } } return Array.from(result); } getEntitiesInDomainOfAnyProperty() { const quadsArray = this.store.getQuads(null, RDFS.DOMAIN, null, null); const items = new Set(); for (const quad of quadsArray) { // we are not looking at domains of _any_ property // the property we are looking at must be a Sparnatural property, with a known type var objectPropertyId = quad.subject.value; var typeClass = quad.object.termType; var classId = quad.object.value; var classAsRDFTerm = quad.object; // empty string means we are searching without specifying a range if (this.getProperty(objectPropertyId).getPropertyType("")) { // keep only Sparnatural classes in the list if (typeClass == "BlankNode" || this.isSparnaturalClass(classId)) { // always exclude "remote classes" that should not have a type that from first list if (this.getEntity(classId).hasTypeCriteria()) { if (!this._isUnionClass(classAsRDFTerm)) { items.add(classId); } else { // read union content - /!\ this returns RDFTerm var classesInUnion = this.graph.readAsList(classAsRDFTerm, OWL.UNION_OF); for (const aUnionClass of classesInUnion) { items.add(aUnionClass.value); } } } } } } return this._sort(Array.from(items)); } getEntitiesTreeInDomainOfAnyProperty() { // 1. get the entities that are in a domain of a property let entities = this.getEntitiesInDomainOfAnyProperty().map(s => this.getEntity(s)); // build dag from flat list let dag = new Dag(); dag.initFlatTreeFromFlatList(entities); return dag; } isSparnaturalClass(classUri) { return (this.store.getQuads(factory.namedNode(classUri), RDFS.SUBCLASS_OF, factory.namedNode(Config.SPARNATURAL_CLASS), null).length > 0 || this.store.getQuads(factory.namedNode(classUri), RDFS.SUBCLASS_OF, factory.namedNode(Config.NOT_INSTANTIATED_CLASS), null).length > 0 || this.store.getQuads(factory.namedNode(classUri), RDFS.SUBCLASS_OF, factory.namedNode(Config.RDFS_LITERAL), null).length > 0); } expandSparql(sparql, prefixes) { // for each owl:equivalentProperty ... var equivalentPropertiesPerProperty = {}; this.store .getQuads(null, OWL.EQUIVALENT_PROPERTY, null, null) .forEach((quad) => { // store it if multiple equivalences are declared if (!equivalentPropertiesPerProperty[quad.subject.value]) { equivalentPropertiesPerProperty[quad.subject.value] = []; } equivalentPropertiesPerProperty[quad.subject.value].push(quad.object.value); }); // join the equivalences with a | for (let [property, equivalents] of Object.entries(equivalentPropertiesPerProperty)) { var re = new RegExp("<" + property + ">", "g"); sparql = sparql.replace(re, "<" + equivalents.join(">|<") + ">"); } // for each owl:equivalentClass ... var equivalentClassesPerClass = {}; this.store .getQuads(null, OWL.EQUIVALENT_CLASS, null, null) .forEach((quad) => { // store it if multiple equivalences are declared if (!equivalentClassesPerClass[quad.subject.value]) { equivalentClassesPerClass[quad.subject.value] = []; } equivalentClassesPerClass[quad.subject.value].push(quad.object.value); }); // use a VALUES if needed var i = 0; for (let [aClass, equivalents] of Object.entries(equivalentClassesPerClass)) { var re = new RegExp("<" + aClass + ">", "g"); if (equivalents.length == 1) { sparql = sparql.replace(re, "<" + equivalents[0] + ">"); } else { sparql = sparql.replace(re, "?class" + i + " . VALUES ?class" + i + " { <" + equivalents.join("> <") + "> } "); } i++; } // for each sparqlString this.store .getQuads(null, factory.namedNode(Config.SPARQL_STRING), null, null) .forEach((quad) => { // prepare the regex let classUri = quad.subject.value; let sparqlString = quad.object.value; // first pass to work with classes sparqlString that can contain a long expression // with variables and MINUSes, like // <http://exemple.com/MyClass> MINUS { $this <http://exemple.com/myProp> ?x VALUES ?x { A B } } // replace the $this with the name of the original variable in the query // \S matches any non-whitespace character var re = new RegExp("(\\S*) (rdf:type|a) <" + classUri + ">", "g"); // prepare the function that will return the string to replace let replacer = function (match, p1, offset, fullString) { // first substitutes any other variable name with a prefix // so that we garantee unicity across the complete query var reVariables = new RegExp("\\?(\\S*)", "g"); let whereClauseReplacedVariables = p1 + " rdf:type " + sparqlString.replace(reVariables, "?$1_" + p1.substring(1)); // then, replace the match on the original URI with the whereClause of the target // replacing "$this" with the original variable name var reThis = new RegExp("\\$this", "g"); let whereClauseReplacedThis = whereClauseReplacedVariables.replace(reThis, p1); return whereClauseReplacedThis; }; sparql = sparql.replace(re, replacer); // then a second pass simpler one that will work for properties var re = new RegExp("<" + quad.subject.value + ">", "g"); sparql = sparql.replace(re, quad.object.value); }); // reparse the query, apply prefixes, and reserialize the query var query = __classPrivateFieldGet(this, _OWLSpecificationProvider_parser, "f").parse(sparql); for (var key in prefixes) { query.prefixes[key] = prefixes[key]; } let finalString = __classPrivateFieldGet(this, _OWLSpecificationProvider_generator, "f").stringify(query); return finalString; } _sort(items) { var me = this; const compareFunction = function (item1, item2) { // return me.getLabel(item1).localeCompare(me.getLabel(item2)); var entity1 = me.getEntity(item1); var entity2 = me.getEntity(item2); var order1 = entity1.getOrder(); var order2 = entity2.getOrder(); if (order1) { if (order2) { if (order1 == order2) { return entity1.getLabel().localeCompare(entity2.getLabel()); } else { // if the order is actually a number, convert it to number and use a number conversion if (!isNaN(Number(order1)) && !isNaN(Number(order2))) { return Number(order1) - Number(order2); } else { return (order1 > order2) ? 1 : -1; } } } else { return -1; } } else { if (order2) { return 1; } else { return entity1.getLabel().localeCompare(entity2.getLabel()); } } }; // sort according to order or label items.sort(compareFunction); return items; } /** * Reads config:order of an entity and returns it, or null if not set **/ _readOrder(uri) { return this.graph.readSingleProperty(uri, factory.namedNode(Config.ORDER))?.value; } /*** Handling of UNION classes ***/ _readUnionContent(classUri) { var lists = this.graph.readProperty(factory.namedNode(classUri), OWL.UNION_OF); if (lists.length > 0) { return this.graph.readListContent(lists[0]); } } _isUnionClass(classUriOrBNodeIdentifier) { return this.graph.hasProperty(classUriOrBNodeIdentifier, OWL.UNION_OF); } } _OWLSpecificationProvider_parser = new WeakMap(), _OWLSpecificationProvider_generator = new WeakMap(); //# sourceMappingURL=OWLSpecificationProvider.js.map