Add toRdf algorithm.
Makefile.am
| 6 | 6 | jsonld/context-processing.scm \ | |
| 7 | 7 | jsonld/context.scm \ | |
| 8 | 8 | jsonld/create-term-definition.scm \ | |
| 9 | + | jsonld/deserialize-jsonld.scm \ | |
| 9 | 10 | jsonld/download.scm \ | |
| 10 | 11 | jsonld/expansion.scm \ | |
| 11 | 12 | jsonld/flattening.scm \ | |
… | |||
| 15 | 16 | jsonld/iri-expansion.scm \ | |
| 16 | 17 | jsonld/iri.scm \ | |
| 17 | 18 | jsonld/json.scm \ | |
| 19 | + | jsonld/list-to-rdf.scm \ | |
| 18 | 20 | jsonld/memoization.scm \ | |
| 19 | 21 | jsonld/merge-node-maps.scm \ | |
| 20 | 22 | jsonld/node-map-generation.scm \ | |
| 23 | + | jsonld/object-to-rdf.scm \ | |
| 21 | 24 | jsonld/options.scm \ | |
| 22 | 25 | jsonld/term-selection.scm \ | |
| 23 | 26 | jsonld/value-compaction.scm \ | |
… | |||
| 32 | 35 | TESTS = tests/compact.scm \ | |
| 33 | 36 | tests/expand.scm \ | |
| 34 | 37 | tests/flatten.scm \ | |
| 35 | - | #tests/html.scm \ not properly implemented | |
| 36 | 38 | tests/remote-doc.scm | |
| 37 | 39 | EXTRA_DIST += $(TESTS) | |
| 38 | 40 | ||
README.md
| 121 | 121 | to carry additional configuration information. An additional context can be | |
| 122 | 122 | passed in order to run the compaction algorithm on the result. | |
| 123 | 123 | ||
| 124 | + | **Scheme Procedure**: jsonld->rdf input [#:options (new-jsonld-options)] | |
| 125 | + | ||
| 126 | + | Transforms the given input into an RDF dataset (in the format expected by | |
| 127 | + | guile-rdf). This procedure takes an input, which can be a Json object (as | |
| 128 | + | produced by the guile-json library) or a string representing the URL of a JsonLD | |
| 129 | + | document. The options can be used to carry additional configuration information. | |
| 130 | + | ||
| 124 | 131 | ### The JsonLDOptions Type | |
| 125 | 132 | ||
| 126 | 133 | The `jsonld-options` type is used to pass various options to the JsonLdProcessor |
configure.ac
| 29 | 29 | AC_CONFIG_FILES([tests/html.scm], [chmod +x tests/html.scm]) | |
| 30 | 30 | AC_CONFIG_FILES([tests/remote-doc.scm], [chmod +x tests/remote-doc.scm]) | |
| 31 | 31 | AC_CONFIG_FILES([tests/report.scm], [chmod +x tests/report.scm]) | |
| 32 | + | AC_CONFIG_FILES([tests/tordf.scm], [chmod +x tests/tordf.scm]) | |
| 32 | 33 | AC_CONFIG_FILES(Makefile) | |
| 33 | 34 | AC_REQUIRE_AUX_FILE([tap-driver.sh]) | |
| 34 | 35 | AC_PROG_AWK |
jsonld.scm
| 19 | 19 | #:use-module (jsonld compaction) | |
| 20 | 20 | #:use-module (jsonld context) | |
| 21 | 21 | #:use-module (jsonld context-processing) | |
| 22 | + | #:use-module (jsonld deserialize-jsonld) | |
| 22 | 23 | #:use-module (jsonld download) | |
| 23 | 24 | #:use-module (jsonld expansion) | |
| 24 | 25 | #:use-module (jsonld flattening) | |
| 26 | + | #:use-module (jsonld generate-blank-node-identifier) | |
| 25 | 27 | #:use-module (jsonld inverse-context-creation) | |
| 26 | 28 | #:use-module (jsonld iri) | |
| 27 | 29 | #:use-module (jsonld iri-compaction) | |
| 28 | 30 | #:use-module (jsonld json) | |
| 31 | + | #:use-module (jsonld node-map-generation) | |
| 29 | 32 | #:use-module (jsonld options) | |
| 33 | + | #:use-module (rdf rdf) | |
| 30 | 34 | #:export (compact | |
| 31 | 35 | expand | |
| 32 | - | flatten)) | |
| 36 | + | flatten | |
| 37 | + | jsonld->rdf)) | |
| 33 | 38 | ||
| 34 | 39 | (define* (compact input context #:key (options (new-jsonld-options))) | |
| 35 | 40 | (call-with-values | |
… | |||
| 177 | 182 | ;; TODO | |
| 178 | 183 | (set! flattened-output (compact flattened-output context #:options options))) | |
| 179 | 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 | + | (pk 'expanded expanded-input) | |
| 194 | + | (let* ((generate-blank-node (get-generate-blank-node-identifier)) | |
| 195 | + | (generate-node-map (get-node-map-generation generate-blank-node)) | |
| 196 | + | (node-map (generate-node-map expanded-input '())) | |
| 197 | + | (node-map (assoc-ref node-map "node-map"))) | |
| 198 | + | (pk node-map) | |
| 199 | + | (deserialize-jsonld | |
| 200 | + | generate-blank-node node-map (make-rdf-dataset '() '()) | |
| 201 | + | #:produce-generalized-rdf? | |
| 202 | + | (jsonld-options-produce-generalized-rdf? options) | |
| 203 | + | #:rdf-direction (jsonld-options-rdf-direction options)))))) | |
jsonld/deserialize-jsonld.scm unknown status 1
| 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 deserialize-jsonld) | |
| 19 | + | #:use-module (ice-9 match) | |
| 20 | + | #:use-module (jsonld iri) | |
| 21 | + | #:use-module (jsonld json) | |
| 22 | + | #:use-module (jsonld generate-blank-node-identifier) | |
| 23 | + | #:use-module (jsonld object-to-rdf) | |
| 24 | + | #:use-module ((rdf rdf) #:hide (blank-node?)) | |
| 25 | + | #:export (deserialize-jsonld | |
| 26 | + | well-formed? | |
| 27 | + | rdf-iri | |
| 28 | + | xsd-iri | |
| 29 | + | blank-node->rdf-blank-node)) | |
| 30 | + | ||
| 31 | + | (define (uniq lst) | |
| 32 | + | (match lst | |
| 33 | + | (() '()) | |
| 34 | + | ((element lst ...) | |
| 35 | + | (if (member element lst) | |
| 36 | + | (uniq lst) | |
| 37 | + | (cons element (uniq lst)))))) | |
| 38 | + | ||
| 39 | + | (define (blank-node->rdf-blank-node node) | |
| 40 | + | "Convert a blank node generated from the generate blank node algorithm to | |
| 41 | + | a representation suitable for guile-rdf. This involves removing the leading | |
| 42 | + | _:b and converting to a number." | |
| 43 | + | (string->number (substring node 3))) | |
| 44 | + | ||
| 45 | + | (define (rdf-iri name) | |
| 46 | + | (string-append "http://www.w3.org/1999/02/22-rdf-syntax-ns#" name)) | |
| 47 | + | ||
| 48 | + | (define (xsd-iri name) | |
| 49 | + | (string-append "http://www.w3.org/2001/XMLSchema#" name)) | |
| 50 | + | ||
| 51 | + | (define (well-formed? node) | |
| 52 | + | (or (absolute-iri? node) (blank-node? node))) | |
| 53 | + | ||
| 54 | + | (define* (deserialize-jsonld generate-blank-node node-map dataset | |
| 55 | + | #:key produce-generalized-rdf? rdf-direction) | |
| 56 | + | ;; 1 | |
| 57 | + | (for-each-pair | |
| 58 | + | (lambda (graph-name graph) | |
| 59 | + | ;; 1.1 | |
| 60 | + | (when (or (well-formed? graph-name) (equal? graph-name "@default")) | |
| 61 | + | ;; 1.2 | |
| 62 | + | (let ((triples (if (equal? graph-name "@default") | |
| 63 | + | (rdf-dataset-default-graph dataset) | |
| 64 | + | '()))) | |
| 65 | + | ;; 1.3 | |
| 66 | + | (for-each-pair | |
| 67 | + | (lambda (subject node) | |
| 68 | + | ;; 1.3.1 | |
| 69 | + | (when (well-formed? subject) | |
| 70 | + | (when (blank-node? subject) | |
| 71 | + | (set! subject (blank-node->rdf-blank-node subject))) | |
| 72 | + | ;; 1.3.2 | |
| 73 | + | (for-each-pair | |
| 74 | + | (lambda (property values) | |
| 75 | + | (cond | |
| 76 | + | ((equal? property "@type") | |
| 77 | + | (for-each | |
| 78 | + | (lambda (type) | |
| 79 | + | (when (well-formed? type) | |
| 80 | + | (when (blank-node? type) | |
| 81 | + | (set! type (blank-node->rdf-blank-node type))) | |
| 82 | + | (set! triples | |
| 83 | + | (cons | |
| 84 | + | (make-rdf-triple subject (rdf-iri "type") | |
| 85 | + | type) | |
| 86 | + | triples)))) | |
| 87 | + | (array->list values))) | |
| 88 | + | ((json-keyword? property) | |
| 89 | + | #t) | |
| 90 | + | ((and (blank-node? property) (not produce-generalized-rdf?)) | |
| 91 | + | #t) | |
| 92 | + | ((not (well-formed? property)) | |
| 93 | + | #t) | |
| 94 | + | (else | |
| 95 | + | (when (blank-node? property) | |
| 96 | + | (set! property (blank-node->rdf-blank-node property))) | |
| 97 | + | (for-each | |
| 98 | + | (lambda (item) | |
| 99 | + | (let* ((res | |
| 100 | + | (object-to-rdf generate-blank-node | |
| 101 | + | rdf-direction item '())) | |
| 102 | + | (list-triples (assoc-ref res "list-triples")) | |
| 103 | + | (res (assoc-ref res "result"))) | |
| 104 | + | (unless (equal? res #nil) | |
| 105 | + | (set! triples | |
| 106 | + | (cons | |
| 107 | + | (make-rdf-triple subject property res) | |
| 108 | + | (append triples list-triples)))))) | |
| 109 | + | (array->list values))))) | |
| 110 | + | (alist-sort-by-key node)))) | |
| 111 | + | (alist-sort-by-key graph)) | |
| 112 | + | ;; 1.2 (cont.) | |
| 113 | + | (set! triples (uniq triples)) | |
| 114 | + | (if (equal? graph-name "@default") | |
| 115 | + | (set! dataset | |
| 116 | + | (make-rdf-dataset triples (rdf-dataset-named-graphs dataset))) | |
| 117 | + | (unless (null? triples) | |
| 118 | + | (set! dataset | |
| 119 | + | (make-rdf-dataset (rdf-dataset-default-graph dataset) | |
| 120 | + | (alist-set | |
| 121 | + | (rdf-dataset-named-graphs dataset) | |
| 122 | + | (if (blank-node? graph-name) | |
| 123 | + | (blank-node->rdf-blank-node graph-name) | |
| 124 | + | graph-name) | |
| 125 | + | triples)))))))) | |
| 126 | + | node-map) | |
| 127 | + | dataset) |
jsonld/iri.scm
| 111 | 111 | ||
| 112 | 112 | ;; This algorithm is not always called with sane values, so prevent errors | |
| 113 | 113 | ;; in some edge cases. | |
| 114 | - | (if (and base (string? reference)) | |
| 114 | + | (if (and base (string? reference) (not (string->uri reference)) | |
| 115 | + | (string->uri-reference reference)) | |
| 115 | 116 | (uri->string | |
| 116 | 117 | (transform-references (set-iri-path (string->uri base)) | |
| 117 | 118 | (string->uri-reference reference))) |
jsonld/list-to-rdf.scm unknown status 1
| 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 list-to-rdf) | |
| 19 | + | #:use-module (jsonld deserialize-jsonld) | |
| 20 | + | #:use-module (jsonld iri) | |
| 21 | + | #:use-module (jsonld json) | |
| 22 | + | #:use-module (jsonld object-to-rdf) | |
| 23 | + | #:use-module (rdf rdf) | |
| 24 | + | #:export (list-to-rdf)) | |
| 25 | + | ||
| 26 | + | (define* (list-to-rdf generate-blank-node rdf-direction lst list-triples) | |
| 27 | + | (let ((result #nil)) | |
| 28 | + | (if (null? lst) | |
| 29 | + | ;; 1 | |
| 30 | + | (set! result (rdf-iri "nil")) | |
| 31 | + | ;; 2 | |
| 32 | + | (let ((bnodes (map | |
| 33 | + | (lambda _ | |
| 34 | + | (blank-node->rdf-blank-node (generate-blank-node #nil))) | |
| 35 | + | lst))) | |
| 36 | + | ;; 3 | |
| 37 | + | (let loop ((bnodes bnodes) (lst lst)) | |
| 38 | + | (unless (null? bnodes) | |
| 39 | + | ;; 3.2 | |
| 40 | + | (let* ((subject (car bnodes)) | |
| 41 | + | (item (car lst)) | |
| 42 | + | (rest (cdr bnodes)) | |
| 43 | + | (rest (if (null? rest) (rdf-iri "nil") (car rest))) | |
| 44 | + | (res (object-to-rdf generate-blank-node rdf-direction | |
| 45 | + | item '())) | |
| 46 | + | (object (assoc-ref res "result")) | |
| 47 | + | (embedded-triples (assoc-ref res "list-triples"))) | |
| 48 | + | ;; 3.3 | |
| 49 | + | (unless (equal? object #nil) | |
| 50 | + | (set! list-triples | |
| 51 | + | (cons (make-rdf-triple subject (rdf-iri "first") object) | |
| 52 | + | list-triples))) | |
| 53 | + | ;; 3.4 | |
| 54 | + | (set! list-triples | |
| 55 | + | (cons (make-rdf-triple subject (rdf-iri "rest") rest) | |
| 56 | + | list-triples)) | |
| 57 | + | ;; 3.5 | |
| 58 | + | (set! list-triples | |
| 59 | + | (append list-triples embedded-triples))) | |
| 60 | + | (loop (cdr bnodes) (cdr lst)))) | |
| 61 | + | ;; 4 | |
| 62 | + | (if (null? bnodes) | |
| 63 | + | (set! result (rdf-iri "nil")) | |
| 64 | + | (set! result (car bnodes))))) | |
| 65 | + | `(("result" . ,result) | |
| 66 | + | ("list-triples" . ,list-triples)))) |
jsonld/node-map-generation.scm
| 152 | 152 | ;; 6 | |
| 153 | 153 | (when (node-object? element) | |
| 154 | 154 | ;; 6.1 | |
| 155 | - | (let* ((id (if (json-has-key? element "@id") | |
| 156 | - | (assoc-ref element "@id") | |
| 157 | - | #f)) | |
| 158 | - | (id (if id | |
| 159 | - | (if (blank-node? id) (generate-blank-node id) id) | |
| 160 | - | (generate-blank-node #nil)))) | |
| 155 | + | (let ((id (if (json-has-key? element "@id") | |
| 156 | + | (if (blank-node? (assoc-ref element "@id")) | |
| 157 | + | (generate-blank-node (assoc-ref element "@id")) | |
| 158 | + | (assoc-ref element "@id")) | |
| 159 | + | (generate-blank-node #nil)))) | |
| 161 | 160 | ;; 6.3 | |
| 162 | - | (unless (json-has-key? graph id) | |
| 161 | + | (unless (or (json-has-key? graph id) (not id)) | |
| 163 | 162 | (set! graph | |
| 164 | 163 | (alist-set graph id `(("@id" . ,id)))) | |
| 165 | 164 | (set! node-map (alist-set node-map active-graph graph))) | |
| 166 | 165 | ;; 6.4 | |
| 167 | - | (let ((node (assoc-ref graph id))) | |
| 166 | + | (let ((node (or (assoc-ref graph id) '()))) | |
| 168 | 167 | (cond | |
| 169 | 168 | ;; 6.5 | |
| 170 | 169 | ((json-object? active-subject) | |
… | |||
| 175 | 174 | ;; 6.5.1 | |
| 176 | 175 | (set! node | |
| 177 | 176 | (alist-set node active-property `#(,active-subject)))) | |
| 178 | - | (set! graph (alist-set graph id node)) | |
| 177 | + | (when id | |
| 178 | + | (set! graph (alist-set graph id node))) | |
| 179 | 179 | (set! node-map (alist-set node-map active-graph graph))) | |
| 180 | 180 | ;; 6.6 | |
| 181 | 181 | ((not (equal? active-property #nil)) | |
… | |||
| 202 | 202 | (when (json-has-key? element "@type") | |
| 203 | 203 | (set! node | |
| 204 | 204 | (append-if-not-in node "@type" (assoc-ref element "@type"))) | |
| 205 | - | (set! graph | |
| 206 | - | (alist-set graph id node)) | |
| 205 | + | (when id | |
| 206 | + | (set! graph (alist-set graph id node))) | |
| 207 | 207 | (set! node-map (alist-set node-map active-graph graph))) | |
| 208 | 208 | ;; 6.8 | |
| 209 | 209 | (when (json-has-key? element "@index") | |
… | |||
| 236 | 236 | (set! graph (assoc-ref node-map active-graph)) | |
| 237 | 237 | (set! subject-node (or (assoc-ref graph active-subject) | |
| 238 | 238 | '())) | |
| 239 | - | (set! node (assoc-ref graph id)))) | |
| 239 | + | (when id | |
| 240 | + | (set! node (assoc-ref graph id))))) | |
| 240 | 241 | (array->list values))) | |
| 241 | 242 | reverse-map) | |
| 242 | 243 | ;; 6.9.4 | |
… | |||
| 250 | 251 | (set! node-map (assoc-ref res "node-map")) | |
| 251 | 252 | (set! graph (assoc-ref node-map active-graph)) | |
| 252 | 253 | (set! subject-node (or (assoc-ref graph active-subject) '())) | |
| 253 | - | (set! node (assoc-ref graph id))) | |
| 254 | + | (when id | |
| 255 | + | (set! node (assoc-ref graph id)))) | |
| 254 | 256 | (set! element (alist-remove element "@graph"))) | |
| 255 | 257 | ;; 6.11 | |
| 256 | 258 | (when (json-has-key? element "@included") | |
… | |||
| 261 | 263 | (set! node-map (assoc-ref res "node-map")) | |
| 262 | 264 | (set! graph (assoc-ref node-map active-graph)) | |
| 263 | 265 | (set! subject-node (or (assoc-ref graph active-subject) '())) | |
| 264 | - | (set! node (assoc-ref graph id))) | |
| 266 | + | (when id | |
| 267 | + | (set! node (assoc-ref graph id)))) | |
| 265 | 268 | (set! element (alist-remove element "@included"))) | |
| 266 | 269 | ;; 6.12 | |
| 267 | 270 | (for-each-pair | |
… | |||
| 272 | 275 | ;; 6.12.2 | |
| 273 | 276 | (unless (json-has-key? node property) | |
| 274 | 277 | (set! node (alist-set node property #())) | |
| 275 | - | (set! graph (alist-set graph id node)) | |
| 278 | + | (when id | |
| 279 | + | (set! graph (alist-set graph id node))) | |
| 276 | 280 | (set! node-map (alist-set node-map active-graph graph))) | |
| 277 | 281 | ;; 6.12.3 | |
| 278 | 282 | (let ((res (node-map-generation | |
… | |||
| 282 | 286 | (set! node-map (assoc-ref res "node-map")) | |
| 283 | 287 | (set! graph (assoc-ref node-map active-graph)) | |
| 284 | 288 | (set! subject-node (or (assoc-ref graph active-subject) '())) | |
| 285 | - | (set! node (assoc-ref graph id)))) | |
| 289 | + | (when id | |
| 290 | + | (set! node (assoc-ref graph id))))) | |
| 286 | 291 | (alist-sort-by-key element)) | |
| 287 | - | (set! graph (alist-set graph id node))))) | |
| 292 | + | (when id | |
| 293 | + | (set! graph (alist-set graph id node)))))) | |
| 288 | 294 | (when (string? active-subject) | |
| 289 | 295 | (set! graph (alist-set graph active-subject subject-node))) | |
| 290 | 296 | (set! node-map (alist-set node-map active-graph graph)))) | |
jsonld/object-to-rdf.scm unknown status 1
| 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 object-to-rdf) | |
| 19 | + | #:use-module (ice-9 match) | |
| 20 | + | #:use-module (ice-9 regex) | |
| 21 | + | #:use-module (jsonld deserialize-jsonld) | |
| 22 | + | #:use-module (jsonld iri) | |
| 23 | + | #:use-module (jsonld json) | |
| 24 | + | #:use-module (jsonld list-to-rdf) | |
| 25 | + | #:use-module (json) | |
| 26 | + | #:use-module ((rdf rdf) #:hide (blank-node?)) | |
| 27 | + | #:use-module (srfi srfi-1) | |
| 28 | + | #:export (object-to-rdf | |
| 29 | + | well-formed-language-tag?)) | |
| 30 | + | ||
| 31 | + | (define (canonical-double value) | |
| 32 | + | (let ((exponent (inexact->exact (floor (log10 value))))) | |
| 33 | + | (string-append | |
| 34 | + | (number->string (exact->inexact (/ value (expt 10 exponent)))) | |
| 35 | + | "E" | |
| 36 | + | (number->string exponent)))) | |
| 37 | + | ||
| 38 | + | (define (canonical-json value) | |
| 39 | + | (cond | |
| 40 | + | ((member value '(#t #f #nil)) | |
| 41 | + | value) | |
| 42 | + | ((string? value) value) | |
| 43 | + | ((number? value) | |
| 44 | + | (if (integer? (inexact->exact value)) | |
| 45 | + | (inexact->exact value) | |
| 46 | + | value)) | |
| 47 | + | ((list? value) | |
| 48 | + | (map | |
| 49 | + | (match-lambda | |
| 50 | + | ((k . v) | |
| 51 | + | (cons k (canonical-json v)))) | |
| 52 | + | (alist-sort-by-key value))) | |
| 53 | + | ((array? value) | |
| 54 | + | (list->array | |
| 55 | + | 1 | |
| 56 | + | (fold-right | |
| 57 | + | (lambda (val result) | |
| 58 | + | (cons (canonical-json val) result)) | |
| 59 | + | '() | |
| 60 | + | (array->list value)))))) | |
| 61 | + | ||
| 62 | + | (define (well-formed-language-tag? tag) | |
| 63 | + | (let ((match (string-match "[a-z]{1,8}(-[0-9a-z]{1,8})*" tag))) | |
| 64 | + | (if match | |
| 65 | + | (let* ((match (cadr (array->list match))) | |
| 66 | + | (fst (car match)) | |
| 67 | + | (snd (cdr match))) | |
| 68 | + | (and (equal? fst 0) | |
| 69 | + | (equal? snd (string-length tag)))) | |
| 70 | + | #f))) | |
| 71 | + | ||
| 72 | + | (define* (object-to-rdf generate-blank-node rdf-direction item list-triples) | |
| 73 | + | (let ((result #nil)) | |
| 74 | + | (cond | |
| 75 | + | ;; 1 | |
| 76 | + | ((and (node-object? item) (not (well-formed? (assoc-ref item "@id")))) | |
| 77 | + | (set! result #nil)) | |
| 78 | + | ;; 2 | |
| 79 | + | ((node-object? item) | |
| 80 | + | (set! result (assoc-ref item "@id"))) | |
| 81 | + | ;; 3 | |
| 82 | + | ((list-object? item) | |
| 83 | + | (let* ((res (list-to-rdf generate-blank-node rdf-direction | |
| 84 | + | (array->list (assoc-ref item "@list")) | |
| 85 | + | list-triples)) | |
| 86 | + | (lst (assoc-ref res "list-triples")) | |
| 87 | + | (res (assoc-ref res "result"))) | |
| 88 | + | (set! result res) | |
| 89 | + | (set! list-triples lst))) | |
| 90 | + | (else | |
| 91 | + | ;; 4 | |
| 92 | + | (let ((value (assoc-ref item "@value")) | |
| 93 | + | (datatype (or (assoc-ref item "@type") #nil))) | |
| 94 | + | (cond | |
| 95 | + | ;; 6 | |
| 96 | + | ((and (not (equal? datatype #nil)) (not (equal? datatype "@json")) | |
| 97 | + | (not (well-formed? datatype))) | |
| 98 | + | (set! result #nil)) | |
| 99 | + | ;; 7 | |
| 100 | + | ((and | |
| 101 | + | (json-has-key? item "@language") | |
| 102 | + | (not (well-formed-language-tag? (assoc-ref item "@language")))) | |
| 103 | + | (set! result #nil)) | |
| 104 | + | (else | |
| 105 | + | ;; 8 | |
| 106 | + | (when (equal? datatype "@json") | |
| 107 | + | (set! value (scm->json-string (canonical-json value))) | |
| 108 | + | (set! datatype (rdf-iri "JSON"))) | |
| 109 | + | (cond | |
| 110 | + | ;; 9 | |
| 111 | + | ((boolean? value) | |
| 112 | + | (when (equal? datatype #nil) | |
| 113 | + | (set! datatype (xsd-iri "boolean"))) | |
| 114 | + | (set! value (if value "true" "false"))) | |
| 115 | + | ;; 10 | |
| 116 | + | ((and (number? value) | |
| 117 | + | (or (not (integer? (inexact->exact value))) | |
| 118 | + | (>= (abs value) (expt 10 21)) | |
| 119 | + | (equal? datatype (xsd-iri "double")))) | |
| 120 | + | (when (equal? datatype #nil) | |
| 121 | + | (set! datatype (xsd-iri "double"))) | |
| 122 | + | (set! value (canonical-double value))) | |
| 123 | + | ;; 11 | |
| 124 | + | ((number? value) | |
| 125 | + | (set! value (number->string (inexact->exact value))) | |
| 126 | + | (when (equal? datatype #nil) | |
| 127 | + | (set! datatype (xsd-iri "integer")))) | |
| 128 | + | ;; 12 | |
| 129 | + | ((equal? datatype #nil) | |
| 130 | + | (set! datatype | |
| 131 | + | (if (json-has-key? item "@language") | |
| 132 | + | (rdf-iri "langString") | |
| 133 | + | (xsd-iri "string"))))) | |
| 134 | + | (if (and (json-has-key? item "@direction") (not (equal? rdf-direction #f))) | |
| 135 | + | ;; 13 | |
| 136 | + | (let* ((language (or (assoc-ref item "@language") "")) | |
| 137 | + | (language (string-downcase language))) | |
| 138 | + | (if (equal? rdf-direction "i18n-datatype") | |
| 139 | + | ;; 13.2 | |
| 140 | + | (begin | |
| 141 | + | (set! datatype | |
| 142 | + | (string-append "https://www.w3.org/ns/i18n#" language "_" | |
| 143 | + | (assoc-ref item "@direction"))) | |
| 144 | + | (set! result | |
| 145 | + | (make-rdf-literal value datatype #f))) | |
| 146 | + | ;; 13.3 | |
| 147 | + | (when (equal? rdf-direction "compound-literal") | |
| 148 | + | (let ((literal (blank-node->rdf-blank-node | |
| 149 | + | (generate-blank-node #nil)))) | |
| 150 | + | ;; 13.3.2 | |
| 151 | + | (set! list-triples | |
| 152 | + | (cons | |
| 153 | + | ;; XXX: the spec says "of the @value in item as object", | |
| 154 | + | ;; but should it be "value" instead? | |
| 155 | + | (make-rdf-triple literal (rdf-iri "value") | |
| 156 | + | (make-rdf-literal | |
| 157 | + | (assoc-ref item "@value") | |
| 158 | + | (xsd-iri "string") | |
| 159 | + | #f)) | |
| 160 | + | list-triples)) | |
| 161 | + | ;; 13.3.3 | |
| 162 | + | (when (json-has-key? item "@language") | |
| 163 | + | (set! list-triples | |
| 164 | + | (cons | |
| 165 | + | (make-rdf-triple literal (rdf-iri "language") | |
| 166 | + | (make-rdf-literal | |
| 167 | + | language | |
| 168 | + | (xsd-iri "string") | |
| 169 | + | #f)) | |
| 170 | + | list-triples))) | |
| 171 | + | (set! list-triples | |
| 172 | + | (cons | |
| 173 | + | (make-rdf-triple literal (rdf-iri "direction") | |
| 174 | + | (make-rdf-literal | |
| 175 | + | (assoc-ref item "@direction") | |
| 176 | + | (xsd-iri "string") | |
| 177 | + | #f)) | |
| 178 | + | list-triples)) | |
| 179 | + | (set! result literal))))) | |
| 180 | + | ;; 14 | |
| 181 | + | (set! result | |
| 182 | + | (make-rdf-literal value datatype (assoc-ref item "@language"))))))))) | |
| 183 | + | (when (blank-node? result) | |
| 184 | + | (set! result (blank-node->rdf-blank-node result))) | |
| 185 | + | `(("result" . ,result) | |
| 186 | + | ("list-triples" . ,list-triples)))) |
test-modules/download.scm
| 21 | 21 | #:use-module (jsonld json) | |
| 22 | 22 | #:use-module (jsonld memoization) | |
| 23 | 23 | #:use-module (jsonld options) | |
| 24 | + | #:use-module (nquads tordf) | |
| 25 | + | #:use-module (rnrs bytevectors) | |
| 24 | 26 | #:use-module (test-modules testsuite) | |
| 25 | 27 | #:use-module (web client) | |
| 26 | 28 | #:use-module (web response) | |
| 27 | 29 | #:use-module (web uri) | |
| 28 | - | #:export (test-http-get get-test-document-loader)) | |
| 30 | + | #:export (test-http-get get-test-document-loader download-nq)) | |
| 29 | 31 | ||
| 30 | 32 | (define* (update-response response | |
| 31 | 33 | #:key | |
… | |||
| 93 | 95 | (lambda args | |
| 94 | 96 | (apply download-json | |
| 95 | 97 | (append args `(#:http-get ,(test-http-get options))))))) | |
| 98 | + | ||
| 99 | + | (define (download-nq url) | |
| 100 | + | (call-with-values | |
| 101 | + | (lambda () | |
| 102 | + | (http-get url)) | |
| 103 | + | (lambda (hdr body) | |
| 104 | + | (if (equal? (response-code hdr) 200) | |
| 105 | + | (nquads->rdf | |
| 106 | + | (if (string? body) | |
| 107 | + | body | |
| 108 | + | (utf8->string body))) | |
| 109 | + | (throw 'download-error (response-code hdr) url))))) | |
test-modules/online.scm
| 27 | 27 | #:use-module (jsonld) | |
| 28 | 28 | #:use-module (jsonld options) | |
| 29 | 29 | #:use-module (jsonld iri) | |
| 30 | + | #:use-module (rdf rdf) | |
| 31 | + | #:use-module (nquads fromrdf) | |
| 30 | 32 | #:export (run-test-suite | |
| 31 | 33 | run-test-suites | |
| 32 | 34 | get-test-doc)) | |
… | |||
| 40 | 42 | ;; us to download a few other JsonLD documents, run a function on them and compare | |
| 41 | 43 | ;; the result. This is what this file does. | |
| 42 | 44 | ||
| 45 | + | (define (download-document url) | |
| 46 | + | (match (car (reverse (string-split url #\.))) | |
| 47 | + | ("nq" (download-nq url)) | |
| 48 | + | (_ (json-document-document (download-json url))))) | |
| 49 | + | ||
| 50 | + | (define (good-result? result expected) | |
| 51 | + | (if (rdf-dataset? result) | |
| 52 | + | (begin | |
| 53 | + | (with-output-to-file "test-result.nq" | |
| 54 | + | (lambda _ | |
| 55 | + | (format #t "~a~%" (rdf->nquads result)))) | |
| 56 | + | (pk 'result result) | |
| 57 | + | (pk 'expected expected) | |
| 58 | + | (rdf-dataset-isomorphic? result expected)) | |
| 59 | + | (same-json? result expected))) | |
| 60 | + | ||
| 43 | 61 | (define (execute-test test) | |
| 44 | 62 | "Execute one test described by a Json object @var{test}. Return a Json object | |
| 45 | 63 | as the output of the test, or throws an exception if something went wrong." | |
… | |||
| 48 | 66 | (context (assoc-ref document "context")) | |
| 49 | 67 | (type (array->list (assoc-ref document "@type"))) | |
| 50 | 68 | (options (assoc-ref document "option")) | |
| 69 | + | (requires (assoc-ref document "requires")) | |
| 51 | 70 | (spec-version (assoc-ref options "specVersion")) | |
| 52 | 71 | (document-loader (get-test-document-loader options))) | |
| 53 | 72 | (cond | |
… | |||
| 119 | 138 | ,@(if (json-has-key? options "compactArrays") | |
| 120 | 139 | `(#:compact-arrays? ,(assoc-ref options "compactArrays")) | |
| 121 | 140 | '()))))) | |
| 141 | + | ((member "jld:ToRDFTest" type) | |
| 142 | + | (when (equal? requires "GeneralizedRdf") | |
| 143 | + | (throw 'cannot-run-test "Expected file is not in a valid nquads format")) | |
| 144 | + | (jsonld->rdf (string-append jsonld-test-url input) | |
| 145 | + | #:options | |
| 146 | + | (apply | |
| 147 | + | new-jsonld-options | |
| 148 | + | #:ordered? #t | |
| 149 | + | #:document-loader document-loader | |
| 150 | + | `(,@(if (assoc-ref options "base") | |
| 151 | + | `(#:base ,(assoc-ref options "base")) | |
| 152 | + | '()) | |
| 153 | + | ,@(if (assoc-ref options "processingMode") | |
| 154 | + | `(#:processing-mode ,(assoc-ref options "processingMode")) | |
| 155 | + | '()) | |
| 156 | + | ,@(if (assoc-ref options "produceGeneralizedRdf") | |
| 157 | + | `(#:produce-generalized-rdf? #t) | |
| 158 | + | `(#:produce-generalized-rdf? #f)) | |
| 159 | + | ,@(if (assoc-ref options "expandContext") | |
| 160 | + | `(#:expand-context ,(string-append | |
| 161 | + | jsonld-test-url | |
| 162 | + | (assoc-ref options "expandContext"))) | |
| 163 | + | '()) | |
| 164 | + | ,@(if (assoc-ref options "rdfDirection") | |
| 165 | + | `(#:rdf-direction | |
| 166 | + | ,(assoc-ref options "rdfDirection")) | |
| 167 | + | '()))))) | |
| 122 | 168 | (else (throw 'unrecognized-test type))))) | |
| 123 | 169 | ||
| 124 | 170 | (define (run-test test) | |
… | |||
| 155 | 201 | (update-test-case test | |
| 156 | 202 | #:result 'skip | |
| 157 | 203 | #:reason "unsupported JsonLD version")) | |
| 204 | + | ((equal? key 'cannot-run-test) | |
| 205 | + | (update-test-case test | |
| 206 | + | #:result 'skip | |
| 207 | + | #:reason (format #f "impossible to run test: ~a" value))) | |
| 158 | 208 | ((equal? (jsonld-error->string key) expect-error) | |
| 159 | 209 | (update-test-case test #:result 'pass)) | |
| 160 | 210 | (else | |
… | |||
| 182 | 232 | (update-test-case test | |
| 183 | 233 | #:result 'skip | |
| 184 | 234 | #:reason "unsupported JsonLD version")) | |
| 235 | + | ((equal? key 'cannot-run-test) | |
| 236 | + | (update-test-case test | |
| 237 | + | #:result 'skip | |
| 238 | + | #:reason (format #f "impossible to run test: ~a" value))) | |
| 185 | 239 | (else | |
| 186 | 240 | (update-test-case test | |
| 187 | 241 | #:result 'fail | |
| 188 | 242 | #:reason (format #f "Expected success but got ~a: ~a" | |
| 189 | 243 | key value))))) | |
| 190 | - | (_ (let ((expected (json-document-document | |
| 191 | - | (download-json | |
| 192 | - | (string-append jsonld-test-url expect))))) | |
| 193 | - | (if (same-json? result expected) | |
| 194 | - | (update-test-case test #:result 'pass) | |
| 195 | - | (update-test-case test | |
| 196 | - | #:result 'fail | |
| 197 | - | #:reason (format #f "Expected ~a but got ~a" | |
| 198 | - | expected result))))))))) | |
| 244 | + | (_ (if (member "jld:PositiveSyntaxTest" type) | |
| 245 | + | (update-test-case test #:result 'pass) | |
| 246 | + | (let ((expected (download-document | |
| 247 | + | (string-append jsonld-test-url expect)))) | |
| 248 | + | (if (good-result? result expected) | |
| 249 | + | (update-test-case test #:result 'pass) | |
| 250 | + | (update-test-case test | |
| 251 | + | #:result 'fail | |
| 252 | + | #:reason (format #f "Expected ~a but got ~a" | |
| 253 | + | expected result)))))))))) | |
| 199 | 254 | ||
| 200 | 255 | (define (run-tests tests expected-failures driver) | |
| 201 | 256 | "Run all the tests of the @var{tests} test suite, using identifiers starting | |
test-modules/testsuite.scm
| 22 | 22 | flatten-test-url | |
| 23 | 23 | html-test-url | |
| 24 | 24 | remote-doc-test-url | |
| 25 | - | jsonld-test-url)) | |
| 25 | + | jsonld-test-url | |
| 26 | + | tordf-test-url)) | |
| 26 | 27 | ||
| 27 | 28 | (define jsonld-test-url "https://w3c.github.io/json-ld-api/tests/") | |
| 28 | 29 | ||
… | |||
| 41 | 42 | (define remote-doc-test-url | |
| 42 | 43 | (string-append jsonld-test-url "remote-doc-manifest.jsonld")) | |
| 43 | 44 | ||
| 45 | + | (define tordf-test-url | |
| 46 | + | (string-append jsonld-test-url "toRdf-manifest.jsonld")) | |
| 47 | + | ||
| 44 | 48 | (define expected-failures | |
| 45 | 49 | `(("https://w3c.github.io/json-ld-api/tests/html-manifest.jsonld#te010" . | |
| 46 | 50 | "entities are not preserved by xml->sxml") | |
tests/tordf.scm unknown status 1
| 1 | + | #!/data/tyreunom/projects/guile-jsonld/pre-inst-env guile | |
| 2 | + | !# | |
| 3 | + | ;;;; Copyright (C) 2020 Julien Lepiller <julien@lepiller.eu> | |
| 4 | + | ;;;; | |
| 5 | + | ;;;; This library is free software; you can redistribute it and/or | |
| 6 | + | ;;;; modify it under the terms of the GNU Lesser General Public | |
| 7 | + | ;;;; License as published by the Free Software Foundation; either | |
| 8 | + | ;;;; version 3 of the License, or (at your option) any later version. | |
| 9 | + | ;;;; | |
| 10 | + | ;;;; This library is distributed in the hope that it will be useful, | |
| 11 | + | ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | + | ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 | + | ;;;; Lesser General Public License for more details. | |
| 14 | + | ;;;; | |
| 15 | + | ;;;; You should have received a copy of the GNU Lesser General Public | |
| 16 | + | ;;;; License along with this library; if not, write to the Free Software | |
| 17 | + | ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 18 | + | ;;;; | |
| 19 | + | ||
| 20 | + | (use-modules (test-modules online)) | |
| 21 | + | (use-modules (test-modules result)) | |
| 22 | + | (use-modules (test-modules testsuite)) | |
| 23 | + | ||
| 24 | + | (run-test-suite tordf-test-url expected-failures tap-driver) |