This is an automated email from the ASF dual-hosted git repository.

andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git


The following commit(s) were added to refs/heads/main by this push:
     new e68c9dd07d GH-2555: Allow ^^rdf:langString in result sets
e68c9dd07d is described below

commit e68c9dd07d64a2b98edd0e5bd8e1b20326611905
Author: Andy Seaborne <a...@apache.org>
AuthorDate: Fri Jul 5 18:50:27 2024 +0100

    GH-2555: Allow ^^rdf:langString in result sets
---
 jena-arq/pom.xml                                   |   5 +
 .../org/apache/jena/riot/rowset/RowSetReader.java  |   7 +-
 .../jena/riot/rowset/RowSetReaderRegistry.java     |   9 ++
 .../jena/riot/resultset/TS_ResultSetRIOT.java      |  10 +-
 .../org/apache/jena/riot/rowset/TS_RowSetRIOT.java |  12 ++-
 .../jena/riot/rowset/rw/TestRowSetReader.java      | 120 +++++++++++++++++++++
 .../java/org/apache/jena/graph/NodeFactory.java    |  30 ++++--
 .../apache/jena/graph/test/TestNodeEdgeCases.java  |  47 ++++++++
 .../apache/jena/graph/test/TestPackage_graph.java  |   1 +
 9 files changed, 224 insertions(+), 17 deletions(-)

diff --git a/jena-arq/pom.xml b/jena-arq/pom.xml
index 0efa9cd1c8..952b52a4ae 100644
--- a/jena-arq/pom.xml
+++ b/jena-arq/pom.xml
@@ -127,6 +127,11 @@
       <scope>test</scope>
     </dependency>
 
+    <dependency>
+      <groupId>org.junit.platform</groupId>
+      <artifactId>junit-platform-suite-engine</artifactId>
+    </dependency>
+
     <dependency>
       <groupId>org.awaitility</groupId>
       <artifactId>awaitility</artifactId>
diff --git 
a/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReader.java 
b/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReader.java
index 264f9cf9f6..c45b525488 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReader.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReader.java
@@ -21,12 +21,12 @@ package org.apache.jena.riot.rowset;
 import java.io.InputStream;
 import java.io.Reader;
 
+import org.apache.jena.riot.Lang;
 import org.apache.jena.sparql.exec.QueryExecResult;
 import org.apache.jena.sparql.exec.RowSet;
 import org.apache.jena.sparql.util.Context;
 
 public interface RowSetReader {
-
     /**
      * Read from an {@code InputStream} and produce a {@link RowSet}.
      * Note that return row set may stream and so the input stream may be read
@@ -67,4 +67,9 @@ public interface RowSetReader {
     public default RowSet read(Reader in, Context context) {
         throw new UnsupportedOperationException("RowSetReader.read - input 
from a Java Reader not supported.  Use an InputStream.");
     }
+
+    /** Convenience operation - create a {@link RowSetReader} for {@link Lang} 
or return null. */
+    public static RowSetReader createReader(Lang lang) {
+        return RowSetReaderRegistry.createReader(lang);
+    }
 }
diff --git 
a/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReaderRegistry.java 
b/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReaderRegistry.java
index 582fe3ba31..20da936741 100644
--- 
a/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReaderRegistry.java
+++ 
b/jena-arq/src/main/java/org/apache/jena/riot/rowset/RowSetReaderRegistry.java
@@ -35,6 +35,15 @@ public class RowSetReaderRegistry {
         return registry.get(lang);
     }
 
