sparnatural
Version:
Visual client-side SPARQL query builder and knowledge graph exploration tool
816 lines (698 loc) • 32.3 kB
text/typescript
import { BaseRDFReader, RDF, RDFS } from "../BaseRDFReader";
import { DataFactory, NamedNode } from 'rdf-data-factory';
import { DASH, SH, SHACLSpecificationProvider, SKOS, VOLIPI, XSD } from "./SHACLSpecificationProvider";
import { SHACLSpecificationEntry } from "./SHACLSpecificationEntry";
import { SHACLSpecificationProperty } from "./SHACLSpecificationProperty";
import ISHACLSpecificationEntity from "./ISHACLSpecificationEntity";
import { GEOSPARQL } from "../../components/widgets/MapWidget";
import { RdfStore } from "rdf-stores";
import { Quad_Subject, Term } from "@rdfjs/types";
import { StoreModel } from "../StoreModel";
import { DagIfc, Dag } from "../../dag/Dag";
import ISpecificationEntity from "../ISpecificationEntity";
import ISpecificationProperty from "../ISpecificationProperty";
const factory = new DataFactory();
export class SHACLSpecificationEntity extends SHACLSpecificationEntry implements ISHACLSpecificationEntity {
constructor(uri:string, provider: SHACLSpecificationProvider, n3store: RdfStore, lang: string) {
super(uri, provider, n3store, lang);
}
getLabel(): string {
// first try to read an rdfs:label
let label = this.graph.readSinglePropertyInLang(factory.namedNode(this.uri), RDFS.LABEL, this.lang)?.value;
if(!label) {
// attempt to read it on the targetClass, if we have it
if(this.graph.hasTriple(factory.namedNode(this.uri), SH.TARGET_CLASS, null)) {
let targetClass = this.graph.readSingleProperty(factory.namedNode(this.uri), SH.TARGET_CLASS);
label = this.graph.readSinglePropertyInLang(targetClass as Term, RDFS.LABEL, this.lang)?.value;
}
}
if(!label) {
// attempt to read the local part of the targetClass URI
if(this.graph.hasTriple(factory.namedNode(this.uri), SH.TARGET_CLASS, null)) {
let targetClass = this.graph.readSingleProperty(factory.namedNode(this.uri), SH.TARGET_CLASS);
label = StoreModel.getLocalName(targetClass.value) as string;
}
}
if(!label) {
// default : read the local part of the URI
label = StoreModel.getLocalName(this.uri) as string;
}
return label;
}
getTooltip(): string | undefined {
let tooltip = this.graph.readSinglePropertyInLang(factory.namedNode(this.uri), VOLIPI.MESSAGE, this.lang)?.value;
if(!tooltip) {
// try with sh:description
tooltip = this.graph.readSinglePropertyInLang(factory.namedNode(this.uri), SH.DESCRIPTION, this.lang)?.value;
}
if(this.graph.hasTriple(factory.namedNode(this.uri), SH.TARGET_CLASS, null)) {
if(!tooltip) {
// try to read an rdfs:comment on the class itself
// note that we try to read the value even in case the target is a blank node, e.g. SPARQL target
tooltip = this.graph.readSinglePropertyInLang(
this.graph.readSingleProperty(factory.namedNode(this.uri), SH.TARGET_CLASS) as Term,
SKOS.DEFINITION,
this.lang)?.value;
}
if(!tooltip) {
// try to read an rdfs:comment on the class itself
// note that we try to read the value even in case the target is a blank node, e.g. SPARQL target
tooltip = this.graph.readSinglePropertyInLang(
this.graph.readSingleProperty(factory.namedNode(this.uri), SH.TARGET_CLASS) as Term,
RDFS.COMMENT,
this.lang)?.value;
}
}
return tooltip;
}
getConnectingProperties(range: string): string[] {
// read all sh:property and find the ones that can target the selected class
var items: string[] = [];
let propShapes = this.getProperties();
propShapes.forEach(ps => {
let prop = new SHACLSpecificationProperty(ps, this.provider, this.store, this.lang);
let pRange = prop.getRange();
if(pRange.indexOf(range) > -1) {
items.push(ps);
}
});
// add properties available from parents - recursively
let parents = this.provider.getEntity(range).getParents();
parents.forEach(aParent => {
items = [...items, ...this.getConnectingProperties(aParent)];
})
// dedup, although probably dedup is not necessary here
var dedupItems = [...new Set(items)];
// sort dedups
var sortedDedups = SHACLSpecificationEntry.sort(dedupItems.map(s => new SHACLSpecificationProperty(s, this.provider, this.store, this.lang)));
// return dedup array of strings
return sortedDedups.map(e => e.getId());
}
/**
* Return the tree of properties connecting this entity to the specified range entity
* @param range The URI of the selected target entity
* @returns
*/
getConnectingPropertiesTree(range: string): DagIfc<ISpecificationProperty> {
// 1. get list of properties
let properties:ISpecificationProperty[] = this.getConnectingProperties(range).map(s => this.provider.getProperty(s)) as ISpecificationProperty[];
// retrive the potential parents
while(!properties.every(property => {
return property.getParents().every(parent => {
return (properties.find(anotherProperty => anotherProperty.getId() === parent) != undefined);
});
})) {
let parentsToAdd:ISpecificationProperty[] = [];
properties.forEach(property => {
property.getParents().forEach(parent => {
if(!properties.find(anotherProperty => anotherProperty.getId() === parent)) {
parentsToAdd.push(this.provider.getProperty(parent) as ISpecificationProperty);
}
})
});
parentsToAdd.forEach(p => properties.push(p));
}
// 2. turn it into a flat tree
let dag:Dag<ISpecificationProperty> = new Dag<ISpecificationProperty>();
// dag.initFlatTreeFromFlatList(properties);
dag.initFromParentableAndIdAbleEntity(properties, []);
// sort the tree with compare function
dag.sort(SHACLSpecificationProperty.compare);
return dag;
}
getConnectedEntities(): string[] {
var items: string[] = [];
// read all properties that make sense for Sparnatural
let propShapes = this.getProperties();
propShapes
.forEach(ps => {
// read the property
let prop = new SHACLSpecificationProperty(ps, this.provider, this.store, this.lang);
// and then read their ranges
items.push(...prop.getRange());
});
// dedup
var dedupItems = [...new Set(items)];
// sort dedups
var sortedDedups = SHACLSpecificationEntry.sort(dedupItems.map(s => new SHACLSpecificationEntity(s, this.provider, this.store, this.lang)));
// return dedup array of strings
return sortedDedups.map(e => e.getId());
}
getConnectedEntitiesTree(): DagIfc<ISpecificationEntity> {
// 1. get directly connected entities
let entities:SHACLSpecificationEntity[] = this.getConnectedEntities().map(s => this.provider.getEntity(s)) as SHACLSpecificationEntity[];
// 2. add the children of these entities - recursively
while(!entities.every(entity => {
return entity.getChildren().every(child => {
return (entities.find(anotherEntity => anotherEntity.getId() === child) != undefined);
});
})) {
let childrenToAdd:SHACLSpecificationEntity[] = [];
entities.forEach(entity => {
entity.getChildren().forEach(child => {
if(!entities.find(anotherEntity => anotherEntity.getId() === child)) {
childrenToAdd.push(this.provider.getEntity(child) as SHACLSpecificationEntity);
}
})
});
childrenToAdd.forEach(p => entities.push(p));
}
// 3. complement the initial list with their parents
let disabledList:string[] = new Array<string>();
// while not all parents of all entities are not part of the list...
while(!entities.every(entity => {
return entity.getParents().every(parent => {
return (entities.find(anotherEntity => anotherEntity.getId() === parent) != undefined);
});
})) {
let parentsToAdd:SHACLSpecificationEntity[] = [];
entities.forEach(entity => {
entity.getParents().forEach(parent => {
if(!entities.find(anotherEntity => anotherEntity.getId() === parent)) {
parentsToAdd.push(this.provider.getEntity(parent) as SHACLSpecificationEntity);
}
})
});
parentsToAdd.forEach(p => entities.push(p));
// also keep that as a disabled node
parentsToAdd.forEach(p => disabledList.push(p.getId()));
}
let dag:Dag<ISpecificationEntity> = new Dag<ISpecificationEntity>();
dag.initFromParentableAndIdAbleEntity(entities, disabledList);
// sort the tree with compare function
dag.sort(SHACLSpecificationEntity.compare);
return dag;
}
hasConnectedEntities(): boolean {
return (this.getConnectedEntities().length > 0)
}
/**
* @returns all (non-deactivated) properties available on this node shape, including inherited properties from superclasses
*/
getProperties(): string[] {
var items: string[] = [];
// read all sh:property
let propShapes =
this.graph.readProperty(factory.namedNode(this.uri), SH.PROPERTY)
.map(node => node.value);
// add all properties from parents (either through sh:node or sh:targetClass/rdfs:subClassOf/^sh:targetClass)
let parents:string[] = this.getParents();
parents.forEach(p => {
let parentEntity = new SHACLSpecificationEntity(p,this.provider, this.store, this.lang);
propShapes.push(...parentEntity.getProperties());
});
// filter properties not to be shown
propShapes
.forEach(ps => {
if(SHACLSpecificationProperty.isSparnaturalSHACLSpecificationProperty(ps, this.store)) {
items.push(ps);
}
});
// dedup, although probably dedup is not necessary here
var dedupItems = [...new Set(items)];
// sort dedups
var sortedDedups = SHACLSpecificationEntry.sort(dedupItems.map(s => new SHACLSpecificationProperty(s, this.provider, this.store, this.lang)));
// return dedup array of strings
return sortedDedups.map(e => e.getId());
}
/**
*
* @returns true if sh:nodeKind = sh:Literal, or if sh:datatype is present, or if sh:languageIn is present
*/
isLiteralEntity(): boolean {
var hasNodeKindLiteral = this.graph.hasTriple(factory.namedNode(this.uri), SH.NODE_KIND, SH.LITERAL);
var hasDatatype = this.graph.hasTriple(factory.namedNode(this.uri), SH.DATATYPE, null);
var hasLanguageIn = this.graph.hasTriple(factory.namedNode(this.uri), SH.LANGUAGE_IN, null);
var hasUniqueLang = this.graph.hasTriple(factory.namedNode(this.uri), SH.UNIQUE_LANG, null);
return hasNodeKindLiteral || hasDatatype || hasLanguageIn || hasUniqueLang;
}
/**
* @returns true if this shape has a target, either a targetClass or sh:target, or is itself a Class
*/
hasTypeCriteria(): boolean {
var hasTargetClass = this.graph.hasTriple(factory.namedNode(this.uri), SH.TARGET_CLASS, null);
var hasTarget = this.graph.hasTriple(factory.namedNode(this.uri), SH.TARGET, null);
var isItselfClass = this.graph.hasTriple(factory.namedNode(this.uri), RDF.TYPE, RDFS.CLASS);
return (hasTargetClass || hasTarget || isItselfClass);
}
/**
* @returns a property labelled with dash:propertyRole = dash:LabelRole
*/
getDefaultLabelProperty(): string | undefined {
var items: any[] = [];
// read all properties
let propShapes = this.graph.readProperty(factory.namedNode(this.uri), SH.PROPERTY);
propShapes.forEach(ps => {
if (this.store.getQuads(
ps,
DASH.PROPERTY_ROLE,
DASH.LABEL_ROLE,
null
).length > 0) {
items.push(ps);
}
});
// nothing found, see if we can inherit it
if(items.length == 0) {
let parents = this.getParents();
let parentDefaultLabelProp:string|undefined;
parents.forEach(p => {
// if not found already, set it to the parent default label prop - otherwise keep the value we found
if(!parentDefaultLabelProp) {
let parentEntity = new SHACLSpecificationEntity(p,this.provider, this.store, this.lang);
parentDefaultLabelProp = parentEntity.getDefaultLabelProperty();
}
});
// could be undefined or a string
return parentDefaultLabelProp;
} else {
// return the first one found
return items[0].value
}
}
getParents(): string[] {
let parentsFromSuperClasses = this.#findShapesTargetingClassIn(this.getImmediateSuperClassesOfTargetClass());
if(parentsFromSuperClasses.length == 0) {
parentsFromSuperClasses = this.#findShapesTargetingClassIn(this.getSuperClassesOfTargetClass(2));
}
if(parentsFromSuperClasses.length == 0) {
parentsFromSuperClasses = this.#findShapesTargetingClassIn(this.getSuperClassesOfTargetClass(3));
}
if(parentsFromSuperClasses.length == 0) {
parentsFromSuperClasses = this.#findShapesTargetingClassIn(this.getSuperClassesOfTargetClass(4));
}
if(parentsFromSuperClasses.length == 0) {
parentsFromSuperClasses = this.#findShapesTargetingClassIn(this.getSuperClassesOfTargetClass(5));
}
// get the parents from sh:node
let parentsFromShNode = this.#getShNode();
// concat parents from superclasses and from node - deduplicated
let parents = [...new Set([...parentsFromSuperClasses, ...parentsFromShNode])];
return parents
// and simply return the string value
.map(term => term.value);
}
#findShapesTargetingClassIn(classes: Term[]) {
// note : we exclude blank nodes
return classes.filter(term => term.termType == "NamedNode")
// we find the shape targeting this class - it can be the class itself
.map(term => {
if(this.graph.hasTriple(term as Quad_Subject, RDF.TYPE, RDFS.CLASS)) {
return term;
} else {
return this.graph.findSingleSubjectOf(SH.TARGET_CLASS, term);
}
})
// remove those for which the shape was not found
.filter(term => (term != undefined));
}
getChildren(): string[] {
let cildrenFromSuperClasses = this.getSubClassesOfTargetClass()
// note : we exclude blank nodes
.filter(term => term.termType == "NamedNode")
// we find the shape targeting this class - it can be the class itself
.map(term => {
if(this.graph.hasTriple(term as Quad_Subject, RDF.TYPE, RDFS.CLASS)) {
return term;
} else {
return this.graph.findSingleSubjectOf(SH.TARGET_CLASS, term);
}
})
// remove those for which the shape was not found
.filter(term => (term != undefined));
// get the children from sh:node
let childrenFromShNode = this.#getInverseOfShNodeForExplicitNodeShapes();
// concat parents from superclasses and from node - deduplicated
let children = [...new Set([...cildrenFromSuperClasses, ...childrenFromShNode])];
return children
// and simply return the string value
.map(term => term.value);
}
/**
* @returns the recursive superclasses of the target class of this Shape (can be the shape itself)
*/
getAllSuperClassesOfTargetClass(): Term[] {
// retrieve target classes
let targetClasses:Term[] = this.#getTargetClasses();
// then retrieve super classes of those classes
let superClasses:Term[] = [];
targetClasses.forEach(tc => {
let allSuperClasses = this.graph.readPropertyRec(tc, RDFS.SUBCLASS_OF);
superClasses.push(...allSuperClasses);
});
return superClasses;
}
/**
* @returns the immediate superclasses of the target class of this Shape (can be the shape itself)
*/
getImmediateSuperClassesOfTargetClass(): Term[] {
return this.getSuperClassesOfTargetClass(1);
}
getSuperClassesOfTargetClass(level: number): Term[] {
// retrieve target classes
let targetClasses:Term[] = this.#getTargetClasses();
// then retrieve super classes of those classes
let superClasses:Term[] = [];
targetClasses.forEach(tc => {
let currentSuperClasses = this.#getSuperClassesAtLevel(tc, level);
superClasses.push(...currentSuperClasses);
});
return superClasses;
}
/**
* @returns the immediate subclasses of the target class of this Shape (can be the shape itself)
*/
getSubClassesOfTargetClass(): Term[] {
// retrieve target classes
let targetClasses:Term[] = this.#getTargetClasses();
// then retrieve sub classes of those classes
let subClasses:Term[] = [];
targetClasses.forEach(tc => {
let currentSubClasses = this.graph.findSubjectsOf(RDFS.SUBCLASS_OF, tc)
subClasses.push(...currentSubClasses);
});
return subClasses;
}
/**
* @returns all super classes, recursively, of the provided classes. This is currently not used.
*/
#getSuperClassesRec(classNode:Term): Term[] {
var items: Term[] = [];
let superClasses = this.graph.readProperty(classNode, RDFS.SUBCLASS_OF);
items.push(...superClasses);
superClasses.forEach(sc => {
items.push(...this.#getSuperClassesRec(sc));
});
return items;
}
/**
* @returns the superClasses of the provided class, at a certain level
*/
#getSuperClassesAtLevel(classNode:Term, level:number): Term[] {
if(level < 1) {
return null;
}
var items: Term[] = [];
let superClasses = this.graph.readProperty(classNode, RDFS.SUBCLASS_OF);
items.push(...superClasses);
if(level == 1) {
return items;
} else {
var result: Term[] = [];
items.forEach(i => result.push(...this.#getSuperClassesAtLevel(i, (level-1))));
return result;
}
}
/**
* @returns the NodeShape IRI that are referenced from this one with sh:node - this is like subClassOf
*/
#getShNode(): Term[] {
return this.graph.readProperty(factory.namedNode(this.uri), SH.NODE);
}
/**
* @returns the NodeShapes IRI that reference this one with sh:node
*/
#getInverseOfShNodeForExplicitNodeShapes(): Term[] {
let subjects:Quad_Subject[] = this.graph.findSubjectsOf(SH.NODE, factory.namedNode(this.uri));
// keep only the sh:node references from NodeShapes, not property shapes or sh:or on property shapes
// there could be more precise ways of doing this
return subjects.filter(term =>
term.termType == "NamedNode"
&&
this.graph.hasTriple(term, RDF.TYPE, SH.NODE_SHAPE)
)
}
isRangeOf(n3store:RdfStore, shapeUri:any) {
return (SHACLSpecificationProperty.readShClassAndShNodeOn(n3store, shapeUri).indexOf(this.uri) > -1);
}
/**
* @returns all targeted classes, either implicitly or explicitly through sh:targetClass
*/
#getTargetClasses():Term[] {
if(this.#isNodeShapeAndClass()) {
return [factory.namedNode(this.uri)];
} else {
return this.getShTargetClass();
}
}
/**
* @returns true if this entity is both a NodeShape and a Class
*/
#isNodeShapeAndClass():boolean {
return (
this.graph.hasTriple(factory.namedNode(this.uri), RDF.TYPE, RDFS.CLASS)
&&
this.graph.hasTriple(factory.namedNode(this.uri), RDF.TYPE, SH.NODE_SHAPE)
);
}
/**
* @returns all values of sh:targetClass on this entity, as RDF Terms
*/
getShTargetClass():Term[] {
return this.graph.readProperty(factory.namedNode(this.uri), SH.TARGET_CLASS);
}
/**
* @returns true if this shape as an sh:target predicate (indicating it is associated to a SPARQL query target)
*/
hasShTarget():boolean {
console.log("hasShTarget "+this.uri+" "+this.graph.hasTriple(factory.namedNode(this.uri), SH.TARGET, null))
return this.graph.hasTriple(factory.namedNode(this.uri), SH.TARGET, null);
}
static compare(item1: SHACLSpecificationEntity, item2: SHACLSpecificationEntity) {
return SHACLSpecificationEntry.compare(item1, item2);
}
}
export class SpecialSHACLSpecificationEntity implements ISHACLSpecificationEntity {
private id:string;
private icon:string;
private label:string;
private isRangeOfFunction:Function;
constructor(id:string, icon:string,label:string, isRangeOfFunction:Function) {
this.id = id;
this.icon = icon;
this.label = label;
this.isRangeOfFunction = isRangeOfFunction;
}
getConnectedEntities(): string[] {
return new Array<string>();
}
getConnectedEntitiesTree(): DagIfc<ISpecificationEntity> {
return new Dag<ISpecificationEntity>();
}
hasConnectedEntities(): boolean {
return false;
}
getConnectingProperties(range: string): string[] {
return new Array<string>();
}
getConnectingPropertiesTree(range: string): DagIfc<ISpecificationProperty> {
return new Dag<ISpecificationProperty>();
}
isLiteralEntity(): boolean {
return true;
}
hasTypeCriteria(): boolean {
return false;
}
getDefaultLabelProperty(): string | undefined {
return undefined;
}
getId(): string {
return this.id;
}
getLabel(): string {
return this.label;
}
getOrder(): string|undefined {
return undefined;
}
getTooltip(): string | undefined {
return undefined;
}
getColor(): string | undefined {
// return "slategray";
return undefined;
}
getDatasource(): any {
return null;
}
getTreeChildrenDatasource(): any {
return null;
}
getTreeRootsDatasource(): any {
return null;
}
getIcon(): string {
return this.icon;
}
getHighlightedIcon(): string {
return "";
}
isRangeOf(n3store:RdfStore, shapeUri:any):boolean {
return this.isRangeOfFunction(n3store, shapeUri);
}
getParents(): string[] {
return [];
}
getChildren(): string[] {
return [];
}
}
export class SpecialSHACLSpecificationEntityRegistry {
private registry:Map<string,SpecialSHACLSpecificationEntity> = new Map<string,SpecialSHACLSpecificationEntity>();
public static SPECIAL_SHACL_ENTITY_DATES = "http://special/Z_Date";
public static SPECIAL_SHACL_ENTITY_LOCATION = "http://special/Z_Location";
public static SPECIAL_SHACL_ENTITY_TEXT = "http://special/Z_Text";
public static SPECIAL_SHACL_ENTITY_NUMBER = "http://special/Z_Number";
public static SPECIAL_SHACL_ENTITY_OTHER = "http://special/ZZ_Other";
static instance = new SpecialSHACLSpecificationEntityRegistry();
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
private constructor() {
this.registry.set(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_OTHER,
new SpecialSHACLSpecificationEntity(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_OTHER,
"fa-solid fa-ellipsis",
"Other",
function(n3store:RdfStore, shapeUri:any):boolean {
// this is in range if nothing else is in range
let graph:StoreModel = new StoreModel(n3store);
return (
!graph.hasTriple(factory.namedNode(shapeUri), SH.NODE, null)
&&
!graph.hasTriple(factory.namedNode(shapeUri), SH.CLASS, null)
&&
!graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.DATE)
&&
!graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.DATE_TIME)
&&
!graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.GYEAR)
&&
!graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, GEOSPARQL.WKT_LITERAL)
&&
!graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.STRING)
&&
!graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, RDF.LANG_STRING)
);
}
)
)
this.registry.set(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_DATES,
new SpecialSHACLSpecificationEntity(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_DATES,
"fa-solid fa-calendar",
"Date",
function(n3store:RdfStore, shapeUri:any):boolean {
let graph:StoreModel = new StoreModel(n3store);
return (
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.DATE)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.DATE_TIME)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.GYEAR)
);
}
)
)
this.registry.set(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_LOCATION,
new SpecialSHACLSpecificationEntity(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_LOCATION,
"fa-solid fa-map-location-dot",
"Location",
function(n3store:RdfStore, shapeUri:any):boolean {
let graph:StoreModel = new StoreModel(n3store);
return graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, GEOSPARQL.WKT_LITERAL)
}
)
)
this.registry.set(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_TEXT,
new SpecialSHACLSpecificationEntity(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_TEXT,
"fa-solid fa-font",
"Text",
function(n3store:RdfStore, shapeUri:any):boolean {
let graph:StoreModel = new StoreModel(n3store);
return (
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.STRING)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, RDF.LANG_STRING)
||
// no datatype but we know it is a Literal
(
graph.hasTriple(factory.namedNode(shapeUri), SH.NODE_KIND, SH.LITERAL)
&&
(
!graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, null)
||
(
!graph.readSingleProperty(factory.namedNode(shapeUri), SH.DATATYPE)?.value.startsWith("http://www.w3.org/2001/XMLSchema#")
&&
!graph.readSingleProperty(factory.namedNode(shapeUri), SH.DATATYPE)?.value.startsWith("http://www.opengis.net/ont/geosparql#")
)
)
)
);
}
)
)
this.registry.set(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_NUMBER,
new SpecialSHACLSpecificationEntity(
SpecialSHACLSpecificationEntityRegistry.SPECIAL_SHACL_ENTITY_NUMBER,
"fa-solid fa-1",
"Number",
function(n3store:RdfStore, shapeUri:any):boolean {
let graph:StoreModel = new StoreModel(n3store);
return (
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.BYTE)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.DECIMAL)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.DOUBLE)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.FLOAT)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.INT)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.INTEGER)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.LONG)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.NONNEGATIVE_INTEGER)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.SHORT)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.UNSIGNED_BYTE)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.UNSIGNED_INT)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.UNSIGNED_LONG)
||
graph.hasTriple(factory.namedNode(shapeUri), SH.DATATYPE, XSD.UNSIGNED_SHORT)
);
}
)
)
}
/**
* The static method that controls the access to the singleton instance.
*
* This implementation let you subclass the Singleton class while keeping
* just one instance of each subclass around.
*/
public static getInstance(): SpecialSHACLSpecificationEntityRegistry {
if (!SpecialSHACLSpecificationEntityRegistry.instance) {
SpecialSHACLSpecificationEntityRegistry.instance = new SpecialSHACLSpecificationEntityRegistry();
}
return SpecialSHACLSpecificationEntityRegistry.instance;
}
public getRegistry(): Map<string,SpecialSHACLSpecificationEntity> {
return this.registry;
}
}