Skip to content

Commit 06cc3ac

Browse files
Adds support for Schema 4.6 changes in Citeproc and Schema.org reading/writing
1 parent ae5783a commit 06cc3ac

10 files changed

+180
-7
lines changed

lib/bolognese/metadata_utils.rb

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ def citeproc_hsh
153153
"language" => language,
154154
"author" => author,
155155
"contributor" => to_citeproc(contributors),
156+
"translator" => contributors ? to_citeproc(contributors.select { |c| c["contributorType"] == "Translator" }) : nil,
156157
"issued" => get_date(dates, "Issued") ? get_date_parts(get_date(dates, "Issued")) : get_date_parts(publication_year.to_s),
157158
"submitted" => Array.wrap(dates).find { |d| d["dateType"] == "Submitted" }.to_h.fetch("__content__", nil),
158159
"abstract" => parse_attributes(descriptions, content: "description", first: true),

lib/bolognese/readers/citeproc_reader.rb

+6
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ def read_citeproc(string: nil, **options)
5252
[{ "nameType" => "Organizational", "name" => ":(unav)" }]
5353
end
5454
contributors = get_authors(from_citeproc(Array.wrap(meta.fetch("editor", nil))))
55+
translators = get_authors(from_citeproc(Array.wrap(meta.fetch("translator", nil))))
56+
translators.each do |translator|
57+
translator["contributorType"] = "Translator"
58+
end
59+
contributors += translators
60+
5561
dates = if date = get_date_from_date_parts(meta.fetch("issued", nil))
5662
if Date.edtf(date).present?
5763
[{ "date" => date,

lib/bolognese/readers/schema_org_reader.rb

+21-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ module SchemaOrgReader
1010
"isPartOf" => "IsPartOf",
1111
"hasPart" => "HasPart",
1212
"isPredecessor" => "IsPreviousVersionOf",
13-
"isSuccessor" => "IsNewVersionOf"
13+
"isSuccessor" => "IsNewVersionOf",
14+
"workTranslation" => "HasTranslation",
15+
"translationOfWork" => "IsTranslationOf"
1416
}
1517

1618
SO_TO_DC_REVERSE_RELATION_TYPES = {
@@ -74,6 +76,12 @@ def read_schema_org(string: nil, **options)
7476
creators = get_authors(from_schema_org_creators(Array.wrap(authors)))
7577
end
7678
contributors = get_authors(from_schema_org_contributors(Array.wrap(meta.fetch("editor", nil))))
79+
translators = get_authors(from_schema_org_contributors(Array.wrap(meta.fetch("translator", nil))))
80+
translators.map! do |translator|
81+
translator["contributorType"] = "Translator"
82+
translator
83+
end
84+
contributors += translators
7785

7886
publisher = {
7987
"name" => parse_attributes(meta.fetch("publisher", nil), content: "name", first: true),
@@ -106,7 +114,9 @@ def read_schema_org(string: nil, **options)
106114
Array.wrap(schema_org_references(meta)) +
107115
Array.wrap(schema_org_is_referenced_by(meta)) +
108116
Array.wrap(schema_org_is_supplement_to(meta)) +
109-
Array.wrap(schema_org_is_supplemented_by(meta))
117+
Array.wrap(schema_org_is_supplemented_by(meta)) +
118+
Array.wrap(schema_org_has_translation(meta)) +
119+
Array.wrap(schema_org_is_translation_of(meta))
110120

111121
rights_list = Array.wrap(meta.fetch("license", nil)).compact.map do |rl|
112122
hsh_to_spdx("__content__" => rl["name"], "rightsURI" => rl["id"])
@@ -127,6 +137,7 @@ def read_schema_org(string: nil, **options)
127137
dates << { "date" => meta.fetch("datePublished"), "dateType" => "Issued" } if Date.edtf(meta.fetch("datePublished", nil)).present?
128138
dates << { "date" => meta.fetch("dateCreated"), "dateType" => "Created" } if Date.edtf(meta.fetch("dateCreated", nil)).present?
129139
dates << { "date" => meta.fetch("dateModified"), "dateType" => "Updated" } if Date.edtf(meta.fetch("dateModified", nil)).present?
140+
dates << { "date" => meta.fetch("temporalCoverage"), "dateType" => "Coverage" } if Date.edtf(meta.fetch("temporalCoverage", nil)).present?
130141
publication_year = meta.fetch("datePublished")[0..3] if meta.fetch("datePublished", nil).present?
131142

132143
if meta.fetch("inLanguage", nil).is_a?(String)
@@ -240,6 +251,14 @@ def schema_org_is_supplemented_by(meta)
240251
schema_org_related_identifier(meta, relation_type: "isBasedOn")
241252
end
242253

254+
def schema_org_has_translation(meta)
255+
schema_org_related_identifier(meta, relation_type: "workTranslation", )
256+
end
257+
258+
def schema_org_is_translation_of(meta)
259+
schema_org_related_identifier(meta, relation_type: "translationOfWork")
260+
end
261+
243262
end
244263
end
245264
end

lib/bolognese/writers/schema_org_writer.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def schema_hsh
1313
"name" => parse_attributes(titles, content: "title", first: true),
1414
"author" => to_schema_org_creators(creators),
1515
"editor" => to_schema_org_contributors(contributors),
16-
"translator" => to_schema_org_contributors(contributors.select { |c| c["contributorType"] == "Translator" }),
16+
"translator" => contributors ? to_schema_org_contributors(contributors.select { |c| c["contributorType"] == "Translator" }) : nil,
1717
"description" => parse_attributes(abstract_description, content: "description", first: true),
1818
"license" => Array.wrap(rights_list).map { |l| l["rightsUri"] }.compact.unwrap,
1919
"version" => version_info,

spec/fixtures/citeproc.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
"family": "Fenner",
2828
"given": "Martin",
2929
"literal": "Fenner, Martin"
30-
}
31-
]
30+
}],
31+
"translator": [{
32+
"family": "Ross",
33+
"given": "Cody",
34+
"literal": "Ross, Cody"
35+
}]
3236
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
{
2+
"@context": "http://schema.org",
3+
"@type": "Project",
4+
"@id": "https://doi.org/10.82433/b09z-4k37",
5+
"additionalType": "Research Project",
6+
"name": "Example Title",
7+
"author": [
8+
{
9+
"name": "ExampleGivenName ExampleFamilyName",
10+
"givenName": "ExampleGivenName",
11+
"familyName": "ExampleFamilyName",
12+
"affiliation": {
13+
"@type": "Organization",
14+
"@id": "https://ror.org/04wxnsj81",
15+
"name": "ExampleAffiliation"
16+
},
17+
"@type": "Person",
18+
"@id": "https://orcid.org/0000-0001-5727-2427"
19+
},
20+
{
21+
"name": "ExampleOrganization",
22+
"@type": "Organization",
23+
"@id": "https://ror.org/04wxnsj81"
24+
}
25+
],
26+
"editor": [
27+
{
28+
"name": "Jane Doe",
29+
"givenName": "Jane",
30+
"familyName": "Doe",
31+
"affiliation": {
32+
"@type": "Organization",
33+
"@id": "https://ror.org/04wxnsj81",
34+
"name": "ExampleAffiliation"
35+
},
36+
"@type": "Person",
37+
"@id": "https://orcid.org/0000-0003-1419-2405"
38+
},
39+
{
40+
"name": "John Smith",
41+
"givenName": "John",
42+
"familyName": "Smith",
43+
"affiliation": {
44+
"@type": "Organization",
45+
"@id": "https://ror.org/04wxnsj81",
46+
"name": "ExampleAffiliation"
47+
},
48+
"@type": "Person"
49+
}
50+
],
51+
"translator": {
52+
"name": "Cody",
53+
"givenName": "Cody",
54+
"familyName": "Ross",
55+
"affiliation": {
56+
"@type": "Organization",
57+
"@id": "https://ror.org/04wxnsj81",
58+
"name": "ExampleAffiliation"
59+
},
60+
"@type": "Person",
61+
"@id": "https://orcid.org/0000-0003-1419-2405"
62+
},
63+
"description": "This dataset illustrates the use of new DataCite fields, including Project and Award resource types, RRID, CSTR, Translator, and others.",
64+
"license": "https://creativecommons.org/licenses/by/4.0/legalcode",
65+
"version": "1",
66+
"keywords": "FOS: Computer and information sciences, FOS: Computer and information sciences, Digital curation and preservation, Example Subject",
67+
"contentSize": "1 MB",
68+
"encodingFormat": "application/xml",
69+
"dateCreated": "2023-01-01",
70+
"datePublished": "2023-01-01",
71+
"dateModified": "2023-01-01",
72+
"temporalCoverage": "2020-01-01",
73+
"spatialCoverage": {
74+
"@type": "Place",
75+
"geo": {
76+
"@type": "GeoCoordinates",
77+
"address": "Vancouver, British Columbia, Canada",
78+
"latitude": "49.2827",
79+
"longitude": "-123.1207"
80+
}
81+
},
82+
"citation": [
83+
{
84+
"@type": "CreativeWork"
85+
},
86+
{
87+
"@type": "CreativeWork"
88+
}
89+
],
90+
"workTranslation": {
91+
"@id": "https://doi.org/10.1234/translated-version",
92+
"@type": "CreativeWork"
93+
},
94+
"translationOfWork": {
95+
"@id": "https://doi.org/10.1234/other-version",
96+
"@type": "CreativeWork"
97+
},
98+
"schemaVersion": "http://datacite.org/schema/kernel-4",
99+
"publisher": {
100+
"@type": "Organization",
101+
"@id": "https://ror.org/04z8jg394",
102+
"name": "Example Publisher"
103+
},
104+
"provider": {
105+
"@type": "Organization",
106+
"name": "datacite"
107+
}
108+
}

