bolognese 2.0.0 → 2.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +1 -1
  3. data/.github/workflows/release.yml +2 -2
  4. data/Gemfile.lock +13 -12
  5. data/bolognese.gemspec +4 -3
  6. data/lib/bolognese/author_utils.rb +5 -5
  7. data/lib/bolognese/datacite_utils.rb +2 -2
  8. data/lib/bolognese/metadata_utils.rb +2 -1
  9. data/lib/bolognese/readers/citeproc_reader.rb +6 -0
  10. data/lib/bolognese/readers/crossref_reader.rb +37 -4
  11. data/lib/bolognese/readers/datacite_reader.rb +1 -1
  12. data/lib/bolognese/readers/schema_org_reader.rb +26 -4
  13. data/lib/bolognese/utils.rb +14 -9
  14. data/lib/bolognese/version.rb +1 -1
  15. data/lib/bolognese/writers/datacite_json_writer.rb +1 -4
  16. data/lib/bolognese/writers/jats_writer.rb +4 -1
  17. data/lib/bolognese/writers/schema_org_writer.rb +5 -1
  18. data/resources/kernel-4/include/datacite-contributorType-v4.xsd +3 -1
  19. data/resources/kernel-4/include/datacite-dateType-v4.xsd +3 -1
  20. data/resources/kernel-4/include/datacite-relatedIdentifierType-v4.xsd +5 -2
  21. data/resources/kernel-4/include/datacite-relationType-v4.xsd +7 -3
  22. data/resources/kernel-4/include/datacite-resourceType-v4.xsd +5 -1
  23. data/resources/kernel-4/include/datacite-titleType-v4.xsd +1 -1
  24. data/resources/kernel-4/metadata.xsd +2 -1
  25. data/resources/kernel-4.6/include/datacite-contributorType-v4.xsd +37 -0
  26. data/resources/kernel-4.6/include/datacite-dateType-v4.xsd +27 -0
  27. data/resources/kernel-4.6/include/datacite-descriptionType-v4.xsd +19 -0
  28. data/resources/kernel-4.6/include/datacite-funderIdentifierType-v4.xsd +16 -0
  29. data/resources/kernel-4.6/include/datacite-nameType-v4.xsd +10 -0
  30. data/resources/kernel-4.6/include/datacite-numberType-v4.xsd +12 -0
  31. data/resources/kernel-4.6/include/datacite-relatedIdentifierType-v4.xsd +37 -0
  32. data/resources/kernel-4.6/include/datacite-relationType-v4.xsd +57 -0
  33. data/resources/kernel-4.6/include/datacite-resourceType-v4.xsd +49 -0
  34. data/resources/kernel-4.6/include/datacite-titleType-v4.xsd +14 -0
  35. data/resources/kernel-4.6/include/xml.xsd +286 -0
  36. data/resources/kernel-4.6/metadata.xsd +712 -0
  37. data/spec/author_utils_spec.rb +13 -7
  38. data/spec/datacite_utils_spec.rb +151 -1
  39. data/spec/fixtures/citeproc.json +6 -2
  40. data/spec/fixtures/crossref_schema_4.6_values.xml +183 -0
  41. data/spec/fixtures/datacite-example-ROR-nameIdentifiers.xml +8 -0
  42. data/spec/fixtures/datacite-example-full-v4.6.xml +114 -0
  43. data/spec/fixtures/datacite-xml-lang.xml +1 -1
  44. data/spec/fixtures/datacite_blank_name_identifier.xml +22 -0
  45. data/spec/fixtures/datacite_blank_publisher.xml +18 -0
  46. data/spec/fixtures/datacite_journal_article.xml +64 -0
  47. data/spec/fixtures/schema_org.json +1 -0
  48. data/spec/fixtures/schema_org_4.6_attributes.json +108 -0
  49. data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/get_crossref_metadata/another_book.yml +5 -45
  50. data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/insert_contributors_Translator/supports_Translator_contributorType.yml +71 -0
  51. data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/insert_dates_with_Coverage/inserts_date_with_dateType_Coverage.yml +71 -0
  52. data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/insert_related_identifiers_CSTR/supports_CSTR_relatedIdentifierType.yml +71 -0
  53. data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/insert_related_identifiers_HasTranslation/supports_HasTranslation_relationType.yml +71 -0
  54. data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/insert_related_identifiers_RRID/supports_RRID_relatedIdentifierType.yml +71 -0
  55. data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/insert_resource_type_with_Award/supports_Award_as_resourceTypeGeneral.yml +71 -0
  56. data/spec/fixtures/vcr_cassettes/Bolognese_Metadata/insert_resource_type_with_Project/supports_Project_as_resourceTypeGeneral.yml +71 -0
  57. data/spec/readers/citeproc_reader_spec.rb +1 -0
  58. data/spec/readers/codemeta_reader_spec.rb +1 -1
  59. data/spec/readers/crossref_reader_spec.rb +31 -0
  60. data/spec/readers/datacite_reader_spec.rb +98 -7
  61. data/spec/readers/schema_org_reader_spec.rb +29 -2
  62. data/spec/writers/citation_writer_spec.rb +10 -1
  63. data/spec/writers/citeproc_writer_spec.rb +9 -0
  64. data/spec/writers/crosscite_writer_spec.rb +2 -2
  65. data/spec/writers/datacite_json_writer_spec.rb +16 -32
  66. data/spec/writers/datacite_writer_spec.rb +73 -2
  67. data/spec/writers/jats_writer_spec.rb +8 -1
  68. data/spec/writers/schema_org_writer_spec.rb +51 -2
  69. metadata +58 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23ccf372b59b7d9c8919ec7ad7137eef6e99512eed488977e847f938f389aa2f
