use crate::bridge::bridge_ontology;
use crate::error::{OwlError, Result};
use crate::OwlBridgeResult;
use horned_owl::io::rdf::reader::read;
use horned_owl::model::{RcAnnotatedComponent, RcStr};
use horned_owl::ontology::component_mapped::ComponentMappedOntology;
use horned_owl::ontology::set::SetOntology;
use ontocore_core::OntologyFormat;
use oxigraph::io::{RdfFormat, RdfSerializer};
use oxigraph::model::Quad;
use std::collections::BTreeMap;
use std::io::Cursor;
use std::path::Path;
#[derive(Debug, Clone)]
pub struct OwlLoadResult {
pub bridge: OwlBridgeResult,
pub incomplete: bool,
pub load_warning: Option<String>,
}
pub fn load_turtle_text(
path: &Path,
ontology_id: &str,
source_text: &str,
quads: &[Quad],
namespaces: &BTreeMap<String, String>,
) -> Result<OwlLoadResult> {
let _ = path;
match load_from_quads(quads) {
Ok((ontology, incomplete)) => {
let bridge = bridge_ontology(ontology, ontology_id, source_text, namespaces);
Ok(OwlLoadResult {
bridge,
incomplete,
load_warning: if incomplete {
Some("Horned-OWL reported incomplete RDF parse".to_string())
} else {
None
},
})
}
Err(e) => Err(e),
}
}
pub fn load_from_quads(
quads: &[Quad],
) -> Result<(
horned_owl::io::rdf::reader::ConcreteRDFOntology<
horned_owl::model::RcStr,
horned_owl::model::RcAnnotatedComponent,
>,
bool,
)> {
let rdf_xml = quads_to_rdf_xml(quads).map_err(OwlError::LoadFailed)?;
let mut cursor = Cursor::new(rdf_xml);
let (ontology, incomplete) =
read(&mut cursor, Default::default()).map_err(|e| OwlError::LoadFailed(e.to_string()))?;
Ok((ontology, !incomplete.is_complete()))
}
fn quads_to_rdf_xml(quads: &[Quad]) -> std::result::Result<Vec<u8>, String> {
let mut serializer = RdfSerializer::from_format(RdfFormat::RdfXml).for_writer(Vec::new());
for quad in quads {
serializer.serialize_quad(quad).map_err(|e| e.to_string())?;
}
serializer.finish().map_err(|e| e.to_string())
}
pub fn load_owx_text(
path: &Path,
ontology_id: &str,
source_text: &str,
namespaces: &BTreeMap<String, String>,
) -> Result<OwlLoadResult> {
let _ = path;
use horned_owl::io::owx::reader::read as read_owx;
let mut cursor = Cursor::new(source_text.as_bytes());
let (set_ont, _mapping): (SetOntology<RcStr>, _) = read_owx(&mut cursor, Default::default())
.map_err(|e| OwlError::LoadFailed(e.to_string()))?;
let mapped: ComponentMappedOntology<RcStr, RcAnnotatedComponent> = set_ont.into();
let bridge = bridge_ontology(mapped, ontology_id, source_text, namespaces);
Ok(OwlLoadResult { bridge, incomplete: false, load_warning: None })
}
pub fn supports_horned_load(format: OntologyFormat) -> bool {
matches!(
format,
OntologyFormat::Turtle
| OntologyFormat::Owl
| OntologyFormat::RdfXml
| OntologyFormat::OwlXml
)
}
#[cfg(test)]
mod tests {
use super::*;
use oxigraph::io::RdfParser;
#[test]
fn loads_fixture_turtle_via_horned() {
let ttl = include_str!("../../../fixtures/example.ttl");
let parser = RdfParser::from_format(RdfFormat::Turtle);
let quads: Vec<Quad> =
parser.for_reader(ttl.as_bytes()).collect::<std::result::Result<Vec<_>, _>>().unwrap();
let namespaces = BTreeMap::from([
("ex".to_string(), "http://example.org/people#".to_string()),
("owl".to_string(), "http://www.w3.org/2002/07/owl#".to_string()),
]);
let result = load_turtle_text(Path::new("example.ttl"), "doc-1", ttl, &quads, &namespaces)
.expect("load");
assert!(!result.bridge.entities.is_empty());
assert!(result.bridge.entities.iter().any(|e| e.short_name == "Person"));
}
}