comparison env/lib/python3.9/site-packages/rdflib_jsonld/context.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # -*- coding: utf-8 -*-
2 """
3 Implementation of the JSON-LD Context structure. See:
4
5 http://json-ld.org/
6
7 """
8 from collections import namedtuple
9 from rdflib.namespace import RDF
10
11 from ._compat import str, str
12 from .keys import (BASE, CONTAINER, CONTEXT, GRAPH, ID, INDEX, LANG, LIST,
13 REV, SET, TYPE, VALUE, VOCAB)
14 from . import errors
15 from .util import source_to_json, urljoin, urlsplit, split_iri, norm_url
16
17
18 NODE_KEYS = set([LANG, ID, TYPE, VALUE, LIST, SET, REV, GRAPH])
19
20 class Defined(int): pass
21 UNDEF = Defined(0)
22
23
24 class Context(object):
25
26 def __init__(self, source=None, base=None):
27 self.language = None
28 self.vocab = None
29 self.base = base
30 self.doc_base = base
31 self.terms = {}
32 # _alias maps NODE_KEY to list of aliases
33 self._alias = {}
34 self._lookup = {}
35 self._prefixes = {}
36 self.active = False
37 if source:
38 self.load(source)
39
40 @property
41 def base(self):
42 return self._base
43
44 @base.setter
45 def base(self, base):
46 if base:
47 hash_index = base.find('#')
48 if hash_index > -1:
49 base = base[0:hash_index]
50 self._base = self.resolve_iri(base) if (
51 hasattr(self, '_base') and base is not None) else base
52 self._basedomain = '%s://%s' % urlsplit(base)[0:2] if base else None
53
54 def subcontext(self, source):
55 # IMPROVE: to optimize, implement SubContext with parent fallback support
56 ctx = Context()
57 ctx.language = self.language
58 ctx.vocab = self.vocab
59 ctx.base = self.base
60 ctx.doc_base = self.doc_base
61 ctx._alias = self._alias.copy()
62 ctx.terms = self.terms.copy()
63 ctx._lookup = self._lookup.copy()
64 ctx._prefixes = self._prefixes.copy()
65 ctx.load(source)
66 return ctx
67
68 def get_id(self, obj):
69 return self._get(obj, ID)
70
71 def get_type(self, obj):
72 return self._get(obj, TYPE)
73
74 def get_language(self, obj):
75 return self._get(obj, LANG)
76
77 def get_value(self, obj):
78 return self._get(obj, VALUE)
79
80 def get_graph(self, obj):
81 return self._get(obj, GRAPH)
82
83 def get_list(self, obj):
84 return self._get(obj, LIST)
85
86 def get_set(self, obj):
87 return self._get(obj, SET)
88
89 def get_rev(self, obj):
90 return self._get(obj, REV)
91
92 def _get(self, obj, key):
93 for alias in self._alias.get(key, []):
94 if alias in obj:
95 return obj.get(alias)
96 return obj.get(key)
97
98 def get_key(self, key):
99 return self.get_keys(key)[0]
100
101 def get_keys(self, key):
102 return self._alias.get(key, [key])
103
104 lang_key = property(lambda self: self.get_key(LANG))
105 id_key = property(lambda self: self.get_key(ID))
106 type_key = property(lambda self: self.get_key(TYPE))
107 value_key = property(lambda self: self.get_key(VALUE))
108 list_key = property(lambda self: self.get_key(LIST))
109 rev_key = property(lambda self: self.get_key(REV))
110 graph_key = property(lambda self: self.get_key(GRAPH))
111
112 def add_term(self, name, idref, coercion=UNDEF, container=UNDEF,
113 language=UNDEF, reverse=False):
114 term = Term(idref, name, coercion, container, language, reverse)
115 self.terms[name] = term
116 self._lookup[(idref, coercion or language, container, reverse)] = term
117 self._prefixes[idref] = name
118
119 def find_term(self, idref, coercion=None, container=UNDEF,
120 language=None, reverse=False):
121 lu = self._lookup
122 if coercion is None:
123 coercion = language
124 if coercion is not UNDEF and container:
125 found = lu.get((idref, coercion, container, reverse))
126 if found: return found
127 if coercion is not UNDEF:
128 found = lu.get((idref, coercion, UNDEF, reverse))
129 if found: return found
130 if container:
131 found = lu.get((idref, coercion, container, reverse))
132 if found: return found
133 elif language:
134 found = lu.get((idref, UNDEF, LANG, reverse))
135 if found: return found
136 else:
137 found = lu.get((idref, coercion or UNDEF, SET, reverse))
138 if found: return found
139 return lu.get((idref, UNDEF, UNDEF, reverse))
140
141 def resolve(self, curie_or_iri):
142 iri = self.expand(curie_or_iri, False)
143 if self.isblank(iri):
144 return iri
145 return self.resolve_iri(iri)
146
147 def resolve_iri(self, iri):
148 return norm_url(self._base, iri)
149
150 def isblank(self, ref):
151 return ref.startswith('_:')
152
153 def expand(self, term_curie_or_iri, use_vocab=True):
154 if use_vocab:
155 term = self.terms.get(term_curie_or_iri)
156 if term:
157 return term.id
158 is_term, pfx, local = self._prep_expand(term_curie_or_iri)
159 if pfx == '_':
160 return term_curie_or_iri
161 if pfx is not None:
162 ns = self.terms.get(pfx)
163 if ns and ns.id:
164 return ns.id + local
165 elif is_term and use_vocab:
166 if self.vocab:
167 return self.vocab + term_curie_or_iri
168 return None
169 return self.resolve_iri(term_curie_or_iri)
170
171 def shrink_iri(self, iri):
172 ns, name = split_iri(str(iri))
173 pfx = self._prefixes.get(ns)
174 if pfx:
175 return ":".join((pfx, name))
176 elif self._base:
177 if str(iri) == self._base:
178 return ""
179 elif iri.startswith(self._basedomain):
180 return iri[len(self._basedomain):]
181 return iri
182
183 def to_symbol(self, iri):
184 iri = str(iri)
185 term = self.find_term(iri)
186 if term:
187 return term.name
188 ns, name = split_iri(iri)
189 if ns == self.vocab:
190 return name
191 pfx = self._prefixes.get(ns)
192 if pfx:
193 return ":".join((pfx, name))
194 return iri
195
196 def load(self, source, base=None):
197 self.active = True
198 sources = []
199 source = source if isinstance(source, list) else [source]
200 self._prep_sources(base, source, sources)
201 for source_url, source in sources:
202 self._read_source(source, source_url)
203
204 def _prep_sources(self, base, inputs, sources, referenced_contexts=None,
205 in_source_url=None):
206 referenced_contexts = referenced_contexts or set()
207 for source in inputs:
208 if isinstance(source, str):
209 source_url = urljoin(base, source)
210 if source_url in referenced_contexts:
211 raise errors.RECURSIVE_CONTEXT_INCLUSION
212 referenced_contexts.add(source_url)
213 source = source_to_json(source_url)
214 if CONTEXT not in source:
215 raise errors.INVALID_REMOTE_CONTEXT
216 else:
217 source_url = in_source_url
218
219 if isinstance(source, dict):
220 if CONTEXT in source:
221 source = source[CONTEXT]
222 source = source if isinstance(source, list) else [source]
223 if isinstance(source, list):
224 self._prep_sources(base, source, sources, referenced_contexts, source_url)
225 else:
226 sources.append((source_url, source))
227
228 def _read_source(self, source, source_url=None):
229 self.vocab = source.get(VOCAB, self.vocab)
230 for key, value in list(source.items()):
231 if key == LANG:
232 self.language = value
233 elif key == VOCAB:
234 continue
235 elif key == BASE:
236 if source_url:
237 continue
238 self.base = value
239 else:
240 self._read_term(source, key, value)
241
242 def _read_term(self, source, name, dfn):
243 idref = None
244 if isinstance(dfn, dict):
245 #term = self._create_term(source, key, value)
246 rev = dfn.get(REV)
247 idref = rev or dfn.get(ID, UNDEF)
248 if idref == TYPE:
249 idref = str(RDF.type)
250 elif idref is not UNDEF:
251 idref = self._rec_expand(source, idref)
252 elif ':' in name:
253 idref = self._rec_expand(source, name)
254 elif self.vocab:
255 idref = self.vocab + name
256 coercion = dfn.get(TYPE, UNDEF)
257 if coercion and coercion not in (ID, TYPE, VOCAB):
258 coercion = self._rec_expand(source, coercion)
259 self.add_term(name, idref, coercion,
260 dfn.get(CONTAINER, UNDEF), dfn.get(LANG, UNDEF), bool(rev))
261 else:
262 if isinstance(dfn, str):
263 idref = self._rec_expand(source, dfn)
264 self.add_term(name, idref)
265
266 if idref in NODE_KEYS:
267 self._alias.setdefault(idref, []).append(name)
268
269 def _rec_expand(self, source, expr, prev=None):
270 if expr == prev or expr in NODE_KEYS:
271 return expr
272
273 is_term, pfx, nxt = self._prep_expand(expr)
274 if pfx:
275 iri = self._get_source_id(source, pfx)
276 if iri is None:
277 if pfx + ':' == self.vocab:
278 return expr
279 else:
280 term = self.terms.get(pfx)
281 if term:
282 iri = term.id
283
284 if iri is None:
285 nxt = expr
286 else:
287 nxt = iri + nxt
288 else:
289 nxt = self._get_source_id(source, nxt) or nxt
290 if ':' not in nxt and self.vocab:
291 return self.vocab + nxt
292
293 return self._rec_expand(source, nxt, expr)
294
295 def _prep_expand(self, expr):
296 if ':' not in expr:
297 return True, None, expr
298 pfx, local = expr.split(':', 1)
299 if not local.startswith('//'):
300 return False, pfx, local
301 else:
302 return False, None, expr
303
304 def _get_source_id(self, source, key):
305 # .. from source dict or if already defined
306 term = source.get(key)
307 if term is None:
308 dfn = self.terms.get(key)
309 if dfn:
310 term = dfn.id
311 elif isinstance(term, dict):
312 term = term.get(ID)
313 return term
314
315
316 Term = namedtuple('Term',
317 'id, name, type, container, language, reverse')
318 Term.__new__.__defaults__ = (UNDEF, UNDEF, UNDEF, False)