4
- data.tar.gz: 390e56023d57e637a52776a98dcd0bea4fa0acd8b8459ced05cbc6785f69fe0a
3
+ metadata.gz: b752f8f05f74d5be1c782812a9359ad7957ee6a024799d220dce7133e83da5e5
4
+ data.tar.gz: 9dbfa358d928c646ce329877765867911f78125ba3cf22311dc1955b53914c9c
5
5
  SHA512:
6
- metadata.gz: 3a7364a75d69846ada1320bc0e8954b72695216d2807ec39ab1694ac4d120d97806addb9ceed8b9da8c1eb06ae28740cf6d2c118cb76a05e15ca993bf81ad470
7
- data.tar.gz: 6281527f6b312d398a96b9f1df9be55de991f6ac939417131633b24ddaa24741c3b86c3b2e4e73408ca1350e0b17addf9439ae30dff998bc6dda07e8c4459db7
6
+ metadata.gz: '04985fba7e3b5c1985e767037d6a6d20a87291bc76cfc556cd4a1b76d92f5e5178be593f475c6f406419306f1f69d6c5e948454f8acce2e0b19a493fe3e5c7e0'
7
+ data.tar.gz: eaa39f50bd69319f7218bf5db4759c670612983c0d5b83d1044fb442863aa750c9e3084721614d8e752b262567bc9be753fd9f3996f381c290c8a10de6cabad9
@@ -7,7 +7,7 @@ jobs:
7
7
  strategy:
8
8
  fail-fast: false
9
9
  matrix:
10
- ruby: ["2.6", "2.7", "3.0", "3.1"]
10
+ ruby: ["3.0", "3.1", "3.2", "3.3"]
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - uses: actions/checkout@v3
@@ -11,10 +11,10 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - uses: actions/checkout@v3
14
- - name: Set up Ruby 2.6
14
+ - name: Set up Ruby 3.1.4
15
15
  uses: ruby/setup-ruby@v1
16
16
  with:
17
- ruby-version: "2.6"
17
+ ruby-version: "3.1.4"
18
18
 
19
19
  - name: Build
20
20
  run: |
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bolognese (2.0.0)
4
+ bolognese (2.3.5)
5
5
  activesupport (>= 4.2.5)
6
6
  benchmark_methods (~> 0.7)
7
7
  bibtex-ruby (>= 5.1.0)
@@ -16,9 +16,9 @@ PATH
16
16
  json-ld-preloaded (~> 3.1, >= 3.1.3)
17
17
  jsonlint (~> 0.3.0)
18
18
  loofah (~> 2.0, >= 2.0.3)
19
- maremma (>= 4.9.4, < 5)
19
+ maremma (~> 5.0)
20
20
  namae (~> 1.0)
21
- nokogiri (>= 1.13.2, < 1.14)
21
+ nokogiri (~> 1.16, >= 1.16.2)
22
22
  oj (~> 3.10)
23
23
  oj_mimic_json (~> 1.0, >= 1.0.1)
24
24
  postrank-uri (~> 1.0, >= 1.0.18)
@@ -95,10 +95,10 @@ GEM
95
95
  concurrent-ruby (~> 1.0)
96
96
  iso8601 (0.9.1)
97
97
  json (2.6.2)
98
- json-canonicalization (0.3.2)
99
- json-ld (3.2.5)
98
+ json-canonicalization (0.3.1)
99
+ json-ld (3.2.4)
100
100
  htmlentities (~> 4.3)
101
- json-canonicalization (~> 0.3, >= 0.3.2)
101
+ json-canonicalization (~> 0.3)
102
102
  link_header (~> 0.0, >= 0.0.8)
103
103
  multi_json (~> 1.15)
104
104
  rack (>= 2.2, < 4)
@@ -114,7 +114,7 @@ GEM
114
114
  loofah (2.21.3)
115
115
  crass (~> 1.0.2)
116
116
  nokogiri (>= 1.12.0)
117
- maremma (4.9.9)
117
+ maremma (5.0.0)
118
118
  activesupport (>= 4.2.5)
119
119
  addressable (>= 2.3.6)
120
120
  builder (~> 3.2, >= 3.2.2)
@@ -125,17 +125,17 @@ GEM
125
125
  faraday-follow_redirects (~> 0.3.0)
126
126
  faraday-gzip (~> 0.1.0)
127
127
  faraday-multipart (~> 1.0.4)
128
- nokogiri (>= 1.13.1, < 1.14.0)
128
+ nokogiri (~> 1.16, >= 1.16.2)
129
129
  oj (>= 2.8.3)
130
130
  oj_mimic_json (~> 1.0, >= 1.0.1)
131
131
  matrix (0.4.2)
132
- mini_portile2 (2.8.0)
132
+ mini_portile2 (2.8.5)
133
133
  minitest (5.18.0)
134
134
  multi_json (1.15.0)