spec/readers/citeproc_reader_spec.rb

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
expect(subject.url).to eq("https://blog.datacite.org/eating-your-own-dog-food")
2121
expect(subject.types).to eq("bibtex"=>"article", "citeproc"=>"post-weblog", "resourceTypeGeneral"=>"Text", "ris"=>"GEN", "schemaOrg"=>"BlogPosting")
2222
expect(subject.creators).to eq([{"familyName"=>"Fenner", "givenName"=>"Martin", "name"=>"Fenner, Martin"}])
23+
expect(subject.contributors).to eq([{"familyName"=>"Ross", "givenName"=>"Cody", "name"=>"Ross, Cody", "contributorType"=>"Translator"}])
2324
expect(subject.publisher).to eq({"name"=>"DataCite"})
2425
expect(subject.titles).to eq([{"title"=>"Eating your own Dog Food"}])
2526
expect(subject.descriptions.first["description"]).to start_with("Eating your own dog food")

spec/readers/datacite_reader_spec.rb

-2
Original file line numberDiff line numberDiff line change
@@ -1815,8 +1815,6 @@
18151815
input = fixture_path + 'datacite-example-full-v4.6.xml'
18161816
subject = Bolognese::Metadata.new(input: input)
18171817

1818-
puts "Validation Errors: #{subject.errors.inspect}"
1819-
18201818
expect(subject.valid?).to be true
18211819

