@skaterqiang/protege-js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/LICENSE +48 -0
- package/README.md +287 -0
- package/docs/API.md +654 -0
- package/docs/design/OWL2-/347/274/272/345/217/243/345/210/206/346/236/220.md +140 -0
- package/docs/owl2-rl/OWL2-RL-/350/247/204/345/210/231/347/273/206/345/210/231.md +168 -0
- package/docs/owl2-rl/owl2-profiles-spec-zh.html +1914 -0
- package/docs/owl2-rl/owl2-profiles-spec.html +1916 -0
- package/docs/owl2-rl/rl_rules.json +392 -0
- package/main.js +46 -0
- package/package.json +76 -0
- package/sample/README.md +74 -0
- package/sample/case1-ecommerce-risk.js +170 -0
- package/sample/case10-ecommerce-customer-service.js +454 -0
- package/sample/case2-family-swrl.js +147 -0
- package/sample/case3-pharma-safety.js +132 -0
- package/sample/case4-knowledge-publishing.js +111 -0
- package/sample/case5-obda-profiles.js +153 -0
- package/sample/case6-medical-ontology.js +152 -0
- package/sample/case7-manufacturing-ppr.js +155 -0
- package/sample/case8-real-medical-bfo-ogms.js +353 -0
- package/sample/case9-real-manufacturing-iao.js +360 -0
- package/sample/ontologies/bfo.owl +1715 -0
- package/sample/ontologies/iao.owl +8532 -0
- package/sample/ontologies/ogms.owl +4320 -0
- package/sample/ontologies/ro-core.owl +1010 -0
- package/scripts/verify-api.js +53 -0
- package/src/index.js +176 -0
- package/src/inference/OWL2ProfileReasoners.js +67 -0
- package/src/inference/OWL2RLReasoner.js +65 -0
- package/src/inference/ReasonerQueries.js +111 -0
- package/src/inference/SWRLReasoner.js +409 -0
- package/src/inference/TripleStore.js +82 -0
- package/src/inference/rdf.js +83 -0
- package/src/inference/rules/owl2el.js +33 -0
- package/src/inference/rules/owl2ql.js +29 -0
- package/src/inference/rules/owl2rl.js +823 -0
- package/src/io/FunctionalSyntaxParser.js +399 -0
- package/src/io/FunctionalSyntaxWriter.js +180 -0
- package/src/io/ManchesterSyntaxParser.js +398 -0
- package/src/io/OWLXMLParser.js +356 -0
- package/src/io/OntologyLoader.js +125 -0
- package/src/io/RDFGraphToOntology.js +702 -0
- package/src/io/RDFXMLParser.js +319 -0
- package/src/io/RDFXMLWriter.js +196 -0
- package/src/io/SWRLParser.js +150 -0
- package/src/io/TurtleParser.js +363 -0
- package/src/io/TurtleWriter.js +393 -0
- package/src/model/IRI.js +62 -0
- package/src/model/OWLAxiom.js +507 -0
- package/src/model/OWLClassExpression.js +242 -0
- package/src/model/OWLEntity.js +142 -0
- package/src/model/OWLLiteral.js +30 -0
- package/src/model/OWLModelManager.js +106 -0
- package/src/model/OWLOntology.js +119 -0
- package/src/model/SWRL.js +152 -0
- package/src/model/event/OWLModelManagerEvent.js +33 -0
- package/src/model/hierarchy/HierarchyProvider.js +214 -0
- package/src/profiles/OWL2Profiles.js +185 -0
- package/src/server/public/app.js +97 -0
- package/src/server/public/index.html +49 -0
- package/src/server/webServer.js +138 -0
- package/src/validation/GlobalRestrictionsValidator.js +172 -0
- package/test/core.test.js +111 -0
- package/test/exports-map.test.js +165 -0
- package/test/owl2/axioms.test.js +160 -0
- package/test/owl2/classExpressions.test.js +99 -0
- package/test/owl2/functional-syntax-writer.test.js +65 -0
- package/test/owl2/functional.test.js +113 -0
- package/test/owl2/global-restrictions.test.js +76 -0
- package/test/owl2/longtail.test.js +74 -0
- package/test/owl2/manchester-syntax.test.js +100 -0
- package/test/owl2/ontology-loader-imports.test.js +62 -0
- package/test/owl2/owlxml-parser.test.js +112 -0
- package/test/owl2/profile-reasoners.test.js +108 -0
- package/test/owl2/profiles.test.js +66 -0
- package/test/owl2/rdf-graph-to-ontology.test.js +177 -0
- package/test/owl2/rdfxml-punning.test.js +25 -0
- package/test/owl2/rdfxml-writer.test.js +55 -0
- package/test/owl2/rdfxml.test.js +91 -0
- package/test/owl2/reasoner-queries.test.js +58 -0
- package/test/owl2/sample-e2e.test.js +195 -0
- package/test/owl2/swrl-parser.test.js +60 -0
- package/test/owl2/swrl.test.js +131 -0
- package/test/owl2/turtle-writer.test.js +84 -0
- package/test/owl2/turtle.test.js +124 -0
- package/test/owl2rl/cax.test.js +57 -0
- package/test/owl2rl/cls.test.js +210 -0
- package/test/owl2rl/dt.test.js +72 -0
- package/test/owl2rl/eq.test.js +95 -0
- package/test/owl2rl/prp.test.js +198 -0
- package/test/owl2rl/scm.test.js +203 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// io/RDFGraphToOntology — convert a TripleStore (raw RDF triples) into a
|
|
5
|
+
// structured OWLOntology. This is the W3C "Mapping to RDF Graphs" inverse.
|
|
6
|
+
//
|
|
7
|
+
// Handles:
|
|
8
|
+
// - Named classes / properties / individuals (owl:Class, owl:ObjectProperty,
|
|
9
|
+
// owl:DatatypeProperty, owl:NamedIndividual)
|
|
10
|
+
// - Anonymous class expressions encoded as RDF blank nodes:
|
|
11
|
+
// owl:Restriction (someValuesFrom / allValuesFrom / hasValue / hasSelf /
|
|
12
|
+
// min/max/exact cardinality, qualified + unqualified)
|
|
13
|
+
// owl:intersectionOf / owl:unionOf / owl:complementOf / owl:oneOf
|
|
14
|
+
// - Data ranges: owl:onDatatype + owl:withRestrictions (facet lists),
|
|
15
|
+
// owl:intersectionOf / unionOf / complementOf / oneOf
|
|
16
|
+
// - Class axioms: rdfs:subClassOf, owl:equivalentClass, owl:disjointWith,
|
|
17
|
+
// owl:disjointUnionOf, owl:hasKey
|
|
18
|
+
// - Property axioms: rdfs:subPropertyOf, owl:inverseOf, rdfs:domain,
|
|
19
|
+
// rdfs:range, owl:propertyChainAxiom
|
|
20
|
+
// - Property characteristics via rdf:type (Functional/InverseFunctional/
|
|
21
|
+
// Transitive/Symmetric/Asymmetric/Reflexive/Irreflexive)
|
|
22
|
+
// - Assertions: rdf:type, owl:sameAs, owl:differentFrom,
|
|
23
|
+
// owl:NegativePropertyAssertion (reified)
|
|
24
|
+
// - N-ary constructs: owl:AllDisjointClasses / owl:AllDifferent /
|
|
25
|
+
// owl:AllDisjointProperties (owl:members / owl:distinctMembers)
|
|
26
|
+
// - Axiom annotations via owl:Axiom reification (owl:annotatedSource /
|
|
27
|
+
// annotatedProperty / annotatedTarget)
|
|
28
|
+
// - Ontology header: owl:Ontology with owl:imports, owl:versionIRI,
|
|
29
|
+
// owl:priorVersion, owl:backwardCompatibleWith, owl:incompatibleWith,
|
|
30
|
+
// plus arbitrary annotation properties on the ontology node itself
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
const { OWLOntology, OWLOntologyID } = require('../model/OWLOntology');
|
|
34
|
+
const {
|
|
35
|
+
OWLClass, OWLObjectProperty, OWLDataProperty, OWLNamedIndividual,
|
|
36
|
+
OWLAnonymousIndividual, OWLDatatype, OWLAnnotationProperty
|
|
37
|
+
} = require('../model/OWLEntity');
|
|
38
|
+
const CE = require('../model/OWLClassExpression');
|
|
39
|
+
const AX = require('../model/OWLAxiom');
|
|
40
|
+
const { OWLLiteral } = require('../model/OWLLiteral');
|
|
41
|
+
const { IRI } = require('../model/IRI');
|
|
42
|
+
const { NS, parseLiteral } = require('../inference/rdf');
|
|
43
|
+
|
|
44
|
+
const RDF = NS.RDF, RDFS = NS.RDFS, OWL = NS.OWL, XSD = NS.XSD;
|
|
45
|
+
|
|
46
|
+
// Facet IRI → name
|
|
47
|
+
const FACET_NAMES = Object.freeze({
|
|
48
|
+
[XSD + 'minInclusive']: 'minInclusive',
|
|
49
|
+
[XSD + 'maxInclusive']: 'maxInclusive',
|
|
50
|
+
[XSD + 'minExclusive']: 'minExclusive',
|
|
51
|
+
[XSD + 'maxExclusive']: 'maxExclusive',
|
|
52
|
+
[XSD + 'length']: 'length',
|
|
53
|
+
[XSD + 'minLength']: 'minLength',
|
|
54
|
+
[XSD + 'maxLength']: 'maxLength',
|
|
55
|
+
[XSD + 'pattern']: 'pattern',
|
|
56
|
+
[XSD + 'totalDigits']: 'totalDigits',
|
|
57
|
+
[XSD + 'fractionDigits']: 'fractionDigits',
|
|
58
|
+
[XSD + 'whiteSpace']: 'whiteSpace'
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const BUILTIN_ANNOTATION_PROPERTIES = new Set([
|
|
62
|
+
RDFS + 'label', RDFS + 'comment', RDFS + 'seeAlso', RDFS + 'isDefinedBy',
|
|
63
|
+
OWL + 'versionInfo', OWL + 'deprecated', OWL + 'priorVersion',
|
|
64
|
+
OWL + 'backwardCompatibleWith', OWL + 'incompatibleWith'
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
const CHARACTERISTIC_RDF_TYPES = {
|
|
68
|
+
[OWL + 'FunctionalProperty']: 'FUNCTIONAL',
|
|
69
|
+
[OWL + 'InverseFunctionalProperty']: 'INVERSE_FUNCTIONAL',
|
|
70
|
+
[OWL + 'TransitiveProperty']: 'TRANSITIVE',
|
|
71
|
+
[OWL + 'SymmetricProperty']: 'SYMMETRIC',
|
|
72
|
+
[OWL + 'AsymmetricProperty']: 'ASYMMETRIC',
|
|
73
|
+
[OWL + 'ReflexiveProperty']: 'REFLEXIVE',
|
|
74
|
+
[OWL + 'IrreflexiveProperty']: 'IRREFLEXIVE'
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Convert a TripleStore into an OWLOntology.
|
|
79
|
+
* @param {TripleStore} store
|
|
80
|
+
* @param {{ontologyIRI?: string}} [opts]
|
|
81
|
+
* @returns {OWLOntology}
|
|
82
|
+
*/
|
|
83
|
+
function triplesToOntology(store, opts = {}) {
|
|
84
|
+
const ont = new OWLOntology(new OWLOntologyID(opts.ontologyIRI || null));
|
|
85
|
+
const ctx = { store, ont, ceCache: new Map(), drCache: new Map(), indCache: new Map() };
|
|
86
|
+
|
|
87
|
+
parseOntologyHeader(ctx);
|
|
88
|
+
const namedClasses = parseEntities(ctx);
|
|
89
|
+
parseClassAxioms(ctx, namedClasses);
|
|
90
|
+
parsePropertyAxioms(ctx);
|
|
91
|
+
parseIndividualAxioms(ctx);
|
|
92
|
+
parseNAryConstructs(ctx);
|
|
93
|
+
parseNegativeAssertions(ctx);
|
|
94
|
+
parseAnnotations(ctx);
|
|
95
|
+
return ont;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Ontology header
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
function parseOntologyHeader(ctx) {
|
|
103
|
+
const { store, ont } = ctx;
|
|
104
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'Ontology')) {
|
|
105
|
+
if (isAnon(s)) continue;
|
|
106
|
+
if (!ont.getOntologyID().ontologyIRI) ont.id.ontologyIRI = s;
|
|
107
|
+
ont.headerSubject = s;
|
|
108
|
+
const v = store.objects(s, OWL + 'versionIRI')[0];
|
|
109
|
+
if (v) ont.id.versionIRI = v;
|
|
110
|
+
ont.imports = store.objects(s, OWL + 'imports').slice();
|
|
111
|
+
ont.priorVersion = store.objects(s, OWL + 'priorVersion').slice();
|
|
112
|
+
ont.backwardCompatibleWith = store.objects(s, OWL + 'backwardCompatibleWith').slice();
|
|
113
|
+
ont.incompatibleWith = store.objects(s, OWL + 'incompatibleWith').slice();
|
|
114
|
+
// Ontology-level annotations: any non-structural predicate on the ontology node
|
|
115
|
+
for (const [_, p, o] of store.match(s, null, null)) {
|
|
116
|
+
if (p.startsWith(RDF) || p.startsWith(OWL + 'imports') || p.startsWith(OWL + 'versionIRI')
|
|
117
|
+
|| p.startsWith(OWL + 'priorVersion') || p.startsWith(OWL + 'backwardCompatibleWith')
|
|
118
|
+
|| p.startsWith(OWL + 'incompatibleWith')) continue;
|
|
119
|
+
if (BUILTIN_ANNOTATION_PROPERTIES.has(p)) {
|
|
120
|
+
const val = literalFromEncoding(o) || IRI.create(o);
|
|
121
|
+
ont.addOntologyAnnotation(new AX.OWLAnnotationAssertionAxiom(
|
|
122
|
+
s, new OWLAnnotationProperty(p), val));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Entity declarations
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
function parseEntities(ctx) {
|
|
133
|
+
const { store, ont } = ctx;
|
|
134
|
+
const namedClasses = new Set();
|
|
135
|
+
|
|
136
|
+
const declare = (iri, mk) => {
|
|
137
|
+
if (isAnon(iri)) return null;
|
|
138
|
+
ont.addAxiom(new AX.OWLDeclarationAxiom(mk(iri)));
|
|
139
|
+
return iri;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'Class')) {
|
|
143
|
+
if (declare(s, (i) => new OWLClass(i))) namedClasses.add(s);
|
|
144
|
+
}
|
|
145
|
+
for (const [s] of store.match(null, RDF + 'type', RDFS + 'Class')) {
|
|
146
|
+
if (declare(s, (i) => new OWLClass(i))) namedClasses.add(s);
|
|
147
|
+
}
|
|
148
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'ObjectProperty')) {
|
|
149
|
+
declare(s, (i) => new OWLObjectProperty(i));
|
|
150
|
+
}
|
|
151
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'DatatypeProperty')) {
|
|
152
|
+
declare(s, (i) => new OWLDataProperty(i));
|
|
153
|
+
}
|
|
154
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'AnnotationProperty')) {
|
|
155
|
+
declare(s, (i) => new OWLAnnotationProperty(i));
|
|
156
|
+
}
|
|
157
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'NamedIndividual')) {
|
|
158
|
+
declare(s, (i) => new OWLNamedIndividual(i));
|
|
159
|
+
}
|
|
160
|
+
for (const [s] of store.match(null, RDF + 'type', RDFS + 'Datatype')) {
|
|
161
|
+
declare(s, (i) => new OWLDatatype(i));
|
|
162
|
+
}
|
|
163
|
+
return namedClasses;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Class axioms (subClassOf / equivalentClass / disjointWith / disjointUnionOf
|
|
168
|
+
// / hasKey). Each super/equivalent side may be a named class or a blank node
|
|
169
|
+
// encoding a class expression.
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
function parseClassAxioms(ctx, namedClasses) {
|
|
173
|
+
const { store, ont } = ctx;
|
|
174
|
+
|
|
175
|
+
const clsOf = (node) => classExpression(ctx, node);
|
|
176
|
+
|
|
177
|
+
for (const c of namedClasses) {
|
|
178
|
+
const cls = new OWLClass(c);
|
|
179
|
+
for (const sup of store.objects(c, RDFS + 'subClassOf')) {
|
|
180
|
+
const ce = clsOf(sup);
|
|
181
|
+
if (ce) ont.addAxiom(new AX.OWLSubClassOfAxiom(cls, ce));
|
|
182
|
+
}
|
|
183
|
+
for (const eq of store.objects(c, OWL + 'equivalentClass')) {
|
|
184
|
+
const ce = clsOf(eq);
|
|
185
|
+
if (ce) ont.addAxiom(new AX.OWLEquivalentClassesAxiom([cls, ce]));
|
|
186
|
+
}
|
|
187
|
+
for (const d of store.objects(c, OWL + 'disjointWith')) {
|
|
188
|
+
const ce = clsOf(d);
|
|
189
|
+
if (ce) ont.addAxiom(new AX.OWLDisjointClassesAxiom([cls, ce]));
|
|
190
|
+
}
|
|
191
|
+
for (const du of store.objects(c, OWL + 'disjointUnionOf')) {
|
|
192
|
+
const members = listNodes(store, du).map(clsOf).filter(Boolean);
|
|
193
|
+
if (members.length >= 2) {
|
|
194
|
+
ont.addAxiom(new AX.OWLDisjointUnionAxiom(cls, members));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
for (const k of store.objects(c, OWL + 'hasKey')) {
|
|
198
|
+
const props = listNodes(store, k).map(n => {
|
|
199
|
+
if (store.match(n, RDF + 'type', OWL + 'ObjectProperty').length) {
|
|
200
|
+
return new OWLObjectProperty(n);
|
|
201
|
+
}
|
|
202
|
+
return new OWLDataProperty(n);
|
|
203
|
+
});
|
|
204
|
+
if (props.length) ont.addAxiom(new AX.OWLHasKeyAxiom(cls, props));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// Property axioms + characteristics
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
function parsePropertyAxioms(ctx) {
|
|
214
|
+
const { store, ont } = ctx;
|
|
215
|
+
|
|
216
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'ObjectProperty')) {
|
|
217
|
+
if (isAnon(s)) continue;
|
|
218
|
+
const p = new OWLObjectProperty(s);
|
|
219
|
+
for (const sup of store.objects(s, RDFS + 'subPropertyOf')) {
|
|
220
|
+
ont.addAxiom(new AX.OWLSubObjectPropertyOfAxiom(p, new OWLObjectProperty(sup)));
|
|
221
|
+
}
|
|
222
|
+
for (const inv of store.objects(s, OWL + 'inverseOf')) {
|
|
223
|
+
ont.addAxiom(new AX.OWLInverseObjectPropertiesAxiom(p, new OWLObjectProperty(inv)));
|
|
224
|
+
}
|
|
225
|
+
for (const d of store.objects(s, RDFS + 'domain')) {
|
|
226
|
+
const ce = classExpression(ctx, d);
|
|
227
|
+
if (ce) ont.addAxiom(new AX.OWLObjectPropertyDomainAxiom(p, ce));
|
|
228
|
+
}
|
|
229
|
+
for (const r of store.objects(s, RDFS + 'range')) {
|
|
230
|
+
const ce = classExpression(ctx, r);
|
|
231
|
+
if (ce) ont.addAxiom(new AX.OWLObjectPropertyRangeAxiom(p, ce));
|
|
232
|
+
}
|
|
233
|
+
for (const ch of store.objects(s, OWL + 'propertyChainAxiom')) {
|
|
234
|
+
const chain = listNodes(store, ch).map(n => new OWLObjectProperty(n));
|
|
235
|
+
if (chain.length >= 2) {
|
|
236
|
+
ont.addAxiom(new AX.OWLSubPropertyChainOfAxiom(chain, p));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
applyCharacteristics(ctx, s, p, true);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'DatatypeProperty')) {
|
|
243
|
+
if (isAnon(s)) continue;
|
|
244
|
+
const p = new OWLDataProperty(s);
|
|
245
|
+
for (const sup of store.objects(s, RDFS + 'subPropertyOf')) {
|
|
246
|
+
ont.addAxiom(new AX.OWLSubDataPropertyOfAxiom(p, new OWLDataProperty(sup)));
|
|
247
|
+
}
|
|
248
|
+
for (const d of store.objects(s, RDFS + 'domain')) {
|
|
249
|
+
const ce = classExpression(ctx, d);
|
|
250
|
+
if (ce) ont.addAxiom(new AX.OWLDataPropertyDomainAxiom(p, ce));
|
|
251
|
+
}
|
|
252
|
+
for (const r of store.objects(s, RDFS + 'range')) {
|
|
253
|
+
const dr = dataRange(ctx, r);
|
|
254
|
+
if (dr) ont.addAxiom(new AX.OWLDataPropertyRangeAxiom(p, dr));
|
|
255
|
+
}
|
|
256
|
+
applyCharacteristics(ctx, s, p, false);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function applyCharacteristics(ctx, propIRI, prop, isObject) {
|
|
261
|
+
const { store, ont } = ctx;
|
|
262
|
+
for (const t of store.objects(propIRI, RDF + 'type')) {
|
|
263
|
+
const kind = CHARACTERISTIC_RDF_TYPES[t];
|
|
264
|
+
if (!kind) continue;
|
|
265
|
+
if (kind === 'FUNCTIONAL') {
|
|
266
|
+
ont.addAxiom(isObject
|
|
267
|
+
? new AX.OWLFunctionalObjectPropertyAxiom(prop)
|
|
268
|
+
: new AX.OWLFunctionalDataPropertyAxiom(prop));
|
|
269
|
+
} else if (isObject) {
|
|
270
|
+
const map = {
|
|
271
|
+
INVERSE_FUNCTIONAL: AX.OWLInverseFunctionalObjectPropertyAxiom,
|
|
272
|
+
TRANSITIVE: AX.OWLTransitiveObjectPropertyAxiom,
|
|
273
|
+
SYMMETRIC: AX.OWLSymmetricObjectPropertyAxiom,
|
|
274
|
+
ASYMMETRIC: AX.OWLAsymmetricObjectPropertyAxiom,
|
|
275
|
+
REFLEXIVE: AX.OWLReflexiveObjectPropertyAxiom,
|
|
276
|
+
IRREFLEXIVE: AX.OWLIrreflexiveObjectPropertyAxiom
|
|
277
|
+
};
|
|
278
|
+
if (map[kind]) ont.addAxiom(new map[kind](prop));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
// Individuals
|
|
285
|
+
// ---------------------------------------------------------------------------
|
|
286
|
+
|
|
287
|
+
function parseIndividualAxioms(ctx) {
|
|
288
|
+
const { store, ont } = ctx;
|
|
289
|
+
// owl:NamedIndividual declarations + type assertions
|
|
290
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'NamedIndividual')) {
|
|
291
|
+
const ind = individualOf(ctx, s);
|
|
292
|
+
for (const t of store.objects(s, RDF + 'type')) {
|
|
293
|
+
if (t === OWL + 'NamedIndividual') continue;
|
|
294
|
+
const ce = classExpression(ctx, t);
|
|
295
|
+
if (ce) ont.addAxiom(new AX.OWLClassAssertionAxiom(ind, ce));
|
|
296
|
+
}
|
|
297
|
+
for (const o of store.objects(s, OWL + 'sameAs')) {
|
|
298
|
+
ont.addAxiom(new AX.OWLSameIndividualAxiom([ind, individualOf(ctx, o)]));
|
|
299
|
+
}
|
|
300
|
+
for (const o of store.objects(s, OWL + 'differentFrom')) {
|
|
301
|
+
ont.addAxiom(new AX.OWLDifferentIndividualsAxiom([ind, individualOf(ctx, o)]));
|
|
302
|
+
}
|
|
303
|
+
// Property assertions: any non-structural triple
|
|
304
|
+
for (const [_, p, o] of store.match(s, null, null)) {
|
|
305
|
+
if (p.startsWith(RDF) || p.startsWith(OWL + 'sameAs') || p.startsWith(OWL + 'differentFrom')) continue;
|
|
306
|
+
if (BUILTIN_ANNOTATION_PROPERTIES.has(p)) continue;
|
|
307
|
+
// Object property?
|
|
308
|
+
if (store.match(p, RDF + 'type', OWL + 'ObjectProperty').length) {
|
|
309
|
+
ont.addAxiom(new AX.OWLObjectPropertyAssertionAxiom(ind, new OWLObjectProperty(p), individualOf(ctx, o)));
|
|
310
|
+
} else if (store.match(p, RDF + 'type', OWL + 'DatatypeProperty').length) {
|
|
311
|
+
const lit = literalFromEncoding(o);
|
|
312
|
+
if (lit) ont.addAxiom(new AX.OWLDataPropertyAssertionAxiom(ind, new OWLDataProperty(p), lit));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// ---------------------------------------------------------------------------
|
|
319
|
+
// N-ary constructs (AllDisjointClasses / AllDifferent / AllDisjointProperties)
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
function parseNAryConstructs(ctx) {
|
|
323
|
+
const { store, ont } = ctx;
|
|
324
|
+
|
|
325
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'AllDisjointClasses')) {
|
|
326
|
+
const members = store.objects(s, OWL + 'members')[0];
|
|
327
|
+
if (!members) continue;
|
|
328
|
+
const ces = listNodes(store, members).map(n => classExpression(ctx, n)).filter(Boolean);
|
|
329
|
+
if (ces.length >= 2) ont.addAxiom(new AX.OWLDisjointClassesAxiom(ces));
|
|
330
|
+
}
|
|
331
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'AllDifferent')) {
|
|
332
|
+
const members = store.objects(s, OWL + 'distinctMembers')[0]
|
|
333
|
+
|| store.objects(s, OWL + 'members')[0];
|
|
334
|
+
if (!members) continue;
|
|
335
|
+
const inds = listNodes(store, members).map(n => individualOf(ctx, n));
|
|
336
|
+
if (inds.length >= 2) ont.addAxiom(new AX.OWLDifferentIndividualsAxiom(inds));
|
|
337
|
+
}
|
|
338
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'AllDisjointProperties')) {
|
|
339
|
+
const members = store.objects(s, OWL + 'members')[0];
|
|
340
|
+
if (!members) continue;
|
|
341
|
+
const nodes = listNodes(store, members);
|
|
342
|
+
const objProps = nodes.filter(n => store.match(n, RDF + 'type', OWL + 'ObjectProperty').length);
|
|
343
|
+
const dataProps = nodes.filter(n => store.match(n, RDF + 'type', OWL + 'DatatypeProperty').length);
|
|
344
|
+
if (objProps.length >= 2) {
|
|
345
|
+
ont.addAxiom(new AX.OWLDisjointObjectPropertiesAxiom(objProps.map(n => new OWLObjectProperty(n))));
|
|
346
|
+
}
|
|
347
|
+
if (dataProps.length >= 2) {
|
|
348
|
+
ont.addAxiom(new AX.OWLDisjointDataPropertiesAxiom(dataProps.map(n => new OWLDataProperty(n))));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Equivalent classes / properties (n-ary via owl:equivalentClass / owl:equivalentProperty pairs)
|
|
352
|
+
// Handled by binary axioms above; multi-node equivalentClasses constructs go through
|
|
353
|
+
// owl:equivalentClass between named classes.
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// ---------------------------------------------------------------------------
|
|
357
|
+
// Negative property assertions (owl:NegativePropertyAssertion reification)
|
|
358
|
+
// ---------------------------------------------------------------------------
|
|
359
|
+
|
|
360
|
+
function parseNegativeAssertions(ctx) {
|
|
361
|
+
const { store, ont } = ctx;
|
|
362
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'NegativePropertyAssertion')) {
|
|
363
|
+
const src = store.objects(s, OWL + 'sourceIndividual')[0];
|
|
364
|
+
const prop = store.objects(s, OWL + 'assertionProperty')[0];
|
|
365
|
+
if (!src || !prop) continue;
|
|
366
|
+
const tgtInd = store.objects(s, OWL + 'targetIndividual')[0];
|
|
367
|
+
const tgtVal = store.objects(s, OWL + 'targetValue')[0];
|
|
368
|
+
const subj = individualOf(ctx, src);
|
|
369
|
+
if (tgtInd) {
|
|
370
|
+
ont.addAxiom(new AX.OWLNegativeObjectPropertyAssertionAxiom(
|
|
371
|
+
subj, new OWLObjectProperty(prop), individualOf(ctx, tgtInd)));
|
|
372
|
+
} else if (tgtVal) {
|
|
373
|
+
const lit = literalFromEncoding(tgtVal);
|
|
374
|
+
if (lit) {
|
|
375
|
+
ont.addAxiom(new AX.OWLNegativeDataPropertyAssertionAxiom(
|
|
376
|
+
subj, new OWLDataProperty(prop), lit));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// ---------------------------------------------------------------------------
|
|
383
|
+
// Annotations on entities + axiom annotations (owl:Axiom reification)
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
|
|
386
|
+
function parseAnnotations(ctx) {
|
|
387
|
+
const { store, ont } = ctx;
|
|
388
|
+
|
|
389
|
+
// Entity-level annotations: any triple (s, p, o) where p is an AnnotationProperty
|
|
390
|
+
const annProps = new Set(BUILTIN_ANNOTATION_PROPERTIES);
|
|
391
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'AnnotationProperty')) {
|
|
392
|
+
if (!isAnon(s)) annProps.add(s);
|
|
393
|
+
}
|
|
394
|
+
for (const p of annProps) {
|
|
395
|
+
for (const [s, , o] of store.match(null, p, null)) {
|
|
396
|
+
// Skip ontology header (already collected as ontology annotations)
|
|
397
|
+
if (ont.headerSubject === s) continue;
|
|
398
|
+
const val = literalFromEncoding(o) || IRI.create(o);
|
|
399
|
+
ont.addAxiom(new AX.OWLAnnotationAssertionAxiom(
|
|
400
|
+
s, new OWLAnnotationProperty(p), val));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Axiom annotations via owl:Axiom reification
|
|
405
|
+
for (const [s] of store.match(null, RDF + 'type', OWL + 'Axiom')) {
|
|
406
|
+
const src = store.objects(s, OWL + 'annotatedSource')[0];
|
|
407
|
+
const prop = store.objects(s, OWL + 'annotatedProperty')[0];
|
|
408
|
+
const tgt = store.objects(s, OWL + 'annotatedTarget')[0];
|
|
409
|
+
if (!src || !prop || tgt === undefined) continue;
|
|
410
|
+
// Reconstruct the annotated axiom
|
|
411
|
+
const ax = reconstructAxiom(ctx, src, prop, tgt);
|
|
412
|
+
if (!ax) continue;
|
|
413
|
+
// Collect the reified node's other properties as annotations on that axiom
|
|
414
|
+
for (const [_, p, o] of store.match(s, null, null)) {
|
|
415
|
+
if (p === RDF + 'type' || p === OWL + 'annotatedSource'
|
|
416
|
+
|| p === OWL + 'annotatedProperty' || p === OWL + 'annotatedTarget') continue;
|
|
417
|
+
if (BUILTIN_ANNOTATION_PROPERTIES.has(p) || annProps.has(p)) {
|
|
418
|
+
const val = literalFromEncoding(o) || IRI.create(o);
|
|
419
|
+
ax.annotations.push({
|
|
420
|
+
property: new OWLAnnotationProperty(p),
|
|
421
|
+
value: val
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
ont.addAxiom(ax);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function reconstructAxiom(ctx, src, prop, tgt) {
|
|
430
|
+
const { store } = ctx;
|
|
431
|
+
// SubClassOf
|
|
432
|
+
if (prop === RDFS + 'subClassOf') {
|
|
433
|
+
const sub = classExpression(ctx, src);
|
|
434
|
+
const sup = classExpression(ctx, tgt);
|
|
435
|
+
return sub && sup ? new AX.OWLSubClassOfAxiom(sub, sup) : null;
|
|
436
|
+
}
|
|
437
|
+
// ClassAssertion
|
|
438
|
+
if (prop === RDF + 'type') {
|
|
439
|
+
const ind = individualOf(ctx, src);
|
|
440
|
+
const ce = classExpression(ctx, tgt);
|
|
441
|
+
return ce ? new AX.OWLClassAssertionAxiom(ind, ce) : null;
|
|
442
|
+
}
|
|
443
|
+
// SubObjectPropertyOf
|
|
444
|
+
if (prop === RDFS + 'subPropertyOf') {
|
|
445
|
+
if (store.match(src, RDF + 'type', OWL + 'ObjectProperty').length
|
|
446
|
+
|| store.match(tgt, RDF + 'type', OWL + 'ObjectProperty').length) {
|
|
447
|
+
return new AX.OWLSubObjectPropertyOfAxiom(new OWLObjectProperty(src), new OWLObjectProperty(tgt));
|
|
448
|
+
}
|
|
449
|
+
return new AX.OWLSubDataPropertyOfAxiom(new OWLDataProperty(src), new OWLDataProperty(tgt));
|
|
450
|
+
}
|
|
451
|
+
// ObjectPropertyAssertion
|
|
452
|
+
if (store.match(prop, RDF + 'type', OWL + 'ObjectProperty').length) {
|
|
453
|
+
return new AX.OWLObjectPropertyAssertionAxiom(
|
|
454
|
+
individualOf(ctx, src), new OWLObjectProperty(prop), individualOf(ctx, tgt));
|
|
455
|
+
}
|
|
456
|
+
if (store.match(prop, RDF + 'type', OWL + 'DatatypeProperty').length) {
|
|
457
|
+
const lit = literalFromEncoding(tgt);
|
|
458
|
+
if (lit) {
|
|
459
|
+
return new AX.OWLDataPropertyAssertionAxiom(
|
|
460
|
+
individualOf(ctx, src), new OWLDataProperty(prop), lit);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// ---------------------------------------------------------------------------
|
|
467
|
+
// Class expression reconstruction from blank nodes
|
|
468
|
+
// ---------------------------------------------------------------------------
|
|
469
|
+
|
|
470
|
+
function classExpression(ctx, node) {
|
|
471
|
+
if (node === null || node === undefined) return null;
|
|
472
|
+
if (typeof node !== 'string') return null;
|
|
473
|
+
|
|
474
|
+
// Named class IRI
|
|
475
|
+
if (!isAnon(node) && !isLiteralEncoding(node)) {
|
|
476
|
+
return new OWLClass(node);
|
|
477
|
+
}
|
|
478
|
+
if (isLiteralEncoding(node)) return null;
|
|
479
|
+
|
|
480
|
+
// Blank node — look up its defining shape
|
|
481
|
+
const { store, ceCache } = ctx;
|
|
482
|
+
if (ceCache.has(node)) return ceCache.get(node);
|
|
483
|
+
|
|
484
|
+
const mark = (ce) => { ceCache.set(node, ce); return ce; };
|
|
485
|
+
|
|
486
|
+
// owl:Restriction
|
|
487
|
+
if (store.match(node, RDF + 'type', OWL + 'Restriction').length
|
|
488
|
+
|| store.objects(node, OWL + 'onProperty').length) {
|
|
489
|
+
const onProp = store.objects(node, OWL + 'onProperty')[0];
|
|
490
|
+
if (!onProp) return mark(null);
|
|
491
|
+
const isObjProp = store.match(onProp, RDF + 'type', OWL + 'ObjectProperty').length > 0
|
|
492
|
+
|| store.match(onProp, RDF + 'type', OWL + 'DatatypeProperty').length === 0;
|
|
493
|
+
const prop = isObjProp ? new OWLObjectProperty(onProp) : new OWLDataProperty(onProp);
|
|
494
|
+
|
|
495
|
+
const some = store.objects(node, OWL + 'someValuesFrom')[0];
|
|
496
|
+
if (some) {
|
|
497
|
+
return mark(isObjProp
|
|
498
|
+
? new CE.OWLObjectSomeValuesFrom(prop, classExpression(ctx, some))
|
|
499
|
+
: new CE.OWLDataSomeValuesFrom(prop, dataRange(ctx, some)));
|
|
500
|
+
}
|
|
501
|
+
const all = store.objects(node, OWL + 'allValuesFrom')[0];
|
|
502
|
+
if (all) {
|
|
503
|
+
return mark(isObjProp
|
|
504
|
+
? new CE.OWLObjectAllValuesFrom(prop, classExpression(ctx, all))
|
|
505
|
+
: new CE.OWLDataAllValuesFrom(prop, dataRange(ctx, all)));
|
|
506
|
+
}
|
|
507
|
+
const hasV = store.objects(node, OWL + 'hasValue')[0];
|
|
508
|
+
if (hasV !== undefined) {
|
|
509
|
+
if (isObjProp) {
|
|
510
|
+
return mark(new CE.OWLObjectHasValue(prop, individualOf(ctx, hasV)));
|
|
511
|
+
}
|
|
512
|
+
const lit = literalFromEncoding(hasV);
|
|
513
|
+
if (lit) return mark(new CE.OWLDataHasValue(prop, lit));
|
|
514
|
+
}
|
|
515
|
+
const hasSelf = store.objects(node, OWL + 'hasSelf')[0];
|
|
516
|
+
if (hasSelf && isObjProp) {
|
|
517
|
+
const v = literalFromEncoding(hasSelf);
|
|
518
|
+
if (v && (v.lexicalValue === 'true' || v.lexicalValue === '1')) {
|
|
519
|
+
return mark(new CE.OWLObjectHasSelf(prop));
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
// Cardinalities
|
|
523
|
+
const minQ = store.objects(node, OWL + 'minQualifiedCardinality')[0];
|
|
524
|
+
const maxQ = store.objects(node, OWL + 'maxQualifiedCardinality')[0];
|
|
525
|
+
const exactQ = store.objects(node, OWL + 'qualifiedCardinality')[0];
|
|
526
|
+
const min = store.objects(node, OWL + 'minCardinality')[0];
|
|
527
|
+
const max = store.objects(node, OWL + 'maxCardinality')[0];
|
|
528
|
+
const exact = store.objects(node, OWL + 'cardinality')[0];
|
|
529
|
+
const onCls = store.objects(node, OWL + 'onClass')[0];
|
|
530
|
+
const onDR = store.objects(node, OWL + 'onDataRange')[0];
|
|
531
|
+
|
|
532
|
+
const numeric = (enc) => {
|
|
533
|
+
const lit = literalFromEncoding(enc);
|
|
534
|
+
return lit ? parseInt(lit.lexicalValue, 10) : null;
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
const mkCard = (qualOrPlain, nEnc, fillerNode, isDataSide) => {
|
|
538
|
+
// qualOrPlain: 'min' | 'max' | 'exact'
|
|
539
|
+
const n = numeric(nEnc);
|
|
540
|
+
if (n === null) return null;
|
|
541
|
+
const filler = fillerNode
|
|
542
|
+
? (isDataSide ? dataRange(ctx, fillerNode) : classExpression(ctx, fillerNode))
|
|
543
|
+
: null;
|
|
544
|
+
const T = CE.ClassExpressionType;
|
|
545
|
+
const suffix = qualOrPlain === 'min' ? 'MIN_CARDINALITY'
|
|
546
|
+
: qualOrPlain === 'max' ? 'MAX_CARDINALITY' : 'EXACT_CARDINALITY';
|
|
547
|
+
const qualSuffix = filler ? 'QUALIFIED_CARDINALITY' : null;
|
|
548
|
+
let type;
|
|
549
|
+
if (isDataSide) {
|
|
550
|
+
type = filler
|
|
551
|
+
? T['DATA_' + qualOrPlain.toUpperCase() + '_CARDINALITY']
|
|
552
|
+
: T['DATA_' + suffix];
|
|
553
|
+
return new CE.OWLDataCardinalityRestriction(type, n, prop, filler);
|
|
554
|
+
}
|
|
555
|
+
type = filler
|
|
556
|
+
? T['OBJECT_' + qualOrPlain.toUpperCase() + '_QUALIFIED_CARDINALITY']
|
|
557
|
+
: T['OBJECT_' + suffix];
|
|
558
|
+
return new CE.OWLObjectCardinalityRestriction(type, n, prop, filler);
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
if (minQ) return mark(isObjProp ? mkCard('min', minQ, onCls, false) : mkCard('min', minQ, onDR, true));
|
|
562
|
+
if (maxQ) return mark(isObjProp ? mkCard('max', maxQ, onCls, false) : mkCard('max', maxQ, onDR, true));
|
|
563
|
+
if (exactQ) return mark(isObjProp ? mkCard('exact', exactQ, onCls, false) : mkCard('exact', exactQ, onDR, true));
|
|
564
|
+
if (min) return mark(isObjProp ? mkCard('min', min, null, false) : mkCard('min', min, null, true));
|
|
565
|
+
if (max) return mark(isObjProp ? mkCard('max', max, null, false) : mkCard('max', max, null, true));
|
|
566
|
+
if (exact) return mark(isObjProp ? mkCard('exact', exact, null, false) : mkCard('exact', exact, null, true));
|
|
567
|
+
return mark(null);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// owl:intersectionOf
|
|
571
|
+
const inter = store.objects(node, OWL + 'intersectionOf')[0];
|
|
572
|
+
if (inter) {
|
|
573
|
+
const ops = listNodes(store, inter).map(n => classExpression(ctx, n)).filter(Boolean);
|
|
574
|
+
if (ops.length) return mark(new CE.OWLObjectIntersectionOf(ops));
|
|
575
|
+
}
|
|
576
|
+
// owl:unionOf
|
|
577
|
+
const union = store.objects(node, OWL + 'unionOf')[0];
|
|
578
|
+
if (union) {
|
|
579
|
+
const ops = listNodes(store, union).map(n => classExpression(ctx, n)).filter(Boolean);
|
|
580
|
+
if (ops.length) return mark(new CE.OWLObjectUnionOf(ops));
|
|
581
|
+
}
|
|
582
|
+
// owl:complementOf
|
|
583
|
+
const compl = store.objects(node, OWL + 'complementOf')[0];
|
|
584
|
+
if (compl) {
|
|
585
|
+
const op = classExpression(ctx, compl);
|
|
586
|
+
if (op) return mark(new CE.OWLObjectComplementOf(op));
|
|
587
|
+
}
|
|
588
|
+
// owl:oneOf (class)
|
|
589
|
+
const oneOf = store.objects(node, OWL + 'oneOf')[0];
|
|
590
|
+
if (oneOf) {
|
|
591
|
+
const ops = listNodes(store, oneOf);
|
|
592
|
+
// If elements are literals, this is a DataOneOf not class
|
|
593
|
+
const anyLit = ops.some(o => isLiteralEncoding(o));
|
|
594
|
+
if (!anyLit) {
|
|
595
|
+
const inds = ops.map(n => individualOf(ctx, n));
|
|
596
|
+
if (inds.length) return mark(new CE.OWLObjectOneOf(inds));
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return mark(null);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// ---------------------------------------------------------------------------
|
|
603
|
+
// Data range reconstruction from blank nodes
|
|
604
|
+
// ---------------------------------------------------------------------------
|
|
605
|
+
|
|
606
|
+
function dataRange(ctx, node) {
|
|
607
|
+
if (node === null || node === undefined) return null;
|
|
608
|
+
if (typeof node !== 'string') return null;
|
|
609
|
+
if (!isAnon(node)) return new OWLDatatype(node);
|
|
610
|
+
|
|
611
|
+
const { store, drCache } = ctx;
|
|
612
|
+
if (drCache.has(node)) return drCache.get(node);
|
|
613
|
+
const mark = (dr) => { drCache.set(node, dr); return dr; };
|
|
614
|
+
|
|
615
|
+
// owl:onDatatype + owl:withRestrictions → DatatypeRestriction
|
|
616
|
+
const onDt = store.objects(node, OWL + 'onDatatype')[0];
|
|
617
|
+
if (onDt) {
|
|
618
|
+
const dt = new OWLDatatype(onDt);
|
|
619
|
+
const withR = store.objects(node, OWL + 'withRestrictions')[0];
|
|
620
|
+
if (withR) {
|
|
621
|
+
const frNodes = listNodes(store, withR);
|
|
622
|
+
const frs = [];
|
|
623
|
+
for (const fr of frNodes) {
|
|
624
|
+
for (const [_, p, o] of store.match(fr, null, null)) {
|
|
625
|
+
if (p === RDF + 'type') continue;
|
|
626
|
+
const facetName = FACET_NAMES[p];
|
|
627
|
+
const lit = literalFromEncoding(o);
|
|
628
|
+
if (facetName && lit) frs.push({ facet: IRI.create(p), value: lit });
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (frs.length) return mark(new CE.OWLDatatypeRestriction(dt, frs));
|
|
632
|
+
}
|
|
633
|
+
return mark(dt);
|
|
634
|
+
}
|
|
635
|
+
// Data intersectionOf / unionOf / complementOf / oneOf
|
|
636
|
+
const inter = store.objects(node, OWL + 'intersectionOf')[0];
|
|
637
|
+
if (inter) {
|
|
638
|
+
const ops = listNodes(store, inter).map(n => dataRange(ctx, n)).filter(Boolean);
|
|
639
|
+
if (ops.length) return mark(new CE.OWLDataIntersectionOf(ops));
|
|
640
|
+
}
|
|
641
|
+
const union = store.objects(node, OWL + 'unionOf')[0];
|
|
642
|
+
if (union) {
|
|
643
|
+
const ops = listNodes(store, union).map(n => dataRange(ctx, n)).filter(Boolean);
|
|
644
|
+
if (ops.length) return mark(new CE.OWLDataUnionOf(ops));
|
|
645
|
+
}
|
|
646
|
+
const compl = store.objects(node, OWL + 'datatypeComplementOf')[0];
|
|
647
|
+
if (compl) {
|
|
648
|
+
const op = dataRange(ctx, compl);
|
|
649
|
+
if (op) return mark(new CE.OWLDataComplementOf(op));
|
|
650
|
+
}
|
|
651
|
+
const oneOf = store.objects(node, OWL + 'oneOf')[0];
|
|
652
|
+
if (oneOf) {
|
|
653
|
+
const lits = listNodes(store, oneOf).map(literalFromEncoding).filter(Boolean);
|
|
654
|
+
if (lits.length) return mark(new CE.OWLDataOneOf(lits));
|
|
655
|
+
}
|
|
656
|
+
return mark(null);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// ---------------------------------------------------------------------------
|
|
660
|
+
// Individual (named or anonymous)
|
|
661
|
+
// ---------------------------------------------------------------------------
|
|
662
|
+
|
|
663
|
+
function individualOf(ctx, node) {
|
|
664
|
+
const { indCache } = ctx;
|
|
665
|
+
if (indCache.has(node)) return indCache.get(node);
|
|
666
|
+
const ind = isAnon(node)
|
|
667
|
+
? new OWLAnonymousIndividual(node)
|
|
668
|
+
: new OWLNamedIndividual(node);
|
|
669
|
+
indCache.set(node, ind);
|
|
670
|
+
return ind;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// ---------------------------------------------------------------------------
|
|
674
|
+
// Helpers
|
|
675
|
+
// ---------------------------------------------------------------------------
|
|
676
|
+
|
|
677
|
+
function isAnon(node) {
|
|
678
|
+
return typeof node === 'string' && node.startsWith('_:');
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function isLiteralEncoding(node) {
|
|
682
|
+
return typeof node === 'string' && node.startsWith('"');
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
function literalFromEncoding(encoded) {
|
|
686
|
+
if (!isLiteralEncoding(encoded)) return null;
|
|
687
|
+
try {
|
|
688
|
+
const parsed = parseLiteral(encoded);
|
|
689
|
+
if (!parsed) return null;
|
|
690
|
+
const dt = parsed.dt ? new OWLDatatype(parsed.dt) : null;
|
|
691
|
+
return new OWLLiteral(parsed.lex, dt, parsed.lang || null);
|
|
692
|
+
} catch {
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function listNodes(store, head) {
|
|
698
|
+
if (!head) return [];
|
|
699
|
+
return store.listElements(head);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
module.exports = { triplesToOntology };
|