Skip to content

Commit

Permalink
121978: Add ORCID IDs to OAI records
Browse files Browse the repository at this point in the history
  • Loading branch information
nona-luypaert committed Dec 31, 2024
1 parent 5a43e6b commit 048b38f
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 0 deletions.
45 changes: 45 additions & 0 deletions dspace-oai/src/main/java/org/dspace/xoai/util/ItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,21 @@
import com.lyncode.xoai.util.Base64Utils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.common.SolrDocumentList;
import org.dspace.app.util.factory.UtilServiceFactory;
import org.dspace.app.util.service.MetadataExposureService;
import org.dspace.authority.AuthoritySearchService;
import org.dspace.authority.factory.AuthorityServiceFactory;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataValue;
import org.dspace.content.authority.Choices;
import org.dspace.content.authority.factory.ContentAuthorityServiceFactory;
import org.dspace.content.authority.service.MetadataAuthorityService;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.ItemService;
Expand Down Expand Up @@ -59,6 +65,13 @@ public class ItemUtils {

private static final ConfigurationService configurationService
= DSpaceServicesFactory.getInstance().getConfigurationService();

private static final AuthoritySearchService authoritySearchService
= AuthorityServiceFactory.getInstance().getAuthoritySearchService();

private static final MetadataAuthorityService metadataAuthorityService
= ContentAuthorityServiceFactory.getInstance().getMetadataAuthorityService();

/**
* Default constructor
*/
Expand Down Expand Up @@ -223,9 +236,41 @@ private static void fillSchemaElement(Element schema, MetadataValue val) throws
if (val.getConfidence() != Choices.CF_NOVALUE) {
valueElem.getField().add(createValue("confidence", val.getConfidence() + ""));
}
addOrcidIdentifier(valueElem, val);
}
}

