Add RDF entailment regime
Makefile.am
1 | 1 | include guile.am | |
2 | 2 | ||
3 | 3 | SOURCES= \ | |
4 | + | rdf/entailment/d.scm \ | |
5 | + | rdf/entailment/rdf.scm \ | |
4 | 6 | rdf/entailment/simple.scm \ | |
5 | 7 | rdf/rdf.scm \ | |
6 | 8 | rdf/xsd.scm \ |
rdf/entailment/d.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 (rdf entailment d) | |
19 | + | #:use-module (ice-9 match) | |
20 | + | #:use-module (rdf rdf) | |
21 | + | #:use-module ((rdf entailment simple) #:prefix simple:) | |
22 | + | #:use-module (srfi srfi-1) | |
23 | + | #:export (consistent-graph? | |
24 | + | entails?)) | |
25 | + | ||
26 | + | (define (consistent-graph? graph) | |
27 | + | (define consistent-data? | |
28 | + | (match-lambda | |
29 | + | (($ rdf-literal form ($ rdf-datatype _ _ lexical? _ _ _) _) | |
30 | + | (lexical? form)) | |
31 | + | (_ #t))) | |
32 | + | ||
33 | + | (match graph | |
34 | + | ('() #t) | |
35 | + | ((($ rdf-triple subject predicate object) graph ...) | |
36 | + | (and (consistent-data? subject) (consistent-data? object) | |
37 | + | (consistent-graph? graph))))) | |
38 | + | ||
39 | + | ;; G entails E if E has an instance (where blank nodes are replaced by literals | |
40 | + | ;; or IRIs) that is a subgraph of G. | |
41 | + | ;; | |
42 | + | ;; We re-use similar procedures to verifying isomorphism of graphs, but this time | |
43 | + | ;; blank nodes can also map to literals and IRIs. | |
44 | + | ||
45 | + | (define (sat? equivalences) | |
46 | + | "Return whether the set of equivalences satisfies the condition that it represents | |
47 | + | an isomorphism between two blank node sets: for every equality, check that the | |
48 | + | first component is always associated to the same second component, and that the | |
49 | + | second component is always associated with the first." | |
50 | + | (match equivalences | |
51 | + | ('() #t) | |
52 | + | (((first . second) equivalences ...) | |
53 | + | (if (and (null? (filter | |
54 | + | (lambda (eq) | |
55 | + | (and (equal? (car eq) first) | |
56 | + | (not (equal? (cdr eq) second)))) | |
57 | + | equivalences)) | |
58 | + | (null? (filter | |
59 | + | (lambda (eq) | |
60 | + | (and (not (equal? (car eq) first)) | |
61 | + | (equal? (cdr eq) second))) | |
62 | + | equivalences))) | |
63 | + | (sat? equivalences) | |
64 | + | #f)))) | |
65 | + | ||
66 | + | (define (merge-joins l1 l2) | |
67 | + | (cond | |
68 | + | ((null? l1) l2) | |
69 | + | ((null? l2) l1) | |
70 | + | (else | |
71 | + | (fold | |
72 | + | (lambda (e1 res) | |
73 | + | (append | |
74 | + | (map (lambda (e2) | |
75 | + | (append e1 e2)) | |
76 | + | l2) | |
77 | + | res)) | |
78 | + | '() | |
79 | + | l1)))) | |
80 | + | ||
81 | + | (define (to-disjunctions constraints) | |
82 | + | (match constraints | |
83 | + | (('equiv b1 b2) (list (list (cons b1 b2)))) | |
84 | + | ('none (list (list))) | |
85 | + | ('bot 'bot) | |
86 | + | (('or e1 e2) | |
87 | + | (let ((e1 (to-disjunctions e1)) | |
88 | + | (e2 (to-disjunctions e2))) | |
89 | + | (cond | |
90 | + | ((equal? e2 'bot) | |
91 | + | e1) | |
92 | + | ((equal? e1 'bot) | |
93 | + | e2) | |
94 | + | (else | |
95 | + | (append e1 e2))))) | |
96 | + | (('and e1 e2) | |
97 | + | (let ((e1 (to-disjunctions e1)) | |
98 | + | (e2 (to-disjunctions e2))) | |
99 | + | (cond | |
100 | + | ((equal? e1 'bot) | |
101 | + | 'bot) | |
102 | + | ((equal? e2 'bot) | |
103 | + | 'bot) | |
104 | + | (else | |
105 | + | (merge-joins e1 e2))))))) | |
106 | + | ||
107 | + | (define (generate-triple-constraints t1 t2) | |
108 | + | (match t1 | |
109 | + | (($ rdf-triple s1 p1 o1) | |
110 | + | (match t2 | |
111 | + | (($ rdf-triple s2 p2 o2) | |
112 | + | (if (and (or (equiv? s1 s2) (blank-node? s1)) | |
113 | + | (equal? p1 p2) | |
114 | + | (or (equiv? o1 o2) (blank-node? o1))) | |
115 | + | (list 'and | |
116 | + | (if (blank-node? s1) | |
117 | + | (list 'equiv s1 s2) | |
118 | + | 'none) | |
119 | + | (if (blank-node? o1) | |
120 | + | (list 'equiv o1 o2) | |
121 | + | 'none)) | |
122 | + | #f)))))) | |
123 | + | ||
124 | + | (define (generate-constraints t1 g2) | |
125 | + | (match g2 | |
126 | + | ('() 'bot) | |
127 | + | ((t2 g2 ...) | |
128 | + | (let ((c (generate-triple-constraints t1 t2))) | |
129 | + | (if c | |
130 | + | (list 'or c (generate-constraints t1 g2)) | |
131 | + | (generate-constraints t1 g2)))))) | |
132 | + | ||
133 | + | (define (equiv? n1 n2) | |
134 | + | (match (list n1 n2) | |
135 | + | ((($ rdf-literal l1 ($ rdf-datatype _ _ _ _ lexical->value1 _) lang1) | |
136 | + | ($ rdf-literal l2 ($ rdf-datatype _ _ _ _ lexical->value2 _) lang2)) | |
137 | + | (and (equal? (and lang1 (string-downcase lang1)) | |
138 | + | (and lang2 (string-downcase lang2))) | |
139 | + | (equal? (lexical->value1 l1)) | |
140 | + | (equal? (lexical->value2 l2)))) | |
141 | + | (_ (equal? n1 n2)))) | |
142 | + | ||
143 | + | (define (validate-mapping mapping g1 g2) | |
144 | + | (match g1 | |
145 | + | ('() #t) | |
146 | + | ((t1 g1 ...) | |
147 | + | (and (not (null? (filter | |
148 | + | (lambda (t2) | |
149 | + | (let ((s1 (rdf-triple-subject t1)) | |
150 | + | (s2 (rdf-triple-subject t2)) | |
151 | + | (p1 (rdf-triple-predicate t1)) | |
152 | + | (p2 (rdf-triple-predicate t2)) | |
153 | + | (o1 (rdf-triple-object t1)) | |
154 | + | (o2 (rdf-triple-object t2))) | |
155 | + | (and | |
156 | + | (if (blank-node? s1) | |
157 | + | (equiv? (assoc-ref mapping s1) s2) | |
158 | + | (equiv? s1 s2)) | |
159 | + | (equal? p1 p2) | |
160 | + | (if (blank-node? o1) | |
161 | + | (equiv? (assoc-ref mapping o1) o2) | |
162 | + | (equiv? o1 o2))))) | |
163 | + | g2))) | |
164 | + | (validate-mapping mapping g1 g2))))) | |
165 | + | ||
166 | + | (define (entails? g e) | |
167 | + | "Return true if g entails e" | |
168 | + | (or (not (consistent-graph? g)) | |
169 | + | (let* ((constraints (fold (lambda (t constraints) | |
170 | + | (list 'and (generate-constraints t g) constraints)) | |
171 | + | 'none e)) | |
172 | + | (disjunctions (to-disjunctions constraints))) | |
173 | + | (if (equal? disjunctions 'bot) | |
174 | + | #f | |
175 | + | (let loop ((disjunctions (filter sat? disjunctions))) | |
176 | + | (match disjunctions | |
177 | + | ('() #f) | |
178 | + | ((mapping disjunctions ...) | |
179 | + | (if (validate-mapping mapping e g) | |
180 | + | #t | |
181 | + | (loop disjunctions))))))))) |
rdf/entailment/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 (rdf entailment rdf) | |
19 | + | #:use-module (ice-9 match) | |
20 | + | #:use-module (rdf rdf) | |
21 | + | #:use-module ((rdf entailment d) #:prefix d:) | |
22 | + | #:use-module (srfi srfi-1) | |
23 | + | #:export (consistent-graph? | |
24 | + | entails?)) | |
25 | + | ||
26 | + | (define (rdf-iri name) | |
27 | + | (string-append "http://www.w3.org/1999/02/22-rdf-syntax-ns#" name)) | |
28 | + | ||
29 | + | (define (consistent-graph? graph) | |
30 | + | (define (non-overlapping-types? graph) | |
31 | + | (let loop ((graph graph) (type-mappings '())) | |
32 | + | (if (null? graph) | |
33 | + | #t | |
34 | + | (let* ((t (car graph))) | |
35 | + | (if (equal? (rdf-triple-predicate t) (rdf-iri "type")) | |
36 | + | (if (assoc-ref type-mappings (rdf-triple-subject t)) | |
37 | + | #f | |
38 | + | (loop (cdr graph) | |
39 | + | (cons | |
40 | + | (cons (rdf-triple-subject t) (rdf-triple-object t)) | |
41 | + | type-mappings))) | |
42 | + | (loop (cdr graph) type-mappings)))))) | |
43 | + | (and (d:consistent-graph? graph) | |
44 | + | (non-overlapping-types? graph))) | |
45 | + | ||
46 | + | ;; G entails E if E has an instance (where blank nodes are replaced by literals | |
47 | + | ;; or IRIs) that is a subgraph of G. | |
48 | + | ;; | |
49 | + | ;; We re-use similar procedures to verifying isomorphism of graphs, but this time | |
50 | + | ;; blank nodes can also map to literals and IRIs. | |
51 | + | ||
52 | + | ;; We follow appendix A and use a subgraph comparison (like the simple:entails? | |
53 | + | ;; procedure) after augmenting the graph with additional true triples. | |
54 | + | ||
55 | + | (define rdf-axioms | |
56 | + | (list | |
57 | + | (make-rdf-triple (rdf-iri "type") (rdf-iri "type") (rdf-iri "Property")) | |
58 | + | (make-rdf-triple (rdf-iri "subject") (rdf-iri "type") (rdf-iri "Property")) | |
59 | + | (make-rdf-triple (rdf-iri "predicate") (rdf-iri "type") (rdf-iri "Property")) | |
60 | + | (make-rdf-triple (rdf-iri "object") (rdf-iri "type") (rdf-iri "Property")) | |
61 | + | (make-rdf-triple (rdf-iri "first") (rdf-iri "type") (rdf-iri "Property")) | |
62 | + | (make-rdf-triple (rdf-iri "rest") (rdf-iri "type") (rdf-iri "Property")) | |
63 | + | (make-rdf-triple (rdf-iri "value") (rdf-iri "type") (rdf-iri "Property")) | |
64 | + | (make-rdf-triple (rdf-iri "nil") (rdf-iri "type") (rdf-iri "List")))) | |
65 | + | ||
66 | + | (define (rdf-axioms-container container) | |
67 | + | (list | |
68 | + | (make-rdf-triple | |
69 | + | container (rdf-iri "type") (rdf-iri "Property")))) | |
70 | + | ||
71 | + | (define (rdf-container-property? p) | |
72 | + | (define rdf-container-property-base (rdf-iri "_")) | |
73 | + | (and (string? p) | |
74 | + | (> (string-length p) (string-length rdf-container-property-base)) | |
75 | + | (equal? (substring p 0 (string-length rdf-container-property-base)) | |
76 | + | rdf-container-property-base) | |
77 | + | (string->number | |
78 | + | (substring p (string-length rdf-container-property-base))))) | |
79 | + | ||
80 | + | (define (rdf-container-properties g) | |
81 | + | (let loop ((answer '()) (g g)) | |
82 | + | (match g | |
83 | + | (() answer) | |
84 | + | ((($ rdf-triple subject predicate object) g ...) | |
85 | + | (let* ((answer (if (and (rdf-container-property? subject) | |
86 | + | (not (member subject answer))) | |
87 | + | (cons subject answer) | |
88 | + | answer)) | |
89 | + | (answer (if (and (rdf-container-property? predicate) | |
90 | + | (not (member predicate answer))) | |
91 | + | (cons predicate answer) | |
92 | + | answer)) | |
93 | + | (answer (if (and (rdf-container-property? object) | |
94 | + | (not (member object answer))) | |
95 | + | (cons object answer) | |
96 | + | answer))) | |
97 | + | (loop answer g)))))) | |
98 | + | ||
99 | + | (define (augment g) | |
100 | + | (let* ((g (append rdf-axioms g)) | |
101 | + | (g (append | |
102 | + | (append-map rdf-axioms-container (rdf-container-properties g)) | |
103 | + | g))) | |
104 | + | (let loop ((g g)) | |
105 | + | (let ((augment-set | |
106 | + | (let loop2 ((g2 g) (augment-set '())) | |
107 | + | (match g2 | |
108 | + | (() augment-set) | |
109 | + | ((($ rdf-triple subject predicate object) g2 ...) | |
110 | + | (let ((type-triple | |
111 | + | (if (and (rdf-literal? object) | |
112 | + | (rdf-datatype? (rdf-literal-type object))) | |
113 | + | (make-rdf-triple object (rdf-iri "type") | |
114 | + | (rdf-literal-type object)) | |
115 | + | #f)) | |
116 | + | (property-triple | |
117 | + | (make-rdf-triple predicate (rdf-iri "type") | |
118 | + | (rdf-iri "Property")))) | |
119 | + | (loop2 | |
120 | + | g2 | |
121 | + | (append | |
122 | + | (if (or (not type-triple) (member type-triple g) | |
123 | + | (member type-triple augment-set)) | |
124 | + | '() | |
125 | + | (list type-triple)) | |
126 | + | (if (or (member property-triple g) | |
127 | + | (member type-triple augment-set)) | |
128 | + | '() | |
129 | + | (list property-triple)) | |
130 | + | augment-set)))))))) | |
131 | + | (if (null? augment-set) | |
132 | + | g | |
133 | + | (loop (append augment-set g))))))) | |
134 | + | ||
135 | + | (define (equiv? n1 n2) | |
136 | + | (match (list n1 n2) | |
137 | + | ((($ rdf-literal l1 ($ rdf-datatype _ _ _ _ lexical->value1 _) lang1) | |
138 | + | ($ rdf-literal l2 ($ rdf-datatype _ _ _ _ lexical->value2 _) lang2)) | |
139 | + | (and (equal? lang1 lang2) | |
140 | + | (equal? (lexical->value1 l1)) | |
141 | + | (equal? (lexical->value2 l2)))) | |
142 | + | (_ (equal? n1 n2)))) | |
143 | + | ||
144 | + | (define (validate-mapping mapping g1 g2) | |
145 | + | (match g1 | |
146 | + | ('() #t) | |
147 | + | ((t1 g1 ...) | |
148 | + | (and (not (null? (filter | |
149 | + | (lambda (t2) | |
150 | + | (let ((s1 (rdf-triple-subject t1)) | |
151 | + | (s2 (rdf-triple-subject t2)) | |
152 | + | (p1 (rdf-triple-predicate t1)) | |
153 | + | (p2 (rdf-triple-predicate t2)) | |
154 | + | (o1 (rdf-triple-object t1)) | |
155 | + | (o2 (rdf-triple-object t2))) | |
156 | + | (and | |
157 | + | (if (blank-node? s1) | |
158 | + | (equiv? (assoc-ref mapping s1) s2) | |
159 | + | (equiv? s1 s2)) | |
160 | + | (equal? p1 p2) | |
161 | + | (if (blank-node? o1) | |
162 | + | (equiv? (assoc-ref mapping o1) o2) | |
163 | + | (equiv? o1 o2))))) | |
164 | + | g2))) | |
165 | + | (validate-mapping mapping g1 g2))))) | |
166 | + | ||
167 | + | (define (entails? g e) | |
168 | + | "Return true if g entails e" | |
169 | + | (or (not (consistent-graph? g)) | |
170 | + | (d:entails? (augment g) e))) |
rdf/entailment/simple.scm
94 | 94 | (merge-joins e1 e2))))))) | |
95 | 95 | ||
96 | 96 | (define (generate-triple-constraints t1 t2) | |
97 | - | (pk 'generate t1 t2) | |
98 | 97 | (match t1 | |
99 | 98 | (($ rdf-triple s1 p1 o1) | |
100 | 99 | (match t2 |
test-modules/online.scm
20 | 20 | #:use-module (rnrs bytevectors) | |
21 | 21 | #:use-module (srfi srfi-1) | |
22 | 22 | #:use-module (test-modules result) | |
23 | + | #:use-module ((rdf entailment rdf) #:prefix rdf:) | |
23 | 24 | #:use-module ((rdf entailment simple) #:prefix simple:) | |
24 | 25 | #:use-module (rdf rdf) | |
26 | + | #:use-module ((rdf xsd) #:prefix xsd:) | |
25 | 27 | #:use-module (srfi srfi-1) | |
26 | 28 | #:use-module (turtle tordf) | |
27 | 29 | #:use-module (web client) | |
… | |||
29 | 31 | #:export (run-test-suite | |
30 | 32 | run-test-suites)) | |
31 | 33 | ||
34 | + | (define (find-rest node graph) | |
35 | + | (rdf-triple-object | |
36 | + | (car | |
37 | + | (filter | |
38 | + | (lambda (triple) | |
39 | + | (and (equal? (rdf-triple-subject triple) node) | |
40 | + | (equal? (rdf-triple-predicate triple) | |
41 | + | (string-append "http://www.w3.org/1999/02/22-rdf-syntax-ns" | |
42 | + | "#rest")))) | |
43 | + | graph)))) | |
44 | + | ||
45 | + | (define (find-first node graph) | |
46 | + | (rdf-triple-object | |
47 | + | (car | |
48 | + | (filter | |
49 | + | (lambda (triple) | |
50 | + | (and (equal? (rdf-triple-subject triple) node) | |
51 | + | (equal? (rdf-triple-predicate triple) | |
52 | + | (string-append "http://www.w3.org/1999/02/22-rdf-syntax-ns" | |
53 | + | "#first")))) | |
54 | + | graph)))) | |
55 | + | ||
56 | + | (define (find-list node graph) | |
57 | + | (if (blank-node? node) | |
58 | + | (let loop ((node node) (result '())) | |
59 | + | (let ((first (find-first node graph)) | |
60 | + | (node (find-rest node graph))) | |
61 | + | (if (blank-node? node) | |
62 | + | (loop node (cons first result)) | |
63 | + | (cons first result)))) | |
64 | + | '())) | |
65 | + | ||
32 | 66 | (define (get-objects triples predicate) | |
33 | 67 | (map | |
34 | 68 | rdf-triple-object | |
… | |||
102 | 136 | #:reason (format #f "expected ~a but got ~a" | |
103 | 137 | expected result))))))) | |
104 | 138 | ((member type '("PositiveEntailmentTest" "NegativeEntailmentTest")) | |
139 | + | (pk 'predicates predicates) | |
105 | 140 | (let* ((regime (rdf-literal-lexical-form | |
106 | 141 | (car | |
107 | 142 | (get-objects | |
… | |||
109 | 144 | (string-append | |
110 | 145 | "http://www.w3.org/2001/sw/DataAccess/tests/" | |
111 | 146 | "test-manifest#entailmentRegime"))))) | |
147 | + | (recognized | |
148 | + | (car | |
149 | + | (pk 'recognized-nodes | |
150 | + | (get-objects | |
151 | + | predicates | |
152 | + | (string-append "http://www.w3.org/2001/sw/DataAccess/tests/" | |
153 | + | "test-manifest#recognizedDatatypes")))) | |
154 | + | ) | |
155 | + | (recognized (pk 'lst-reco (find-list recognized predicates))) | |
156 | + | (recognized | |
157 | + | (map | |
158 | + | (lambda (iri) | |
159 | + | (let loop ((types xsd:datatypes)) | |
160 | + | (match types | |
161 | + | (() #f) | |
162 | + | ((type types ...) | |
163 | + | (if (member iri (rdf-datatype-iris type)) | |
164 | + | (pk 'recognized-type type) | |
165 | + | (loop types)))))) | |
166 | + | recognized)) | |
167 | + | (recognized (pk 'reco (append (list xsd:string rdf:langString) recognized))) | |
112 | 168 | (expected | |
113 | 169 | (car | |
114 | 170 | (get-objects | |
… | |||
138 | 194 | #:result 'fail | |
139 | 195 | #:reason (format #f "Expected positive result, got negative")) | |
140 | 196 | (update-test-case test #:result 'pass)))) | |
197 | + | ("RDF" | |
198 | + | (if (if (equal? expected #f) | |
199 | + | (rdf:consistent-graph? result) | |
200 | + | (rdf:entails? (recognize result recognized) | |
201 | + | (recognize expected recognized))) | |
202 | + | (if (equal? type "PositiveEntailmentTest") | |
203 | + | (update-test-case test #:result 'pass) | |
204 | + | (update-test-case test | |
205 | + | #:result 'fail | |
206 | + | #:reason "Expected negative result, got positive")) | |
207 | + | (if (equal? type "PositiveEntailmentTest") | |
208 | + | (update-test-case test | |
209 | + | #:result 'fail | |
210 | + | #:reason (format #f "Expected positive result, got negative")) | |
211 | + | (update-test-case test #:result 'pass)))) | |
141 | 212 | (_ (update-test-case test | |
142 | 213 | #:result 'skip | |
143 | 214 | #:reason (format #f "Unrecognized entailment regime: ~a" | |
… | |||
198 | 269 | "tests/test-manifest#entries")))) | |
199 | 270 | manifest)))) | |
200 | 271 | ||
201 | - | (define (find-rest node) | |
202 | - | (rdf-triple-object | |
203 | - | (car | |
204 | - | (filter | |
205 | - | (lambda (triple) | |
206 | - | (and (equal? (rdf-triple-subject triple) node) | |
207 | - | (equal? (rdf-triple-predicate triple) | |
208 | - | (string-append "http://www.w3.org/1999/02/22-rdf-syntax-ns" | |
209 | - | "#rest")))) | |
210 | - | manifest)))) | |
211 | - | ||
212 | - | (define (find-first node) | |
213 | - | (rdf-triple-object | |
214 | - | (car | |
215 | - | (filter | |
216 | - | (lambda (triple) | |
217 | - | (and (equal? (rdf-triple-subject triple) node) | |
218 | - | (equal? (rdf-triple-predicate triple) | |
219 | - | (string-append "http://www.w3.org/1999/02/22-rdf-syntax-ns" | |
220 | - | "#first")))) | |
221 | - | manifest)))) | |
272 | + | (define tests (find-list tests-node manifest)) | |
222 | 273 | ||
223 | - | (define tests | |
224 | - | (let loop ((tests-node tests-node) (tests '())) | |
225 | - | (let ((first (find-first tests-node)) | |
226 | - | (tests-node (find-rest tests-node))) | |
227 | - | (if (blank-node? tests-node) | |
228 | - | (loop tests-node (cons first tests)) | |
229 | - | tests)))) | |
274 | + | (define (subgraph-at graph node) | |
275 | + | (let ((nodes (filter | |
276 | + | (lambda (t) | |
277 | + | (equal? (rdf-triple-subject t) node)) | |
278 | + | graph))) | |
279 | + | (if (null? nodes) | |
280 | + | '() | |
281 | + | (apply append nodes | |
282 | + | (map | |
283 | + | (lambda (n) | |
284 | + | (subgraph-at graph (rdf-triple-object n))) | |
285 | + | nodes))))) | |
230 | 286 | ||
231 | 287 | (cdr | |
232 | 288 | (fold | |
233 | 289 | (lambda (test result) | |
234 | 290 | (let* ((num (car result)) | |
235 | 291 | (result (cdr result)) | |
236 | - | (test-predicates (filter | |
237 | - | (lambda (t) | |
238 | - | (equal? (rdf-triple-subject t) test)) | |
239 | - | manifest)) | |
292 | + | (test-predicates (subgraph-at manifest test)) | |
240 | 293 | (name (lexical->value (car (get-objects test-predicates "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#name")))) | |
241 | 294 | (description (lexical->value (car (get-objects test-predicates "http://www.w3.org/2000/01/rdf-schema#comment"))))) | |
242 | 295 | (cons (+ 1 num) | |
243 | - | (cons (make-test-case test num name description | |
244 | - | (filter | |
245 | - | (lambda (t) | |
246 | - | (equal? (rdf-triple-subject t) test)) | |
247 | - | manifest) | |
296 | + | (cons (make-test-case test num name description test-predicates | |
248 | 297 | #f #f) | |
249 | 298 | result)))) | |
250 | 299 | `(,num . ()) |