Skip to content

Commit

Permalink
enhanced shacl or resolution for literals
Browse files Browse the repository at this point in the history
  • Loading branch information
s-tittel committed Oct 12, 2023
1 parent 78f9ef6 commit 81a409f
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 23 deletions.
43 changes: 41 additions & 2 deletions src/constraints.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { BlankNode, NamedNode, Quad } from 'n3'
import { BlankNode, Literal, NamedNode, Quad } from 'n3'
import { Term } from '@rdfjs/types'
import { ShaclNode } from "./node"
import { ShaclProperty, createPropertyInstance } from "./property"
import { Config } from './config'
import { SHAPES_GRAPH } from './constants'
import { PREFIX_SHACL, RDF_PREDICATE_TYPE, SHAPES_GRAPH } from './constants'
import { findLabel, removePrefixes } from './util'
import { ShaclPropertyTemplate } from './property-template'


export function createShaclOrConstraint(options: Term[], context: ShaclNode | ShaclProperty, config: Config): HTMLElement {
Expand Down Expand Up @@ -62,3 +63,41 @@ export function createShaclOrConstraint(options: Term[], context: ShaclNode | Sh
}
return constraintElement
}

export function resolveShaclOrConstraint(template: ShaclPropertyTemplate, value: Term): ShaclPropertyTemplate {
if (!template.shaclOr) {
console.warn('can\'t resolve sh:or because template has no options', template)
return template
}
if (value instanceof Literal) {
// value is a literal, try to match given value datatype
const valueType = value.datatype
for (const option of template.shaclOr) {
const shaclOrDatatypes = template.config.shapesGraph.getObjects(option, `${PREFIX_SHACL}datatype`, SHAPES_GRAPH)
if (shaclOrDatatypes.length && shaclOrDatatypes[0].equals(valueType)) {
template = template.clone()
template.datatype = shaclOrDatatypes[0] as NamedNode
return template
}
}
console.warn('couldn\'t resolve sh:or datatype for literal', value)
} else {
// value is a NamedNode or BlankNode
// find rdf:type of given value. if more than one available, choose first one for now
let types = template.config.dataGraph.getObjects(value, RDF_PREDICATE_TYPE, null)
if (types.length > 0) {
const type = types[0] as NamedNode
template = template.clone()
// try to find node shape that has requested target class
const nodeShapes = template.config.shapesGraph.getSubjects(`${PREFIX_SHACL}targetClass`, type, SHAPES_GRAPH)
if (nodeShapes.length > 0) {
template.node = nodeShapes[0] as NamedNode
// remove label since this is a node type property now
template.label = ''
} else {
template.class = type
}
}
}
return template
}
2 changes: 1 addition & 1 deletion src/editors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ export function editorFactory(template: ShaclPropertyTemplate, value?: Term): HT
}
}

// check if it a langstring
// check if it is a langstring
if (template.datatype?.value === `${PREFIX_RDF}langString` || template.languageIn?.length) {
return createLangStringEditor(template, value)
}
Expand Down
23 changes: 3 additions & 20 deletions src/property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { BlankNode, DataFactory, NamedNode, Store } from 'n3'
import { Term } from '@rdfjs/types'
import { ShaclNode } from './node'
import { focusFirstInputElement } from './util'
import { RDF_PREDICATE_TYPE, PREFIX_SHACL, SHAPES_GRAPH } from './constants'
import { createShaclOrConstraint } from './constraints'
import { SHAPES_GRAPH } from './constants'
import { createShaclOrConstraint, resolveShaclOrConstraint } from './constraints'
import { Config } from './config'
import { ShaclPropertyTemplate } from './property-template'
import { Editor, editorFactory, toRDF } from './editors'
Expand Down Expand Up @@ -55,28 +55,11 @@ export class ShaclProperty extends HTMLElement {
let instance: HTMLElement
if (this.template.shaclOr?.length) {
if (value) {
let template = this.template
// find rdf:type of given value. if more than one available, choose first one for now
let types = this.template.config.dataGraph.getObjects(value, RDF_PREDICATE_TYPE, null)
if (types.length > 0) {
const type = types[0] as NamedNode
template = template.clone()
// try to find node shape that has requested target class
const nodeShapes = template.config.shapesGraph.getSubjects(`${PREFIX_SHACL}targetClass`, type, SHAPES_GRAPH)
if (nodeShapes.length > 0) {
template.node = nodeShapes[0] as NamedNode
// remove label since this is a node type property now
template.label = ''
} else {
template.class = type
}
}
instance = createPropertyInstance(template, value, true)
instance = createPropertyInstance(resolveShaclOrConstraint(this.template, value), value, true)
} else {
instance = createShaclOrConstraint(this.template.shaclOr, this, this.template.config)
appendRemoveButton(instance, '')
}

} else {
instance = createPropertyInstance(this.template, value)
}
Expand Down

0 comments on commit 81a409f

Please sign in to comment.