18221820
# Test resourceTypeGeneral for Project

spec/readers/schema_org_reader_spec.rb

+27
Original file line numberDiff line numberDiff line change
@@ -340,5 +340,32 @@
340340
"funderIdentifierType"=>"Crossref Funder ID",
341341
"funderName"=>"European Commission"}])
342342
end
343+
344+
it "Schema 4.6 attributes" do
345+
input = fixture_path + 'schema_org_4.6_attributes.json'
346+
subject = Bolognese::Metadata.new(input: input)
347+
348+
expect(subject.related_identifiers).to eq(
349+
[
350+
{"relatedIdentifier"=>"10.1234/translated-version", "relatedIdentifierType"=>"DOI", "relationType"=>"HasTranslation"},
351+
{"relatedIdentifier"=>"10.1234/other-version", "relatedIdentifierType"=>"DOI", "relationType"=>"IsTranslationOf"},
352+
]
353+
)
354+
expect(subject.dates).to eq(
355+
[
356+
{"date"=>"2023-01-01", "dateType"=>"Issued"},
357+
{"date"=>"2023-01-01", "dateType"=>"Created"},
358+
{"date"=>"2023-01-01", "dateType"=>"Updated"},
359+
{"date"=>"2020-01-01", "dateType"=>"Coverage"}
360+
]
361+
)
362+
expect(subject.contributors).to eq(
363+
[
364+
{"name"=>"Doe, Jane", "givenName"=>"Jane", "familyName"=>"Doe", "nameType"=>"Personal", "affiliation"=>[{"name"=>"ExampleAffiliation", "affiliationIdentifier"=>"https://ror.org/04wxnsj81", "affiliationIdentifierScheme"=>"ROR"}], "nameIdentifiers"=>[{"nameIdentifier"=>"https://orcid.org/0000-0003-1419-2405", "schemeUri"=>"https://orcid.org", "nameIdentifierScheme"=>"ORCID"}]},
365+
{"name"=>"Smith, John", "givenName"=>"John", "familyName"=>"Smith", "nameType"=>"Personal", "affiliation"=>[{"name"=>"ExampleAffiliation", "affiliationIdentifier"=>"https://ror.org/04wxnsj81", "affiliationIdentifierScheme"=>"ROR"}]},
366+
{"name"=>"Ross, Cody", "givenName"=>"Cody", "familyName"=>"Ross", "nameType"=>"Personal", "affiliation"=>[{"name"=>"ExampleAffiliation", "affiliationIdentifier"=>"https://ror.org/04wxnsj81", "affiliationIdentifierScheme"=>"ROR"}], "nameIdentifiers"=>[{"nameIdentifier"=>"https://orcid.org/0000-0003-1419-2405", "schemeUri"=>"https://orcid.org", "nameIdentifierScheme"=>"ORCID"}], "contributorType"=>"Translator"},
367+
]
368+
)
369+
end
343370
end
344371
end

spec/writers/citeproc_writer_spec.rb

+9
Original file line numberDiff line numberDiff line change
@@ -286,5 +286,14 @@
286286
expect(json["DOI"]).to eq("10.34747/g6yb-3412")
287287
expect(json["issued"]).to eq("date-parts"=>[[2019]])
288288
end
289+
290+
it "from Schema 4.6 with Translator contributor" do
291+
input = fixture_path + 'datacite-example-full-v4.6.xml'
292+
subject = Bolognese::Metadata.new(input: input)
293+
json = JSON.parse(subject.citeproc)
294+
expect(json["translator"]).to eq([
295+
{"family"=>"Doe", "given"=>"Jane"},
296+
])
297+
end
289298
end
290299
end

0 commit comments

Comments
 (0)