generate-vocabulary.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 | (define-module (schema.org generate-vocabulary) |
| 18 | #:use-module (ice-9 match) |
| 19 | #:use-module (json) |
| 20 | #:use-module (jsonld) |
| 21 | #:export (generate-schema)) |
| 22 | |
| 23 | (define (generate-schema filename description-file) |
| 24 | (define input (if (equal? description-file "") |
| 25 | "https://schema.org/version/8.0/schema.jsonld" |
| 26 | (call-with-input-file description-file json->scm))) |
| 27 | (define definitions (assoc-ref (car (array->list (expand input))) "@graph")) |
| 28 | |
| 29 | (with-output-to-file filename |
| 30 | (lambda _ |
| 31 | (format #t ";; Module generated by (schema.org generate-vocabulary)~%") |
| 32 | (format #t ";; from the schema.org jsonld description.") |
| 33 | (format #t "(define-module (schema.org ~a)~%" (basename filename ".scm")) |
| 34 | (format #t " #:use-module (activitystreams predicates)~%") |
| 35 | (format #t " #:use-module (activitystreams ontology)~%") |
| 36 | (format #t " #:export (schema.org-ontology)~%~%") |
| 37 | (for-each |
| 38 | (lambda (definition) |
| 39 | (let ((types (array->list (assoc-ref definition "@type")))) |
| 40 | (if (member "http://www.w3.org/2000/01/rdf-schema#Class" types) |
| 41 | (unless (datatype? definition) |
| 42 | (generate-class definition)) |
| 43 | (generate-property definition)))) |
| 44 | (array->list definitions)) |
| 45 | (let* ((types (filter |
| 46 | (lambda (def) |
| 47 | (member "http://www.w3.org/2000/01/rdf-schema#Class" |
| 48 | (array->list (assoc-ref def "@type")))) |
| 49 | (array->list definitions))) |
| 50 | (types (map |
| 51 | (lambda (def) |
| 52 | (assoc-ref def "http://www.w3.org/2000/01/rdf-schema#label")) |
| 53 | types)) |
| 54 | (types (map |
| 55 | (lambda (def) |
| 56 | (assoc-ref (car (array->list def)) "@value")) |
| 57 | types)) |
| 58 | (predicates (filter |
| 59 | (lambda (def) |
| 60 | (and |
| 61 | (not (datatype? def)) |
| 62 | (not |
| 63 | (member "http://www.w3.org/2000/01/rdf-schema#Class" |
| 64 | (array->list (assoc-ref def "@type")))))) |
| 65 | (array->list definitions))) |
| 66 | (predicates (map |
| 67 | (lambda (def) |
| 68 | (assoc-ref def "http://www.w3.org/2000/01/rdf-schema#label")) |
| 69 | predicates)) |
| 70 | (predicates (map |
| 71 | (lambda (def) |
| 72 | (assoc-ref (car (array->list def)) "@value")) |
| 73 | predicates))) |
| 74 | (format #t "(define schema.org-ontology~%") |
| 75 | (format #t " (make-ontology~%") |
| 76 | (format #t " '(\"http://schema.org/\")~%") |
| 77 | (format #t " (list ~a)~%" (cut-str-list types 80)) |
| 78 | (format #t " (list ~a)))~%" (cut-str-list predicates 80)))))) |
| 79 | |
| 80 | (define (cut-str str n) |
| 81 | "Cut a string @var{str} at @var{n} characters by placing a @code{\\n}, so that |
| 82 | the string is aligned to @var{n} characters." |
| 83 | (let loop ((str str)) |
| 84 | (if (< (string-length str) (+ n 1)) |
| 85 | str |
| 86 | (string-append |
| 87 | (substring str 0 n) |
| 88 | "\n" |
| 89 | (loop (substring str n)))))) |
| 90 | |
| 91 | (define (cut-str-list lst n) |
| 92 | (let loop ((lst lst) (result '(()))) |
| 93 | (match lst |
| 94 | (() (string-join |
| 95 | (reverse (map (lambda (l) (string-join l " ")) (map reverse result))) |
| 96 | "\n")) |
| 97 | ((word lst ...) |
| 98 | (let ((current-line (car result))) |
| 99 | (if (> (string-length (string-join (cons word current-line) " ")) n) |
| 100 | (loop lst (cons (list word) result)) |
| 101 | (loop lst (cons (cons word current-line) (cdr result))))))))) |
| 102 | |
| 103 | |
| 104 | (define (generate-class definition) |
| 105 | (let* ((id (assoc-ref definition "@id")) |
| 106 | (comment (assoc-ref definition "http://www.w3.org/2000/01/rdf-schema#comment")) |
| 107 | (comment (assoc-ref (car (array->list comment)) "@value")) |
| 108 | (comment (cut-str comment 76)) |
| 109 | (comment (string-join (string-split comment #\") "\\\"")) |
| 110 | (label (assoc-ref definition "http://www.w3.org/2000/01/rdf-schema#label")) |
| 111 | (label (assoc-ref (car (array->list label)) "@value")) |
| 112 | (subclass-of (assoc-ref definition "http://www.w3.org/2000/01/rdf-schema#subClassOf")) |
| 113 | (subclass-of (if subclass-of (array->list subclass-of) '())) |
| 114 | (subclass-of (map (lambda (c) (basename (assoc-ref c "@id"))) |
| 115 | subclass-of))) |
| 116 | (format #t "(define-public ~a~%" label) |
| 117 | (format #t " (build-as-type \"~a\"~% #:uri \"~a\"~% #:comment~% \"~a\"" |
| 118 | label id comment) |
| 119 | (unless (null? subclass-of) |
| 120 | (format #t "~% #:subclass-of (list ~a)" (string-join subclass-of " "))) |
| 121 | (format #t "))~%~%"))) |
| 122 | |
| 123 | |
| 124 | (define (generate-property definition) |
| 125 | (let* ((id (assoc-ref definition "@id")) |
| 126 | (comment (assoc-ref definition "http://www.w3.org/2000/01/rdf-schema#comment")) |
| 127 | (comment (assoc-ref (car (array->list comment)) "@value")) |
| 128 | (comment (cut-str comment 76)) |
| 129 | (comment (string-join (string-split comment #\") "\\\"")) |
| 130 | (label (assoc-ref definition "http://www.w3.org/2000/01/rdf-schema#label")) |
| 131 | (label (assoc-ref (car (array->list label)) "@value")) |
| 132 | (domain (assoc-ref definition "http://schema.org/domainIncludes")) |
| 133 | (domain (if domain (array->list domain) '())) |
| 134 | (domain (map (lambda (c) (basename (assoc-ref c "@id"))) domain)) |
| 135 | (domain (map (lambda (c) (or (assoc-ref datatypes c) c)) domain)) |
| 136 | (range (assoc-ref definition "http://schema.org/rangeIncludes")) |
| 137 | (range (if range (array->list range) '())) |
| 138 | (range (map (lambda (c) (basename (assoc-ref c "@id"))) range)) |
| 139 | (range (map (lambda (c) (or (assoc-ref datatypes c) c)) range)) |
| 140 | (subproperty-of (assoc-ref definition "http://www.w3.org/2000/01/rdf-schema#subPropertyOf")) |
| 141 | (subproperty-of (if subproperty-of (array->list subproperty-of) '())) |
| 142 | (subproperty-of (map (lambda (c) (basename (assoc-ref c "@id"))) |
| 143 | subproperty-of))) |
| 144 | (format #t "(define-public ~a~%" label) |
| 145 | (format #t " (build-as-property~%") |
| 146 | (format #t " \"~a\" (list ~a) (list ~a)~%" label (string-join domain " ") |
| 147 | (string-join range " ")) |
| 148 | (format #t " #:uri \"~a\"~%" id) |
| 149 | (format #t " #:comment~% \"~a\"" comment) |
| 150 | (unless (null? subproperty-of) |
| 151 | (format #t "~% #:subproperty-of (list ~a)" (string-join subproperty-of " "))) |
| 152 | (format #t "))~%~%"))) |
| 153 | |
| 154 | (define datatypes |
| 155 | `(("False" . "(lambda (t) (equal? t #f))") |
| 156 | ("True" . "(lambda (t) (equal? t #t))") |
| 157 | ("DataType" . "procedure?") |
| 158 | ("Boolean" . "boolean?") |
| 159 | ("Date" . "date?") |
| 160 | ("DateTime" . "date-time?") |
| 161 | ("Number" . "number?") |
| 162 | ("Float" . "number?") |
| 163 | ("Integer" . "integer?") |
| 164 | ("Text" . "string-or-lang-string?") |
| 165 | ("CssSelectorType" . "string?") |
| 166 | ("PronounceableText" . "string-or-lang-string?") |
| 167 | ("URL" . "uri?") |
| 168 | ("XPathType" . "string?") |
| 169 | ("Time" . "time?"))) |
| 170 | |
| 171 | (define (datatype? definition) |
| 172 | (let* ((labels (array->list (assoc-ref definition "http://www.w3.org/2000/01/rdf-schema#label"))) |
| 173 | (label (assoc-ref (car labels) "@value"))) |
| 174 | (member label (map car datatypes)))) |
| 175 |