135
135
  multipart-post (2.3.0)
136
136
  namae (1.1.1)
137
- nokogiri (1.13.9)
138
- mini_portile2 (~> 2.8.0)
137
+ nokogiri (1.16.2)
138
+ mini_portile2 (~> 2.8.2)
139
139
  racc (~> 1.4)
140
140
  oj (3.14.2)
141
141
  oj_mimic_json (1.0.1)
@@ -225,6 +225,7 @@ DEPENDENCIES
225
225
  bundler (>= 1.0)
226
226
  byebug
227
227
  hashdiff (>= 1.0.0.beta1, < 2.0.0)
228
+ json-canonicalization (= 0.3.1)
228
229
  rack-test (~> 0)
229
230
  rake (~> 12.0)
230
231
  rspec (~> 3.4)
@@ -234,4 +235,4 @@ DEPENDENCIES
234
235
  webmock (~> 3.0, >= 3.0.1)
235
236
 
236
237
  BUNDLED WITH
237
- 2.4.20
238
+ 2.5.5
data/bolognese.gemspec CHANGED
@@ -13,12 +13,12 @@ Gem::Specification.new do |s|
13
13
  s.version = Bolognese::VERSION
14
14
  s.extra_rdoc_files = ["README.md"]
15
15
  s.license = 'MIT'
16
- s.required_ruby_version = ['>=2.3']
16
+ s.required_ruby_version = ['>=3.0']
17
17
 
18
18
  # Declare dependencies here, rather than in the Gemfile
19
- s.add_dependency 'maremma', '>= 4.9.4', '< 5'
19
+ s.add_dependency 'maremma', '~> 5.0'
20
20
  #s.add_dependency 'faraday', '~> 0.17.3'
21
- s.add_dependency 'nokogiri', '>= 1.13.2', '< 1.14'
21
+ s.add_dependency 'nokogiri', '~> 1.16', '>= 1.16.2'
22
22
  s.add_dependency 'loofah', '~> 2.0', '>= 2.0.3'
23
23
  s.add_dependency 'builder', '~> 3.2', '>= 3.2.2'
24
24
  s.add_dependency 'activesupport', '>= 4.2.5'
@@ -50,6 +50,7 @@ Gem::Specification.new do |s|
50
50
  s.add_development_dependency 'simplecov', '0.17.1'
51
51
  s.add_development_dependency 'hashdiff', ['>= 1.0.0.beta1', '< 2.0.0']
52
52
  s.add_development_dependency 'byebug'
53
+ s.add_development_dependency 'json-canonicalization', '0.3.1'
53
54
 
54
55
  s.require_paths = ["lib"]
55
56
  s.files = `git ls-files`.split($/)
@@ -30,20 +30,20 @@ module Bolognese
30
30
  name_type = parse_attributes(author.fetch("creatorName", nil), content: "nameType", first: true) || parse_attributes(author.fetch("contributorName", nil), content: "nameType", first: true)
31
31
 
32
32
  name_identifiers = Array.wrap(author.fetch("nameIdentifier", nil)).map do |ni|
33
- ni["__content__"] = ni["__content__"].strip
33
+ name_identifier = ni["__content__"].strip if ni["__content__"].present?
34
34
  if ni["nameIdentifierScheme"] == "ORCID"
35
35
  {
36
- "nameIdentifier" => normalize_orcid(ni["__content__"]),
36
+ "nameIdentifier" => normalize_orcid(name_identifier),
37
37
  "schemeUri" => "https://orcid.org",
38
38
  "nameIdentifierScheme" => "ORCID" }.compact
39
39
  elsif ni["nameIdentifierScheme"] == "ROR"
40
40
  {
41
- "nameIdentifier" => normalize_ror(ni["__content__"]),
41
+ "nameIdentifier" => normalize_ror(name_identifier),
42
42
  "schemeUri" => "https://ror.org",
43
43
  "nameIdentifierScheme" => "ROR" }.compact
44
44
  else
45
45
  {
46
- "nameIdentifier" => ni["__content__"],
46
+ "nameIdentifier" => name_identifier,
47
47
  "schemeUri" => ni.fetch("schemeURI", nil),
48
48
  "nameIdentifierScheme" => ni["nameIdentifierScheme"] }.compact
49
49
  end
@@ -100,7 +100,7 @@ module Bolognese
100
100
 
101
101
  # titleize strings
102
102
  # remove non-standard space characters
103
- author.my_titleize.gsub(/[[:space:]]/, ' ')
103
+ author.gsub(/[[:space:]]/, ' ')
104
104
  end
105
105
 
106
106
  def is_personal_name?(author)
@@ -69,7 +69,7 @@ module Bolognese
69
69
 
70
70
  xml.contributors do
71
71
  Array.wrap(contributors).each do |con|
72
- xml.contributor("contributorType" => con["contributorType"] || "Other") do
72
+ xml.contributor("contributorType" => con["contributorType"]) do
73
73
  insert_person(xml, con, "contributor")
74
74
  end
75
75
  end
@@ -128,7 +128,7 @@ module Bolognese
128
128
  def insert_resource_type(xml)
129
129
  return xml unless types.is_a?(Hash) && (types["schemaOrg"].present? || types["resourceTypeGeneral"])
130
130
 
