guile-fediverse/schema.org/generate-vocabulary.scm

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