Skip to content

Commit 13fb129

Browse files
authored
GH-5215 Support apostrophe in local name for SPARQL 1.1 and Turtle/Trig/etc. (#5216)
1 parent 79e4307 commit 13fb129

12 files changed

Lines changed: 108 additions & 89 deletions

File tree

core/model/src/main/java/org/eclipse/rdf4j/model/util/URIUtil.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,19 @@ public static boolean isValidLocalName(String name) {
228228

229229
for (int i = 1; i < name.length(); i++) {
230230
if (!isNameChar(name.charAt(i))) {
231+
232+
// PLX
233+
if (name.charAt(i) == '%') {
234+
continue;
235+
} else if (name.charAt(i) == '\\') {
236+
if (i + 1 < name.length() && isPN_LOCAL_ESC(name.substring(i, i + 2))) {
237+
i++;
238+
continue;
239+
} else {
240+
return false;
241+
}
242+
}
243+
231244
return false;
232245
}
233246

@@ -341,7 +354,7 @@ private static boolean isNameStartChar(int codePoint) {
341354
* @return <code>true</code> if the supplied code point represents a valid name char, <code>false</code> otherwise.
342355
*/
343356
private static boolean isNameChar(int codePoint) {
344-
return isPN_CHARS(codePoint) || codePoint == '.' || codePoint == ':' | codePoint == '\\' || codePoint == '%';
357+
return isPN_CHARS(codePoint) || codePoint == '.' || codePoint == ':';
345358
}
346359

347360
/**

core/model/src/test/java/org/eclipse/rdf4j/model/util/URIUtilTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,6 @@ public void isValidLocalName() {
108108
assertFalse(URIUtil.isValidLocalName("foo\tbar"));
109109
assertFalse(URIUtil.isValidLocalName("foo\nbar"));
110110
assertFalse(URIUtil.isValidLocalName("*foobar"));
111+
assertTrue(URIUtil.isValidLocalName("fo\\'obar"));
111112
}
112113
}

core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/SyntaxTreeBuilderTokenManager.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2296,7 +2296,7 @@ private int jjMoveNfa_0_curCharLessThan64(int startsAt, int i, int kind) {
22962296
}
22972297
break;
22982298
case 82:
2299-
if ((0xa800ff7e00000000L & l) != 0L) {
2299+
if ((0xa800fffa00000000L & l) != 0L) {
23002300
jjCheckNAddStates(44, 47);
23012301
}
23022302
break;
@@ -2326,12 +2326,12 @@ private int jjMoveNfa_0_curCharLessThan64(int startsAt, int i, int kind) {
23262326
}
23272327
break;
23282328
case 88:
2329-
if ((0xa800ff7e00000000L & l) != 0L && kind > 146) {
2329+
if ((0xa800fffa00000000L & l) != 0L && kind > 146) {
23302330
kind = 146;
23312331
}
23322332
break;
23332333
case 90:
2334-
if ((0xa800ff7e00000000L & l) == 0L) {
2334+
if ((0xa800fffa00000000L & l) == 0L) {
23352335
break;
23362336
}
23372337
if (kind > 146) {

core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/ast/sparql.jjt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ TOKEN:
345345
| <#PN_LOCAL: (<PN_CHARS_U> | ":" | <NUM> | <PLX> ) ( (<PN_CHARS> | "." | ":" | <PLX>)* ( <PN_CHARS> | ":" | <PLX>) )?>
346346
| <#PLX: <PERCENT> | <PN_LOCAL_ESC>>
347347
| <#PERCENT: "%" <HEX> <HEX>>
348-
| <#PN_LOCAL_ESC: "\\" [ "_", "~", ".", "-", "!", "$", "&", "\"", "(", ")", "*", "+", ",", ";", "=", "/", "?", "#", "@", "%" ]>
348+
| <#PN_LOCAL_ESC: "\\" [ "_", "~", ".", "-", "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=", "/", "?", "#", "@", "%" ]>
349349
| <#VARNAME: (<PN_CHARS_U> | <NUM> ) (<VAR_CHAR>)*>
350350
| <TRIPLE_OPEN: "<<">
351351
| <TRIPLE_CLOSE: ">>">

core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/SPARQLParserTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,32 @@ public void testGroupByProjectionHandling_function() {
976976
verifySerializable(parsedQuery.getTupleExpr());
977977
}
978978

979+
@Test
980+
public void testApostrophe() {
981+
String query = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
982+
"select * where { \n" +
983+
" rdf:Test\\'s ?p1 ?o1\n" +
984+
"}";
985+
986+
HashSet<Namespace> customPrefixes = new HashSet<>();
987+
SPARQLParser parser = new SPARQLParser(customPrefixes);
988+
989+
parser.parseQuery(query, null);
990+
}
991+
992+
@Test
993+
public void testApostropheInsertData() {
994+
String query = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
995+
"INSERT DATA { \n" +
996+
" rdf:Test\\'s a <http://example.com/Test> .\n" +
997+
"}";
998+
999+
HashSet<Namespace> customPrefixes = new HashSet<>();
1000+
SPARQLParser parser = new SPARQLParser(customPrefixes);
1001+
1002+
parser.parseUpdate(query, null);
1003+
}
1004+
9791005
private AggregateFunctionFactory buildDummyFactory() {
9801006
return new AggregateFunctionFactory() {
9811007
@Override

core/rio/trig/src/test/resources/testcases/trig/trig-syntax-minimal-whitespace-01.trig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ d:<http://example/d/>.
1919
_:s{:s :p :o .:s :p"Alice".:s :p _:o.}
2020
:{: : :}{: : :}:{: : :}
2121
:{():()}{():[]}:{[]:[]}
22+
{b:a\'s a :Foo}
23+

core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleUtil.java

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.util.Arrays;
1414

1515
import org.eclipse.rdf4j.common.text.ASCIIUtil;
16+
import org.eclipse.rdf4j.model.util.URIUtil;
1617
import org.slf4j.Logger;
1718
import org.slf4j.LoggerFactory;
1819

@@ -366,41 +367,7 @@ public static boolean isPN_LOCAL_ESC(String name) {
366367
}
367368

368369
public static boolean isPN_LOCAL(String name) {
369-
// Empty names are legal
370-
if (name.isEmpty()) {
371-
return true;
372-
}
373-
374-
if (!isPN_CHARS_U(name.charAt(0)) && name.charAt(0) != ':' && !ASCIIUtil.isNumber(name.charAt(0))
375-
&& !isPLX_START(name)) {
376-
logger.debug("PN_LOCAL was not valid (start characters invalid) i=" + 0 + " nextchar="
377-
+ name.charAt(0) + " name=" + name);
378-
return false;
379-
}
380-
381-
if (!isNameStartChar(name.charAt(0))) {
382-
logger.debug("name was not valid (start character invalid) i=" + 0 + " nextchar=" + name.charAt(0)
383-
+ " name=" + name);
384-
return false;
385-
}
386-
387-
for (int i = 1; i < name.length(); i++) {
388-
if (!isNameChar(name.charAt(i))) {
389-
logger.debug("name was not valid (intermediate character invalid) i=" + i + " nextchar="
390-
+ name.charAt(i) + " name=" + name);
391-
return false;
392-
}
393-
394-
// Check if the percent encoding was less than two characters from the
395-
// end of the prefix, in which case it is invalid
396-
if (name.charAt(i) == '%' && (name.length() - i) < 3) {
397-
logger.debug("name was not valid (short percent escape) i=" + i + " nextchar=" + name.charAt(i)
398-
+ " name=" + name);
399-
return false;
400-
}
401-
}
402-
403-
return true;
370+
return URIUtil.isValidLocalName(name);
404371
}
405372

406373
// public static boolean isLegalName(String name) {

core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleUtilTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ public final void testIsPN_LOCAL() {
229229
assertFalse(TurtleUtil.isPN_LOCAL("foo\tbar"));
230230
assertFalse(TurtleUtil.isPN_LOCAL("foo\nbar"));
231231
assertFalse(TurtleUtil.isPN_LOCAL("*foobar"));
232+
assertTrue(TurtleUtil.isPN_LOCAL("foo\\'bar"));
232233
}
233234

234235
/**

core/rio/turtle/src/test/resources/test-newlines.ttl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
ex:a a ex:Foo .
66
ex:b a ex:Foo .
77
ex:b ex:value '''^M'''.
8-
ex:c
8+
ex:c
99
:foo ex:Foo .
10+
rdf:Test\'s a ex:Foo .
1011
ex:a ex:value 1.0 .
1112
ex:a ex:value 3.0 .

e2e/package-lock.json

Lines changed: 48 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)