Coverage report: /development/source/library/org/datagraph/spocq-shard/src/core/encoding/json-ld/low-level-api.lisp
| Kind | Covered | All | % |
| expression | 3 | 984 | 0.3 |
| branch | 0 | 126 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; -*- Mode: lisp; Syntax: ansi-common-lisp; Base: 10; Package: org.datagraph.spocq.implementation; -*-
3
(in-package :org.datagraph.spocq.implementation)
5
(:documentation "low-level api"
6
"These operators implement the primitive JSON-LD context and term algorithms:
7
- merge-contexts : the core of context instantiation
8
- create-term-definition : instantiate a term definition for a given key based on the
9
declaration in a local context and the existing definition in an active context
10
- expand-iri : interpret an iri designator in context
11
- expand-element : provides object-walking control for expand-iri and error checking
15
;;; json-ld context processing
17
(defparameter *json-ld-cache* (make-hash-table :test 'equal))
18
(defparameter json-ld::*verbose* nil)
20
(defgeneric json-ld:get-json-ld (location)
21
;; need to handle redirection
22
(:method ((location spocq:iri))
23
(let ((key (spocq:iri-lexical-form location)))
24
(or (gethash key *json-ld-cache*)
25
(setf (gethash key *json-ld-cache*)
26
(handler-case (parse-json location :accept "application/ld+json, application/json")
28
(json-ld:loading-remote-context-failed-error :location location
29
:condition condition)))))))
30
(:method ((location string))
31
(when (eql (char location 0) #\<)
32
(setf location (subseq location 1 (1- (length location)))))
33
(json-ld:get-json-ld (merge-and-intern-iri location :base-iri (json-ld:base-iri))))
34
(:method ((location pathname))
35
(or (gethash location *json-ld-cache*)
36
(setf (gethash location *json-ld-cache*)
37
(parse-json location)))))
40
(defgeneric json-ld:merge-contexts (base addition)
41
(:documentation "The core of context operator is to merge two contexts, the two principle use cases
42
being instantiation, in which the context declaration is merged with a null context, and extension,
43
in which a declaration is merged with an existing context.")
46
(:method ((active-context json-ld:context) (addition vector))
47
(loop for addition across addition
48
do (setf active-context (json-ld:merge-contexts active-context addition)))
50
(:method ((active json-ld:context) (addition null))
51
;; given a null addition clear the result
52
(clone-instance active))
55
;; the recommendation describes, the effect of a base option in the JSON-LD API invocation is to
56
;; "over-ride the base IRI". thus, in this context, that invocation-specific value is the new base
57
;; value, rather than clearin git to null.
58
(:method ((active json-ld:context) (addition (eql :|null|)))
59
;; given a null addition clear the result
60
(make-instance 'json-ld:context :base (json-ld:base-iri)))
63
(:method ((active json-ld:context) (addition t))
64
(json-ld:invalid-local-context-error :datum addition))
67
(:method ((active json-ld:context) (addition string))
68
(json-ld:merge-contexts active (merge-and-intern-iri addition :base-iri (json-ld:base-iri))))
70
(:method ((active json-ld:context) (addition spocq:iri))
71
(when (find (iri-lexical-form addition) *json-ld-context-references*)
72
(json-ld:recursive-content-inclusion-error :location addition))
73
(let* ((json-ld (json-ld:get-json-ld addition))
74
(addition (json-ld:object-member-value json-ld @:|@context|)))
76
(json-ld:merge-contexts active addition)
77
(json-ld:invalid-remote-context-error :location addition))))
79
(:method ((active-context json-ld:context) (addition json-ld:context))
80
(json-ld:merge-contexts active-context (json-ld:object-members addition)))
82
;; the interesting part: a context instance with an alist of definitions
83
(:method ((active-context json-ld:context) (addition cons))
84
;; if the addition is itself a context definition, continue with its parts
85
(cond ((json-ld:object-member addition @:|@context|)
86
(json-ld:merge-contexts active-context (json-ld:object-member-value addition @:|@context|)))
88
(setf (json-ld:object-members active-context)
89
(append addition (json-ld:object-members active-context)))
90
(let ((addition-base (json-ld:object-member-value addition @:|@base|)))
92
(cond ((or (null addition-base) *json-ld-context-references*) )
93
((eq addition-base :|null|)
94
(setf (json-ld:object-base active-context) nil))
95
((json-ld:absolute-iri-p addition-base)
96
(setf (json-ld:object-base active-context) (intern-iri addition-base)))
97
((json-ld:object-base active-context)
98
(setf (json-ld:object-base active-context)
99
(merge-and-intern-iri addition-base :base-iri (json-ld:object-base active-context))))
100
(t (json-ld:invalid-base-iri-error :datum addition-base))))
102
(let ((addition-vocabulary (json-ld:object-member-value addition @:|@vocab|)))
103
(when addition-vocabulary
104
(setf (json-ld:context-vocabulary active-context) addition-vocabulary)))
106
(let ((addition-language (json-ld:object-member-value addition @:|@language|)))
107
(when addition-language
108
(setf (json-ld:context-language active-context) addition-language)))
109
;; 3.7,8: the individual definitions
110
(loop for (name . value) in addition
111
for name-key = (json-ld:keywordp name)
112
for value-key = (json-ld:keywordp value)
113
do (cond ((member name-key '(@:|@base| @:|@language| @:|@vocab|))
115
((or (zerop (length name)) (eql (char name 0) #\@))
116
(when json-ld::*verbose* (log-warn "json-ld:merge-contexts : key ignored: ~s: ~s"
119
(print (list :mc.alias-map name value value-key))
120
(setf (key-alias active-context value-key) name))
122
(json-ld:create-term-definition active-context addition name ()))))
126
(defun json-ld:create-term-definition (active-context local-context key defined)
127
"instantiate a term definition for a given key based on the
128
declaration in a local context and the existing definition in an active context"
130
(ecase (rest (assoc key defined :test #'string=))
133
(:false (json-ld:cyclic-iri-mapping-error :context local-context :term key))
135
;; 2 : new definition
136
(setf defined (acons key :false defined))
138
(when (json-ld:keywordp key)
139
(json-ld:keyword-redefinition-error :context local-context :term key))
141
(setf (json-ld:find-term-definition active-context key) nil)
143
(let ((value (json-ld:object-member-value local-context key)))
147
(return-from json-ld:create-term-definition nil))
148
(cons (when (eq :|null| (json-ld:object-member-value value @:|@id|))
150
(return-from json-ld:create-term-definition nil)))
152
(string (setf value (acons @:|@id| value nil)))
154
(t (json-ld:invalid-term-definition-error :key key :datum value)))
155
(let ((definition (json-ld:make-term-definition :key key))
156
(type (json-ld:object-member-value value @:|@type|))
157
(reverse (json-ld:object-member-value value @:|@reverse|))
158
(id (json-ld:object-member-value value @:|@id|))
159
(container (json-ld:object-member-value value @:|@container|))
160
(language (json-ld:object-member-value value @:|@language|)))
161
(flet ((define-term-and-return ()
162
(setf (json-ld:find-term-definition active-context key) definition)
163
(return-from json-ld:create-term-definition definition)))
168
;; when a string, expand wrt the active/local context
169
(setf (json-ld:term-definition-type definition) (json-ld:expand-iri active-context type
172
:local-context local-context
175
;; otherwise, attempt to set as-is
176
(setf (json-ld:term-definition-type definition) type))))
179
(when id (json-ld:invalid-reverse-property-error :datum value))
181
(string (let ((expanded-reverse (json-ld:expand-iri active-context reverse
184
:local-context local-context
186
(typecase expanded-reverse
187
((or absolute-iri spocq:blank-node)
188
(setf (json-ld:term-definition-term definition) expanded-reverse))
190
(json-ld:invalid-iri-mapping-error :datum value))))
192
(unless (member container '(@:|@set| @:|@index|) :test #'json-ld:key=)
193
(json-ld:invalid-reverse-property-error :datum value))
194
(setf (json-ld:term-definition-container definition) container))
195
(setf (json-ld:term-definition-reverse-property definition) t)
196
(define-term-and-return))
197
(t (json-ld:invalid-iri-mapping-error :datum value :clause "11.3"))))
199
(setf (json-ld:term-definition-reverse-property definition) nil)
201
(cond ((and id (not (equalp id key)))
204
(string (let ((expanded-id (json-ld:expand-iri active-context id
207
:local-context local-context
209
(typecase expanded-id
210
((or json-ld:keyword absolute-iri spocq:blank-node)
211
(setf (json-ld:term-definition-term definition) expanded-id))
213
(json-ld:invalid-iri-mapping-error :datum (list :value value :expanded-id expanded-id)
216
(t (json-ld:invalid-iri-mapping-error :datum value
218
((find #\: (string key))
219
(multiple-value-bind (prefix local-part) (parse-qname key)
221
(when (json-ld:object-member-value local-context prefix)
222
(json-ld:create-term-definition active-context local-context prefix defined))
223
(let ((prefix-definition (json-ld:find-term-definition active-context prefix)))
224
(setf (json-ld:term-definition-term definition)
225
(cond (prefix-definition
228
(iri-lexical-form (json-ld:term-definition-term prefix-definition))
231
((and (equal prefix "_") (is-blank_node_label local-part))
232
(setf (json-ld:term-definition-term definition)
233
(json-ld:make-blank-node local-part)))
235
(json-ld:make-iri key)))))))
237
((json-ld:context-vocabulary active-context)
238
(setf (json-ld:term-definition-term definition)
240
(iri-lexical-form (json-ld:context-vocabulary active-context))
243
(json-ld:invalid-iri-mapping-error :datum value :clause "create-term-definition:15")))
245
(setf (json-ld:term-definition-container definition) container))
247
(setf (json-ld:term-definition-language definition) language))
248
(define-term-and-return)))))))
251
(defgeneric json-ld:expand-iri (active-context key &key relative-p vocabulary-p local-context defined base-iri)
252
(:documentation "re-interpret the given iri with respect to the active (and optionally the local) context.
253
This allows qname expansion and term mapping.
254
Return an absolute iri or a blank node")
256
(:method ((active-context json-ld:context) (key null) &key &allow-other-keys)
259
(:method ((active-context json-ld:context) (key symbol) &rest args)
260
(declare (dynamic-extent args))
261
(if (json-ld:keywordp key)
263
(apply #'json-ld:expand-iri active-context (iri-lexical-form key) args)))
265
(:method ((active-context json-ld:context) (key spocq:iri) &rest args)
266
(declare (dynamic-extent args))
267
(apply #'json-ld:expand-iri active-context (iri-lexical-form key) args))
269
(:method ((active-context json-ld:context) (key string) &key relative-p vocabulary-p local-context defined
270
(base-iri (json-ld:base-iri)))
271
(cond ((json-ld:keywordp key)) ;; 1, returns the interned keyword
274
(when (and local-context (json-ld:object-member-value local-context key)
275
(not (eql :true (rest (assoc key defined :test #'equal)))))
276
(json-ld:create-term-definition active-context local-context key defined))
277
(cond ((and vocabulary-p
278
(json-ld:find-term-definition active-context key))
280
(json-ld:term-definition-term (json-ld:find-term-definition active-context key)))
281
((find #\: key :test #'eql)
283
(multiple-value-bind (prefix local-part) (parse-qname key)
284
(cond ((and (equal prefix "_") (is-blank_node_label local-part))
286
(json-ld:make-blank-node key))
287
((string-equal "//" local-part :end2 (min 2 (length local-part)))
289
(json-ld:make-iri key))
291
(when (and (json-ld:object-member-value local-context prefix)
292
(not (eql :true (rest (assoc prefix defined)))))
294
(json-ld:create-term-definition active-context local-context prefix defined))
295
(let ((definition (json-ld:find-term-definition active-context prefix)))
297
;; 4.4 : n.b. _not_ an iri merge, but rather, a catenation
298
(json-ld:make-iri (concatenate 'string
299
(iri-lexical-form (json-ld:term-definition-term definition))
302
(json-ld:make-iri key)))))))
304
((and vocabulary-p (json-ld:context-vocabulary active-context))
305
(json-ld:make-iri (concatenate 'string
306
(iri-lexical-form (json-ld:context-vocabulary active-context))
310
;; n.b. _not_ catenated, but rather, an iri merge
311
(merge-and-intern-iri key :base-iri base-iri))
313
(json-ld:make-iri key)))))))
318
(defgeneric json-ld:expand (context property element)
319
(:method ((context t) (property t) (element t))
320
(json-ld:expand-element nil context property element)))
322
(defgeneric json-ld:expand-element (parent context property element)
323
(:argument-precedence-order element property parent context)
324
(:method ((parent t) (context t) (property t) (element t)) ; 2
325
(json-ld:expand-value context property element)) ; 2.2
327
(:method ((parent t) (context t) (property t) (element (eql :|null|))) ; 1
329
(:method ((parent t) (context t) (property (eql :|null|)) (element string))
331
(:method ((parent t) (context t) (property (eql @:|@graph|)) (element string))
334
(:method ((parent t) (context t) (property t) (element vector)) ; 3
335
(let ((into (make-array (length element) :adjustable t :fill-pointer 0))
336
(list-property-p (or (eq property @:|@list|) (eq (json-ld:find-term-definition-container context property) @:|@list|))))
337
(loop for item across element
338
for expanded-item = (json-ld:expand-element parent context property item) ; 3.2.1
339
when (and list-property-p (or (json-ld:arrayp expanded-item) (json-ld:list-object-p expanded-item))) ; 3.2.2
340
do (json-ld:list-of-lists-error :datum expanded-item) ; 3.2.3
341
if (json-ld:arrayp expanded-item)
342
do (loop for expanded-item-item across expanded-item
343
do (vector-push-extend expanded-item-item into))
344
else do (vector-push-extend expanded-item into))
347
(:method ((parent t) (context t) (property t) (element list)) ; 4
348
(json-ld:expand-object (json-ld:make-object ) context property element))
349
(:method ((parent t) (context t) (property t) (element json-ld:object)) ; 4
350
(json-ld:expand-object (json-ld:make-object ) context property element))
351
(:method ((parent json-ld:frame) (context t) (property t) (element list)) ; 4
352
(json-ld:expand-object (json-ld:make-frame :context context) context property element))
353
(:method ((parent json-ld:frame) (context t) (property t) (element json-ld:object)) ; 4
354
(json-ld:expand-object (json-ld:make-frame :context context) context property element))
358
(defgeneric json-ld:expand-value (context property scalar-value)
359
(:documentation "Normalize a scalar-value to incorporate declarations from the context for
360
id, vocab, type, and/or language. The json-ld 'Processing Algorithms and API' recommendation
361
describes a process whcich computes an annotated JSON object. As these algorithms are implemented
362
in terms of RDF terms, it avoids the circumlocution and computes the respective term directly.
363
- @id or @vocab type mappings yield an IRI
364
- @type yields an interned term
365
- @language yields a xsd:langString
367
[1]: http://www.w3.org/TR/json-ld-api/#value-expansion")
369
(:method ((context json-ld:context) (property t) (scalar-value t))
370
(let ((type (json-ld:find-term-definition-type context property)))
372
(@:|@id| (json-ld:expand-iri context property :relative-p t))
373
(@:|@vocab| (json-ld:expand-iri context property :relative-p t :vocabulary-p t))
374
((nil) (cond ((stringp scalar-value)
375
(let ((language (or (json-ld:find-term-definition-language context property)
376
(json-ld:context-language context))))
378
(string (intern-plain-literal scalar-value language))
385
(unless (equal type |xsd|:|boolean|)
386
(invalid-argument-type json-ld:expand-value scalar-value |xsd|:|boolean|))
389
(unless (equal type |xsd|:|boolean|)
390
(invalid-argument-type json-ld:expand-value scalar-value |xsd|:|boolean|))
395
(typecase scalar-value
396
(number scalar-value)
397
(string (intern-literal scalar-value type))
399
(when json-ld::*verbose*
400
(log-warn "unexpected json type to intern ~s : ~s" type scalar-value)))))))))))
403
(defgeneric json-ld:expand-object (result context property object)
404
(:method ((result json-ld:object) (context json-ld:context) (property t) (from t))
405
(flet ((ensure-array (value)
407
(json-ld:array value)
408
(t (make-array 1 :fill-pointer 1 :adjustable t :initial-contents (list value))))))
409
(let ((local-context (json-ld:object-member-value from @:|@context|)))
410
(when local-context ; 5
411
(setf context (json-ld:merge-contexts context local-context))))
412
(when (json-ld:frame-p result)
413
(setf (json-ld:frame-context result) context))
414
(json-ld:map-members (key value) from ; 7
415
;; (print (list :map-members "7" key value))
416
(unless (json-ld:key= key @:|@context|) ; 7.1
417
(let ((expanded-key (json-ld:expand-iri context key :vocabulary-p t)) ; 7.2
418
(expanded-value nil))
419
;; (print (list "7.4.start" expanded-key value expanded-value))
420
(cond ((or (eq expanded-key :|null|)
421
(and (not (json-ld:keywordp expanded-key))
422
(not (iri-p expanded-key))))) ; 7.3
423
((json-ld:keywordp expanded-key) ; 7.4
425
(when (eq property @:|@reverse|)
426
(json-ld:invalid-reverse-property-map-error :datum expanded-key))
428
(when (json-ld:object-member context expanded-key)
429
(json-ld:colliding-keywords-error :datum expanded-key))
432
(unless (stringp value)
433
(json-ld:invalid-type-value-error :datum value))
434
(setf expanded-value (json-ld:expand-iri context value
436
(@:|@type| ; 7.4.4 . says string or array of such, but framr 2.2 allows an empty object
438
(string (setf expanded-value (json-ld:expand-iri context value
442
(setf expanded-value (make-array (length value)))
443
(loop for value across value
446
do (setf (aref expanded-value i) (json-ld:expand-iri context value
449
else do (json-ld:invalid-type-value-error :datum value)))
451
(setf expanded-value (json-ld:make-object )))
453
(json-ld:invalid-type-value-error :datum value))))
455
(setf expanded-value (json-ld:expand-element result context property value)))
457
(unless (or (json-ld:atomp value) (json-ld:null value))
458
(json-ld:invalid-value-object-value-error :datum value))
459
(setf expanded-value value)
460
(when (eq value :|null|)
461
(setf (json-ld:object-member-value result @:|@value|) value)))
462
(@:|@language| ; 7.4.7
463
(unless (stringp value)
464
(json-ld:invalid-language-tagged-string-error :datum expanded-value))
465
(setf expanded-value (string-downcase value)))
467
(unless (stringp value)
468
(json-ld:invalid-index-value-error :datum expanded-value))
469
(setf expanded-value value))
470
(@:|@list| ; (print "7.4.9")
471
(unless (or (json-ld:null property) (eq property @:|@graph|))
472
(setf expanded-value (json-ld:expand-element result context property value))
473
(when (json-ld:list-object-p expanded-value)
474
(json-ld:list-of-lists-error :datum expanded-value))))
476
(setf expanded-value (json-ld:expand-element result context property value)))
477
(@:|@reverse| ; 7.4.11
478
(unless (json-ld:object-p value)
479
(json-ld:invalid-reverse-value-error :datum value))
480
(setf expanded-value (json-ld:expand-element result context @:|@reverse| value)) ; 7.4.11.1
481
(let ((reverse-map nil)) ; 7.4.11.3.1, 2
482
(flet ((reverse-map ()
484
(json-ld:object-member-value result @:|@reverse|) ; 7.4.11.3.1, 2
485
(setf (json-ld:object-member-value result @:|@reverse|)
486
(json-ld:make-object )))))
487
(json-ld:map-members (property item) expanded-value
489
(@:|@reverse| ; (print "7.4.11.2")
490
(json-ld:map-members (property item) item
491
(json-ld:append-object-member-value result property item)))
492
((or (json-ld:value-object-p item) (json-ld:list-object-p item))
493
(json-ld:invalid-reverse-property-value-error :datum item :property property))
495
(json-ld:append-object-member-value (reverse-map) property item)))))))) ; 7.4.11.3.3.1.3))))))
496
;; (print (list "7.4.end" expanded-key expanded-value))
497
(setf (json-ld:object-member-value result expanded-key) expanded-value))
499
;; (print (list "7.5.start" expanded-key value expanded-value))
500
(if (json-ld:object-p value)
501
(cond ((eql @:|@language| (json-ld:find-term-definition-container context key)) ; 7.5
502
(let ((expanded-value (make-array 0 :fill-pointer 0 :adjustable t))) ; 7.5.1
503
(json-ld:map-members (language language-value) value
504
;; (print (list :map-members "7.5.1" language language-value))
505
(flet ((append-simple-string (string) ; (print (list :append string))
507
(string (vector-push-extend (intern-plain-literal string language) expanded-value))
508
(t (json-ld:invalid-language-map-value-error :datum string :property key)))))
509
(typecase language-value
510
(string (append-simple-string language-value))
511
(json-ld:array (loop for language-value across language-value
512
do (append-simple-string language-value)))
513
(t (json-ld:invalid-language-map-value-error :datum language-value)))))))
514
((eql @:|@index| (json-ld:find-term-definition-container context key)) ; (print "7.6")
515
(setf expanded-value (make-array 0 :fill-pointer 0 :adjustable t))
516
(json-ld:map-members (index-index index-value) value ; 7.6.2
517
;; (print (list :map-members "7.6" index-index index-value))
518
(setf index-value (json-ld:expand-element result context key (ensure-array index-value))) ; 7.6.2.1
519
;; (print (list :map-members "7.6" index-index :expanded index-value))
520
(loop for item across index-value
521
when (and (json-ld:object-p item) (not (json-ld:object-member item @:|@index|)))
522
do (setf (json-ld:object-member-value item @:|@index|) index-index)
523
do (vector-push-extend item expanded-value))))
525
(setf expanded-value (json-ld:expand-element result context key value))))
526
(setf expanded-value (json-ld:expand context key value)))
528
(unless (json-ld:null expanded-value) ; 7.8
529
(cond ((eql @:|@list| (json-ld:find-term-definition-container context key)) ; (print "7.9")
530
(unless (json-ld:list-object-p expanded-value)
531
(setf expanded-value (json-ld:make-object `((@:|@list| . ,(ensure-array expanded-value)))))))
532
((json-ld:find-term-definition-reverse-property context key) ; 7.10
533
(let ((reverse-map (or (json-ld:object-member-value result @:|@reverse|)
534
(setf (json-ld:object-member-value result @:|@reverse|)
535
(json-ld:make-object)))))
536
(setf expanded-value (ensure-array expanded-value)) ; 7.10.3
537
(loop for item across expanded-value
538
;; do (print (list "7.10.4.1" item))
539
if (or (json-ld:value-object-p item) (json-ld:list-object-p item))
540
do (json-ld:invalid-reverse-property-value-error :datum item) ;
541
do (json-ld:append-object-member-value reverse-map expanded-key item))))
543
(json-ld:append-object-member-value result expanded-key expanded-value))))))))))
545
;; 8 : skipped as values are normalized
547
(let ((set-result (json-ld:object-member-value result @:|@set|))) ; 10.2
549
(setf result set-result)))