use crate::model::{OwlDlOntology, ClassExpression, PropertyExpression, Axiom};
use fukurow_lite::model::OwlIri;
use crate::OwlDlError;
use fukurow_store::store::RdfStore;
use fukurow_lite::loader::{OntologyLoader, DefaultOntologyLoader};
use fukurow_lite::OwlLiteReasoner;
use std::collections::HashMap;
pub trait OwlDlOntologyLoader {
fn load_from_store(&self, store: &RdfStore) -> Result<OwlDlOntology, OwlDlError>;
}
pub struct DefaultOwlDlOntologyLoader {
lite_loader: DefaultOntologyLoader,
lite_reasoner: OwlLiteReasoner,
}
impl DefaultOwlDlOntologyLoader {
pub fn new() -> Self {
Self {
lite_loader: DefaultOntologyLoader,
lite_reasoner: OwlLiteReasoner::new(),
}
}
}
impl OwlDlOntologyLoader for DefaultOwlDlOntologyLoader {
fn load_from_store(&self, store: &RdfStore) -> Result<OwlDlOntology, OwlDlError> {
let lite_ontology = self.lite_reasoner.load_ontology(store)
.map_err(|e| OwlDlError::LoaderError(format!("Failed to load as OWL Lite: {}", e)))?;
let mut dl_ontology = OwlDlOntology::new();
dl_ontology.iri = lite_ontology.iri;
dl_ontology.classes = lite_ontology.classes;
dl_ontology.properties = lite_ontology.properties;
dl_ontology.individuals = lite_ontology.individuals;
for axiom in lite_ontology.axioms {
dl_ontology.add_axiom(Axiom::OwlLite(axiom));
}
self.load_dl_constructs(store, &mut dl_ontology)?;
Ok(dl_ontology)
}
}
impl DefaultOwlDlOntologyLoader {
fn load_dl_constructs(&self, store: &RdfStore, ontology: &mut OwlDlOntology) -> Result<(), OwlDlError> {
let owl_intersection_of = "http://www.w3.org/2002/07/owl#intersectionOf";
let owl_union_of = "http://www.w3.org/2002/07/owl#unionOf";
let owl_complement_of = "http://www.w3.org/2002/07/owl#complementOf";
let owl_one_of = "http://www.w3.org/2002/07/owl#oneOf";
let owl_some_values_from = "http://www.w3.org/2002/07/owl#someValuesFrom";
let owl_all_values_from = "http://www.w3.org/2002/07/owl#allValuesFrom";
let owl_has_value = "http://www.w3.org/2002/07/owl#hasValue";
let owl_min_cardinality = "http://www.w3.org/2002/07/owl#minCardinality";
let owl_max_cardinality = "http://www.w3.org/2002/07/owl#maxCardinality";
let owl_exact_cardinality = "http://www.w3.org/2002/07/owl#exactCardinality";
let owl_inverse_of = "http://www.w3.org/2002/07/owl#inverseOf";
let owl_same_as = "http://www.w3.org/2002/07/owl#sameAs";
let owl_different_from = "http://www.w3.org/2002/07/owl#differentFrom";
let mut intersection_classes = HashMap::new();
let mut union_classes = HashMap::new();
let mut complement_classes = HashMap::new();
let mut enumeration_classes = HashMap::new();
let mut restriction_classes = HashMap::new();
let mut inverse_properties = HashMap::new();
for stored_triple in store.all_triples().values().flatten() {
let triple = &stored_triple.triple;
if triple.predicate == owl_intersection_of {
intersection_classes.insert(triple.subject.clone(), triple.object.clone());
}
else if triple.predicate == owl_union_of {
union_classes.insert(triple.subject.clone(), triple.object.clone());
}
else if triple.predicate == owl_complement_of {
complement_classes.insert(triple.subject.clone(), triple.object.clone());
}
else if triple.predicate == owl_one_of {
enumeration_classes.insert(triple.subject.clone(), triple.object.clone());
}
else if triple.predicate == owl_some_values_from {
restriction_classes.entry(triple.subject.clone())
.or_insert_with(HashMap::new)
.insert("someValuesFrom".to_string(), triple.object.clone());
}
else if triple.predicate == owl_all_values_from {
restriction_classes.entry(triple.subject.clone())
.or_insert_with(HashMap::new)
.insert("allValuesFrom".to_string(), triple.object.clone());
}
else if triple.predicate == owl_has_value {
restriction_classes.entry(triple.subject.clone())
.or_insert_with(HashMap::new)
.insert("hasValue".to_string(), triple.object.clone());
}
else if triple.predicate == owl_min_cardinality {
restriction_classes.entry(triple.subject.clone())
.or_insert_with(HashMap::new)
.insert("minCardinality".to_string(), triple.object.clone());
}
else if triple.predicate == owl_max_cardinality {
restriction_classes.entry(triple.subject.clone())
.or_insert_with(HashMap::new)
.insert("maxCardinality".to_string(), triple.object.clone());
}
else if triple.predicate == owl_exact_cardinality {
restriction_classes.entry(triple.subject.clone())
.or_insert_with(HashMap::new)
.insert("exactCardinality".to_string(), triple.object.clone());
}
else if triple.predicate == owl_inverse_of {
inverse_properties.insert(triple.subject.clone(), triple.object.clone());
}
}
for (class_iri, list_iri) in intersection_classes {
if let Some(expressions) = self.parse_rdf_list(store, &list_iri) {
let class_expr = ClassExpression::IntersectionOf(
expressions.into_iter().map(|iri| self.iri_to_class_expression(&iri)).collect()
);
ontology.add_class_expression(&class_expr);
}
}
for (class_iri, list_iri) in union_classes {
if let Some(expressions) = self.parse_rdf_list(store, &list_iri) {
let class_expr = ClassExpression::UnionOf(
expressions.into_iter().map(|iri| self.iri_to_class_expression(&iri)).collect()
);
ontology.add_class_expression(&class_expr);
}
}
for (class_iri, complement_iri) in complement_classes {
let complement_expr = self.iri_to_class_expression(&complement_iri);
let class_expr = ClassExpression::ComplementOf(Box::new(complement_expr));
ontology.add_class_expression(&class_expr);
}
for (class_iri, list_iri) in enumeration_classes {
if let Some(individuals) = self.parse_individual_list(store, &list_iri) {
let class_expr = ClassExpression::OneOf(individuals);
ontology.add_class_expression(&class_expr);
}
}
for (restriction_iri, properties) in restriction_classes {
let on_property = self.find_restriction_property(store, &restriction_iri)?;
if let Some(some_values) = properties.get("someValuesFrom") {
let class_expr = self.iri_to_class_expression(some_values);
let restriction = ClassExpression::SomeValuesFrom {
property: on_property.clone(),
class: Box::new(class_expr),
};
ontology.add_class_expression(&restriction);
}
if let Some(all_values) = properties.get("allValuesFrom") {
let class_expr = self.iri_to_class_expression(all_values);
let restriction = ClassExpression::AllValuesFrom {
property: on_property.clone(),
class: Box::new(class_expr),
};
ontology.add_class_expression(&restriction);
}
if let Some(has_value) = properties.get("hasValue") {
let individual = fukurow_lite::Individual(OwlIri::new(has_value.clone()));
let restriction = ClassExpression::HasValue {
property: on_property.clone(),
individual,
};
ontology.add_class_expression(&restriction);
}
if let Some(min_card) = properties.get("minCardinality") {
if let Ok(cardinality) = min_card.parse::<u32>() {
let restriction = ClassExpression::MinCardinality {
cardinality,
property: on_property.clone(),
class: None, };
ontology.add_class_expression(&restriction);
}
}
if let Some(max_card) = properties.get("maxCardinality") {
if let Ok(cardinality) = max_card.parse::<u32>() {
let restriction = ClassExpression::MaxCardinality {
cardinality,
property: on_property.clone(),
class: None, };
ontology.add_class_expression(&restriction);
}
}
if let Some(exact_card) = properties.get("exactCardinality") {
if let Ok(cardinality) = exact_card.parse::<u32>() {
let restriction = ClassExpression::ExactCardinality {
cardinality,
property: on_property.clone(),
class: None, };
ontology.add_class_expression(&restriction);
}
}
}
for (prop_iri, inverse_iri) in inverse_properties {
let base_prop = PropertyExpression::ObjectProperty(OwlIri::new(prop_iri.clone()));
let inverse_prop = PropertyExpression::InverseOf(Box::new(base_prop));
ontology.add_property_expression(&inverse_prop);
let inverse_base = PropertyExpression::ObjectProperty(OwlIri::new(inverse_iri.clone()));
let inverse_inverse = PropertyExpression::InverseOf(Box::new(inverse_base));
ontology.add_property_expression(&inverse_inverse);
}
let rdf_type = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
let owl_named_individual = "http://www.w3.org/2002/07/owl#NamedIndividual";
let owl_object_property = "http://www.w3.org/2002/07/owl#ObjectProperty";
for stored_triple in store.all_triples().values().flatten() {
let triple = &stored_triple.triple;
if triple.predicate.starts_with("http://www.w3.org/2002/07/owl#") {
continue;
}
if triple.predicate == rdf_type {
if triple.object == owl_named_individual {
continue;
} else if triple.object == owl_object_property {
continue;
} else {
let class = fukurow_lite::Class::Named(OwlIri::new(triple.object.clone()));
let individual = fukurow_lite::Individual(OwlIri::new(triple.subject.clone()));
let axiom = Axiom::OwlLite(fukurow_lite::Axiom::ClassAssertion(class, individual));
ontology.add_axiom(axiom);
}
} else {
let subject_individual = fukurow_lite::Individual(OwlIri::new(triple.subject.clone()));
let object_individual = fukurow_lite::Individual(OwlIri::new(triple.object.clone()));
let property_expr = PropertyExpression::ObjectProperty(OwlIri::new(triple.predicate.clone()));
let axiom = Axiom::ObjectPropertyAssertion(property_expr, subject_individual, object_individual);
ontology.add_axiom(axiom);
}
}
Ok(())
}
fn parse_rdf_list(&self, store: &RdfStore, list_head: &str) -> Option<Vec<String>> {
let rdf_first = "http://www.w3.org/1999/02/22-rdf-syntax-ns#first";
let rdf_rest = "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest";
let rdf_nil = "http://www.w3.org/1999/02/22-rdf-syntax-ns#nil";
let mut result = Vec::new();
let mut current = list_head.to_string();
loop {
let mut found_first = false;
for stored_triple in store.all_triples().values().flatten() {
let triple = &stored_triple.triple;
if triple.subject == current && triple.predicate == rdf_first {
result.push(triple.object.clone());
found_first = true;
break;
}
}
if !found_first {
return None; }
let mut found_rest = false;
for stored_triple in store.all_triples().values().flatten() {
let triple = &stored_triple.triple;
if triple.subject == current && triple.predicate == rdf_rest {
if triple.object == rdf_nil {
return Some(result); }
current = triple.object.clone();
found_rest = true;
break;
}
}
if !found_rest {
return None; }
}
}
fn parse_individual_list(&self, store: &RdfStore, list_head: &str) -> Option<Vec<fukurow_lite::Individual>> {
self.parse_rdf_list(store, list_head)
.map(|iris| iris.into_iter()
.map(|iri| fukurow_lite::Individual(OwlIri::new(iri)))
.collect())
}
fn find_restriction_property(&self, store: &RdfStore, restriction_iri: &str) -> Result<PropertyExpression, OwlDlError> {
let owl_on_property = "http://www.w3.org/2002/07/owl#onProperty";
for stored_triple in store.all_triples().values().flatten() {
let triple = &stored_triple.triple;
if triple.subject == restriction_iri && triple.predicate == owl_on_property {
return Ok(PropertyExpression::ObjectProperty(OwlIri::new(triple.object.clone())));
}
}
Err(OwlDlError::LoaderError(format!("No onProperty found for restriction {}", restriction_iri)))
}
fn iri_to_class_expression(&self, iri: &str) -> ClassExpression {
if iri == "http://www.w3.org/2002/07/owl#Thing" {
ClassExpression::Thing
} else if iri == "http://www.w3.org/2002/07/owl#Nothing" {
ClassExpression::Nothing
} else {
ClassExpression::Named(OwlIri::new(iri.to_string()))
}
}
}