+    /** Create a {@link RowSetReader} for {@link Lang} or return null. */
+    public static RowSetReader createReader(Lang lang) {
+        Objects.requireNonNull(lang);
+        RowSetReaderFactory factory = getFactory(lang);
+        if ( factory == null )
+            return null;
+        return factory.create(lang);
+    }
+
     /** Register a {@link RowSetReaderFactory} for a {@link Lang} */
     public static void register(Lang lang, RowSetReaderFactory factory) {
         Objects.requireNonNull(lang);
diff --git 
a/jena-arq/src/test/java/org/apache/jena/riot/resultset/TS_ResultSetRIOT.java 
b/jena-arq/src/test/java/org/apache/jena/riot/resultset/TS_ResultSetRIOT.java
index f29ee4b0d8..8b214fedf5 100644
--- 
a/jena-arq/src/test/java/org/apache/jena/riot/resultset/TS_ResultSetRIOT.java
+++ 
b/jena-arq/src/test/java/org/apache/jena/riot/resultset/TS_ResultSetRIOT.java
@@ -20,15 +20,15 @@ package org.apache.jena.riot.resultset;
 
 import org.apache.jena.riot.resultset.rw.TestResultSetWriterCSV;
 import org.apache.jena.riot.resultset.rw.TestResultSetWriterTSV;
-import org.junit.runner.RunWith ;
-import org.junit.runners.Suite ;
+import org.junit.platform.suite.api.*;
 
-@RunWith(Suite.class)
-@Suite.SuiteClasses( {
+@Suite
+@SelectClasses({
     TestResultSetIO.class
+    , TestResultSetLang.class
     , TestResultSetWriterCSV.class
     , TestResultSetWriterTSV.class
     , TestResultSetLang.class
-})
+    })
 
 public class TS_ResultSetRIOT { }
diff --git 
a/jena-arq/src/test/java/org/apache/jena/riot/rowset/TS_RowSetRIOT.java 
b/jena-arq/src/test/java/org/apache/jena/riot/rowset/TS_RowSetRIOT.java
index 2cd1f05b4b..d2d91e562d 100644
--- a/jena-arq/src/test/java/org/apache/jena/riot/rowset/TS_RowSetRIOT.java
+++ b/jena-arq/src/test/java/org/apache/jena/riot/rowset/TS_RowSetRIOT.java
@@ -18,15 +18,17 @@
 
 package org.apache.jena.riot.rowset;
 
+import org.apache.jena.riot.rowset.rw.TestRowSetReader;
 import org.apache.jena.riot.rowset.rw.TestRowSetWriterCSV;
 import org.apache.jena.riot.rowset.rw.TestRowSetWriterTSV;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import org.junit.platform.suite.api.SelectClasses;
+import org.junit.platform.suite.api.Suite;;
 
-@RunWith(Suite.class)
-@Suite.SuiteClasses( {
+@Suite
+@SelectClasses({
     TestRowSetWriterCSV.class,
-    TestRowSetWriterTSV.class
+    TestRowSetWriterTSV.class,
+    TestRowSetReader.class
 })
 
 public class TS_RowSetRIOT { }
diff --git 
a/jena-arq/src/test/java/org/apache/jena/riot/rowset/rw/TestRowSetReader.java 
b/jena-arq/src/test/java/org/apache/jena/riot/rowset/rw/TestRowSetReader.java
new file mode 100644
index 0000000000..c340a19023
--- /dev/null
+++ 
b/jena-arq/src/test/java/org/apache/jena/riot/rowset/rw/TestRowSetReader.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.riot.rowset.rw;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.jena.atlas.io.IOX;
+import org.apache.jena.atlas.lib.Bytes;
+import org.apache.jena.query.ARQ;
+import org.apache.jena.riot.Lang;
+import org.apache.jena.riot.resultset.ResultSetLang;
+import org.apache.jena.riot.rowset.RowSetReader;
+import org.apache.jena.sparql.exec.RowSet;
+import org.apache.jena.sparql.exec.RowSetOps;
+import org.apache.jena.sys.JenaSystem;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Addition tests for result readers.
+ * The SPARQl test suite cover most usage. This class adds tests
+ */
+public class TestRowSetReader {
+    static { JenaSystem.init(); }
+
+    // Check "abc"^^rdf:langString and "abc"^^rdf:dirLangString and "
+    @Test public void resultSet_json_1() {
+        String r = """
+                {
+                  "head": { "vars": [ "s" , "p" , "o" ] } ,
+                  "results": {
+                    "bindings": [
+                      {
+                        "s": { "type": "uri" , "value": "http://example/s"; } ,
+                        "p": { "type": "uri" , "value": "http://example/p"; } ,
+                        "o": { "type": "literal" , "datatype": 
"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString"; , "value": "abc" }
+                      } ,
+                      {
+                        "s": { "type": "uri" , "value": "http://example/s"; } ,
+                        "p": { "type": "uri" , "value": "http://example/p"; } ,
+                        "o": { "type": "literal" , "datatype": 
"http://www.w3.org/1999/02/22-rdf-syntax-ns#dirLangString"; , "value": "abc" }
+                      }
+                    ]
+                }}
+                """;
+        RowSet rowset = read(r, ResultSetLang.RS_JSON);
+        assertNotNull(rowset);
+        assertEquals(2, RowSetOps.count(rowset));
+    }
+
+    @Test public void resultSet_xml_1() {
+        String r = """
+<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#";>
+  <head>
+    <variable name="s"/>
+    <variable name="p"/>
+    <variable name="o"/>
+  </head>
+  <results>
+    <result>
+      <binding name="s">
+        <uri>http://example/s</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://example/p</uri>
+      </binding>
+      <binding name="o">
+        <literal 
datatype="http://www.w3.org/1999/02/22-rdf-syntax-ns#langString";>abc</literal>
+      </binding>
+    </result>
+        <result>
+      <binding name="s">
+        <uri>http://example/s</uri>
+      </binding>
+      <binding name="p">
+        <uri>http://example/p</uri>
+      </binding>
+      <binding name="o">
+        <literal 
datatype="http://www.w3.org/1999/02/22-rdf-syntax-ns#dirLangString";>abc</literal>
+      </binding>
+    </result>
+
+  </results>
+</sparql>
+                """;
+        RowSet rowset = read(r, ResultSetLang.RS_XML);
+        assertNotNull(rowset);
+        assertEquals(2, RowSetOps.count(rowset));
+    }
+
+    private static RowSet read(String x, Lang rsLang) {
+        try ( InputStream input = new 
ByteArrayInputStream(Bytes.string2bytes(x)) ) {
+            RowSet rowSet = RowSetReader.createReader(rsLang)
+                    .read(input, ARQ.getContext().copy())
+                    .materialize();
+            return rowSet;
+        } catch (IOException ex) { throw IOX.exception(ex); }
+    }
+}
diff --git a/jena-core/src/main/java/org/apache/jena/graph/NodeFactory.java 
b/jena-core/src/main/java/org/apache/jena/graph/NodeFactory.java
index 264046092f..4979cb06c8 100644
--- a/jena-core/src/main/java/org/apache/jena/graph/NodeFactory.java
+++ b/jena-core/src/main/java/org/apache/jena/graph/NodeFactory.java
@@ -224,22 +224,40 @@ public class NodeFactory {
                     if ( ! dtype.equals(RDFLangString.rdfLangString) )
                         throw new JenaException("Datatype is not 
rdf:langString but a language was given");
                 } else {
-                    if (  ! dtype.equals(RDFDirLangString.rdfDirLangString) )
+                    if ( ! dtype.equals(RDFDirLangString.rdfDirLangString) )
                         throw new JenaException("Datatype is not 
rdf:dirLangString but a language and initial text direction was given");
                 }
             }
 
             return createLiteralDirLang(lex, langFmt, textDir);
         }
+
         if ( dtype == null )
             // No datatype, no lang (it is null or "") => xsd:string.
             return createLiteralString(lex);
 
-        // No lang, with a datatype
-        if ( dtype.equals(RDFLangString.rdfLangString) )
-            throw new JenaException("Datatype is rdf:langString but no 
language given");
-        if ( dtype.equals(RDFDirLangString.rdfDirLangString) && 
noTextDir(textDir) )
-            throw new JenaException("Datatype is rdf:dirLangString but no 
initial text direction given");
+        // No language. Has a datatype.
+        boolean hasTextDirLang = ( textDir != null );
+        if ( hasTextDirLang ) {
+            if ( dtype.equals(RDFDirLangString.rdfDirLangString) ) {
+                // No language. Datatype is rdf:dirLangString, Does have an 
initial text direction
+                throw new JenaException("Datatype is rdf:dirLangString and has 
an initial text direction but no language given");
+            } else if ( dtype.equals(RDFLangString.rdfLangString) ) {
+                // No language. Datatype is rdf:langString, Does have an 
initial text direction.
+                throw new JenaException("Datatype is rdf:langString and has an 
initial text direction but no language given");
+            }
+        }
+
+        // Datatype. No language, no initial text direction.
+        // Allow "abc"^^rdf:langString
+        // Allow "abc"^^rdf:dirLangString
+
+        // To disallow.
+//        if ( dtype.equals(RDFLangString.rdfLangString) )
+//            throw new JenaException("Datatype is rdf:langString but no 
language given");
+//        if ( dtype.equals(RDFDirLangString.rdfDirLangString) && 
noTextDir(textDir) )
+//            throw new JenaException("Datatype is rdf:dirLangString but no 
initial text direction given");
+
         Node n = createLiteralDT(lex, dtype);
         return n;
     }
diff --git 
a/jena-core/src/test/java/org/apache/jena/graph/test/TestNodeEdgeCases.java 
b/jena-core/src/test/java/org/apache/jena/graph/test/TestNodeEdgeCases.java
new file mode 100644
index 0000000000..43cd6f2813
--- /dev/null
+++ b/jena-core/src/test/java/org/apache/jena/graph/test/TestNodeEdgeCases.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.graph.test;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.jena.datatypes.xsd.impl.RDFDirLangString;
+import org.apache.jena.datatypes.xsd.impl.RDFLangString;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.junit.Test;
+
+public class TestNodeEdgeCases {
+
+    // Corner cases of NodeFactory
+    @Test public void term_create_01() {
+        // "abc"^^rdf:langString (no language)
+        Node node1 = NodeFactory.createLiteral("abc", null, (String)null, 
RDFLangString.rdfLangString);
+        assertNotNull(node1);
+        Node node2 = NodeFactory.createLiteralDT("abc", 
RDFLangString.rdfLangString);
+        assertNotNull(node2);
+    }
+
+    @Test public void term_create_02() {
+        // "abc"^rdf:dirLangString (no language, no initial text direction)
+        Node node1 = NodeFactory.createLiteral("abc", null, (String)null, 
RDFDirLangString.rdfDirLangString);
+        assertNotNull(node1);
+        Node node2 = NodeFactory.createLiteralDT("abc", 
RDFDirLangString.rdfDirLangString);
+        assertNotNull(node2);
+    }
+}
diff --git 
a/jena-core/src/test/java/org/apache/jena/graph/test/TestPackage_graph.java 
b/jena-core/src/test/java/org/apache/jena/graph/test/TestPackage_graph.java
index 5236ca13b5..ee2606b951 100644
--- a/jena-core/src/test/java/org/apache/jena/graph/test/TestPackage_graph.java
+++ b/jena-core/src/test/java/org/apache/jena/graph/test/TestPackage_graph.java
@@ -55,6 +55,7 @@ public class TestPackage_graph extends TestSuite {
         addTestSuite( TestGraphBaseToString.class );
         addTest( new JUnit4TestAdapter(TestNodeExtras.class) );
         addTest( new JUnit4TestAdapter(TestRDFStringLiterals.class) );
+        addTest( new JUnit4TestAdapter(TestNodeEdgeCases.class) );
 
         // Has to be in a different package.
         addTest( new JUnit4TestAdapter(TestGraphUtil.class) );

Reply via email to