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 |