diff --git a/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java index 7dbf92b9852..8af88040406 100644 --- a/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java +++ b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java @@ -203,6 +203,15 @@ public Choices getBestMatch(String text, String locale) { return new Choices(choices.toArray(new Choice[choices.size()]), 0, choices.size(), Choices.CF_AMBIGUOUS, false); } + /** + * - If the string doesn't contain any single quotes, it wraps the string in single quotes. + * - If the string contains single quotes but no double quotes, it wraps the string in double quotes. + * - If the string contains both single and double quotes, + * it constructs an XPath expression using the concat function. + * The goal is to allow the string to be safely used in XPath expressions regardless of the presence of quotes. + * @param text + * @return + */ private String escapeQuotes(String text) { // If we don't have any quote then enquote string in single quote if (!text.contains("'")) { @@ -228,7 +237,7 @@ private String escapeQuotes(String text) { sb.append(","); } - sb.append(String.format("\"%s\",'\"'", text.substring(lastPos, nextPos - lastPos))); + sb.append(String.format("\"%s\",'\"'", text.substring(lastPos, nextPos))); lastPos = ++nextPos; // Find next occurrence diff --git a/dspace-api/src/test/data/dspaceFolder/config/controlled-vocabularies/srsc.xml b/dspace-api/src/test/data/dspaceFolder/config/controlled-vocabularies/srsc.xml index 9c81c75a675..c2ef1182c9c 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/controlled-vocabularies/srsc.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/controlled-vocabularies/srsc.xml @@ -367,6 +367,12 @@ Datorlingvistik + + Datorlingvistik + + + Datorlingvistik + Datorlingvistik diff --git a/dspace-server-webapp/src/test/data/dspaceFolder/config/controlled-vocabularies/srsc.xml b/dspace-server-webapp/src/test/data/dspaceFolder/config/controlled-vocabularies/srsc.xml index 9c81c75a675..c2ef1182c9c 100644 --- a/dspace-server-webapp/src/test/data/dspaceFolder/config/controlled-vocabularies/srsc.xml +++ b/dspace-server-webapp/src/test/data/dspaceFolder/config/controlled-vocabularies/srsc.xml @@ -367,6 +367,12 @@ Datorlingvistik + + Datorlingvistik + + + Datorlingvistik + Datorlingvistik diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyEntryDetailsIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyEntryDetailsIT.java index 84dda6765a6..1c9490971da 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyEntryDetailsIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/VocabularyEntryDetailsIT.java @@ -491,10 +491,45 @@ public void testSearchWithComma() throws Exception { } @Test - public void testSearchWithColumn() throws Exception { + public void testSearchWithColon() throws Exception { String tokenAdmin = getAuthToken(admin.getEmail(), password); getClient(tokenAdmin).perform(get("/api/submission/vocabularies/srsc/entries?filter=test:example&exact=true")) .andExpect(status().isOk()) .andExpect(jsonPath("_embedded.entries[0].display").value("test:example")); } + + @Test + public void testSearchWithApostropheAndQuoteReversed() throws Exception { + String tokenAdmin = getAuthToken(admin.getEmail(), password); + getClient(tokenAdmin).perform( + get("/api/submission/vocabularies/srsc/entries?filter=test2\"test'example\"'\"" + + "&exact==false")) + .andExpect(status().isOk()) + .andExpect(jsonPath("_embedded.entries[0].display").value("test2\"test'example\"'\"test")); + getClient(tokenAdmin).perform( + get("/api/submission/vocabularies/srsc/entries?filter=test2\"test'exam" + + "&exact==false")) + .andExpect(status().isOk()) + .andExpect(jsonPath("_embedded.entries[0].display").value("test2\"test'example\"'\"test")); + getClient(tokenAdmin).perform( + get("/api/submission/vocabularies/srsc/entries?filter=test2\"test'exam" + + "&exact==true")) + .andExpect(status().isOk()) + .andExpect(jsonPath("_embedded.entries[0].display").value("test2\"test'example\"'\"test")); + getClient(tokenAdmin).perform( + get("/api/submission/vocabularies/srsc/entries?filter=University's s\"" + + "&exact==false")) + .andExpect(status().isOk()) + .andExpect(jsonPath("_embedded.entries[0].display").value("University's s\"P\"apers")); + getClient(tokenAdmin).perform( + get("/api/submission/vocabularies/srsc/entries?filter=University's s\"P\"" + + "&exact==false")) + .andExpect(status().isOk()) + .andExpect(jsonPath("_embedded.entries[0].display").value("University's s\"P\"apers")); + getClient(tokenAdmin).perform( + get("/api/submission/vocabularies/srsc/entries?filter=University's s\"P\"apers" + + "&exact==true")) + .andExpect(status().isOk()) + .andExpect(jsonPath("_embedded.entries[0].display").value("University's s\"P\"apers")); + } }