'''
This module contains functions dealing with jsonld reading and writing.
.. versionadded:: 0.7.0
'''
from skosprovider.skos import (
Concept,
Collection,
ConceptScheme,
label
)
from skosprovider.utils import (
extract_language,
add_lang_to_html
)
import logging
log = logging.getLogger(__name__)
MINI_CONTEXT = {
"@version": 1.1,
"dct": "http://purl.org/dc/terms/",
"skos": "http://www.w3.org/2004/02/skos/core#",
"iso-thes": "http://purl.org/iso25964/skos-thes#",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"void": "http://rdfs.org/ns/void#",
"uri": "@id",
"type": "@type",
"id": "dct:identifier",
"label": "rdfs:label",
"concept": "skos:Concept",
"collection": "skos:Collection",
}
CONTEXT = {
"@version": 1.1,
"dct": "http://purl.org/dc/terms/",
"skos": "http://www.w3.org/2004/02/skos/core#",
"iso-thes": "http://purl.org/iso25964/skos-thes#",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"void": "http://rdfs.org/ns/void#",
"uri": "@id",
"type": "@type",
"id": "dct:identifier",
"label": "rdfs:label",
"concept": "skos:Concept",
"collection": "skos:Collection",
"lbl": "@value",
"nt": "@value",
"ct": "@value",
"HTML": "rdf:HTML",
"concept_scheme": {
"@id": "skos:inScheme",
"@type": "@id"
},
"in_dataset": {
"@id": "void:inDataset",
"@type": "@id"
},
"top_concepts": {
"@id": "skos:hasTopConcept",
"@type": "@id"
},
"labels": "@nest",
"notes": "@nest",
"matches": "@nest",
"sources": {
"@id": "dct:source",
"@container": "@set"
},
"citations": {
"@id": "dct:bibliographicCitation",
"@container": "@set"
},
"pref_labels": {
"@nest": "labels",
"@id": "skos:prefLabel",
"@container": "@set"
},
"alt_labels": {
"@nest": "labels",
"@id": "skos:altLabel",
"@container": "@set"
},
"hidden_labels": {
"@nest": "labels",
"@id": "skos:hiddenLabel",
"@container": "@set"
},
"general_notes": {
"@nest": "notes",
"@id": "skos:note",
"@container": "@set"
},
"scope_notes": {
"@nest": "notes",
"@id": "skos:scopeNote",
"@container": "@set"
},
"definitions": {
"@nest": "notes",
"@id": "skos:definition",
"@container": "@set"
},
"history_notes": {
"@nest": "notes",
"@id": "skos:historyNote",
"@container": "@set"
},
"editorial_notes": {
"@nest": "notes",
"@id": "skos:editorialNote",
"@container": "@set"
},
"change_notes": {
"@nest": "notes",
"@id": "skos:changeNote",
"@container": "@set"
},
"examples": {
"@nest": "notes",
"@id": "skos:example",
"@container": "@set"
},
"exact_matches": {
"@id": "skos:exactMatch",
"@type": "@id",
"@container": "@set"
},
"close_matches": {
"@id": "skos:closeMatch",
"@type": "@id",
"@container": "@set"
},
"broad_matches": {
"@id": "skos:broadMatch",
"@type": "@id",
"@container": "@set"
},
"narrow_matches": {
"@id": "skos:narrowMatch",
"@type": "@id",
"@container": "@set"
},
"related_matches": {
"@id": "skos:relatedMatch",
"@type": "@id",
"@container": "@set"
},
"member_of": {
"@reverse": "skos:member",
"@type": "@id",
"@container": "@set"
},
"members": {
"@id": "skos:member",
"@type": "@id",
"@container": "@set"
},
"subordinate_arrays": {
"@id": "iso-thes:subordinateArray",
"@type": "@id",
"@container": "@set"
},
"broader": {
"@id": "skos:broader",
"@type": "@id",
"@container": "@set"
},
"narrower": {
"@id": "skos:narrower",
"@type": "@id",
"@container": "@set"
},
"related": {
"@id": "skos:related",
"@type": "@id",
"@container": "@set"
},
"languages": {
"@id": "dct:language",
"@type": "@id",
"@container": "@set"
}
}
[docs]def jsonld_dumper(provider, context = None, language = None):
'''
Dump a provider to a JSON-LD serialisable dictionary.
:param skosprovider.providers.VocabularyProvider provider: The provider
that wil be turned into a JSON-LD `dict`.
:param str or dict context: Context as a dict or link to context file.
:param string language: Language to render a single label in.
:rtype: A `dict`
'''
if not language:
language = provider.metadata.get('default_language', 'en')
doc = {
'@graph': []
}
if context:
doc['@context'] = context
doc['@graph'].append(jsonld_conceptscheme_dumper(
provider, None,
relations_profile = 'uri', language = language
))
for c in provider.get_all():
doc['@graph'].append(jsonld_c_dumper(
provider, c['id'], None,
relations_profile = 'uri', language = language
))
return doc
[docs]def jsonld_c_dumper(provider, id, context = None, relations_profile =
'partial', language = 'en'):
'''
Dump a concept or collection to a JSON-LD serialisable dictionary.
:param skosprovider.providers.VocabularyProvider provider: The provider
that contains the concept or collection.
:param str or int id: Identifier of the concept to dump.
:param str or dict context: Context as a dict or link to context file.
:param str relations_profile: Either `partial` or `uri` to render links to
other resources with some information or just a :term:`URI`.
:param string language: Language to render a single label in.
:rtype: A `dict`
'''
c = provider.get_by_id(id)
doc = _jsonld_c_basic_renderer(c, language)
if context:
doc['@context'] = context
if relations_profile == 'partial':
doc['concept_scheme'] = _jsonld_cs_basic_renderer(c.concept_scheme, language)
else:
doc['concept_scheme'] = c.concept_scheme.uri
dataset_uri = provider.get_metadata().get('dataset', {}).get('uri', None)
if dataset_uri:
doc['in_dataset'] = dataset_uri
doc.update(_jsonld_labels_renderer(c))
doc.update(_jsonld_notes_renderer(c))
doc.update(_jsonld_sources_renderer(c))
doc.update(_jsonld_member_of_renderer(c, provider, relations_profile, language))
if c.type == 'concept':
doc.update(_jsonld_matches_renderer(c))
doc.update(_jsonld_broader_renderer(c, provider, relations_profile, language))
doc.update(_jsonld_narrower_renderer(c, provider, relations_profile, language))
doc.update(_jsonld_related_renderer(c, provider, relations_profile, language))
doc.update(_jsonld_subordinate_arrays_renderer(c, provider, relations_profile, language))
elif c.type == 'collection':
doc['infer_concept_relations'] = True
doc.update(_jsonld_members_renderer(c, provider, relations_profile, language))
doc.update(_jsonld_superordinates_renderer(c, provider, relations_profile, language))
return doc
def _jsonld_c_basic_renderer(c, language = 'en'):
doc = {
'id': c.id,
'uri': c.uri,
'type': c.type
}
label = c.label(language)
if label:
doc['label'] = label.label
return doc
def _jsonld_cs_basic_renderer(cs, language = 'en'):
doc = {
'uri': cs.uri,
'type': 'skos:ConceptScheme'
}
label = cs.label(language)
if label:
doc['label'] = label.label
return doc
def _jsonld_labels_renderer(c):
doc = {
'labels': {}
}
def lbl_renderer(l):
language = extract_language(l.language)
return {
'language': language,
'@language': language,
'lbl': l.label
}
ltypemap = {
'prefLabel': 'pref_labels',
'altLabel': 'alt_labels',
'hiddenLabel': 'hidden_labels',
'sortLabel': 'hidden_labels'
}
for l in c.labels:
doc['labels'].setdefault(ltypemap[l.type], []).append(lbl_renderer(l))
return doc
def _jsonld_notes_renderer(c):
doc = {
'notes': {}
}
def nt_renderer(n):
language = extract_language(n.language)
note = {
'language': language,
'@language': language,
'nt': n.note
}
if n.markup is not None:
del note['@language']
note['nt'] = add_lang_to_html(note['nt'], language)
note['@type'] = n.markup
return note
ntypemap = {
'note': 'general_notes',
'scopeNote': 'scope_notes',
'definition': 'definitions',
'historyNote': 'history_notes',
'editorialNote': 'editorial_notes',
'changeNote': 'change_notes',
'example': 'examples'
}
for n in c.notes:
doc['notes'].setdefault(ntypemap[n.type], []).append(nt_renderer(n))
return doc
def _jsonld_sources_renderer(c):
doc = {
'sources': []
}
def s_renderer(s):
source = {
'type': 'dct:BibliographicResource',
'citations': [{
'ct': s.citation
}]
}
if s.markup is not None:
source['citations'][0]['@type'] = s.markup
return source
for s in c.sources:
doc['sources'].append(s_renderer(s))
return doc
def _jsonld_matches_renderer(c):
doc = {
'matches': {}
}
for k,v in c.matches.items():
doc['matches'].setdefault('%s_matches' % k, []).extend(v)
return doc
def _jsonld_superordinates_renderer(c, provider, profile = 'partial', language = 'en'):
return _jsonld_relation_renderer(c, provider, 'superordinates', profile, language)
def _jsonld_members_renderer(c, provider, profile = 'partial', language = 'en'):
return _jsonld_relation_renderer(c, provider, 'members', profile, language)
def _jsonld_member_of_renderer(c, provider, profile = 'partial', language = 'en'):
return _jsonld_relation_renderer(c, provider, 'member_of', profile, language)
def _jsonld_broader_renderer(c, provider, profile = 'partial', language = 'en'):
return _jsonld_relation_renderer(c, provider, 'broader', profile, language)
def _jsonld_narrower_renderer(c, provider, profile = 'partial', language = 'en'):
return _jsonld_relation_renderer(c, provider, 'narrower', profile, language)
def _jsonld_related_renderer(c, provider, profile = 'partial', language = 'en'):
return _jsonld_relation_renderer(c, provider, 'related', profile, language)
def _jsonld_subordinate_arrays_renderer(c, provider, profile = 'partial', language = 'en'):
return _jsonld_relation_renderer(c, provider, 'subordinate_arrays', profile, language)
def _jsonld_relation_renderer(c, provider, relation, profile = 'partial', language = 'en'):
doc = {
relation: []
}
for m in getattr(c, relation):
relc = provider.get_by_id(m)
if profile == 'partial':
doc[relation].append(_jsonld_c_basic_renderer(relc, language))
else:
doc[relation].append(relc.uri)
return doc
def _jsonld_topconcepts_renderer(provider, profile = 'partial'):
doc = {
'top_concepts': []
}
for c in provider.get_top_concepts():
if profile == 'partial':
doc['top_concepts'].append(c)
else:
doc['top_concepts'].append(c['uri'])
return doc
def _jsonld_cs_languages_renderer(cs):
doc = {
'languages': []
}
for l in cs.languages:
doc['languages'].append(l)
return doc
[docs]def jsonld_conceptscheme_dumper(provider, context = None,
relations_profile = 'partial', language = 'en'):
'''
Dump a conceptscheme to a JSON-LD serialisable dictionary.
:param skosprovider.providers.VocabularyProvider provider: The provider
that contains the conceptscheme.
:param str or dict context: Context as a dict or link to context file.
:param str relations_profile: Either `partial` or `uri` to render links to
other resources with some information or just a :term:`URI`.
:param string language: Language to render a single label in.
:rtype: A `dict`
'''
cs = provider.concept_scheme
doc = _jsonld_cs_basic_renderer(cs)
if context:
doc['@context'] = context
dataset_uri = provider.get_metadata().get('dataset', {}).get('uri', None)
if dataset_uri:
doc['in_dataset'] = dataset_uri
doc['id'] = provider.get_metadata()['id']
doc.update(_jsonld_labels_renderer(cs))
doc.update(_jsonld_notes_renderer(cs))
doc.update(_jsonld_sources_renderer(cs))
doc.update(_jsonld_cs_languages_renderer(cs))
doc.update(_jsonld_topconcepts_renderer(provider, relations_profile))
return doc