diff --git a/doc/release-notes/11793 - ext. vocab. improvements.md b/doc/release-notes/11793 - ext. vocab. improvements.md new file mode 100644 index 00000000000..46998e56b60 --- /dev/null +++ b/doc/release-notes/11793 - ext. vocab. improvements.md @@ -0,0 +1 @@ +This version of Dataverse includes extensions of the Dataverse External Vocabulary mechanism (https://guides.dataverse.org/en/latest/admin/metadatacustomization.html#using-external-vocabulary-services) that improve Dataverse's ability to include metadata about vocabulary terms and external identifiers such as ORCID and ROR in it's metadata exports. More information on how to configure external vocabulary scripts to use this functionality can be found at https://github.com/gdcc/dataverse-external-vocab-support/blob/main/docs/readme.md and in the examples in the https://github.com/gdcc/dataverse-external-vocab-support repository. \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java index 0b6b74e6a73..811c67c52d6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetFieldServiceBean.java @@ -764,13 +764,24 @@ Object processPathSegment(int index, String[] pathParts, JsonValue curPath, Stri JsonValue val = jo.get(keyVal[0]); if (val != null) { if (val.getValueType().equals(ValueType.STRING)) { + //Match a string value if (((JsonString) val).getString().equals(expected)) { logger.fine("Found: " + jo); curPath = jo; return processPathSegment(index + 1, pathParts, curPath, termUri); } - } else { - logger.warning("Expected a string value for " + keyVal[0] + " but found: " + val.getValueType()); + } else if (val.getValueType() == JsonValue.ValueType.ARRAY) { + // Match one string in an array + JsonArray jsonArray = (JsonArray) val; + for (JsonValue arrayVal : jsonArray) { + if (arrayVal.getValueType() == JsonValue.ValueType.STRING) { + if (((JsonString) arrayVal).getString().equals(expected)) { + logger.fine("Found match in array: " + jo.toString()); + curPath = jo; + return processPathSegment(index + 1, pathParts, curPath, termUri); + } + } + } } } } diff --git a/src/test/java/edu/harvard/iq/dataverse/DatasetFieldServiceBeanTest.java b/src/test/java/edu/harvard/iq/dataverse/DatasetFieldServiceBeanTest.java index 873d417131d..8e6fc76c134 100644 --- a/src/test/java/edu/harvard/iq/dataverse/DatasetFieldServiceBeanTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/DatasetFieldServiceBeanTest.java @@ -1,6 +1,9 @@ package edu.harvard.iq.dataverse; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.IOException; @@ -17,7 +20,10 @@ import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonObject; +import jakarta.json.JsonObjectBuilder; public class DatasetFieldServiceBeanTest { @@ -152,6 +158,57 @@ void getIndexableStringsByTermUriOrcid() throws IOException { assertEquals(Collections.emptySet(), result); } + @Test + public void testProcessPathSegmentWithArrayStringMatching() { + // Create a DatasetFieldServiceBean instance + DatasetFieldServiceBean bean = new DatasetFieldServiceBean(); + + String termUri = "http://example.org/term/123"; + + // Create a JSON structure with an array containing string values + JsonArrayBuilder tagsArrayBuilder = Json.createArrayBuilder(); + JsonObject testObject = Json.createObjectBuilder().add("tag", Json.createArrayBuilder().add("research").add("science")).add("name", "one").build(); + tagsArrayBuilder.add(testObject); + JsonObject testObject2 = Json.createObjectBuilder().add("tag", "art").add("name", "two").build(); + tagsArrayBuilder.add(testObject2); + JsonObject testObject3 = Json.createObjectBuilder().add("tag", termUri).add("name", "three").build(); + tagsArrayBuilder.add(testObject3); + JsonArray tags = tagsArrayBuilder.build(); + + // Test case 1: Match a string in an array of strings + String[] pathParts = { "tag=research", "name" }; + Object result = bean.processPathSegment(0, pathParts, tags, termUri); + + // The method should return the test object when a match is found + // Result should not be null when a match is found + assertNotNull(result); + assertEquals("one", result, "Result should be the original test object"); + + // Test case 2: Match a string + pathParts[0] = "tag=art"; + result = bean.processPathSegment(0, pathParts, tags, termUri); + + // The method should return the test object when a match is found + // Result should not be null when a match is found + assertNotNull(result); + assertEquals("two", result, "Result should be the original test object"); + + // Test case 3: No match in the array + String[] noMatchPathParts = { "tags=nonexistent" }; + Object noMatchResult = bean.processPathSegment(0, noMatchPathParts, testObject, termUri); + + // The method should return null when no match is found + assertNull(noMatchResult, "Result should be null when no match is found"); + + // Test case 4: Match with @id substitution + + String[] idPathParts = { "tag=@id", "name" }; + Object idResult = bean.processPathSegment(0, idPathParts, tags, termUri); + + assertNotNull(idResult, "Result should not be null when matching with @id"); + assertEquals("three", idResult, "Result should be the original test object"); + } + /** * Prepare unit tests with mock methods. *