sssom-js
Version:
Simple Standard for Sharing Ontology Mappings (SSOM) JavaScript library
170 lines (141 loc) • 6.53 kB
JavaScript
import { Namespaces } from "namespace-lookup"
export const mappingTypes = {
"http://www.w3.org/2004/02/skos/core#mappingRelation": "http://www.w3.org/2004/02/skos/core#mappingRelation",
"http://www.w3.org/2004/02/skos/core#closeMatch": "http://www.w3.org/2004/02/skos/core#closeMatch",
"http://www.w3.org/2004/02/skos/core#exactMatch": "http://www.w3.org/2004/02/skos/core#exactMatch",
"http://www.w3.org/2004/02/skos/core#broadMatch": "http://www.w3.org/2004/02/skos/core#broadMatch",
"http://www.w3.org/2004/02/skos/core#narrowMatch": "http://www.w3.org/2004/02/skos/core#narrowMatch",
"http://www.w3.org/2004/02/skos/core#relatedMatch": "http://www.w3.org/2004/02/skos/core#relatedMatch",
"http://www.w3.org/2002/07/owl#sameAs": "http://www.w3.org/2004/02/skos/core#exactMatch",
"http://www.w3.org/2002/07/owl#equivalentClass": "http://www.w3.org/2004/02/skos/core#exactMatch",
"http://www.w3.org/2002/07/owl#equivalentProperty": "http://www.w3.org/2004/02/skos/core#exactMatch",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#subClassOf": "http://www.w3.org/2004/02/skos/core#narrowMatch",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#subPropertyOf": "http://www.w3.org/2004/02/skos/core#narrowMatch",
"http://www.geneontology.org/formats/oboInOwl#hasDbXref": "http://www.w3.org/2004/02/skos/core#relatedMatch",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#seeAlso": "http://www.w3.org/2004/02/skos/core#relatedMatch",
}
export const predicate2mappingTypes = uri => uri in mappingTypes
? [mappingTypes[uri]] : ["http://www.w3.org/2004/02/skos/core#mappingRelation", uri]
export function jskosItem(uri, language, label, scheme) {
const item = uri ? { uri } : {}
if (label) {
language ||= "und"
item.prefLabel = { [language]: label }
}
if (scheme) {
item.inScheme = [ scheme ]
}
return item
}
const map = {
// common slots (+ creator_id, creator_label)
comment: ["note", (note, language) => ({ [language]: [note]})],
publication_date: ["published"],
see_also: null, // TODO: could be url but url is not multivalued!
// propagatable slots
mapping_date: ["created"],
mapping_provider: ["publisher", url => [{url}]], // TODO: uri or url?
mapping_tool: null, // TODO
mapping_tool_version: null, // TODO
// mapping slots (+ subject_id, subject_label, object_id, object_label...)
mapping_id: ["uri"],
mapping_justification: ["justification"], // JSKOS 0.7.0
mapping_source: ["source", uri => [{uri}]],
confidence: ["mappingRelevance"],
issue_tracker_item: ["issue", uri => [{uri}]], // JSKOS 0.7.0
curation_rule: null, // TODO
curation_rule_text: null, // TODO
// mapping set slots
license: ["license", uri => [ { uri } ]], // TODO: only for mapping set!
mapping_set_id: ["uri"],
mapping_set_version: ["versionId"], // JSKOS 0.7.0
mapping_set_source: ["source", uri => [{uri}]],
mapping_set_title: ["prefLabel", (label, language) => ({ [language]: label })],
mapping_set_description: ["definition", (label, language) => ({ [language]: [label]})],
issue_tracker: ["issueTracker", uri => [{uri}]], // JSKOS 0.7.0
}
function mapSlots(sssom, jskos, language) {
// TODO: don't mix mapping and mappingSet slots
Object.entries(map).filter(([_,def])=>def).forEach(([slot, [key, transform]]) => {
if (sssom[slot]) {
jskos[key] = transform ? transform(sssom[slot], language || "und") : sssom[slot]
}
})
// TODO: mapping_tool and mapping_tool_version => tool (JSKOS 0.7.0)
// TODO: curation_rule, curation_rule_text => guidelines (JSKOS 0.7.0)
const contributor = []
sssom.author_id?.forEach(id => contributor.push(jskosItem(id)))
sssom.author_label?.forEach(label => contributor.push(jskosItem(null, language, label)))
if (contributor.length) {
jskos.contributor = contributor
}
const creator = []
sssom.creator_id?.forEach(id => creator.push(jskosItem(id)))
sssom.creator_label?.forEach(label => creator.push(jskosItem(null, language, label)))
if (creator.length) {
jskos.creator = creator
}
const reviewers = []
sssom.reviewer_id?.forEach(id => reviewers.push({ id }))
sssom.reviewer_label?.forEach(name => reviewers.push({ name }))
if (reviewers.length) {
jskos.annotations = reviewers.map(creator => ({ type: "Annotation", motivation: "moderating", creator }))
}
return jskos
}
const schemes2namespaces = schemes => {
if (schemes instanceof Namespaces) {
return schemes
} else {
const prefixes = schemes
.map(({uri, namespace}) => uri && namespace ? [ namespace, uri ] : false)
.filter(Boolean)
return new Namespaces(Object.fromEntries(prefixes))
}
}
const jskosScheme = (uri, version) => uri ? (version ? { uri, version } : { uri } ) : null
// TODO: document options
export const toJskosMapping = (mapping, { schemes, namespaces, language } = {}) => {
const { predicate_id, subject_id, subject_label, object_id, object_label } = mapping
const from = [], to = []
// TODO: subject_type
if (subject_id && subject_id !== "https://w3id.org/sssom/NoTermFound") {
const scheme = jskosScheme(mapping.subject_source, mapping.subject_source_version)
from[0] = jskosItem(subject_id, language, subject_label, scheme)
}
// TODO: object_type
if (object_id && object_id !== "https://w3id.org/sssom/NoTermFound") {
const scheme = jskosScheme(mapping.object_source, mapping.object_source_version)
to[0] = jskosItem(object_id, language, object_label, scheme)
}
// TODO: move to SSSOM parser to populate subject_source and object_source
if (schemes && !namespaces) {
namespaces = schemes2namespaces(schemes)
}
if (namespaces) {
for (let item of [...from, ...to]) {
if (!item.inScheme) {
const uri = namespaces.lookup(item.uri)
if (uri) {
item.inScheme = [{uri}]
}
} // TODO: else: check if scheme is known?
}
}
const jskos = {
type: predicate2mappingTypes(predicate_id),
from: { memberSet: from },
to: { memberSet: to },
}
return mapSlots(mapping, jskos, language)
}
export const toJskosRegistry = (sssom, { schemes, language } = {}) => {
const jskos = mapSlots(sssom, {}, language)
if (sssom.mappings) {
const namespaces = schemes ? schemes2namespaces(schemes) : null
jskos.mappings = sssom.mappings.map(m => toJskosMapping(m, { namespaces, language }))
}
return jskos
}
export const sssomOrJskos = (sssom, { to, ...options }) =>
sssom && to === "jskos" ? toJskosRegistry(sssom, options) : sssom