@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,319 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { OWLOntology, OWLOntologyID } = require('../model/OWLOntology');
|
|
4
|
+
const {
|
|
5
|
+
OWLClass, OWLObjectProperty, OWLDataProperty, OWLNamedIndividual,
|
|
6
|
+
OWLAnnotationProperty
|
|
7
|
+
} = require('../model/OWLEntity');
|
|
8
|
+
const {
|
|
9
|
+
OWLDeclarationAxiom, OWLSubClassOfAxiom, OWLEquivalentClassesAxiom,
|
|
10
|
+
OWLSubObjectPropertyOfAxiom, OWLSubDataPropertyOfAxiom,
|
|
11
|
+
OWLObjectPropertyDomainAxiom, OWLObjectPropertyRangeAxiom,
|
|
12
|
+
OWLDataPropertyDomainAxiom, OWLClassAssertionAxiom,
|
|
13
|
+
OWLObjectPropertyAssertionAxiom, OWLDataPropertyAssertionAxiom,
|
|
14
|
+
OWLAnnotationAssertionAxiom,
|
|
15
|
+
OWLDisjointClassesAxiom, OWLInverseObjectPropertiesAxiom,
|
|
16
|
+
OWLSameIndividualAxiom, OWLDifferentIndividualsAxiom,
|
|
17
|
+
OWLFunctionalObjectPropertyAxiom, OWLInverseFunctionalObjectPropertyAxiom,
|
|
18
|
+
OWLTransitiveObjectPropertyAxiom, OWLSymmetricObjectPropertyAxiom,
|
|
19
|
+
OWLAsymmetricObjectPropertyAxiom, OWLReflexiveObjectPropertyAxiom,
|
|
20
|
+
OWLIrreflexiveObjectPropertyAxiom, OWLFunctionalDataPropertyAxiom
|
|
21
|
+
} = require('../model/OWLAxiom');
|
|
22
|
+
const { OWLLiteral } = require('../model/OWLLiteral');
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// io/RDFXMLParser — mirrors the RDF/XML document handler role of OWLAPI's
|
|
26
|
+
// parsers as wrapped by org.protege.editor.owl.model.io.OntologyLoader.
|
|
27
|
+
//
|
|
28
|
+
// A lightweight, dependency-free RDF/XML reader: extracts typed nodes,
|
|
29
|
+
// rdf:about / rdf:ID identity, owl:subClassOf / subPropertyOf / domain /
|
|
30
|
+
// range / type triples, and rdfs:label / annotation literals.
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
const NS = Object.freeze({
|
|
34
|
+
RDF: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
|
35
|
+
RDFS: 'http://www.w3.org/2000/01/rdf-schema#',
|
|
36
|
+
OWL: 'http://www.w3.org/2002/07/owl#',
|
|
37
|
+
XSD: 'http://www.w3.org/2001/XMLSchema#'
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function expandIRI(token, base, prefixes) {
|
|
41
|
+
if (!token) return null;
|
|
42
|
+
if (token.startsWith('http://') || token.startsWith('https://') || token.startsWith('urn:')) {
|
|
43
|
+
return token;
|
|
44
|
+
}
|
|
45
|
+
const idx = token.indexOf(':');
|
|
46
|
+
if (idx > 0) {
|
|
47
|
+
const ns = prefixes[token.slice(0, idx)];
|
|
48
|
+
if (ns) return ns + token.slice(idx + 1);
|
|
49
|
+
}
|
|
50
|
+
return base ? base + token : token;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Parse RDF/XML text into an OWLOntology. */
|
|
54
|
+
function parseRDFXML(xmlText, ontologyIRI = null) {
|
|
55
|
+
const prefixes = { rdf: NS.RDF, rdfs: NS.RDFS, owl: NS.OWL, xsd: NS.XSD };
|
|
56
|
+
|
|
57
|
+
// Collect namespace declarations.
|
|
58
|
+
const nsRe = /xmlns:([A-Za-z0-9_-]+)\s*=\s*"([^"]+)"/g;
|
|
59
|
+
let m;
|
|
60
|
+
while ((m = nsRe.exec(xmlText)) !== null) {
|
|
61
|
+
prefixes[m[1]] = m[2];
|
|
62
|
+
}
|
|
63
|
+
const baseMatch = /xml:base\s*=\s*"([^"]+)"/.exec(xmlText);
|
|
64
|
+
const base = baseMatch ? baseMatch[1] : null;
|
|
65
|
+
|
|
66
|
+
const ontIRI = ontologyIRI
|
|
67
|
+
|| (/<owl:Ontology[^>]*rdf:about="([^"]+)"/.exec(xmlText) || [])[1]
|
|
68
|
+
|| null;
|
|
69
|
+
const ont = new OWLOntology(new OWLOntologyID(ontIRI));
|
|
70
|
+
ont.format = 'RDF/XML';
|
|
71
|
+
|
|
72
|
+
// --- element scanning (flat, order-independent) --------------------------
|
|
73
|
+
// We use a simple element splitter: match top-level typed blocks, plus the
|
|
74
|
+
// generic rdf:Description style where the entity type comes from rdf:type.
|
|
75
|
+
const classBlocks = matchBlocks(xmlText, 'owl:Class');
|
|
76
|
+
const objPropBlocks = matchBlocks(xmlText, 'owl:ObjectProperty');
|
|
77
|
+
const dataPropBlocks = matchBlocks(xmlText, 'owl:DatatypeProperty');
|
|
78
|
+
const individualBlocks = matchBlocks(xmlText, 'owl:NamedIndividual');
|
|
79
|
+
|
|
80
|
+
const descBlocks = matchDescriptionBlocks(xmlText);
|
|
81
|
+
for (const b of descBlocks) {
|
|
82
|
+
// Punning: a single Description may carry MULTIPLE entity types
|
|
83
|
+
// (e.g. both owl:Class and owl:ObjectProperty). Register the block in
|
|
84
|
+
// EVERY matching category instead of breaking after the first.
|
|
85
|
+
for (const t of b.types) {
|
|
86
|
+
if (t === NS.OWL + 'Class' || t === NS.RDFS + 'Class') { classBlocks.push(b); continue; }
|
|
87
|
+
if (t === NS.OWL + 'ObjectProperty') { objPropBlocks.push(b); continue; }
|
|
88
|
+
if (t === NS.OWL + 'DatatypeProperty') { dataPropBlocks.push(b); continue; }
|
|
89
|
+
if (t === NS.OWL + 'NamedIndividual') { individualBlocks.push(b); continue; }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (const b of classBlocks) {
|
|
94
|
+
const iri = entityIRIFromTag(b.tag, base, prefixes);
|
|
95
|
+
if (!iri) continue;
|
|
96
|
+
const cls = new OWLClass(iri);
|
|
97
|
+
ont.addAxiom(new OWLDeclarationAxiom(cls));
|
|
98
|
+
parseClassBody(cls, b.body, ont, base, prefixes);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const b of objPropBlocks) {
|
|
102
|
+
const iri = entityIRIFromTag(b.tag, base, prefixes);
|
|
103
|
+
if (!iri) continue;
|
|
104
|
+
const p = new OWLObjectProperty(iri);
|
|
105
|
+
ont.addAxiom(new OWLDeclarationAxiom(p));
|
|
106
|
+
parsePropertyBody(p, b.body, ont, base, prefixes, true);
|
|
107
|
+
applyCharacteristics(p, b.body, ont, base, prefixes, true);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (const b of dataPropBlocks) {
|
|
111
|
+
const iri = entityIRIFromTag(b.tag, base, prefixes);
|
|
112
|
+
if (!iri) continue;
|
|
113
|
+
const p = new OWLDataProperty(iri);
|
|
114
|
+
ont.addAxiom(new OWLDeclarationAxiom(p));
|
|
115
|
+
parsePropertyBody(p, b.body, ont, base, prefixes, false);
|
|
116
|
+
applyCharacteristics(p, b.body, ont, base, prefixes, false);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (const b of individualBlocks) {
|
|
120
|
+
const iri = entityIRIFromTag(b.tag, base, prefixes);
|
|
121
|
+
if (!iri) continue;
|
|
122
|
+
const ind = new OWLNamedIndividual(iri);
|
|
123
|
+
ont.addAxiom(new OWLDeclarationAxiom(ind));
|
|
124
|
+
parseIndividualBody(ind, b.body, ont, base, prefixes);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return ont;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// --- helpers ---------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
function matchBlocks(xml, tagName) {
|
|
133
|
+
const blocks = [];
|
|
134
|
+
// Self-closing: <owl:Class rdf:about="..."/>
|
|
135
|
+
const selfRe = new RegExp(`<${tagName}([^>]*)/>`, 'g');
|
|
136
|
+
let m;
|
|
137
|
+
while ((m = selfRe.exec(xml)) !== null) {
|
|
138
|
+
blocks.push({ tag: m[1], body: '' });
|
|
139
|
+
}
|
|
140
|
+
// Paired: <owl:Class rdf:about="..."> ... </owl:Class>
|
|
141
|
+
const pairRe = new RegExp(`<${tagName}([^>]*)>([\\s\\S]*?)</${tagName}>`, 'g');
|
|
142
|
+
while ((m = pairRe.exec(xml)) !== null) {
|
|
143
|
+
blocks.push({ tag: m[1], body: m[2] });
|
|
144
|
+
}
|
|
145
|
+
return blocks;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Also support the generic `rdf:Description` style where the entity type is
|
|
150
|
+
* given by an inner `<rdf:type rdf:resource="...#Class"/>` triple. Returns
|
|
151
|
+
* blocks in the same {tag, body} shape but with a derived `type` field.
|
|
152
|
+
*/
|
|
153
|
+
function matchDescriptionBlocks(xml) {
|
|
154
|
+
const blocks = [];
|
|
155
|
+
const pairRe = /<rdf:Description([^>]*)>([\s\S]*?)<\/rdf:Description>/g;
|
|
156
|
+
let m;
|
|
157
|
+
while ((m = pairRe.exec(xml)) !== null) {
|
|
158
|
+
const attrs = m[1];
|
|
159
|
+
const body = m[2];
|
|
160
|
+
// Collect ALL rdf:type values (an individual may have several types).
|
|
161
|
+
const types = [];
|
|
162
|
+
const tRe = /<rdf:type[^>]*rdf:resource="([^"]+)"/g;
|
|
163
|
+
let tm;
|
|
164
|
+
while ((tm = tRe.exec(body)) !== null) types.push(tm[1]);
|
|
165
|
+
if (!types.length) continue;
|
|
166
|
+
blocks.push({ tag: attrs, body, types });
|
|
167
|
+
}
|
|
168
|
+
return blocks;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function entityIRIFromTag(tagAttrs, base, prefixes) {
|
|
172
|
+
const about = /rdf:about="([^"]+)"/.exec(tagAttrs);
|
|
173
|
+
if (about) return expandIRI(about[1], base, prefixes);
|
|
174
|
+
const id = /rdf:ID="([^"]+)"/.exec(tagAttrs);
|
|
175
|
+
if (id) return base ? base + '#' + id[1] : '#' + id[1];
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function resourcesOf(body, tagName) {
|
|
180
|
+
const out = [];
|
|
181
|
+
const re = new RegExp(`<${tagName}[^>]*rdf:resource="([^"]+)"`, 'g');
|
|
182
|
+
let m;
|
|
183
|
+
while ((m = re.exec(body)) !== null) out.push(m[1]);
|
|
184
|
+
return out;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function literalsOf(body, tagName) {
|
|
188
|
+
const out = [];
|
|
189
|
+
const re = new RegExp(`<${tagName}[^>]*>([^<]*)</${tagName}>`, 'g');
|
|
190
|
+
let m;
|
|
191
|
+
while ((m = re.exec(body)) !== null) out.push(m[1].trim());
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function parseClassBody(cls, body, ont, base, prefixes) {
|
|
196
|
+
for (const r of resourcesOf(body, 'rdfs:subClassOf')) {
|
|
197
|
+
const supIRI = expandIRI(r, base, prefixes);
|
|
198
|
+
ont.addAxiom(new OWLDeclarationAxiom(new OWLClass(supIRI)));
|
|
199
|
+
ont.addAxiom(new OWLSubClassOfAxiom(cls, new OWLClass(supIRI)));
|
|
200
|
+
}
|
|
201
|
+
for (const r of resourcesOf(body, 'owl:equivalentClass')) {
|
|
202
|
+
const eqIRI = expandIRI(r, base, prefixes);
|
|
203
|
+
ont.addAxiom(new OWLDeclarationAxiom(new OWLClass(eqIRI)));
|
|
204
|
+
ont.addAxiom(new OWLEquivalentClassesAxiom([cls, new OWLClass(eqIRI)]));
|
|
205
|
+
}
|
|
206
|
+
for (const r of resourcesOf(body, 'owl:disjointWith')) {
|
|
207
|
+
const dIRI = expandIRI(r, base, prefixes);
|
|
208
|
+
ont.addAxiom(new OWLDeclarationAxiom(new OWLClass(dIRI)));
|
|
209
|
+
ont.addAxiom(new OWLDisjointClassesAxiom([cls, new OWLClass(dIRI)]));
|
|
210
|
+
}
|
|
211
|
+
addLabels(cls.getIRI().toString(), body, ont);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function parsePropertyBody(prop, body, ont, base, prefixes, isObject) {
|
|
215
|
+
const subTag = 'rdfs:subPropertyOf';
|
|
216
|
+
const subType = isObject ? OWLSubObjectPropertyOfAxiom : OWLSubDataPropertyOfAxiom;
|
|
217
|
+
const mk = isObject ? (i) => new OWLObjectProperty(i) : (i) => new OWLDataProperty(i);
|
|
218
|
+
for (const r of resourcesOf(body, subTag)) {
|
|
219
|
+
const supIRI = expandIRI(r, base, prefixes);
|
|
220
|
+
ont.addAxiom(new OWLDeclarationAxiom(mk(supIRI)));
|
|
221
|
+
ont.addAxiom(new subType(prop, mk(supIRI)));
|
|
222
|
+
}
|
|
223
|
+
for (const r of resourcesOf(body, 'rdfs:domain')) {
|
|
224
|
+
const dIRI = expandIRI(r, base, prefixes);
|
|
225
|
+
const dCls = new OWLClass(dIRI);
|
|
226
|
+
ont.addAxiom(new OWLDeclarationAxiom(dCls));
|
|
227
|
+
ont.addAxiom(isObject
|
|
228
|
+
? new OWLObjectPropertyDomainAxiom(prop, dCls)
|
|
229
|
+
: new OWLDataPropertyDomainAxiom(prop, dCls));
|
|
230
|
+
}
|
|
231
|
+
for (const r of resourcesOf(body, 'rdfs:range')) {
|
|
232
|
+
const rIRI = expandIRI(r, base, prefixes);
|
|
233
|
+
const rCls = new OWLClass(rIRI);
|
|
234
|
+
ont.addAxiom(new OWLDeclarationAxiom(rCls));
|
|
235
|
+
if (isObject) ont.addAxiom(new OWLObjectPropertyRangeAxiom(prop, rCls));
|
|
236
|
+
}
|
|
237
|
+
if (isObject) {
|
|
238
|
+
for (const r of resourcesOf(body, 'owl:inverseOf')) {
|
|
239
|
+
const invIRI = expandIRI(r, base, prefixes);
|
|
240
|
+
const invProp = new OWLObjectProperty(invIRI);
|
|
241
|
+
ont.addAxiom(new OWLDeclarationAxiom(invProp));
|
|
242
|
+
ont.addAxiom(new OWLInverseObjectPropertiesAxiom(prop, invProp));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
addLabels(prop.getIRI().toString(), body, ont);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Property characteristics expressed as rdf:type of the property node.
|
|
249
|
+
const CHARACTERISTIC_TYPES = {
|
|
250
|
+
[NS.OWL + 'FunctionalProperty']: (p, ont, isObject) => {
|
|
251
|
+
ont.addAxiom(isObject
|
|
252
|
+
? new OWLFunctionalObjectPropertyAxiom(p)
|
|
253
|
+
: new OWLFunctionalDataPropertyAxiom(p));
|
|
254
|
+
},
|
|
255
|
+
[NS.OWL + 'InverseFunctionalProperty']: (p, ont) => {
|
|
256
|
+
ont.addAxiom(new OWLInverseFunctionalObjectPropertyAxiom(p));
|
|
257
|
+
},
|
|
258
|
+
[NS.OWL + 'TransitiveProperty']: (p, ont) => {
|
|
259
|
+
ont.addAxiom(new OWLTransitiveObjectPropertyAxiom(p));
|
|
260
|
+
},
|
|
261
|
+
[NS.OWL + 'SymmetricProperty']: (p, ont) => {
|
|
262
|
+
ont.addAxiom(new OWLSymmetricObjectPropertyAxiom(p));
|
|
263
|
+
},
|
|
264
|
+
[NS.OWL + 'AsymmetricProperty']: (p, ont) => {
|
|
265
|
+
ont.addAxiom(new OWLAsymmetricObjectPropertyAxiom(p));
|
|
266
|
+
},
|
|
267
|
+
[NS.OWL + 'ReflexiveProperty']: (p, ont) => {
|
|
268
|
+
ont.addAxiom(new OWLReflexiveObjectPropertyAxiom(p));
|
|
269
|
+
},
|
|
270
|
+
[NS.OWL + 'IrreflexiveProperty']: (p, ont) => {
|
|
271
|
+
ont.addAxiom(new OWLIrreflexiveObjectPropertyAxiom(p));
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
function applyCharacteristics(prop, body, ont, base, prefixes, isObject) {
|
|
276
|
+
for (const r of resourcesOf(body, 'rdf:type')) {
|
|
277
|
+
const tIRI = expandIRI(r, base, prefixes);
|
|
278
|
+
const fn = CHARACTERISTIC_TYPES[tIRI];
|
|
279
|
+
if (fn) fn(prop, ont, isObject);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function parseIndividualBody(ind, body, ont, base, prefixes) {
|
|
284
|
+
for (const r of resourcesOf(body, 'rdf:type')) {
|
|
285
|
+
const tIRI = expandIRI(r, base, prefixes);
|
|
286
|
+
if (tIRI === NS.OWL + 'NamedIndividual') continue;
|
|
287
|
+
const tCls = new OWLClass(tIRI);
|
|
288
|
+
ont.addAxiom(new OWLDeclarationAxiom(tCls));
|
|
289
|
+
ont.addAxiom(new OWLClassAssertionAxiom(ind, tCls));
|
|
290
|
+
}
|
|
291
|
+
for (const r of resourcesOf(body, 'owl:sameAs')) {
|
|
292
|
+
const oIRI = expandIRI(r, base, prefixes);
|
|
293
|
+
ont.addAxiom(new OWLSameIndividualAxiom([ind, new OWLNamedIndividual(oIRI)]));
|
|
294
|
+
}
|
|
295
|
+
for (const r of resourcesOf(body, 'owl:differentFrom')) {
|
|
296
|
+
const oIRI = expandIRI(r, base, prefixes);
|
|
297
|
+
ont.addAxiom(new OWLDifferentIndividualsAxiom([ind, new OWLNamedIndividual(oIRI)]));
|
|
298
|
+
}
|
|
299
|
+
addLabels(ind.getIRI().toString(), body, ont);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function addLabels(subjectIRI, body, ont) {
|
|
303
|
+
for (const text of literalsOf(body, 'rdfs:label')) {
|
|
304
|
+
ont.addAxiom(new OWLAnnotationAssertionAxiom(
|
|
305
|
+
subjectIRI,
|
|
306
|
+
new OWLAnnotationProperty(NS.RDFS + 'label'),
|
|
307
|
+
new OWLLiteral(text)
|
|
308
|
+
));
|
|
309
|
+
}
|
|
310
|
+
for (const text of literalsOf(body, 'rdfs:comment')) {
|
|
311
|
+
ont.addAxiom(new OWLAnnotationAssertionAxiom(
|
|
312
|
+
subjectIRI,
|
|
313
|
+
new OWLAnnotationProperty(NS.RDFS + 'comment'),
|
|
314
|
+
new OWLLiteral(text)
|
|
315
|
+
));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
module.exports = { parseRDFXML, NS };
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// io/RDFXMLWriter — serialize an OWLOntology to RDF/XML.
|
|
5
|
+
// Compact writer covering the common axiom shapes; counterpart to
|
|
6
|
+
// RDFXMLParser. Produces rdf:RDF with owl:Class / owl:ObjectProperty
|
|
7
|
+
// elements and rdf:Description-based assertions.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
const { ClassExpressionType: T } = require('../model/OWLClassExpression');
|
|
11
|
+
const { AxiomType: A } = require('../model/OWLAxiom');
|
|
12
|
+
|
|
13
|
+
const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
14
|
+
const RDFS = 'http://www.w3.org/2000/01/rdf-schema#';
|
|
15
|
+
const OWL = 'http://www.w3.org/2002/07/owl#';
|
|
16
|
+
const XSD = 'http://www.w3.org/2001/XMLSchema#';
|
|
17
|
+
|
|
18
|
+
function esc(s) {
|
|
19
|
+
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function iriOf(x) {
|
|
23
|
+
return x && x.getIRI ? x.getIRI().toString() : String(x);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function litXML(l) {
|
|
27
|
+
const v = esc(l.lexicalValue !== undefined ? l.lexicalValue : l.getLiteral());
|
|
28
|
+
const dt = l.datatype ? iriOf(l.datatype) : null;
|
|
29
|
+
const lang = l.lang || null;
|
|
30
|
+
if (lang) return ` xml:lang="${esc(lang)}">${v}`;
|
|
31
|
+
if (dt && dt !== XSD + 'string') return ` rdf:datatype="${esc(dt)}">${v}`;
|
|
32
|
+
return `>${v}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class RDFXMLWriter {
|
|
36
|
+
constructor(ont) {
|
|
37
|
+
this.ont = ont;
|
|
38
|
+
this.out = [];
|
|
39
|
+
this.bn = 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
write() {
|
|
43
|
+
const o = this.ont;
|
|
44
|
+
const id = o.getOntologyID();
|
|
45
|
+
const oIRI = id && id.ontologyIRI ? iriOf(id.ontologyIRI) : null;
|
|
46
|
+
|
|
47
|
+
this.out.push('<?xml version="1.0"?>');
|
|
48
|
+
this.out.push(`<rdf:RDF xmlns:rdf="${RDF}"`);
|
|
49
|
+
this.out.push(` xmlns:rdfs="${RDFS}"`);
|
|
50
|
+
this.out.push(` xmlns:owl="${OWL}"`);
|
|
51
|
+
this.out.push(` xmlns:xsd="${XSD}"${oIRI ? `\n xml:base="${esc(oIRI)}"` : ''}>`);
|
|
52
|
+
|
|
53
|
+
if (oIRI) {
|
|
54
|
+
this.out.push(` <owl:Ontology rdf:about="${esc(oIRI)}">`);
|
|
55
|
+
for (const imp of (o.imports || [])) {
|
|
56
|
+
this.out.push(` <owl:imports rdf:resource="${esc(iriOf(imp))}"/>`);
|
|
57
|
+
}
|
|
58
|
+
this.out.push(` </owl:Ontology>`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (const ax of o.getAxioms()) {
|
|
62
|
+
this._axiom(ax);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.out.push('</rdf:RDF>');
|
|
66
|
+
return this.out.join('\n') + '\n';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_bnode() { return 'b' + (this.bn++); }
|
|
70
|
+
|
|
71
|
+
// class expression → nested XML (returns string to embed)
|
|
72
|
+
_ce(e, indent) {
|
|
73
|
+
const pad = ' '.repeat(indent);
|
|
74
|
+
if (!e) return '';
|
|
75
|
+
if (e.getIRI) return `<rdf:Description rdf:about="${esc(iriOf(e))}"/>`;
|
|
76
|
+
switch (e.type) {
|
|
77
|
+
case T.OBJECT_SOME_VALUES_FROM:
|
|
78
|
+
return `<owl:Restriction><owl:onProperty rdf:resource="${esc(iriOf(e.property))}"/><owl:someValuesFrom rdf:resource="${esc(iriOf(e.filler))}"/></owl:Restriction>`;
|
|
79
|
+
case T.OBJECT_ALL_VALUES_FROM:
|
|
80
|
+
return `<owl:Restriction><owl:onProperty rdf:resource="${esc(iriOf(e.property))}"/><owl:allValuesFrom rdf:resource="${esc(iriOf(e.filler))}"/></owl:Restriction>`;
|
|
81
|
+
case T.OBJECT_HAS_VALUE:
|
|
82
|
+
return `<owl:Restriction><owl:onProperty rdf:resource="${esc(iriOf(e.property))}"/><owl:hasValue rdf:resource="${esc(iriOf(e.value))}"/></owl:Restriction>`;
|
|
83
|
+
case T.OBJECT_INTERSECTION_OF: {
|
|
84
|
+
const items = e.operands.map(x => `<rdf:Description rdf:about="${esc(iriOf(x))}"/>`).join('');
|
|
85
|
+
return `<owl:Class><owl:intersectionOf rdf:parseType="Collection">${items}</owl:intersectionOf></owl:Class>`;
|
|
86
|
+
}
|
|
87
|
+
default:
|
|
88
|
+
return `<rdf:Description rdf:about="${esc(iriOf(e))}"/>`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
_axiom(ax) {
|
|
93
|
+
switch (ax.getAxiomType()) {
|
|
94
|
+
case A.DECLARATION: {
|
|
95
|
+
const e = ax.entity;
|
|
96
|
+
const tagMap = {
|
|
97
|
+
OWLClass: 'owl:Class',
|
|
98
|
+
OWLObjectProperty: 'owl:ObjectProperty',
|
|
99
|
+
OWLDataProperty: 'owl:DatatypeProperty',
|
|
100
|
+
OWLNamedIndividual: 'owl:NamedIndividual',
|
|
101
|
+
OWLAnnotationProperty: 'owl:AnnotationProperty',
|
|
102
|
+
OWLDatatype: 'rdfs:Datatype'
|
|
103
|
+
};
|
|
104
|
+
const tag = tagMap[e.constructor.name];
|
|
105
|
+
if (tag) this.out.push(` <${tag} rdf:about="${esc(iriOf(e))}"/>`);
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case A.SUBCLASS_OF: {
|
|
109
|
+
const sub = ax.subClass, sup = ax.superClass;
|
|
110
|
+
if (sub.getIRI) {
|
|
111
|
+
if (sup.getIRI) {
|
|
112
|
+
this.out.push(` <owl:Class rdf:about="${esc(iriOf(sub))}"><rdfs:subClassOf rdf:resource="${esc(iriOf(sup))}"/></owl:Class>`);
|
|
113
|
+
} else {
|
|
114
|
+
this.out.push(` <owl:Class rdf:about="${esc(iriOf(sub))}"><rdfs:subClassOf>${this._ce(sup, 4)}</rdfs:subClassOf></owl:Class>`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
case A.EQUIVALENT_CLASSES: {
|
|
120
|
+
const ces = ax.classExpressions;
|
|
121
|
+
for (let i = 0; i < ces.length - 1; i++) {
|
|
122
|
+
if (ces[i].getIRI && ces[i + 1].getIRI) {
|
|
123
|
+
this.out.push(` <owl:Class rdf:about="${esc(iriOf(ces[i]))}"><owl:equivalentClass rdf:resource="${esc(iriOf(ces[i + 1]))}"/></owl:Class>`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case A.DISJOINT_CLASSES: {
|
|
129
|
+
const ces = ax.classExpressions;
|
|
130
|
+
for (let i = 0; i < ces.length; i++) {
|
|
131
|
+
for (let j = i + 1; j < ces.length; j++) {
|
|
132
|
+
if (ces[i].getIRI && ces[j].getIRI) {
|
|
133
|
+
this.out.push(` <owl:Class rdf:about="${esc(iriOf(ces[i]))}"><owl:disjointWith rdf:resource="${esc(iriOf(ces[j]))}"/></owl:Class>`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case A.OBJECT_PROPERTY_DOMAIN:
|
|
140
|
+
if (ax.domain.getIRI) this.out.push(` <owl:ObjectProperty rdf:about="${esc(iriOf(ax.property))}"><rdfs:domain rdf:resource="${esc(iriOf(ax.domain))}"/></owl:ObjectProperty>`);
|
|
141
|
+
break;
|
|
142
|
+
case A.OBJECT_PROPERTY_RANGE:
|
|
143
|
+
if (ax.range.getIRI) this.out.push(` <owl:ObjectProperty rdf:about="${esc(iriOf(ax.property))}"><rdfs:range rdf:resource="${esc(iriOf(ax.range))}"/></owl:ObjectProperty>`);
|
|
144
|
+
break;
|
|
145
|
+
case A.SUB_OBJECT_PROPERTY_OF:
|
|
146
|
+
this.out.push(` <owl:ObjectProperty rdf:about="${esc(iriOf(ax.subProperty))}"><rdfs:subPropertyOf rdf:resource="${esc(iriOf(ax.superProperty))}"/></owl:ObjectProperty>`);
|
|
147
|
+
break;
|
|
148
|
+
case A.INVERSE_OBJECT_PROPERTIES:
|
|
149
|
+
this.out.push(` <owl:ObjectProperty rdf:about="${esc(iriOf(ax.property1))}"><owl:inverseOf rdf:resource="${esc(iriOf(ax.property2))}"/></owl:ObjectProperty>`);
|
|
150
|
+
break;
|
|
151
|
+
case A.FUNCTIONAL_OBJECT_PROPERTY:
|
|
152
|
+
this.out.push(` <owl:ObjectProperty rdf:about="${esc(iriOf(ax.property))}"><rdf:type rdf:resource="${OWL}FunctionalProperty"/></owl:ObjectProperty>`);
|
|
153
|
+
break;
|
|
154
|
+
case A.TRANSITIVE_OBJECT_PROPERTY:
|
|
155
|
+
this.out.push(` <owl:ObjectProperty rdf:about="${esc(iriOf(ax.property))}"><rdf:type rdf:resource="${OWL}TransitiveProperty"/></owl:ObjectProperty>`);
|
|
156
|
+
break;
|
|
157
|
+
case A.CLASS_ASSERTION:
|
|
158
|
+
this.out.push(` <owl:NamedIndividual rdf:about="${esc(iriOf(ax.individual))}"><rdf:type rdf:resource="${esc(iriOf(ax.classExpression))}"/></owl:NamedIndividual>`);
|
|
159
|
+
break;
|
|
160
|
+
case A.OBJECT_PROPERTY_ASSERTION: {
|
|
161
|
+
// Use rdf:Description with property element
|
|
162
|
+
this.out.push(` <rdf:Description rdf:about="${esc(iriOf(ax.subject))}"><ns0:${localName(iriOf(ax.property))} xmlns:ns0="${namespaceOf(iriOf(ax.property))}" rdf:resource="${esc(iriOf(ax.object))}"/></rdf:Description>`);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case A.SAME_INDIVIDUAL: {
|
|
166
|
+
const inds = ax.individuals;
|
|
167
|
+
for (let i = 0; i < inds.length - 1; i++) {
|
|
168
|
+
this.out.push(` <rdf:Description rdf:about="${esc(iriOf(inds[i]))}"><owl:sameAs rdf:resource="${esc(iriOf(inds[i + 1]))}"/></rdf:Description>`);
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
default:
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function localName(iri) {
|
|
179
|
+
const i = Math.max(iri.lastIndexOf('#'), iri.lastIndexOf('/'));
|
|
180
|
+
return i >= 0 ? iri.slice(i + 1) : iri;
|
|
181
|
+
}
|
|
182
|
+
function namespaceOf(iri) {
|
|
183
|
+
const i = Math.max(iri.lastIndexOf('#'), iri.lastIndexOf('/'));
|
|
184
|
+
return i >= 0 ? iri.slice(0, i + 1) : iri;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Serialize an OWLOntology to RDF/XML.
|
|
189
|
+
* @param {OWLOntology} ont
|
|
190
|
+
* @returns {string}
|
|
191
|
+
*/
|
|
192
|
+
function writeRDFXML(ont) {
|
|
193
|
+
return new RDFXMLWriter(ont).write();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
module.exports = { writeRDFXML, RDFXMLWriter };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// io/SWRLParser — parse Protégé-style SWRL text rules into SWRLRule objects.
|
|
5
|
+
// Syntax: Antecedent ^ Antecedent ... -> Consequent ^ Consequent ...
|
|
6
|
+
// Atoms:
|
|
7
|
+
// Class(?x) → SWRLClassAtom
|
|
8
|
+
// prop(?x, ?y) → ObjectPropertyAtom or DataPropertyAtom (resolved)
|
|
9
|
+
// sameAs(?x, ?y) → SWRLSameAsAtom
|
|
10
|
+
// differentFrom(?x,?y) → SWRLDifferentFromAtom
|
|
11
|
+
// builtin(?x, "lit") → SWRLBuiltInAtom (swrlb namespace)
|
|
12
|
+
// Variables: ?name. Individuals/IRIs: prefixed name or <iri> or bare token.
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
SWRLRule, SWRLVariable, SWRLClassAtom, SWRLObjectPropertyAtom,
|
|
17
|
+
SWRLDataPropertyAtom, SWRLSameAsAtom, SWRLDifferentFromAtom,
|
|
18
|
+
SWRLBuiltInAtom, SWRLB_NS
|
|
19
|
+
} = require('../model/SWRL');
|
|
20
|
+
const {
|
|
21
|
+
OWLClass, OWLObjectProperty, OWLDataProperty, OWLNamedIndividual
|
|
22
|
+
} = require('../model/OWLEntity');
|
|
23
|
+
const { OWLLiteral } = require('../model/OWLLiteral');
|
|
24
|
+
const { IRI } = require('../model/IRI');
|
|
25
|
+
|
|
26
|
+
const DEFAULT_PREFIXES = {
|
|
27
|
+
rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
|
28
|
+
rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
|
|
29
|
+
owl: 'http://www.w3.org/2002/07/owl#',
|
|
30
|
+
xsd: 'http://www.w3.org/2001/XMLSchema#',
|
|
31
|
+
swrlb: SWRLB_NS
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
class SWRLParser {
|
|
35
|
+
/**
|
|
36
|
+
* @param {Object} [opts]
|
|
37
|
+
* @param {Object<string,string>} [opts.prefixes] extra prefix map
|
|
38
|
+
* @param {(iri:string)=>('class'|'objectProperty'|'dataProperty'|'individual'|null)} [opts.resolve]
|
|
39
|
+
* Resolve an entity IRI to its kind so that prop(?x,?y) can be typed.
|
|
40
|
+
*/
|
|
41
|
+
constructor(opts = {}) {
|
|
42
|
+
this.prefixes = Object.assign({}, DEFAULT_PREFIXES, opts.prefixes || {});
|
|
43
|
+
this.resolve = opts.resolve || (() => null);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
expandIRI(token) {
|
|
47
|
+
if (token.startsWith('<') && token.endsWith('>')) return token.slice(1, -1);
|
|
48
|
+
if (token.startsWith('http://') || token.startsWith('https://') || token.startsWith('urn:')) return token;
|
|
49
|
+
const idx = token.indexOf(':');
|
|
50
|
+
if (idx > 0) {
|
|
51
|
+
const ns = this.prefixes[token.slice(0, idx)];
|
|
52
|
+
if (ns) return ns + token.slice(idx + 1);
|
|
53
|
+
}
|
|
54
|
+
return token;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Parse a single SWRL rule string.
|
|
59
|
+
* @param {string} text
|
|
60
|
+
* @returns {SWRLRule}
|
|
61
|
+
*/
|
|
62
|
+
parse(text) {
|
|
63
|
+
const ruleText = text.trim();
|
|
64
|
+
const arrow = ruleText.indexOf('->');
|
|
65
|
+
if (arrow < 0) throw new Error('SWRL rule missing "->": ' + ruleText);
|
|
66
|
+
const bodyText = ruleText.slice(0, arrow).trim();
|
|
67
|
+
const headText = ruleText.slice(arrow + 2).trim();
|
|
68
|
+
const body = this._parseAtomList(bodyText);
|
|
69
|
+
const head = this._parseAtomList(headText);
|
|
70
|
+
return new SWRLRule(body, head);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Parse several rules separated by newlines or '. ' boundaries. */
|
|
74
|
+
parseAll(text) {
|
|
75
|
+
const rules = [];
|
|
76
|
+
// Split on newlines that contain '->'
|
|
77
|
+
for (const line of text.split(/\r?\n/)) {
|
|
78
|
+
const t = line.trim();
|
|
79
|
+
if (!t || t.startsWith('#') || t.startsWith('//')) continue;
|
|
80
|
+
if (!t.includes('->')) continue;
|
|
81
|
+
rules.push(this.parse(t));
|
|
82
|
+
}
|
|
83
|
+
return rules;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_parseAtomList(text) {
|
|
87
|
+
const atoms = [];
|
|
88
|
+
// Split on '^' at top level (not inside parens/strings)
|
|
89
|
+
let depth = 0, inStr = false, cur = '';
|
|
90
|
+
for (let i = 0; i < text.length; i++) {
|
|
91
|
+
const ch = text[i];
|
|
92
|
+
if (ch === '"') inStr = !inStr;
|
|
93
|
+
if (!inStr && ch === '(') depth++;
|
|
94
|
+
if (!inStr && ch === ')') depth--;
|
|
95
|
+
if (!inStr && depth === 0 && ch === '^') {
|
|
96
|
+
atoms.push(this._atom(cur.trim()));
|
|
97
|
+
cur = '';
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
cur += ch;
|
|
101
|
+
}
|
|
102
|
+
if (cur.trim()) atoms.push(this._atom(cur.trim()));
|
|
103
|
+
return atoms;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
_atom(text) {
|
|
107
|
+
const m = /^([\w:<][\w:.\-<>/]*)\(([^)]*)\)$/.exec(text.trim());
|
|
108
|
+
if (!m) throw new Error('Malformed SWRL atom: ' + text);
|
|
109
|
+
const name = m[1];
|
|
110
|
+
const args = m[2].split(',').map(s => s.trim()).filter(Boolean).map(a => this._arg(a));
|
|
111
|
+
|
|
112
|
+
const iri = this.expandIRI(name);
|
|
113
|
+
if (iri === 'http://www.w3.org/2002/07/owl#sameAs' || name === 'sameAs') {
|
|
114
|
+
return new SWRLSameAsAtom(args[0], args[1]);
|
|
115
|
+
}
|
|
116
|
+
if (iri === 'http://www.w3.org/2002/07/owl#differentFrom' || name === 'differentFrom') {
|
|
117
|
+
return new SWRLDifferentFromAtom(args[0], args[1]);
|
|
118
|
+
}
|
|
119
|
+
if (name.startsWith('swrlb:') || this.prefixes.swrlb && iri.startsWith(SWRLB_NS)) {
|
|
120
|
+
return new SWRLBuiltInAtom(IRI.create(iri), args);
|
|
121
|
+
}
|
|
122
|
+
const kind = this.resolve(iri);
|
|
123
|
+
if (kind === 'class' || (!kind && args.length === 1)) {
|
|
124
|
+
return new SWRLClassAtom(new OWLClass(iri), args[0]);
|
|
125
|
+
}
|
|
126
|
+
if (kind === 'dataProperty') {
|
|
127
|
+
return new SWRLDataPropertyAtom(new OWLDataProperty(iri), args[0], args[1]);
|
|
128
|
+
}
|
|
129
|
+
// default: object property
|
|
130
|
+
return new SWRLObjectPropertyAtom(new OWLObjectProperty(iri), args[0], args[1]);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
_arg(token) {
|
|
134
|
+
if (token.startsWith('?')) return new SWRLVariable(IRI.create('urn:swrl:var:' + token.slice(1)));
|
|
135
|
+
// Literal "..." or "..."^^dt
|
|
136
|
+
if (token.startsWith('"')) {
|
|
137
|
+
const m = /^"((?:[^"\\]|\\.)*)"(?:\^\^(.+))?$/.exec(token);
|
|
138
|
+
const lex = m ? m[1] : token.slice(1, -1);
|
|
139
|
+
let dt = null;
|
|
140
|
+
if (m && m[2]) {
|
|
141
|
+
const { OWLDatatype } = require('../model/OWLEntity');
|
|
142
|
+
dt = new OWLDatatype(this.expandIRI(m[2]));
|
|
143
|
+
}
|
|
144
|
+
return new OWLLiteral(lex, dt);
|
|
145
|
+
}
|
|
146
|
+
return new OWLNamedIndividual(this.expandIRI(token));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = { SWRLParser };
|