/**
* Adds a ORCID identifier field to the provided Element, if applicable.
*/
private static void addOrcidIdentifier(Element valueElem, MetadataValue mdValue) {
// Stop if the metadata value's field isn't enabled for ORCID authorities.
if (!isOrcidAuthorityControlled(mdValue.getMetadataField())) {
return;
}

try {
// Query the authority core using the authority key on the metadata value.
SolrQuery query = new SolrQuery();
query.setQuery("id:" + mdValue.getAuthority());
SolrDocumentList results = authoritySearchService.search(query).getResults();

if (results.getNumFound() > 0 && results.get(0).get("orcid_id") != null) {
// If there is one, add the ORCID identifier to the Element.
valueElem.getField().add(createValue("orcid_id", (String) results.get(0).get("orcid_id")));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static boolean isOrcidAuthorityControlled(MetadataField field) {
String solrAuthorAuthority = configurationService.getProperty("choices.plugin." + field.toString('.'));
return metadataAuthorityService.isAuthorityControlled(metadataAuthorityService.makeFieldKey(field))
&& solrAuthorAuthority != null
&& solrAuthorAuthority.equals("SolrAuthorAuthority");
}

/**
* Utility method to retrieve a structured XML in XOAI format
* @param context
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.xoai.tests.stylesheets;

import static org.dspace.xoai.tests.support.XmlMatcherBuilder.xml;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;

import org.dspace.xoai.tests.support.XmlMatcherBuilder;
import org.junit.Test;

public class OpenAireXslTest extends AbstractXSLTest {

@Test
public void openAireCanTransformOrcidAuthors() throws Exception {
String result = apply("oai_openaire.xsl").to(resource("xoai-test2.xml"));

// match title
assertThat(result, openAire().withXPath(
"/oaire:resource/datacite:titles/datacite:title",
containsString("Test Item")));

// match authors
assertThat(result, openAire().withXPath(
"/oaire:resource/datacite:creators/datacite:creator[1]/datacite:creatorName",
containsString("PlainText, One")));
assertThat(result, openAire().withXPath(
"/oaire:resource/datacite:creators/datacite:creator[2]/datacite:creatorName",
containsString("Smith, John")));
assertThat(result, openAire().withXPath(
"/oaire:resource/datacite:creators/datacite:creator[3]/datacite:creatorName",
containsString("Doe, Jane")));
assertThat(result, openAire().withXPath(
"/oaire:resource/datacite:creators/datacite:creator[4]/datacite:creatorName",
containsString("PlainText, Two")));

// match ORCID IDs
// first author shouldn't have an ORCID ID
assertThat(result, openAire().withXPath(
"/oaire:resource/datacite:creators/datacite:creator[1]/datacite:nameIdentifier" +
"[@schemeURI='http://orcid.org']", containsString("")));
assertThat(result, openAire().withXPath(
"/oaire:resource/datacite:creators/datacite:creator[2]/datacite:nameIdentifier" +
"[@schemeURI='http://orcid.org']", containsString("0000-0000-0000-1234")));
assertThat(result, openAire().withXPath(
"/oaire:resource/datacite:creators/datacite:creator[3]/datacite:nameIdentifier" +
"[@schemeURI='http://orcid.org']", containsString("0000-0000-0000-5678")));
// final author shouldn't have an ORCID ID
assertThat(result, openAire().withXPath(
"/oaire:resource/datacite:creators/datacite:creator[1]/datacite:nameIdentifier" +
"[@schemeURI='http://orcid.org']", containsString("")));

}

private XmlMatcherBuilder openAire() {
return xml().withNamespace("oaire", "http://namespace.openaire.eu/schema/oaire/")
.withNamespace("datacite", "http://datacite.org/schema/kernel-4")
.withNamespace("dc", "http://purl.org/dc/elements/1.1/")
.withNamespace("doc", "http://www.lyncode.com/xoai")
.withNamespace("rdf", "http://www.w3.org/TR/rdf-concepts/")
.withNamespace("vc", "http://www.w3.org/2007/XMLSchema-versioning")
.withNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
}
}
123 changes: 123 additions & 0 deletions dspace-oai/src/test/resources/xoai-test2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
The contents of this file are subject to the license and copyright
detailed in the LICENSE and NOTICE files at the root of the source
tree and available online at
http://www.dspace.org/license/
-->
<metadata xmlns="http://www.lyncode.com/xoai" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.lyncode.com/xoai http://www.lyncode.com/xsd/xoai.xsd">
<element name="dc">
<element name="contributor">
<element name="author">
<element name="none">
<field name="value">PlainText, One</field>
<field name="authority">e069e116-6ed5-40dd-85da-8a7d3e30d663</field>
<field name="confidence">-1</field>
<field name="value">Smith, John</field>
<field name="authority">376bbd13-dac5-4a32-9d35-70742e3f84c5</field>
<field name="confidence">600</field>
<field name="orcid_id">0000-0000-0000-1234</field>
<field name="value">Doe, Jane</field>
<field name="authority">102616ab-95dd-4974-af1a-8f587c61eed1</field>
<field name="confidence">600</field>
<field name="orcid_id">0000-0000-0000-5678</field>
<field name="value">PlainText, Two</field>
<field name="authority">a485dbe7-c5de-470f-ae33-ca166e6cdbae</field>
<field name="confidence">-1</field>
</element>
</element>
</element>
<element name="date">
<element name="accessioned">
<element name="none">
<field name="value">2024-12-29</field>
</element>
</element>
<element name="available">
<element name="none">
<field name="value">2024-12-31</field>
</element>
</element>
<element name="issued">
<element name="none">
<field name="value">2024-12-30</field>
</element>
</element>
</element>
<element name="identifier">
<element name="uri">
<element name="none">
<field name="value">http://localhost:4000/handle/123456789/5</field>
</element>
</element>
</element>
<element name="description">
<element name="abstract">
<element name="none">
<field name="value">This is a test item.</field>
</element>
</element>
</element>
<element name="title">
<element name="none">
<field name="value">Test Item</field>
</element>
</element>
</element>
<element name="bundles">
<element name="bundle">
<field name="name">ORIGINAL</field>
<element name="bitstreams">
<element name="bitstream">
<field name="name">test.pdf</field>
<field name="originalName">test.pdf</field>
<field name="format">application/pdf</field>
<field name="size">28425</field>
<field name="url">http://localhost:4000/bitstreams/0e26b0db-1714-48e5-9ac0-77499ebe5cd8/download
</field>
<field name="checksum">0cf16e811f0070cd46ba2e43ca956a3d</field>
<field name="checksumAlgorithm">MD5</field>
<field name="sid">1</field>
</element>
</element>
</element>
<element name="bundle">
<field name="name">LICENSE</field>
<element name="bitstreams">
<element name="bitstream">
<field name="name">license.txt</field>
<field name="originalName">license.txt</field>
<field name="format">text/plain; charset=utf-8</field>
<field name="size">1748</field>
<field name="url">http://localhost:4000/bitstreams/fc78f4c5-350f-434a-8aa5-a89477994e73/download
</field>
<field name="checksum">8a4605be74aa9ea9d79846c1fba20a33</field>
<field name="checksumAlgorithm">MD5</field>
<field name="sid">1</field>
</element>
</element>
</element>
</element>
<element name="others">
<field name="handle">123456789/5</field>
<field name="identifier">oai:localhost:123456789/5</field>
<field name="lastModifyDate">2024-12-31 14:35:41.465</field>
<element name="access-status">
<field name="value">open.access</field>
</element>
</element>
<element name="repository">
<field name="url">http://localhost:4000</field>
<field name="name">DSpace at My University</field>
<field name="mail">[email protected]</field>
</element>
<element name="license">
<field name="bin">
Tk9URTogUExBQ0UgWU9VUiBPV04gTElDRU5TRSBIRVJFClRoaXMgc2FtcGxlIGxpY2Vuc2UgaXMgcHJvdmlkZWQgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seS4KCk5PTi1FWENMVVNJVkUgRElTVFJJQlVUSU9OIExJQ0VOU0UKCkJ5IHNpZ25pbmcgYW5kIHN1Ym1pdHRpbmcgdGhpcyBsaWNlbnNlLCB5b3UgKHRoZSBhdXRob3Iocykgb3IgY29weXJpZ2h0Cm93bmVyKSBncmFudHMgdG8gRFNwYWNlIFVuaXZlcnNpdHkgKERTVSkgdGhlIG5vbi1leGNsdXNpdmUgcmlnaHQgdG8gcmVwcm9kdWNlLAp0cmFuc2xhdGUgKGFzIGRlZmluZWQgYmVsb3cpLCBhbmQvb3IgZGlzdHJpYnV0ZSB5b3VyIHN1Ym1pc3Npb24gKGluY2x1ZGluZwp0aGUgYWJzdHJhY3QpIHdvcmxkd2lkZSBpbiBwcmludCBhbmQgZWxlY3Ryb25pYyBmb3JtYXQgYW5kIGluIGFueSBtZWRpdW0sCmluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gYXVkaW8gb3IgdmlkZW8uCgpZb3UgYWdyZWUgdGhhdCBEU1UgbWF5LCB3aXRob3V0IGNoYW5naW5nIHRoZSBjb250ZW50LCB0cmFuc2xhdGUgdGhlCnN1Ym1pc3Npb24gdG8gYW55IG1lZGl1bSBvciBmb3JtYXQgZm9yIHRoZSBwdXJwb3NlIG9mIHByZXNlcnZhdGlvbi4KCllvdSBhbHNvIGFncmVlIHRoYXQgRFNVIG1heSBrZWVwIG1vcmUgdGhhbiBvbmUgY29weSBvZiB0aGlzIHN1Ym1pc3Npb24gZm9yCnB1cnBvc2VzIG9mIHNlY3VyaXR5LCBiYWNrLXVwIGFuZCBwcmVzZXJ2YXRpb24uCgpZb3UgcmVwcmVzZW50IHRoYXQgdGhlIHN1Ym1pc3Npb24gaXMgeW91ciBvcmlnaW5hbCB3b3JrLCBhbmQgdGhhdCB5b3UgaGF2ZQp0aGUgcmlnaHQgdG8gZ3JhbnQgdGhlIHJpZ2h0cyBjb250YWluZWQgaW4gdGhpcyBsaWNlbnNlLiBZb3UgYWxzbyByZXByZXNlbnQKdGhhdCB5b3VyIHN1Ym1pc3Npb24gZG9lcyBub3QsIHRvIHRoZSBiZXN0IG9mIHlvdXIga25vd2xlZGdlLCBpbmZyaW5nZSB1cG9uCmFueW9uZSdzIGNvcHlyaWdodC4KCklmIHRoZSBzdWJtaXNzaW9uIGNvbnRhaW5zIG1hdGVyaWFsIGZvciB3aGljaCB5b3UgZG8gbm90IGhvbGQgY29weXJpZ2h0LAp5b3UgcmVwcmVzZW50IHRoYXQgeW91IGhhdmUgb2J0YWluZWQgdGhlIHVucmVzdHJpY3RlZCBwZXJtaXNzaW9uIG9mIHRoZQpjb3B5cmlnaHQgb3duZXIgdG8gZ3JhbnQgRFNVIHRoZSByaWdodHMgcmVxdWlyZWQgYnkgdGhpcyBsaWNlbnNlLCBhbmQgdGhhdApzdWNoIHRoaXJkLXBhcnR5IG93bmVkIG1hdGVyaWFsIGlzIGNsZWFybHkgaWRlbnRpZmllZCBhbmQgYWNrbm93bGVkZ2VkCndpdGhpbiB0aGUgdGV4dCBvciBjb250ZW50IG9mIHRoZSBzdWJtaXNzaW9uLgoKSUYgVEhFIFNVQk1JU1NJT04gSVMgQkFTRUQgVVBPTiBXT1JLIFRIQVQgSEFTIEJFRU4gU1BPTlNPUkVEIE9SIFNVUFBPUlRFRApCWSBBTiBBR0VOQ1kgT1IgT1JHQU5JWkFUSU9OIE9USEVSIFRIQU4gRFNVLCBZT1UgUkVQUkVTRU5UIFRIQVQgWU9VIEhBVkUKRlVMRklMTEVEIEFOWSBSSUdIVCBPRiBSRVZJRVcgT1IgT1RIRVIgT0JMSUdBVElPTlMgUkVRVUlSRUQgQlkgU1VDSApDT05UUkFDVCBPUiBBR1JFRU1FTlQuCgpEU1Ugd2lsbCBjbGVhcmx5IGlkZW50aWZ5IHlvdXIgbmFtZShzKSBhcyB0aGUgYXV0aG9yKHMpIG9yIG93bmVyKHMpIG9mIHRoZQpzdWJtaXNzaW9uLCBhbmQgd2lsbCBub3QgbWFrZSBhbnkgYWx0ZXJhdGlvbiwgb3RoZXIgdGhhbiBhcyBhbGxvd2VkIGJ5IHRoaXMKbGljZW5zZSwgdG8geW91ciBzdWJtaXNzaW9uLgo=
</field>
</element>
</metadata>
8 changes: 8 additions & 0 deletions dspace/config/crosswalks/oai/metadataFormats/oai_openaire.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@
<datacite:creators>
<!-- datacite.creator -->
<xsl:for-each select="./doc:element/doc:field[@name='value']">
<!-- set 'orcid' variable if there is an 'orcid_id' field and if the first preceding 'value' field matches the text of the current node -->
<xsl:variable name="orcid" select="../doc:field[@name='orcid_id' and preceding-sibling::doc:field[@name='value'][ 1]/text() = current()/text()]" />
<xsl:variable name="isRelatedEntity">
<xsl:call-template name="isRelatedEntity">
<xsl:with-param name="element" select="."/>
Expand All @@ -164,6 +166,12 @@
<datacite:creatorName>
<xsl:value-of select="./text()"/>
</datacite:creatorName>
<xsl:if test="$orcid">
<!-- https://guidelines.openaire.eu/en/latest/data/field_creator.html#nameidentifier-r -->
<datacite:nameIdentifier nameIdentifierScheme="ORCID" schemeURI="http://orcid.org">
<xsl:value-of select="$orcid"/>
</datacite:nameIdentifier>
</xsl:if>
</datacite:creator>
</xsl:otherwise>
</xsl:choose>
Expand Down

0 comments on commit 048b38f

Please sign in to comment.