131
- xml.resourceType(types["resourceType"] || types["schemaOrg"],
131
+ xml.resourceType(types["resourceType"],
132
132
  'resourceTypeGeneral' => types["resourceTypeGeneral"] || Metadata::SO_TO_DC_TRANSLATIONS[types["schemaOrg"]] || "Other")
133
133
  end
134
134
 
@@ -96,7 +96,7 @@ module Bolognese
96
96
  if container.present?
97
97
  container["title"]
98
98
  elsif types["citeproc"] == "article-journal"
99
- publisher
99
+ publisher["name"] if publisher.present?
100
100
  else
101
101
  nil
102
102
  end
@@ -153,6 +153,7 @@ module Bolognese
153
153
  "language" => language,
154
154
  "author" => author,
155
155
  "contributor" => to_citeproc(contributors),
156
+ "translator" => contributors ? to_citeproc(contributors.select { |c| c["contributorType"] == "Translator" }) : nil,
156
157
  "issued" => get_date(dates, "Issued") ? get_date_parts(get_date(dates, "Issued")) : get_date_parts(publication_year.to_s),
157
158
  "submitted" => Array.wrap(dates).find { |d| d["dateType"] == "Submitted" }.to_h.fetch("__content__", nil),
158
159
  "abstract" => parse_attributes(descriptions, content: "description", first: true),
@@ -52,6 +52,12 @@ module Bolognese
52
52
  [{ "nameType" => "Organizational", "name" => ":(unav)" }]
53
53
  end
54
54
  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
+
55
61
  dates = if date = get_date_from_date_parts(meta.fetch("issued", nil))
56
62
  if Date.edtf(date).present?
57
63
  [{ "date" => date,
@@ -4,6 +4,12 @@ module Bolognese
4
4
  module Readers
5
5
  module CrossrefReader
6
6
  # CrossRef types from https://api.crossref.org/types
7
+
8
+ CR_TO_DC_CONTRIBUTOR_TYPES = {
9
+ "editor" => "Editor",
10
+ "translator" => "Translator",
11
+ }
12
+
7
13
  def get_crossref(id: nil, **options)
8
14
  return { "string" => nil, "state" => "not_found" } unless id.present?
9
15
 
@@ -138,7 +144,7 @@ module Bolognese
138
144
 
139
145
  state = meta.present? || read_options.present? ? "findable" : "not_found"
140
146
 
141
- related_identifiers = Array.wrap(crossref_is_part_of(journal_metadata)) + Array.wrap(crossref_references(bibliographic_metadata))
147
+ related_identifiers = Array.wrap(crossref_is_part_of(journal_metadata)) + Array.wrap(crossref_references(bibliographic_metadata)) + Array.wrap(crossref_has_translation(program_metadata)) + Array.wrap(crossref_is_translation_of(program_metadata))
142
148
 
143
149
  container = if journal_metadata.present?
144
150
  issn = normalize_issn(journal_metadata.to_h.fetch("issn", nil))
@@ -187,7 +193,7 @@ module Bolognese
187
193
  "titles" => titles,
188
194
  "identifiers" => identifiers,
189
195
  "creators" => crossref_people(bibliographic_metadata, "author"),
190
- "contributors" => crossref_people(bibliographic_metadata, "editor"),
196
+ "contributors" => crossref_people(bibliographic_metadata, "editor") + crossref_people(bibliographic_metadata, "translator"),
191
197
  "funding_references" => crossref_funding_reference(program_metadata),
192
198
  "publisher" => publisher,
193
199
  "container" => container,
@@ -282,10 +288,11 @@ module Bolognese
282
288
  "givenName" => given_name,
283
289
  "familyName" => family_name,
284
290
  "affiliation" => affiliation.presence,
285
- "contributorType" => contributor_role == "editor" ? "Editor" : nil }.compact
291
+ "contributorType" => contributor_role == 'author' ? nil : CR_TO_DC_CONTRIBUTOR_TYPES[a["contributor_role"]] }.compact
286
292
  else
287
293
  { "nameType" => "Organizational",
288
- "name" => a["name"] || a["__content__"] }
294
+ "name" => a["name"] || a["__content__"],
295
+ "contributorType" => contributor_role == 'author' ? nil : CR_TO_DC_CONTRIBUTOR_TYPES[a["contributor_role"]] }.compact
289
296
  end
290
297
  end
291
298
  end
@@ -362,6 +369,32 @@ module Bolognese
362
369
  end
363
370
  end.compact.unwrap
364
371
  end
372
+
373
+ def crossref_has_translation(program_metadata)
374
+ refs = program_metadata.dig("related_item") if program_metadata.is_a?(Hash)
375
+ Array.wrap(refs).select { |a| a.dig("intra_work_relation", "relationship_type") == "hasTranslation" }.map do |c|
376
+ if c.dig("intra_work_relation", "identifier_type") == "doi"
377
+ { "relatedIdentifier" => parse_attributes(c["intra_work_relation"]).downcase,
378
+ "relationType" => "HasTranslation",
379
+ "relatedIdentifierType" => "DOI" }.compact
380
+ else
381
+ nil
382
+ end
383
+ end.compact.unwrap
384
+ end
385
+
386
+ def crossref_is_translation_of(program_metadata)
387
+ refs = program_metadata.dig("related_item") if program_metadata.is_a?(Hash)
388
+ Array.wrap(refs).select { |a| a.dig("intra_work_relation", "relationship_type") == "isTranslationOf" }.map do |c|
389
+ if c.dig("intra_work_relation", "identifier_type") == "doi"
390
+ { "relatedIdentifier" => parse_attributes(c["intra_work_relation"]).downcase,
391
+ "relationType" => "IsTranslationOf",
392
+ "relatedIdentifierType" => "DOI" }.compact
393
+ else
394
+ nil
395
+ end
396
+ end.compact.unwrap
397
+ end
365
398
  end
