Skip to content

Commit

Permalink
GH-5215 Support apostrophe in local name for SPARQL 1.1 and Turtle/Tr…
Browse files Browse the repository at this point in the history
…ig/etc. (#5216)
  • Loading branch information
hmottestad authored Dec 9, 2024
1 parent 79e4307 commit 13fb129
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,19 @@ public static boolean isValidLocalName(String name) {

for (int i = 1; i < name.length(); i++) {
if (!isNameChar(name.charAt(i))) {

// PLX
if (name.charAt(i) == '%') {
continue;
} else if (name.charAt(i) == '\\') {
if (i + 1 < name.length() && isPN_LOCAL_ESC(name.substring(i, i + 2))) {
i++;
continue;
} else {
return false;
}
}

return false;
}

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

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,6 @@ public void isValidLocalName() {
assertFalse(URIUtil.isValidLocalName("foo\tbar"));
assertFalse(URIUtil.isValidLocalName("foo\nbar"));
assertFalse(URIUtil.isValidLocalName("*foobar"));
assertTrue(URIUtil.isValidLocalName("fo\\'obar"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2296,7 +2296,7 @@ private int jjMoveNfa_0_curCharLessThan64(int startsAt, int i, int kind) {
}
break;
case 82:
if ((0xa800ff7e00000000L & l) != 0L) {
if ((0xa800fffa00000000L & l) != 0L) {
jjCheckNAddStates(44, 47);
}
break;
Expand Down Expand Up @@ -2326,12 +2326,12 @@ private int jjMoveNfa_0_curCharLessThan64(int startsAt, int i, int kind) {
}
break;
case 88:
if ((0xa800ff7e00000000L & l) != 0L && kind > 146) {
if ((0xa800fffa00000000L & l) != 0L && kind > 146) {
kind = 146;
}
break;
case 90:
if ((0xa800ff7e00000000L & l) == 0L) {
if ((0xa800fffa00000000L & l) == 0L) {
break;
}
if (kind > 146) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ TOKEN:
| <#PN_LOCAL: (<PN_CHARS_U> | ":" | <NUM> | <PLX> ) ( (<PN_CHARS> | "." | ":" | <PLX>)* ( <PN_CHARS> | ":" | <PLX>) )?>
| <#PLX: <PERCENT> | <PN_LOCAL_ESC>>
| <#PERCENT: "%" <HEX> <HEX>>
| <#PN_LOCAL_ESC: "\\" [ "_", "~", ".", "-", "!", "$", "&", "\"", "(", ")", "*", "+", ",", ";", "=", "/", "?", "#", "@", "%" ]>
| <#PN_LOCAL_ESC: "\\" [ "_", "~", ".", "-", "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=", "/", "?", "#", "@", "%" ]>
| <#VARNAME: (<PN_CHARS_U> | <NUM> ) (<VAR_CHAR>)*>
| <TRIPLE_OPEN: "<<">
| <TRIPLE_CLOSE: ">>">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,32 @@ public void testGroupByProjectionHandling_function() {
verifySerializable(parsedQuery.getTupleExpr());
}

@Test
public void testApostrophe() {
String query = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
"select * where { \n" +
" rdf:Test\\'s ?p1 ?o1\n" +
"}";

HashSet<Namespace> customPrefixes = new HashSet<>();
SPARQLParser parser = new SPARQLParser(customPrefixes);

parser.parseQuery(query, null);
}

@Test
public void testApostropheInsertData() {
String query = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
"INSERT DATA { \n" +
" rdf:Test\\'s a <http://example.com/Test> .\n" +
"}";

HashSet<Namespace> customPrefixes = new HashSet<>();
SPARQLParser parser = new SPARQLParser(customPrefixes);

parser.parseUpdate(query, null);
}

private AggregateFunctionFactory buildDummyFactory() {
return new AggregateFunctionFactory() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ d:<http://example/d/>.
_:s{:s :p :o .:s :p"Alice".:s :p _:o.}
:{: : :}{: : :}:{: : :}
:{():()}{():[]}:{[]:[]}
{b:a\'s a :Foo}

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.Arrays;

import org.eclipse.rdf4j.common.text.ASCIIUtil;
import org.eclipse.rdf4j.model.util.URIUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -366,41 +367,7 @@ public static boolean isPN_LOCAL_ESC(String name) {
}

public static boolean isPN_LOCAL(String name) {
// Empty names are legal
if (name.isEmpty()) {
return true;
}

if (!isPN_CHARS_U(name.charAt(0)) && name.charAt(0) != ':' && !ASCIIUtil.isNumber(name.charAt(0))
&& !isPLX_START(name)) {
logger.debug("PN_LOCAL was not valid (start characters invalid) i=" + 0 + " nextchar="
+ name.charAt(0) + " name=" + name);
return false;
}

if (!isNameStartChar(name.charAt(0))) {
logger.debug("name was not valid (start character invalid) i=" + 0 + " nextchar=" + name.charAt(0)
+ " name=" + name);
return false;
}

for (int i = 1; i < name.length(); i++) {
if (!isNameChar(name.charAt(i))) {
logger.debug("name was not valid (intermediate character invalid) i=" + i + " nextchar="
+ name.charAt(i) + " name=" + name);
return false;
}

// Check if the percent encoding was less than two characters from the
// end of the prefix, in which case it is invalid
if (name.charAt(i) == '%' && (name.length() - i) < 3) {
logger.debug("name was not valid (short percent escape) i=" + i + " nextchar=" + name.charAt(i)
+ " name=" + name);
return false;
}
}

return true;
return URIUtil.isValidLocalName(name);
}

// public static boolean isLegalName(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ public final void testIsPN_LOCAL() {
assertFalse(TurtleUtil.isPN_LOCAL("foo\tbar"));
assertFalse(TurtleUtil.isPN_LOCAL("foo\nbar"));
assertFalse(TurtleUtil.isPN_LOCAL("*foobar"));
assertTrue(TurtleUtil.isPN_LOCAL("foo\\'bar"));
}

/**
Expand Down
3 changes: 2 additions & 1 deletion core/rio/turtle/src/test/resources/test-newlines.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
ex:a a ex:Foo .
ex:b a ex:Foo .
ex:b ex:value '''^M'''.
ex:c
ex:c
:foo ex:Foo .
rdf:Test\'s a ex:Foo .
ex:a ex:value 1.0 .
ex:a ex:value 3.0 .
90 changes: 48 additions & 42 deletions e2e/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.39.0",
"@types/node": "^20.8.7"
"@playwright/test": "^1.49.0",
"@types/node": "^22.10.1"
}
}
10 changes: 6 additions & 4 deletions e2e/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@

set -e

npm install

for APP_SERVER in tomcat jetty; do
export APP_SERVER

cd ..
cd docker
./run.sh
Expand All @@ -38,16 +40,16 @@ for APP_SERVER in tomcat jetty; do

cd ..
cd docker
./shutdown.sh
./shutdown.sh

# test for error code
if [ $status_npx -ne 0 ] ; then
echo "Error in E2E test for $APP_SERVER"
exit $status_npx
fi

echo "E2E test for $APP_SERVER OK"

# don't redo the whole build process just for making another docker image
export SKIP_BUILD="skip"
done
Expand Down

0 comments on commit 13fb129

Please sign in to comment.