From 3e894398181d71b2532b2757b889ef75dd466b1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20M=2E=20Ottestad?= Date: Thu, 27 Feb 2025 14:32:43 -0300 Subject: [PATCH] Fix SPARQLResultsTSVWriter to quote xsd:string literals Related to #5256 Update `SPARQLResultsTSVWriter` to ensure all `xsd:string` literals are quoted in SPARQL TSV results. * Modify `writeLiteral` method to always quote `xsd:string` literals. * Remove conditions that allowed `xsd:string` literals to be written without quotes. * Ensure special characters in `xsd:string` literals are properly escaped using `encodeString` method. * Update tests in `SPARQLTSVCustomTest` to verify correct quoting of `xsd:string` literals and proper escaping of special characters. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/eclipse-rdf4j/rdf4j/issues/5256?shareId=XXXX-XXXX-XXXX-XXXX). --- .../text/tsv/SPARQLResultsTSVWriter.java | 16 +++++----------- .../resultio/text/tsv/SPARQLTSVCustomTest.java | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/core/queryresultio/text/src/main/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLResultsTSVWriter.java b/core/queryresultio/text/src/main/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLResultsTSVWriter.java index 3bcbfc74a1a..9769a75766a 100644 --- a/core/queryresultio/text/src/main/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLResultsTSVWriter.java +++ b/core/queryresultio/text/src/main/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLResultsTSVWriter.java @@ -194,21 +194,15 @@ private void writeLiteral(Literal lit) throws IOException { // Append the literal's language writer.write("@"); writer.write(lit.getLanguage().get()); - } else if (!XSD.STRING.equals(datatype) || !xsdStringToPlainLiteral()) { - writer.write("\""); - writer.write(encoded); - writer.write("\""); - // Append the literal's datatype - writer.write("^^"); - writeURI(datatype); - } else if (!label.isEmpty() && encoded.equals(label) && label.charAt(0) != '<' && label.charAt(0) != '_' - && !label.matches("^[\\+\\-]?[\\d\\.].*")) { - // no need to include double quotes - writer.write(encoded); } else { writer.write("\""); writer.write(encoded); writer.write("\""); + // Append the literal's datatype if it's not xsd:string or if xsdStringToPlainLiteral is false + if (!XSD.STRING.equals(datatype) || !xsdStringToPlainLiteral()) { + writer.write("^^"); + writeURI(datatype); + } } } diff --git a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVCustomTest.java b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVCustomTest.java index 2dcfc8d3131..fcdd1192d3a 100644 --- a/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVCustomTest.java +++ b/core/queryresultio/text/src/test/java/org/eclipse/rdf4j/query/resultio/text/tsv/SPARQLTSVCustomTest.java @@ -69,6 +69,24 @@ public void testSES2126QuotedLiteralIntegerAsStringImplicitType() throws Excepti assertEquals("?test\n\"1\"\n", result); } + @Test + public void testQuotedXSDStringLiteral() throws Exception { + List bindingNames = List.of("test"); + TupleQueryResult tqr = new IteratingTupleQueryResult(bindingNames, + List.of(new ListBindingSet(bindingNames, SimpleValueFactory.getInstance().createLiteral("example", XSD.STRING)))); + String result = writeTupleResult(tqr); + assertEquals("?test\n\"example\"\n", result); + } + + @Test + public void testQuotedXSDStringLiteralWithSpecialCharacters() throws Exception { + List bindingNames = List.of("test"); + TupleQueryResult tqr = new IteratingTupleQueryResult(bindingNames, + List.of(new ListBindingSet(bindingNames, SimpleValueFactory.getInstance().createLiteral("example\twith\nspecial\"characters", XSD.STRING)))); + String result = writeTupleResult(tqr); + assertEquals("?test\n\"example\\twith\\nspecial\\\"characters\"\n", result); + } + private String writeTupleResult(TupleQueryResult tqr) throws IOException, TupleQueryResultHandlerException, QueryEvaluationException { ByteArrayOutputStream output = new ByteArrayOutputStream();