366
399
  end
367
400
  end
@@ -101,7 +101,7 @@ module Bolognese
101
101
  { "name" => r.strip }
102
102
  elsif r.is_a?(Hash)
103
103
  {
104
- "name" => r["__content__"].strip,
104
+ "name" => r["__content__"].present? ? r["__content__"].strip : nil,
105
105
  "publisherIdentifier" => r["publisherIdentifierScheme"] == "ROR" ? normalize_ror(r["publisherIdentifier"]) : r["publisherIdentifier"],
106
106
  "publisherIdentifierScheme" => r["publisherIdentifierScheme"],
107
107
  "schemeUri" => r["schemeURI"],
@@ -10,7 +10,9 @@ module Bolognese
10
10
  "isPartOf" => "IsPartOf",
11
11
  "hasPart" => "HasPart",
12
12
  "isPredecessor" => "IsPreviousVersionOf",
13
- "isSuccessor" => "IsNewVersionOf"
13
+ "isSuccessor" => "IsNewVersionOf",
14
+ "workTranslation" => "HasTranslation",
15
+ "translationOfWork" => "IsTranslationOf"
14
16
  }
15
17
 
16
18
  SO_TO_DC_REVERSE_RELATION_TYPES = {
@@ -74,8 +76,17 @@ module Bolognese
74
76
  creators = get_authors(from_schema_org_creators(Array.wrap(authors)))
75
77
  end
76
78
  contributors = get_authors(from_schema_org_contributors(Array.wrap(meta.fetch("editor", nil))))
77
- publisher_name = parse_attributes(meta.fetch("publisher", nil), content: "name", first: true)
78
- publisher = { "name" => publisher_name } if publisher_name.present?
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
85
+
86
+ publisher = {
87
+ "name" => parse_attributes(meta.fetch("publisher", nil), content: "name", first: true),
88
+ "publisherIdentifier" => parse_attributes(meta.fetch("publisher", nil), content: "@id", first: true),
89
+ }.compact if meta.fetch("publisher", nil).present?
79
90
 
80
91
  ct = (schema_org == "Dataset") ? "includedInDataCatalog" : "Periodical"
81
92
  container = if meta.fetch(ct, nil).present?
@@ -103,7 +114,9 @@ module Bolognese
103
114
  Array.wrap(schema_org_references(meta)) +
104
115
  Array.wrap(schema_org_is_referenced_by(meta)) +
105
116
  Array.wrap(schema_org_is_supplement_to(meta)) +
106
- 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))
107
120
 
108
121
  rights_list = Array.wrap(meta.fetch("license", nil)).compact.map do |rl|
109
122
  hsh_to_spdx("__content__" => rl["name"], "rightsURI" => rl["id"])
@@ -124,6 +137,7 @@ module Bolognese
124
137
  dates << { "date" => meta.fetch("datePublished"), "dateType" => "Issued" } if Date.edtf(meta.fetch("datePublished", nil)).present?
125
138
  dates << { "date" => meta.fetch("dateCreated"), "dateType" => "Created" } if Date.edtf(meta.fetch("dateCreated", nil)).present?
126
139
  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?
127
141
  publication_year = meta.fetch("datePublished")[0..3] if meta.fetch("datePublished", nil).present?
128
142
 
129
143
  if meta.fetch("inLanguage", nil).is_a?(String)
@@ -237,6 +251,14 @@ module Bolognese
237
251
  schema_org_related_identifier(meta, relation_type: "isBasedOn")
238
252
  end
239
253
 
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
+
240
262
  end
241
263
  end
242
264
  end
@@ -78,7 +78,9 @@ module Bolognese
78
78
  "Other" => "CreativeWork",
79
79
  # not part of DataCite schema, but used internally
80
80
  "Periodical" => "Periodical",
81
- "DataCatalog" => "DataCatalog"
81
+ "DataCatalog" => "DataCatalog",
82
+ "Award" => "Grant",
83
+ "Project" => "Project"
82
84
  }
83
85
 
