diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bb079a62..005d2e0d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed +- Inherit OWLDocumentFormat when performing SPARQL update [#1267] - Updated obographs to [version 0.3.2](https://github.com/geneontology/obographs/releases/tag/v0.3.2) - ## [1.9.8] - 2025-05-15 ### Added diff --git a/docs/examples/nucleus.owl b/docs/examples/nucleus.owl index 186fd1fb5..3d6b78faf 100644 --- a/docs/examples/nucleus.owl +++ b/docs/examples/nucleus.owl @@ -3,6 +3,7 @@ Prefix: rdf: Prefix: xml: Prefix: xsd: Prefix: rdfs: +Prefix: foo: # This prefix declaration should survive the SPARQL update roundtrip to OWL @@ -11,178 +12,178 @@ Ontology: AnnotationProperty: rdfs:label - + Datatype: xsd:string - + ObjectProperty: - Characteristics: + Characteristics: Transitive - - + + Class: - Annotations: + Annotations: rdfs:label "cell" - - SubClassOf: + + SubClassOf: - - + + Class: - Annotations: + Annotations: rdfs:label "intracellular organelle" - - SubClassOf: + + SubClassOf: some , , - - + + Class: - Annotations: + Annotations: rdfs:label "cell part" - - SubClassOf: + + SubClassOf: some , - - + + Class: - Annotations: + Annotations: rdfs:label "organelle" - - SubClassOf: + + SubClassOf: - - + + Class: - Annotations: + Annotations: rdfs:label "nuclear part" - - SubClassOf: + + SubClassOf: some , - - + + Class: - Annotations: + Annotations: rdfs:label "membrane-bounded organelle" - - SubClassOf: + + SubClassOf: - - + + Class: - Annotations: + Annotations: rdfs:label "cellular_component" - - + + Class: - Annotations: + Annotations: rdfs:label "intracellular part" - - SubClassOf: + + SubClassOf: some , - - + + Class: - Annotations: + Annotations: rdfs:label "intracellular" - - SubClassOf: + + SubClassOf: - - + + Class: - Annotations: + Annotations: rdfs:label "organelle part" - - SubClassOf: + + SubClassOf: some , - - + + Class: - Annotations: + Annotations: rdfs:label "membrane-enclosed lumen" - - SubClassOf: + + SubClassOf: - - + + Class: - Annotations: + Annotations: rdfs:label "nucleus" - - SubClassOf: + + SubClassOf: - - + + Class: - Annotations: + Annotations: rdfs:label "intracellular organelle part" - - SubClassOf: + + SubClassOf: some , some , , , some - - + + Class: - Annotations: + Annotations: rdfs:label "intracellular organelle lumen" - - SubClassOf: + + SubClassOf: , some , - - + + Class: - Annotations: + Annotations: rdfs:label "intracellular membrane-bounded organelle" - - SubClassOf: + + SubClassOf: , - - + + Class: - Annotations: + Annotations: rdfs:label "nuclear lumen" - - SubClassOf: + + SubClassOf: some , , - - + + Class: - Annotations: + Annotations: rdfs:label "organelle lumen" - - SubClassOf: + + SubClassOf: , some , diff --git a/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java b/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java index a1a74442c..4c9e49006 100644 --- a/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java +++ b/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java @@ -15,6 +15,7 @@ import org.apache.jena.query.Dataset; import org.apache.jena.rdf.model.Model; import org.apache.jena.tdb.TDBFactory; +import org.semanticweb.owlapi.model.OWLDocumentFormat; import org.semanticweb.owlapi.model.OWLOntology; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -338,7 +339,10 @@ private static OWLOntology executeUpdate( catalogPath = null; } } - return QueryOperation.convertModel(model, ioHelper, catalogPath, useTemporaryFile); + + OWLDocumentFormat format = + inputOntology.getOWLOntologyManager().getOntologyFormat(inputOntology); + return QueryOperation.convertModel(model, ioHelper, catalogPath, useTemporaryFile, format); } /** diff --git a/robot-core/src/main/java/org/obolibrary/robot/QueryOperation.java b/robot-core/src/main/java/org/obolibrary/robot/QueryOperation.java index 9362530cc..6c0a888e7 100644 --- a/robot-core/src/main/java/org/obolibrary/robot/QueryOperation.java +++ b/robot-core/src/main/java/org/obolibrary/robot/QueryOperation.java @@ -267,6 +267,30 @@ public static OWLOntology convertModel(Model model, IOHelper ioHelper, String ca public static OWLOntology convertModel( Model model, IOHelper ioHelper, String catalogPath, boolean useTemporaryFile) throws IOException { + return convertModel(model, ioHelper, catalogPath, false, null); + } + + /** + * Given a Model, an IOHelper, and a path to an XML catalog, convert the model to an OWLOntology + * object. + * + * @param model Model to convert to OWLOntology + * @param ioHelper IOHelper to load ontology + * @param catalogPath String path to XML catalog + * @param useTemporaryFile whether to use a temporary file to store intermediate results or to + * keep them in memory. + * @param format The OWLDocumentFormat to use in the conversion. + * @return OWLOntology object version of model + * @throws IOException on issue loading ontology + */ + public static OWLOntology convertModel( + Model model, + IOHelper ioHelper, + String catalogPath, + boolean useTemporaryFile, + OWLDocumentFormat format) + throws IOException { + OWLOntology updatedOntology; if (useTemporaryFile) { final File tempFile = File.createTempFile("robot", ".owl"); tempFile.deleteOnExit(); @@ -274,13 +298,19 @@ public static OWLOntology convertModel( new BufferedOutputStream(new FileOutputStream(tempFile))) { RDFDataMgr.write(os, model, Lang.TTL); } - return ioHelper.loadOntology( - new BufferedInputStream(new FileInputStream(tempFile)), catalogPath); + updatedOntology = + ioHelper.loadOntology( + new BufferedInputStream(new FileInputStream(tempFile)), catalogPath); } else { ByteArrayOutputStream os = new ByteArrayOutputStream(); RDFDataMgr.write(os, model, Lang.TTL); - return ioHelper.loadOntology(new ByteArrayInputStream(os.toByteArray()), catalogPath); + updatedOntology = + ioHelper.loadOntology(new ByteArrayInputStream(os.toByteArray()), catalogPath); + } + if (format != null) { + updatedOntology.getOWLOntologyManager().setOntologyFormat(updatedOntology, format); } + return updatedOntology; } /** diff --git a/robot-core/src/test/java/org/obolibrary/robot/QueryOperationTest.java b/robot-core/src/test/java/org/obolibrary/robot/QueryOperationTest.java index df832c73b..8b247f41d 100644 --- a/robot-core/src/test/java/org/obolibrary/robot/QueryOperationTest.java +++ b/robot-core/src/test/java/org/obolibrary/robot/QueryOperationTest.java @@ -5,6 +5,7 @@ import com.google.common.collect.Lists; import java.io.*; import java.net.URISyntaxException; +import java.util.Map; import org.apache.jena.query.Dataset; import org.apache.jena.query.ResultSet; import org.apache.jena.query.ResultSetFactory; @@ -12,10 +13,13 @@ import org.apache.jena.rdf.model.*; import org.apache.jena.riot.Lang; import org.junit.Test; +import org.semanticweb.owlapi.formats.PrefixDocumentFormat; import org.semanticweb.owlapi.io.OWLOntologyCreationIOException; import org.semanticweb.owlapi.model.IRI; +import org.semanticweb.owlapi.model.OWLDocumentFormat; import org.semanticweb.owlapi.model.OWLOntology; import org.semanticweb.owlapi.model.OWLOntologyCreationException; +import org.semanticweb.owlapi.model.OWLOntologyManager; import org.semanticweb.owlapi.model.OWLOntologyStorageException; /** @@ -209,4 +213,32 @@ public void test1030CatalogIsUsedForInputIri() fail(); } } + + @Test + public void testPrefixesPreserved() + throws IOException, OWLOntologyStorageException, OWLOntologyCreationException { + OWLOntology inputOntology = loadOntology("/prefix.owl"); + OWLOntologyManager inputManager = inputOntology.getOWLOntologyManager(); + OWLDocumentFormat inputFormat = inputManager.getOntologyFormat(inputOntology); + PrefixDocumentFormat inputPrefixFormat = (PrefixDocumentFormat) inputFormat; + Map inputPrefixMap = inputPrefixFormat.getPrefixName2PrefixMap(); + + Model model = QueryOperation.loadOntologyAsModel(inputOntology); + String updateString = + "PREFIX rdfs: " + + "PREFIX s: " + + "INSERT { " + + "s:test2 rdfs:label \"test 2\" ." + + " } WHERE {}"; + QueryOperation.execUpdate(model, updateString); + + OWLOntology outputOntology = + QueryOperation.convertModel(model, new IOHelper(), null, false, inputFormat); + OWLOntologyManager outputManager = outputOntology.getOWLOntologyManager(); + OWLDocumentFormat outputFormat = outputManager.getOntologyFormat(outputOntology); + PrefixDocumentFormat outputPrefixFormat = (PrefixDocumentFormat) outputFormat; + Map outputPrefixMap = outputPrefixFormat.getPrefixName2PrefixMap(); + + assertEquals(inputPrefixMap, outputPrefixMap); + } } diff --git a/robot-core/src/test/resources/prefix.owl b/robot-core/src/test/resources/prefix.owl new file mode 100644 index 000000000..84dbd97b8 --- /dev/null +++ b/robot-core/src/test/resources/prefix.owl @@ -0,0 +1,13 @@ + + + + + +