guile-jsonld/jsonld.scm

jsonld.scm

1
;;;; Copyright (C) 2019, 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)
19
  #:use-module (iri iri)
20
  #:use-module (jsonld compaction)
21
  #:use-module (jsonld context)
22
  #:use-module (jsonld context-processing)
23
  #:use-module (jsonld deserialize-jsonld)
24
  #:use-module (jsonld download)
25
  #:use-module (jsonld expansion)
26
  #:use-module (jsonld flattening)
27
  #:use-module (jsonld generate-blank-node-identifier)
28
  #:use-module (jsonld iri-compaction)
29
  #:use-module (jsonld json)
30
  #:use-module (jsonld node-map-generation)
31
  #:use-module (jsonld options)
32
  #:use-module (jsonld serialize-rdf)
33
  #:use-module (rdf rdf)
34
  #:export (compact
35
            expand
36
            flatten
37
            jsonld->rdf
38
            rdf->jsonld))
39
40
(define* (compact input context #:key (options (new-jsonld-options)))
41
  (call-with-values
42
    (lambda ()
43
      ;; TODO: set ordered to #f
44
      (expand-with-base input #:options options))
45
    ;; 2 and 3
46
    (lambda (expanded-input context-base)
47
      (when (string? context)
48
        (set! context
49
          (json-document-document
50
            ((jsonld-options-document-loader options)
51
             context))))
52
      ;; 4
53
      (when (json-has-key? context "@context")
54
        (set! context (assoc-ref context "@context")))
55
      (let* ((base-iri (or (jsonld-options-base options)
56
                           (and (jsonld-options-compact-to-relative? options)
57
                                (string? input)
58
                                input)))
59
             (active-context (context-processing (new-active-context
60
                                                   #:base base-iri)
61
                                                 context context-base
62
                                                 #:options options))
63
             (compacted-output
64
               (compaction active-context
65
                           json-null ;; active-property
66
                           expanded-input ;; element
67
                           #:compact-arrays? (jsonld-options-compact-arrays? options)
68
                           #:ordered? (jsonld-options-ordered? options)
69
                           #:processing-mode
70
                           (jsonld-options-processing-mode options))))
71
        (if (equal? compacted-output #())
72
            (set! compacted-output '())
73
            (when (json-array? compacted-output)
74
              (set! compacted-output `((,(iri-compaction active-context
75
                                                         "@graph"
76
                                                         #:vocab? #t
77
                                                         #:reverse? #f) .
78
                                         ,compacted-output)))))
79
        (when (and context (not (null? compacted-output)) (not (null? context)))
80
          (set! compacted-output
81
            (cons (cons "@context" context) compacted-output)))
82
        compacted-output))))
83
84
(define* (expand-with-base input #:key (options (new-jsonld-options)))
85
  (let ((document input)
86
        (remote-document #f)
87
        (active-context (new-active-context
88
                          #:base (jsonld-options-base options)
89
                          #:original-base (jsonld-options-base options)))
90
        (document-base (jsonld-options-base options)))
91
    (when (string? input)
92
      ;; 2
93
      (catch #t
94
        (lambda ()
95
          (set! remote-document
96
            ((jsonld-options-document-loader options)
97
             input
98
             #:extract-all-scripts? (jsonld-options-extract-all-scripts? options))))
99
        (lambda (key . value)
100
          (cond
101
            ((member key '(loading-document-failed multiple-context-link-headers
102
                           invalid-script-element))
103
             (apply throw key value))
104
            (else
105
              (apply throw 'loading-document-failed key value)))))
106
      ;; 3
107
      (set! document (json-document-document remote-document))
108
      (set! document-base (json-document-document-url remote-document))
109
      ;; 4
110
      (set! active-context
111
        (update-active-context active-context
112
                               #:base (or (jsonld-options-base options)
113
                                          (json-document-document-url remote-document))
114
                               #:original-base
115
                               (or (json-document-document-url remote-document)
116
                                   (jsonld-options-base options)))))
117
118
    ;; 5
119
    (when (jsonld-options-expand-context options)
120
      (set! active-context
121
        (let* ((local-context (jsonld-options-expand-context options))
122
               (local-context (if (json-has-key? local-context "@context")
123
                                  (assoc-ref local-context "@context")
124
                                  local-context)))
125
          (context-processing active-context local-context
126
                              (active-context-original-base active-context)))))
127
128
    ;; 6
129
    (when (and remote-document (json-document-context-url remote-document))
130
      (let ((context-url (json-document-context-url remote-document)))
131
        (set! active-context
132
          (context-processing active-context context-url context-url))))
133
134
    ;; 7
135
    (let ((expanded-output (expansion active-context json-null document
136
                                      (if remote-document
137
                                          (or (json-document-document-url remote-document)
138
                                              (jsonld-options-base options))
139
                                          (jsonld-options-base options))
140
                                      #:options options)))
141
142
      (when (and
143
              (json-object? expanded-output)
144
              (json-has-key? expanded-output "@graph")
145
              (null? (filter
146
                       (lambda (kv)
147
                         (not (equal? (car kv) "@graph")))
148
                       expanded-output)))
149
        (set! expanded-output (assoc-ref expanded-output "@graph")))
150
      (when (json-null? expanded-output)
151
        (set! expanded-output #()))
152
      (unless (json-array? expanded-output)
153
        (set! expanded-output `#(,expanded-output)))
154
      ;; 8
155
      (values expanded-output document-base))))
156
157
(define* (expand input #:key (options (new-jsonld-options)))
158
  (call-with-values
159
    (lambda ()
160
      (expand-with-base input #:options options))
161
    (lambda (out base)
162
      out)))
163
164
(define* (flatten input #:key (context #f) (options (new-jsonld-options)))
165
  ;; 2
166
  (let* ((expanded-input
167
           (expand input #:options (update-jsonld-options
168
                                     options #:ordered? #t)))
169
         ;; 3
170
         (base-iri (or (jsonld-options-base options)
171
                       (and (jsonld-options-compact-to-relative? options)
172
                            (string? input)
173
                            input)))
174
         ;; 4
175
         (identifier-map '())
176
         ;; 5
177
         (flattened-output (flattening expanded-input
178
                                       #:ordered?
179
                                       (jsonld-options-ordered? options))))
180
    ;; 5.1
181
    (when context
182
      ;; TODO
183
      (set! flattened-output (compact flattened-output context #:options options)))
184
    flattened-output))
185
186
(define* (jsonld->rdf input #:key (options (new-jsonld-options)))
187
  (call-with-values
188
    (lambda ()
189
      ;; TODO: set ordered to #f
190
      (expand-with-base input #:options options))
191
    ;; 2 and 3
192
    (lambda (expanded-input context-base)
193
      (let* ((generate-blank-node (get-generate-blank-node-identifier))
194
             (generate-node-map (get-node-map-generation generate-blank-node))
195
             (node-map (generate-node-map expanded-input '()))
196
             (node-map (assoc-ref node-map "node-map")))
197
        (deserialize-jsonld
198
          generate-blank-node node-map (make-rdf-dataset '() '())
199
          #:produce-generalized-rdf?
200
          (jsonld-options-produce-generalized-rdf? options)
201
          #:rdf-direction (jsonld-options-rdf-direction options))))))
202
203
(define* (rdf->jsonld input #:key (options (new-jsonld-options)))
204
  (serialize-rdf input
205
                 #:ordered? (jsonld-options-ordered? options)
206
                 #:rdf-direction (jsonld-options-rdf-direction options)
207
                 #:use-native-types? (jsonld-options-use-native-types? options)
208
                 #:use-rdf-type? (jsonld-options-use-rdf-type? options)
209
                 #:processing-mode (jsonld-options-processing-mode options)))
210