84
86
  DC_TO_CP_TRANSLATIONS = {
@@ -600,12 +602,12 @@ module Bolognese
600
602
  end
601
603
 
602
604
  def validate_orcid(orcid)
603
- orcid = Array(/\A(?:(?:http|https):\/\/(?:(?:www|sandbox)?\.)?orcid\.org\/)?(\d{4}[[:space:]-]\d{4}[[:space:]-]\d{4}[[:space:]-]\d{3}[0-9X]+)\z/.match(orcid)).last
605
+ orcid = Array(/\A(?:(?:http|https):\/\/(?:(?:www|sandbox)?\.)?orcid\.org\/)?(\d{4}[[:space:]-]\d{4}[[:space:]-]\d{4}[[:space:]-]\d{3}[0-9X]+)\/{0,1}\z/.match(orcid)).last
604
606
  orcid.gsub(/[[:space:]]/, "-") if orcid.present?
605
607
  end
606
608
 
607
609
  def validate_ror(ror)
608
- Array(/^(?:(?:(?:http|https):\/\/)?ror\.org\/)?(0\w{6}\d{2})$/.match(ror)).last
610
+ Array(/^(?:(?:(?:http|https):\/\/)?ror\.org\/)?(0\w{6}\d{2})\/{0,1}$/.match(ror)).last
609
611
  end
610
612
 
611
613
  def validate_orcid_scheme(orcid_scheme)
@@ -825,7 +827,8 @@ module Bolognese
825
827
 
826
828
  def to_schema_org_contributors(element)
827
829
  element = Array.wrap(element).map do |c|
828
- c["affiliation"] = Array.wrap(c["affiliation"]).map do |a|
830
+ transformed_c = c.dup
831
+ transformed_c["affiliation"] = Array.wrap(c["affiliation"]).map do |a|
829
832
  if a.is_a?(String)
830
833
  name = a
831
834
  affiliation_identifier = nil
@@ -839,10 +842,10 @@ module Bolognese
839
842
  "@id" => affiliation_identifier,
840
843
  "name" => name }.compact
841
844
  end.unwrap
842
- c["@type"] = c["nameType"].present? ? c["nameType"][0..-3] : nil
843
- c["@id"] = Array.wrap(c["nameIdentifiers"]).first.to_h.fetch("nameIdentifier", nil)
844
- c["name"] = c["familyName"].present? ? [c["givenName"], c["familyName"]].join(" ") : c["name"]
845
- c.except("nameIdentifiers", "nameType").compact
845
+ transformed_c["@type"] = c["nameType"].present? ? c["nameType"][0..-3] : nil
846
+ transformed_c["@id"] = Array.wrap(c["nameIdentifiers"]).first.to_h.fetch("nameIdentifier", nil)
847
+ transformed_c["name"] = c["familyName"].present? ? [c["givenName"], c["familyName"]].join(" ") : c["name"]
848
+ transformed_c.except("nameIdentifiers", "nameType").compact
846
849
  end.unwrap
847
850
  end
848
851
 
@@ -1234,7 +1237,9 @@ module Bolognese
1234
1237
  "urn" => "URN",
1235
1238
  "md5" => "md5",
1236
1239
  "minid" => "minid",
1237
- "dataguid" => "dataguid"
1240
+ "dataguid" => "dataguid",
1241
+ "cstr" => "CSTR",
1242
+ "rrid" => "RRID"
1238
1243
  }
1239
1244
 
1240
1245
  identifierTypes[identifier_type.downcase] || identifier_type
@@ -1,3 +1,3 @@
1
1
  module Bolognese
2
- VERSION = "2.0.0"
2
+ VERSION = "2.3.5"
3
3
  end
@@ -4,11 +4,8 @@ module Bolognese
4
4
  module Writers
5
5
  module DataciteJsonWriter
6
6
  def datacite_json
7
- # Remove the following change for the schema 4.5 release
8
7
  if crosscite_hsh.present?
9
- datacite_json_hsh = crosscite_hsh
10
- datacite_json_hsh['publisher'] = self.publisher['name'] if self.publisher&.respond_to?(:to_hash) && self.publisher.has_key?('name') && !self.publisher['name'].blank?
11
- JSON.pretty_generate datacite_json_hsh.transform_keys! { |key| key.camelcase(uppercase_first_letter = :lower) }
8
+ JSON.pretty_generate crosscite_hsh.transform_keys! { |key| key.camelcase(uppercase_first_letter = :lower) }
12
9
  end
13
10
  end
14
11
  end
@@ -86,7 +86,10 @@ module Bolognese
86
86
  end
87
87
 
88
88
  def insert_publisher_name(xml)
89
- xml.send("publisher-name", publisher["name"])
89
+ attributes = {
90
+ "xml:lang" => publisher["lang"]
91
+ }.compact
92
+ xml.send("publisher-name", attributes, publisher["name"])
90
93
  end
91
94
 
92
95
  def insert_publication_date(xml)
@@ -13,6 +13,7 @@ module Bolognese
13
13
  "name" => parse_attributes(titles, content: "title", first: true),
14
14
  "author" => to_schema_org_creators(creators),
15
15
  "editor" => to_schema_org_contributors(contributors),
16
+ "translator" => contributors ? to_schema_org_contributors(contributors.select { |c| c["contributorType"] == "Translator" }) : nil,
16
17
  "description" => parse_attributes(abstract_description, content: "description", first: true),
17
18
  "license" => Array.wrap(rights_list).map { |l| l["rightsUri"] }.compact.unwrap,
18
19
  "version" => version_info,
@@ -23,6 +24,7 @@ module Bolognese
23
24
  "dateCreated" => get_date(dates, "Created"),
24
25
  "datePublished" => get_date(dates, "Issued") || publication_year,
25
26
  "dateModified" => get_date(dates, "Updated"),
27
+ "temporalCoverage" => get_date(dates, "Coverage"),
26
28
  "pageStart" => container.to_h["firstPage"],
27
29
  "pageEnd" => container.to_h["lastPage"],
