guile-jsonld/jsonld/iri-compaction.scm

iri-compaction.scm

1
;;;; Copyright (C) 2020 Julien Lepiller <julien@lepiller.eu>
2
;;;; 
3
;;;; This library is free software; you can redistribute it and/or
4
;;;; modify it under the terms of the GNU Lesser General Public
5
;;;; License as published by the Free Software Foundation; either
6
;;;; version 3 of the License, or (at your option) any later version.
7
;;;; 
8
;;;; This library is distributed in the hope that it will be useful,
9
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
;;;; Lesser General Public License for more details.
12
;;;; 
13
;;;; You should have received a copy of the GNU Lesser General Public
14
;;;; License along with this library; if not, write to the Free Software
15
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
;;;; 
17
18
(define-module (jsonld iri-compaction)
19
  #:use-module (iri iri)
20
  #:use-module (jsonld context)
21
  #:use-module (jsonld inverse-context-creation)
22
  #:use-module (jsonld json)
23
  #:use-module (jsonld term-selection)
24
  #:export (iri-compaction))
25
26
(define-syntax set-cond!
27
  (syntax-rules ()
28
    ((_ var val)
29
     (unless var
30
       (set! var val)))))
31
32
(define* (iri-compaction active-context var
33
                         #:key value vocab? reverse? processing-mode)
34
  ;; not specified, but sometimes the spec leads to var being an array, so
35
  ;; in that case we iri-compact each part of it and return an array.
36
  (cond
37
    ;; 1
38
    ((json-null? var) json-null)
39
    ;; XXX: addition to spec
40
    ((json-array? var)
41
     (list->array 1
42
       (map
43
         (lambda (val)
44
           (iri-compaction active-context val
45
                           #:value value
46
                           #:vocab? vocab?
47
                           #:reverse? reverse?
48
                           #:processing-mode processing-mode))
49
         (array->list var))))
50
    (else
51
     (begin
52
       ;; 2
53
       (when (json-null? (active-context-inverse-context active-context))
54
         (set! active-context
55
           (update-active-context active-context
56
                                  #:inverse-context
57
                                  (inverse-context-creation active-context))))
58
       ;; 3
59
       (let* ((inverse-context (active-context-inverse-context active-context))
60
              (result #f))
61
         ;; 4
62
         (when (and vocab? (json-has-key? inverse-context var))
63
           (let ((default-language
64
                   ;; 4.1
65
                   (if (not-null-or-false (active-context-direction active-context))
66
                       (string-append
67
                         (string-downcase
68
                           (or (not-null-or-false (active-context-language active-context))
69
                               ""))
70
                         "_"
71
                         (active-context-direction active-context))
72
                       (string-downcase
73
                         (or (not-null-or-false (active-context-language active-context))
74
                             "@none"))))
75
                 ;; 4.3
76
                 (containers '())
77
                 ;; 4.4
78
                 (type/language "@language")
79
                 (type/language-value "@null")
80
                 ;; 4.14
81
                 (preferred-values '()))
82
             ;; 4.2
83
             (when (json-has-key? value "@preserve")
84
               (let ((preserve (assoc-ref value "@preserve")))
85
                 (set! value
86
                   (if (json-array? preserve)
87
                       (car (array->list preserve))
88
                       preserve))))
89
             ;; 4.5
90
             (when (and (json-has-key? value "@index")
91
                        (not (graph-object? value)))
92
               (set! containers
93
                 (append containers '("@index" "@index@set"))))
94
             (cond
95
               ;; 4.6
96
               (reverse?
97
                 (set! type/language "@type")
98
                 (set! type/language-value "@reverse")
99
                 (set! containers (append containers '("@set"))))
100
               ;; 4.7
101
               ((list-object? value)
102
                ;; 4.7.1
103
                (unless (json-has-key? value "@index")
104
                  (set! containers (append containers '("@list"))))
105
                ;; 4.7.2
106
                (let ((lst (array->list (assoc-ref value "@list")))
107
                      ;; 4.7.3
108
                      (common-type json-null)
109
                      (common-language json-null))
110
                  (when (null? lst)
111
                    (set! common-language default-language))
112
                  ;; 4.7.4
113
                  (for-each
114
                    (lambda (item)
115
                      ;; 4.7.4.1
116
                      (let ((item-language "@none")
117
                            (item-type "@none"))
118
                        (if (json-has-key? item "@value")
119
                            ;; 4.7.4.2
120
                            (cond
121
                              ((json-has-key? item "@direction")
122
                               (set! item-language
123
                                 (string-append
124
                                   (or (assoc-ref item "@language") "")
125
                                   "_"
126
                                   (assoc-ref item "@direction"))))
127
                              ((json-has-key? item "@language")
128
                               (set! item-language (assoc-ref item "@language")))
129
                              ((json-has-key? item "@type")
130
                               (set! item-type (assoc-ref item "@type")))
131
                              (else
132
                                (set! item-language "@null")))
133
                            ;; 4.7.4.3
134
                            (set! item-type "@id"))
135
                        ;; 4.7.4.4
136
                        (if (json-null? common-language)
137
                            (set! common-language item-language)
138
                            (unless (or (equal? common-language item-language)
139
                                        (not (json-has-key? item "@value")))
140
                              (set! common-language "@none")))
141
                        ;; 4.7.4.6
142
                        (if (json-null? common-type)
143
                            (set! common-type item-type)
144
                            (unless (equal? common-type item-type)
145
                              (set! common-type "@none")))))
146
                    lst)
147
                  ;; 4.7.5
148
                  (when (json-null? common-language)
149
                    (set! common-language "@none"))
150
                  (when (json-null? common-type)
151
                    (set! common-type "@none"))
152
                  (if (not (equal? common-type "@none"))
153
                      (begin
154
                        (set! type/language "@type")
155
                        (set! type/language-value common-type))
156
                      (set! type/language-value common-language))))
157
               ;; 4.8
158
               ((graph-object? value)
159
                ;; 4.8.1
160
                (when (json-has-key? value "@index")
161
                  (set! containers
162
                    (append containers '("@graph@index" "@graph@index@set"))))
163
                ;; 4.8.2
164
                (when (json-has-key? value "@id")
165
                  (set! containers
166
                    (append containers '("@graph@id" "@graph@id@set"))))
167
                ;; 4.8.3
168
                (set! containers
169
                  (append containers '("@graph" "@graph@set" "@set")))
170
                ;; 4.8.4
171
                (unless (json-has-key? value "@index")
172
                  (set! containers
173
                    (append containers '("@graph@index" "@graph@index@set"))))
174
                ;; 4.8.5
175
                (unless (json-has-key? value "@id")
176
                  (set! containers
177
                    (append containers '("@graph@id" "@graph@id@set"))))
178
                ;; 4.8.6
179
                (set! containers
180
                  (append containers '("@index" "@index@set")))
181
                ;; 4.8.7
182
                (set! type/language "@type")
183
                (set! type/language-value "@id"))
184
               ;; 4.9.1 and 4.9.3
185
               ((json-has-key? value "@value")
186
                (cond
187
                  ((and (json-has-key? value "@direction")
188
                        (not (json-has-key? value "@index")))
189
                   (set! type/language-value
190
                     (string-append
191
                       (or (assoc-ref value "@language") "")
192
                       "_"
193
                       (assoc-ref value "@direction")))
194
                   (set! containers
195
                     (append containers '("@language" "@language@set"))))
196
                  ((and (json-has-key? value "@language")
197
                        (not (json-has-key? value "@index")))
198
                   (set! type/language-value (assoc-ref value "@language"))
199
                   (set! containers
200
                     (append containers '("@language" "@language@set"))))
201
                  ((json-has-key? value "@type")
202
                   (set! type/language-value (assoc-ref value "@type"))
203
                   (set! type/language "@type")))
204
                (set! containers (append containers '("@set"))))
205
               ;; 4.9.2 and 4.9.3
206
               (else
207
                (set! type/language "@type")
208
                (set! type/language-value "@id")
209
                (set! containers
210
                  (append containers '("@id" "@id@set" "@type" "@set@type" "@set")))))
211
             ;; 4.10
212
             (set! containers (append containers '("@none")))
213
             ;; 4.11
214
             (unless (processing-mode-1.0? processing-mode)
215
               (unless (json-has-key? value "@index")
216
                 (set! containers (append containers '("@index" "@index@set"))))
217
               ;; 4.12
218
               (when (and (json-has-key? value "@value")
219
                          (null? (filter (lambda (kp) (not (equal? (car kp) "@value")))
220
                                         value)))
221
                 (set! containers (append containers '("@language" "@language@set")))))
222
             ;; 4.13
223
             (when (equal? type/language-value json-null)
224
               (set! type/language-value "@null"))
225
             ;; 4.15
226
             (when (equal? type/language-value "@reverse")
227
               (set! preferred-values (append preferred-values '("@reverse"))))
228
             ;; 4.16
229
             (if (and (or (equal? type/language-value "@reverse")
230
                          (equal? type/language-value "@id"))
231
                      (json-has-key? value "@id"))
232
               (let* ((compacted-iri (iri-compaction active-context
233
                                                     (assoc-ref value "@id")
234
                                                     #:vocab? #t
235
                                                     #:processing-mode processing-mode))
236
                      (def (term-definition-ref active-context compacted-iri))
237
                      (iri (if (term-definition? def)
238
                               (term-definition-iri def)
239
                               #f)))
240
                 (if (equal? iri (assoc-ref value "@id"))
241
                     (set! preferred-values
242
                       (append preferred-values '("@vocab" "@id" "@none")))
243
                     (set! preferred-values
244
                       (append preferred-values '("@id" "@vocab" "@none")))))
245
               ;; 4.17
246
               (begin
247
                 (when (equal? (assoc-ref value "@list") #())
248
                   (set! type/language "@any"))
249
                 (set! preferred-values
250
                   (append preferred-values (list type/language-value "@none")))))
251
             ;; 4.18
252
             (set! preferred-values (append preferred-values '("@any")))
253
             ;; 4.19
254
             (let* ((underscore-vals (filter
255
                                       (lambda (s)
256
                                         (string-index s #\_))
257
                                       preferred-values))
258
                    (underscore (if (null? underscore-vals) #f (car underscore-vals))))
259
               (when (not-null-or-false underscore)
260
                 (set! preferred-values
261
                   (append
262
                     preferred-values
263
                     (list
264
                       (string-join
265
                         (cons "" (cdr (string-split underscore #\_))) "_"))))))
266
             ;; 4.20
267
             (let ((term (term-selection active-context var containers
268
                                         type/language preferred-values)))
269
               (when (not-null-or-false term)
270
                 (set-cond! result term)))))
271
         ;; 5
272
         (when (and vocab? (not-null-or-false (active-context-vocab active-context)))
273
           (let ((vocab (active-context-vocab active-context)))
274
             (when (and (>= (string-length var) (string-length vocab))
275
                        (equal? (substring var 0 (string-length vocab)) vocab))
276
               (let ((suffix (substring var (string-length vocab))))
277
                 (when (not (not-null-or-false (term-definition-ref active-context suffix)))
278
                   (set-cond! result suffix))))))
279
         ;; 6
280
         (let ((compact-iri json-null))
281
           ;; 7
282
           (for-each-pair
283
             (lambda (term def)
284
               ;; 7.1
285
               (unless (or (json-null? (term-definition-iri def))
286
                           (equal? (term-definition-iri def) var)
287
                           (not (string? var))
288
                           (< (string-length var) (string-length (term-definition-iri def)))
289
                           (not (equal?
290
                                  (substring
291
                                    var 0
292
                                    (string-length (term-definition-iri def)))
293
                                  (term-definition-iri def)))
294
                           (not (term-definition-prefix? def)))
295
                 ;; 7.2
296
                 (let ((candidate (string-append term ":"
297
                                                 (substring
298
                                                   var
299
                                                   (string-length
300
                                                     (term-definition-iri def))))))
301
                   ;; 7.3
302
                   (when (or (json-null? compact-iri)
303
                             (< (string-length candidate) (string-length compact-iri))
304
                             (and (= (string-length candidate)
305
                                     (string-length compact-iri))
306
                                  (string<=? candidate compact-iri)))
307
                     (let ((def (term-definition-ref active-context candidate)))
308
                       (when (or (not (term-definition? def))
309
                                 (and (not (not-null-or-false value))
310
                                      (equal? (term-definition-iri def) var)))
311
                         (set! compact-iri candidate)))))))
312
             (active-context-definitions active-context))
313
           ;; 8
314
           (when (not-null-or-false compact-iri)
315
             (set-cond! result compact-iri)))
316
         ;; 9
317
         (unless result
318
           (let* ((components (string-split var #\:))
319
                  (prefix (car components))
320
                  (suffix (string-join (cdr components) ":")))
321
             (unless (null? (filter
322
                              (lambda (kp)
323
                                (and
324
                                  (equal? prefix (car kp))
325
                                  (term-definition-prefix? (cdr kp))))
326
                              (active-context-definitions active-context)))
327
               (unless (and (> (string-length suffix) 2)
328
                            (equal? (substring suffix 0 2) "//"))
329
                 (throw 'iri-confused-with-prefix)))))
330
         ;; 10
331
         (unless vocab?
332
           (when (and (not-null-or-false (active-context-base active-context))
333
                      (absolute-iri? var))
334
             (let ((iri (make-relative-iri var (active-context-base active-context))))
335
               (if (keyword-form? iri)
336
                   (set-cond! result (string-append "./" iri))
337
                   (set-cond! result iri)))))
338
         ;; 11
339
         (set-cond! result var)
340
         result)))))
341