From e1ffff5f8611137c78cfdf5431d24c002ce984cc Mon Sep 17 00:00:00 2001 From: Jim Balhoff Date: Wed, 22 Oct 2025 12:46:21 -0400 Subject: [PATCH 1/5] Inherit OWLDocument format when performing SPARQL update. --- .../main/java/org/obolibrary/robot/QueryCommand.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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..8e999d703 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,14 @@ private static OWLOntology executeUpdate( catalogPath = null; } } - return QueryOperation.convertModel(model, ioHelper, catalogPath, useTemporaryFile); + OWLOntology updatedOntology = + QueryOperation.convertModel(model, ioHelper, catalogPath, useTemporaryFile); + OWLDocumentFormat inputFormat = + inputOntology.getOWLOntologyManager().getOntologyFormat(inputOntology); + if (inputFormat != null) { + updatedOntology.getOWLOntologyManager().setOntologyFormat(updatedOntology, inputFormat); + } + return updatedOntology; } /** From 8fb51f3e79e36568f83d6e24d454eaefc9b61702 Mon Sep 17 00:00:00 2001 From: Jim Balhoff Date: Wed, 22 Oct 2025 12:52:54 -0400 Subject: [PATCH 2/5] Update CHANGELOG. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8f393e5f..11b0f2540 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed +- Inherit OWLDocumentFormat when performing SPARQL update [#1267] + ## [1.9.8] - 2025-05-15 ### Added From 5c0d7e6356c37e7683f36ae7ca9e6cad1f129878 Mon Sep 17 00:00:00 2001 From: Jim Balhoff Date: Wed, 29 Oct 2025 12:30:13 -0400 Subject: [PATCH 3/5] Add test prefix to update example. --- docs/examples/nucleus.owl | 173 +++++++++--------- .../org/obolibrary/robot/CommandState.java | 1 + .../org/obolibrary/robot/QueryCommand.java | 2 + 3 files changed, 90 insertions(+), 86 deletions(-) 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/CommandState.java b/robot-command/src/main/java/org/obolibrary/robot/CommandState.java index cba16ff9a..46ee43224 100644 --- a/robot-command/src/main/java/org/obolibrary/robot/CommandState.java +++ b/robot-command/src/main/java/org/obolibrary/robot/CommandState.java @@ -50,6 +50,7 @@ public String getOntologyPath() { * @param catalogPath the catalog to use */ public void setCatalogPath(String catalogPath) { + System.err.println("Setting catalog path: " + catalogPath); this.catalogPath = catalogPath; } 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 8e999d703..1356f53c0 100644 --- a/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java +++ b/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java @@ -318,6 +318,8 @@ private static OWLOntology executeUpdate( // User may have specified a path to a catalog in the CLI options // Check for this path in state, or check for ontology path in state to guess catalog String catalogPath = state.getCatalogPath(); + System.err.println("CATALOG PATH!"); + System.err.println(catalogPath); if (catalogPath == null) { String ontologyPath = state.getOntologyPath(); // If loading from IRI, ontologyPath might be null From a9e5c7a9eb9b6707c4b55e5d8ae5eeaf9e12ce18 Mon Sep 17 00:00:00 2001 From: "James A. Overton" Date: Thu, 30 Oct 2025 14:48:49 +0000 Subject: [PATCH 4/5] Move logic into QueryOperation, add unit test --- .../org/obolibrary/robot/QueryCommand.java | 12 ++----- .../org/obolibrary/robot/QueryOperation.java | 36 +++++++++++++++++-- .../obolibrary/robot/QueryOperationTest.java | 32 +++++++++++++++++ robot-core/src/test/resources/prefix.owl | 13 +++++++ 4 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 robot-core/src/test/resources/prefix.owl 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 1356f53c0..4c9e49006 100644 --- a/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java +++ b/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java @@ -318,8 +318,6 @@ private static OWLOntology executeUpdate( // User may have specified a path to a catalog in the CLI options // Check for this path in state, or check for ontology path in state to guess catalog String catalogPath = state.getCatalogPath(); - System.err.println("CATALOG PATH!"); - System.err.println(catalogPath); if (catalogPath == null) { String ontologyPath = state.getOntologyPath(); // If loading from IRI, ontologyPath might be null @@ -341,14 +339,10 @@ private static OWLOntology executeUpdate( catalogPath = null; } } - OWLOntology updatedOntology = - QueryOperation.convertModel(model, ioHelper, catalogPath, useTemporaryFile); - OWLDocumentFormat inputFormat = + + OWLDocumentFormat format = inputOntology.getOWLOntologyManager().getOntologyFormat(inputOntology); - if (inputFormat != null) { - updatedOntology.getOWLOntologyManager().setOntologyFormat(updatedOntology, inputFormat); - } - return updatedOntology; + 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 @@ + + + + + + From cbdf8f6aa659ed6db2d2c9078ab56224fda7d83c Mon Sep 17 00:00:00 2001 From: "James A. Overton" Date: Thu, 30 Oct 2025 14:51:57 +0000 Subject: [PATCH 5/5] Remove STDERR message --- .../src/main/java/org/obolibrary/robot/CommandState.java | 1 - 1 file changed, 1 deletion(-) diff --git a/robot-command/src/main/java/org/obolibrary/robot/CommandState.java b/robot-command/src/main/java/org/obolibrary/robot/CommandState.java index 46ee43224..cba16ff9a 100644 --- a/robot-command/src/main/java/org/obolibrary/robot/CommandState.java +++ b/robot-command/src/main/java/org/obolibrary/robot/CommandState.java @@ -50,7 +50,6 @@ public String getOntologyPath() { * @param catalogPath the catalog to use */ public void setCatalogPath(String catalogPath) { - System.err.println("Setting catalog path: " + catalogPath); this.catalogPath = catalogPath; }