28
30
  "spatialCoverage" => to_schema_org_spatial_coverage(geo_locations),
@@ -32,12 +34,14 @@ module Bolognese
32
34
  "predecessor_of" => to_schema_org_relation(related_identifiers: related_identifiers, relation_type: "IsPreviousVersionOf"),
33
35
  "successor_of" => to_schema_org_relation(related_identifiers: related_identifiers, relation_type: "IsNewVersionOf"),
34
36
  "citation" => to_schema_org_relation(related_identifiers: related_identifiers, relation_type: "References"),
37
+ "workTranslation" => to_schema_org_relation(related_identifiers: related_identifiers, relation_type: "HasTranslation"),
38
+ "translationOfWork" => to_schema_org_relation(related_identifiers: related_identifiers, relation_type: "IsTranslationOf"),
35
39
  "@reverse" => reverse.presence,
36
40
  "contentUrl" => Array.wrap(content_url).unwrap,
37
41
  "schemaVersion" => schema_version,
38
42
  "periodical" => types.present? ? ((types["schemaOrg"] != "Dataset") && container.present? ? to_schema_org(container) : nil) : nil,
39
43
  "includedInDataCatalog" => types.present? ? ((types["schemaOrg"] == "Dataset") && container.present? ? to_schema_org_container(container, type: "Dataset") : nil) : nil,
40
- "publisher" => publisher.present? ? { "@type" => "Organization", "name" => publisher["name"] } : nil,
44
+ "publisher" => publisher.present? ? { "@type" => "Organization", "@id" => publisher["publisherIdentifier"], "name" => publisher["name"] }.compact : nil,
41
45
  "funder" => to_schema_org_funder(funding_references),
42
46
  "provider" => agency.present? ? { "@type" => "Organization", "name" => agency } : nil
43
47
  }.compact.presence
@@ -2,7 +2,8 @@
2
2
  <!-- Version 1.0 - Created 2011-01-13 - FZ, TIB, Germany
3
3
  2013-05 v3.0: Addition of ID to simpleType element, added values "ResearchGroup" & "Other"
4
4
  2014-08-20 v3.1: Addition of value "DataCurator"
5
- 2015-05-14 v4.0 dropped value "Funder", use new "funderReference" -->
5
+ 2015-05-14 v4.0 dropped value "Funder", use new "funderReference"
6
+ 2024-12-31 v4.6: Addition of value "Translator" -->
6
7
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://datacite.org/schema/kernel-4" targetNamespace="http://datacite.org/schema/kernel-4" elementFormDefault="qualified">
7
8
  <xs:simpleType name="contributorType" id="contributorType">
8
9
  <xs:annotation>
@@ -29,6 +30,7 @@
29
30
  <xs:enumeration value="Researcher" />
30
31
  <xs:enumeration value="Sponsor" />
31
32
  <xs:enumeration value="Supervisor" />
33
+ <xs:enumeration value="Translator" />
32
34
  <xs:enumeration value="WorkPackageLeader" />
33
35
  </xs:restriction>
34
36
  </xs:simpleType>
@@ -2,7 +2,8 @@
2
2
  <!-- Version 1.0 - Created 2011-01-13 - FZ, TIB, Germany
3
3
  2013-05 v3.0: Addition of ID to simpleType element; addition of value "Collected"; deleted "StartDate" & "EndDate"
4
4
  2017-10-23 v4.1: Addition of value "Other"
5
- 2019-02-14 v4.2: Addition of value "Withdrawn"-->
5
+ 2019-02-14 v4.2: Addition of value "Withdrawn"
6
+ 2024-12-31 v4.6: Addition of value "Coverage"-->
6
7
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://datacite.org/schema/kernel-4" targetNamespace="http://datacite.org/schema/kernel-4" elementFormDefault="qualified">
7
8
  <xs:simpleType name="dateType" id="dateType">
8
9
  <xs:annotation>
@@ -13,6 +14,7 @@
13
14
  <xs:enumeration value="Available" />
14
15
  <xs:enumeration value="Collected" />
15
16
  <xs:enumeration value="Copyrighted" />
17
+ <xs:enumeration value="Coverage" />
16
18
  <xs:enumeration value="Created" />
17
19
  <xs:enumeration value="Issued" />
18
20
  <xs:enumeration value="Other" />
@@ -2,8 +2,9 @@
2
2
  <!-- Version 1.0 - Created 2011-01-13 - FZ, TIB, Germany
3
3
  2013-05 v3.0: Addition of ID to simpleType element; addition of value "PMID"
4
4
  2014-08-20 v3.1: Addition of values "arxiv" and "bibcode"
5
- 2015-02-12 v4.0 Addition of value "IGSN"
6
- 2019-02-14 v4.2 Addition of value "w3id" -->
5
+ 2015-02-12 v4.0: Addition of value "IGSN"
6
+ 2019-02-14 v4.2: Addition of value "w3id"
7
+ 2024-12-31 v4.5: Addition of values "CSTR", "RRID" -->
7
8
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://datacite.org/schema/kernel-4" targetNamespace="http://datacite.org/schema/kernel-4" elementFormDefault="qualified">
8
9
  <xs:simpleType name="relatedIdentifierType" id="relatedIdentifierType">
9
10
  <xs:annotation>
@@ -13,6 +14,7 @@
13
14
  <xs:enumeration value="ARK" />
14
15
  <xs:enumeration value="arXiv" />
15
16
  <xs:enumeration value="bibcode" />
17
+ <xs:enumeration value="CSTR" />
16
18
  <xs:enumeration value="DOI" />
17
19
  <xs:enumeration value="EAN13" />
18
20
  <xs:enumeration value="EISSN" />
@@ -25,6 +27,7 @@
25
27
  <xs:enumeration value="LSID" />
26
28
  <xs:enumeration value="PMID" />
27
29
  <xs:enumeration value="PURL" />
30
+ <xs:enumeration value="RRID" />
28
31
  <xs:enumeration value="UPC" />
29
32
  <xs:enumeration value="URL" />
30
33
  <xs:enumeration value="URN" />
@@ -3,9 +3,11 @@
3
3
  2011-01-13 v1.0 - FZ, TIB, Germany
4
4
  2013-05 v3.0: Addition of ID to simpleType element, addition of values "IsIdenticalTo", "HasMetadata" & "IsMetadataFor"
5
5
  2014-08-20 v3.1: Addition of values "Reviews" & "IsReviewedBy" and "IsDerivedFrom" & "IsSourceOf"
6
- 2017-10-23 v.4.1: Addition of values "Describes", "IsDescribedBy", "HasVersion", "IsVersionOf", "Requires", "IsRequiredBy"
7
- 2019-02-14 v.4.2: Addition of values "Obsoletes", "IsObsoletedBy"
8
- 2021-03-05 v.4.4: Addition of value "IsPublishedIn" -->
6
+ 2017-10-23 v4.1: Addition of values "Describes", "IsDescribedBy", "HasVersion", "IsVersionOf", "Requires", "IsRequiredBy"
7
+ 2019-02-14 v4.2: Addition of values "Obsoletes", "IsObsoletedBy"
8
+ 2021-03-05 v4.4: Addition of value "IsPublishedIn"
9
+ 2024-01-22 v4.5: Addition of values "Collects, "IsCollectedBy"
10
+ 2024-12-31 v4.6: Addition of values "HasTranslation", "IsTranslationOf"-->
9
11
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://datacite.org/schema/kernel-4" targetNamespace="http://datacite.org/schema/kernel-4" elementFormDefault="qualified">
10
12
  <xs:simpleType name="relationType" id="relationType">
11
13
  <xs:annotation>
@@ -48,6 +50,8 @@
48
50
  <xs:enumeration value="IsObsoletedBy" />
49
51
  <xs:enumeration value="Collects" />
50
52
  <xs:enumeration value="IsCollectedBy" />
53
+ <xs:enumeration value="HasTranslation" />
54
+ <xs:enumeration value="IsTranslationOf" />
51
55
  </xs:restriction>
52
56
  </xs:simpleType>
53
57
  </xs:schema>
@@ -3,7 +3,9 @@
3
3
  2013-05 v3.0: Addition of ID to simpleType element; added values "Audiovisual", "Workflow" & "Other"; deleted value "Film"
4
4
  2017-10-23 v4.1: Addition of value "DataPaper"
5
5
  2020-01-14 v4.4: Addition of values "Book", "Book Chapter", "ComputationalNotebook", "ConferencePaper", "ConferenceProceeding".
6
- "Dissertation", "Journal", "JournalArticle", "OutputManagementPlan", "PeerReview", "Preprint", "Report" -->
6
+ "Dissertation", "Journal", "JournalArticle", "OutputManagementPlan", "PeerReview", "Preprint", "Report"
7
+ 2024-01-22 v4.5: Addition of values "Instrument", "StudyRegistration"
8
+ 2024-12-31 v4.6: Addition of values "Award", "Project"-->
7
9
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://datacite.org/schema/kernel-4" targetNamespace="http://datacite.org/schema/kernel-4" elementFormDefault="qualified">
8
10
  <xs:simpleType name="resourceType" id="resourceType">
9
11
  <xs:annotation>
@@ -11,6 +13,7 @@
11
13
  </xs:annotation>
12
14
  <xs:restriction base="xs:string">
13
15
  <xs:enumeration value="Audiovisual" />
16
+ <xs:enumeration value="Award" />
14
17
  <xs:enumeration value="Book" />
15
18
  <xs:enumeration value="BookChapter" />
16
19
  <xs:enumeration value="Collection" />
@@ -31,6 +34,7 @@
31
34
  <xs:enumeration value="PeerReview" />
32
35
  <xs:enumeration value="PhysicalObject" />
33
36
  <xs:enumeration value="Preprint" />
37
+ <xs:enumeration value="Project" />
34
38
  <xs:enumeration value="Report" />
35
39
  <xs:enumeration value="Service" />
36
40
  <xs:enumeration value="Software" />
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <!-- Version 1.0 - Created 2011-01-13 - FZ, TIB, Germany
3
3
  2013-05 v3.0: Addition of ID to simpleType element
4
- 2015-02-12 v4.0 Added value "Other" -->
4
+ 2015-02-12 v4.0: Added value "Other" -->
5
5
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://datacite.org/schema/kernel-4" targetNamespace="http://datacite.org/schema/kernel-4" elementFormDefault="qualified">
6
6
  <xs:simpleType name="titleType" id="titleType">
7
7
  <xs:restriction base="xs:string">