relaton-bib 2.0.0.pre.alpha.1 → 2.0.0

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.rubocop.yml +1 -1
  4. data/CLAUDE.md +96 -0
  5. data/Gemfile +1 -0
  6. data/README.adoc +14 -2
  7. data/grammars/basicdoc.rng +75 -45
  8. data/grammars/biblio-standoc.rng +37 -56
  9. data/grammars/biblio.rng +68 -36
  10. data/grammars/versions.json +25 -25
  11. data/lib/relaton/bib/converter/asciibib/to_asciibib.rb +663 -0
  12. data/lib/relaton/bib/converter/asciibib.rb +13 -0
  13. data/lib/relaton/bib/converter/bibtex/from_bibtex.rb +245 -0
  14. data/lib/relaton/bib/converter/bibtex/to_bibtex.rb +341 -0
  15. data/lib/relaton/bib/converter/bibtex.rb +23 -0
  16. data/lib/relaton/bib/converter/bibxml/from_rfcxml.rb +383 -0
  17. data/lib/relaton/bib/converter/bibxml/from_rfcxml_referencegroup.rb +71 -0
  18. data/lib/relaton/bib/{renderer/rfc.rb → converter/bibxml/to_rfcxml.rb} +100 -92
  19. data/lib/relaton/bib/converter/bibxml/to_rfcxml_referencegroup.rb +52 -0
  20. data/lib/relaton/bib/converter/bibxml.rb +51 -0
  21. data/lib/relaton/bib/hash_parser_v1.rb +121 -78
  22. data/lib/relaton/bib/item_data.rb +83 -22
  23. data/lib/relaton/bib/model/abstract.rb +16 -0
  24. data/lib/relaton/bib/model/date.rb +6 -4
  25. data/lib/relaton/bib/model/depiction.rb +2 -0
  26. data/lib/relaton/bib/model/ext.rb +0 -3
  27. data/lib/relaton/bib/model/formattedref.rb +43 -0
  28. data/lib/relaton/bib/model/ics.rb +9 -0
  29. data/lib/relaton/bib/model/item.rb +12 -4
  30. data/lib/relaton/bib/model/item_base.rb +17 -9
  31. data/lib/relaton/bib/model/keyword.rb +3 -3
  32. data/lib/relaton/bib/model/logo.rb +2 -0
  33. data/lib/relaton/bib/model/organization_type.rb +1 -1
  34. data/lib/relaton/bib/model/relation.rb +2 -2
  35. data/lib/relaton/bib/model/series.rb +5 -3
  36. data/lib/relaton/bib/model/subdivision.rb +2 -0
  37. data/lib/relaton/bib/model/title.rb +38 -0
  38. data/lib/relaton/bib/model/type/string_date.rb +48 -0
  39. data/lib/relaton/bib/model/validity.rb +3 -3
  40. data/lib/relaton/bib/namespace_helper.rb +21 -0
  41. data/lib/relaton/bib/version.rb +1 -1
  42. data/lib/relaton/bib.rb +5 -82
  43. data/relaton-bib.gemspec +5 -2
  44. metadata +63 -29
  45. data/lib/relaton/bib/model/editorial_group.rb +0 -14
  46. data/lib/relaton/bib/model/technical_committee.rb +0 -14
  47. data/lib/relaton/bib/model/workgroup.rb +0 -20
  48. data/lib/relaton/bib/parser/rfc_address.rb +0 -60
  49. data/lib/relaton/bib/parser/rfc_contacts.rb +0 -35
  50. data/lib/relaton/bib/parser/rfc_docidentifier.rb +0 -70
  51. data/lib/relaton/bib/parser/rfc_organization.rb +0 -31
  52. data/lib/relaton/bib/parser/rfc_person.rb +0 -42
  53. data/lib/relaton/bib/parser/rfc_reference.rb +0 -143
  54. data/lib/relaton/bib/parser/rfc_referencegroup.rb +0 -45
  55. data/lib/relaton/bib/parser/rfc_shared.rb +0 -23
  56. data/lib/relaton/bib/renderer/bibtex_builder.rb +0 -348
  57. data/lib/relaton/bibtex_parser.rb +0 -243
  58. data/lib/relaton/bibxml_parser.rb +0 -419
  59. data/lib/relaton/deep_dup.rb +0 -30
  60. data/lib/relaton/hit.rb +0 -52
  61. data/lib/relaton/hit_collection.rb +0 -105
  62. data/lib/relaton/workers_pool.rb +0 -43
  63. data/lib/relaton/xml_parser.rb +0 -716
@@ -1,716 +0,0 @@
1
- require "nokogiri"
2
-
3
- module Relaton
4
- class XMLParser
5
- class << self
6
- #
7
- # Parse XML bibdata
8
- #
9
- # @param [String] xml XML string
10
- #
11
- # @return [Relaton::Bib::Item, nil] bibliographic item
12
- #
13
- def from_xml(xml)
14
- doc = Nokogiri::XML(xml)
15
- doc.remove_namespaces!
16
- bibitem = doc.at "/bibitem|/bibdata"
17
- if bibitem
18
- bib_item item_data(bibitem)
19
- else
20
- Util.warn "Can't find bibitem or bibdata element in the XML"
21
- nil
22
- end
23
- end
24
-
25
- private
26
-
27
- #
28
- # Parse bibitem data
29
- #
30
- # @param bibitem [Nokogiri::XML::Element] bibitem element
31
- #
32
- # @return [Hash] bibitem data
33
- #
34
- def item_data(bibitem) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/MethodLength
35
- ext = bibitem.at "//ext"
36
- {
37
- id: bibitem[:id].nil? || bibitem[:id].empty? ? nil : bibitem[:id],
38
- type: bibitem[:type].nil? || bibitem[:type].empty? ? nil : bibitem[:type],
39
- fetched: bibitem.at("./fetched")&.text,
40
- title: fetch_titles(bibitem),
41
- formattedref: fref(bibitem),
42
- link: fetch_link(bibitem),
43
- docid: fetch_docid(bibitem),
44
- docnumber: bibitem.at("./docnumber")&.text,
45
- date: fetch_dates(bibitem),
46
- contributor: fetch_contributors(bibitem),
47
- edition: fetch_edition(bibitem),
48
- version: fetch_version(bibitem),
49
- biblionote: fetch_note(bibitem),
50
- language: fetch_language(bibitem),
51
- script: fetch_script(bibitem),
52
- abstract: fetch_abstract(bibitem),
53
- docstatus: fetch_status(bibitem),
54
- copyright: fetch_copyright(bibitem),
55
- relation: fetch_relations(bibitem),
56
- series: fetch_series(bibitem),
57
- medium: fetch_medium(bibitem),
58
- place: fetch_place(bibitem),
59
- extent: fetch_extent(bibitem),
60
- size: fetch_size(bibitem),
61
- accesslocation: bibitem.xpath("./accesslocation").map(&:text),
62
- classification: fetch_classification(bibitem),
63
- keyword: bibitem.xpath("keyword").map(&:text),
64
- license: bibitem.xpath("license").map(&:text),
65
- validity: fetch_validity(bibitem),
66
- doctype: fetch_doctype(ext),
67
- subdoctype: ext&.at("subdoctype")&.text,
68
- editorialgroup: fetch_editorialgroup(ext),
69
- ics: fetch_ics(ext),
70
- structuredidentifier: fetch_structuredidentifier(ext),
71
- }
72
- end
73
-
74
- #
75
- # Fetch version.
76
- #
77
- # @param [Nokogiri::XML::Elemetn] item bibitem element
78
- #
79
- # @return [Array<Relaton::Bib::Item::Version>] versions
80
- #
81
- def fetch_version(item)
82
- item.xpath("./version").map do |v|
83
- revision_date = v.at("revision-date")&.text
84
- draft = v.at("draft")&.text
85
- Relaton::Bib::Item::Version.new revision_date, draft
86
- end
87
- end
88
-
89
- #
90
- # Fetch edition
91
- #
92
- # @param [Nokogiri::XML::Elemetn] item bibitem element
93
- #
94
- # @return [Relaton::Bib::Edition, nil] edition
95
- #
96
- def fetch_edition(item)
97
- edt = item.at("./edition")
98
- return unless edt
99
-
100
- Edition.new content: edt.text, number: edt[:number]
101
- end
102
-
103
- #
104
- # Fetch place.
105
- #
106
- # @param [Nokogiri::XML::Element] item bibitem element
107
- #
108
- # @return [Array<Relaton::Bib::Place>] array of places
109
- #
110
- def fetch_place(item)
111
- item.xpath("./place").map do |pl|
112
- if (city = pl.at("./city"))
113
- Place.new(city: city.text, region: create_region_country(pl),
114
- country: create_region_country(pl, "country"))
115
- else
116
- Place.new(name: pl.text)
117
- end
118
- end
119
- end
120
-
121
- #
122
- # Create region or country from place element
123
- #
124
- # @param [Nokogiri::XML::Element] place place element
125
- # @param [String] node name of the node to parse
126
- #
127
- # @return [Array<Relaton::Bib::Place::RegionType>] <description>
128
- #
129
- def create_region_country(place, node = "region")
130
- place.xpath("./#{node}").map do |r|
131
- Place::RegionType.new(name: r.text, iso: r[:iso], recommended: r[:recommended])
132
- end
133
- end
134
-
135
- def fetch_note(item)
136
- bnotes = item.xpath("./note").map do |n|
137
- BiblioNote.new(
138
- content: n.text,
139
- type: n[:type],
140
- format: n[:format],
141
- language: n[:language],
142
- script: n[:script],
143
- )
144
- end
145
- BiblioNoteCollection.new bnotes
146
- end
147
-
148
- #
149
- # Fetch language
150
- #
151
- # @param [Nokogiri::XML::Element] item bibitem element
152
- #
153
- # @return [Array<String>] language en, fr, etc.
154
- #
155
- def fetch_language(item)
156
- item.xpath("./language").reduce([]) do |a, l|
157
- l.text.empty? ? a : a << l.text
158
- end
159
- end
160
-
161
- #
162
- # Fetch script
163
- #
164
- # @param [Nokogiri::XML::Element] item XML element
165
- #
166
- # @return [Array<String>] scripts Latn, Cyr, etc.
167
- #
168
- def fetch_script(item)
169
- item.xpath("./script").reduce([]) do |a, s|
170
- s.text.empty? ? a : a << s.text
171
- end
172
- end
173
-
174
- #
175
- # Fetch series
176
- #
177
- # @param [Nokogiri::XML::Element] item bibitem element
178
- #
179
- # @return [Array<Relaton::Bib::Series>] series
180
- #
181
- def fetch_series(item) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/AbcSize,Metrics/MethodLength,Metrics/PerceivedComplexity
182
- item.xpath("./series").reduce([]) do |mem, sr|
183
- formattedref = fref(sr)
184
- title = ttitle(sr.at("title"))
185
- next mem unless formattedref || title
186
-
187
- abbreviation = localized_string sr.at("abbreviation")
188
- mem << Series.new(
189
- type: sr[:type], formattedref: formattedref,
190
- title: title, place: sr.at("place")&.text,
191
- organization: sr.at("organization")&.text,
192
- abbreviation: abbreviation, from: sr.at("from")&.text,
193
- to: sr.at("to")&.text, number: sr.at("number")&.text,
194
- partnumber: sr.at("partnumber")&.text, run: sr.at("run")&.text
195
- )
196
- end
197
- end
198
-
199
- #
200
- # Fetch medium
201
- #
202
- # @param [Nokogiri::XML::Element] item item element
203
- #
204
- # @return [Relaton::Bib::Medium, nil] medium
205
- #
206
- def fetch_medium(item) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/AbcSize,Metrics/PerceivedComplexity
207
- medium = item.at("./medium")
208
- return unless medium
209
-
210
- Medium.new(
211
- content: medium.at("content")&.text, genre: medium.at("genre")&.text,
212
- form: medium.at("form")&.text, carrier: medium.at("carrier")&.text,
213
- size: medium.at("size")&.text, scale: medium.at("scale")&.text
214
- )
215
- end
216
-
217
- #
218
- # Fetch extent
219
- #
220
- # @param [Nokogiri::XML::Element] item item element
221
- #
222
- # @return [Array<RelatonBib::Extent>] extent
223
- #
224
- def fetch_extent(item)
225
- item.xpath("./extent").map do |ex|
226
- RelatonBib::Extent.new localities(ex)
227
- end
228
- end
229
-
230
- #
231
- # Fetch size
232
- #
233
- # @param [Nokogiri::XML::Element] item item element
234
- #
235
- # @return [Relaton::Bib::BibliographicSize, nil] size
236
- #
237
- def fetch_size(item)
238
- size = item.xpath("./size/value").map do |sz|
239
- BibliographicSize::Value.new type: sz[:type], value: sz.text
240
- end
241
- BibliographicSize.new size if size.any?
242
- end
243
-
244
- #
245
- # Fetch classification
246
- #
247
- # @param [Nokogiri::XML::Element] item bibitem element
248
- #
249
- # @return [Array<Relaton::Bib::Classification>] classifications
250
- #
251
- def fetch_classification(item)
252
- item.xpath("classification").map do |cls|
253
- Classification.new type: cls[:type], value: cls.text
254
- end
255
- end
256
-
257
- #
258
- # Parse validity
259
- #
260
- # @param [Nokogiri::XML::Element] item bibitem element
261
- #
262
- # @return [Relaton::Bib::Validity, nil] validity
263
- #
264
- def fetch_validity(item)
265
- vl = item.at("./validity")
266
- return unless vl
267
-
268
- begins = (b = vl.at("validityBegins")) &&
269
- Time.strptime(b.text, "%Y-%m-%d %H:%M")
270
- ends = (e = vl.at("validityEnds")) &&
271
- Time.strptime(e.text, "%Y-%m-%d %H:%M")
272
- revision = (r = vl.at("revision")) &&
273
- Time.strptime(r.text, "%Y-%m-%d %H:%M")
274
- Validity.new begins: begins, ends: ends, revision: revision
275
- end
276
-
277
- def fetch_doctype(ext)
278
- dt = ext&.at("doctype")
279
- return unless dt
280
-
281
- create_doctype dt
282
- end
283
-
284
- def create_doctype(type)
285
- DocumentType.new type: type.text, abbreviation: type[:abbreviation]
286
- end
287
-
288
- # @param item [Nokogiri::XML::Element]
289
- # @return [Array<Relaton::Bib::Docidentifier>]
290
- def fetch_docid(item)
291
- item.xpath("./docidentifier").map do |id|
292
- args = id.to_h.transform_keys(&:to_sym)
293
- args[:id] = id.children.map { |n| n.text? ? n.content : n.to_xml }.join
294
- args[:primary] = id[:primary] == "true" ? true : nil
295
- create_docid(**args)
296
- end
297
- end
298
-
299
- def create_docid(**args)
300
- DocumentIdentifier.new(**args)
301
- end
302
-
303
- # @param item [Nokogiri::XML::Element]
304
- # @return [Relaton::Bib::TitleCollection]
305
- def fetch_titles(item)
306
- ttl = item.xpath("./title").map { |t| ttitle t }
307
- TitleCollection.new ttl
308
- end
309
-
310
- # @param title [Nokogiri::XML::Element]
311
- # @return [Relaton::Bib::Title]
312
- def ttitle(title)
313
- return unless title
314
-
315
- content = variants(title)
316
- content = title.children.map { |n| n.text? ? n.content : n.to_xml }.join unless content.any?
317
- Typed.new(
318
- type: title[:type], content: content, language: title[:language],
319
- script: title[:script], format: title[:format]
320
- )
321
- end
322
-
323
- # @param title [Nokogiri::XML::Element]
324
- # @return [Array<Relaton::Bib::LocalizedString>]
325
- def variants(elm)
326
- elm.xpath("variant").map { |v| localized_string v }
327
- end
328
-
329
- #
330
- # Parse status
331
- #
332
- # @param [Nokogiri::XML::Element] item XML element
333
- #
334
- # @return [Relaton::Bib::DocumentStatus, nil] status
335
- #
336
- def fetch_status(item)
337
- status = item.at("./status")
338
- return unless status
339
-
340
- stg = status.at "stage"
341
- DocumentStatus.new(
342
- stage: stg ? stage(stg) : status.text,
343
- substage: stage(status.at("substage")),
344
- iteration: status.at("iteration")&.text,
345
- )
346
- end
347
-
348
- # @param node [Nokogiri::XML::Elemen]
349
- # @return [Relaton::Bib::DocumentStatus::Stage]
350
- def stage(elm)
351
- return unless elm
352
-
353
- DocumentStatus::Stage.new(value: elm.text,
354
- abbreviation: elm[:abbreviation])
355
- end
356
-
357
- # @param node [Nokogiri::XML::Elemen]
358
- # @return [Array<Relaton::Bib::Bdate>]
359
- def fetch_dates(item) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
360
- item.xpath("./date").each_with_object([]) do |d, a|
361
- type = d[:type].to_s.empty? ? "published" : d[:type]
362
- if (on = d.at("on"))
363
- a << Relaton::Bib::Bdate.new(type: type, on: on.text,
364
- to: d.at("to")&.text)
365
- elsif (from = d.at("from"))
366
- a << Relaton::Bib::Bdate.new(type: type, from: from.text,
367
- to: d.at("to")&.text)
368
- end
369
- end
370
- end
371
-
372
- #
373
- # Parse organization
374
- #
375
- # @param [Nokogiri::XML::Element] org XML element
376
- #
377
- # @return [Relaton::Bib::Organization, nil] organization
378
- #
379
- def get_org(org) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
380
- return unless org
381
-
382
- names = org.xpath("name").map do |n|
383
- { content: n.text, language: n[:language], script: n[:script] }
384
- end
385
- identifier = org.xpath("./identifier").map do |i|
386
- OrgIdentifier.new(i[:type], i.text)
387
- end
388
- subdiv = org.xpath("subdivision").map &:text
389
- contact = parse_contact org
390
- logo = fetch_image org.at("./logo/image")
391
- Organization.new(
392
- name: names, abbreviation: org.at("abbreviation")&.text,
393
- subdivision: subdiv, # url: org.at("uri")&.text,
394
- identifier: identifier, contact: contact, logo: logo
395
- )
396
- end
397
-
398
- def fetch_image(elm)
399
- return unless elm
400
-
401
- Image.new(**elm.to_h.transform_keys(&:to_sym))
402
- end
403
-
404
- #
405
- # Parse person from XML
406
- #
407
- # @param [Nokogiri::XML::Element] person XML element
408
- #
409
- # @return [Relaton::Bib::Person, nil] person
410
- #
411
- def get_person(person) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
412
- return unless person
413
-
414
- affiliations = person.xpath("./affiliation").map { |a| fetch_affiliation a }
415
-
416
- contact = parse_contact person
417
- identifier = person.xpath("./identifier").map do |pi|
418
- Person::Identifier.new type: pi[:type], content: pi.text
419
- end
420
-
421
- Person.new(
422
- name: full_name(person.at("./name")),
423
- credential: person.xpath("./credential").map(&:text),
424
- affiliation: affiliations,
425
- contact: contact,
426
- identifier: identifier,
427
- )
428
- end
429
-
430
- def full_name(name)
431
- cname = localized_string name.at("./completename")
432
- sname = localized_string name.at("./surname")
433
- abbreviation = localized_string name.at("./abbreviation")
434
-
435
- FullName.new(
436
- completename: cname, surname: sname, abbreviation: abbreviation,
437
- initials: parse_initials(name), forename: parse_forename(name),
438
- addition: name_part(name, "addition"), prefix: name_part(name, "prefix")
439
- )
440
- end
441
-
442
- def fetch_affiliation(elm)
443
- org = get_org elm.at("./organization")
444
- desc = elm.xpath("./description").map do |e|
445
- FormattedString.new(content: e.text, language: e[:language],
446
- script: e[:script], format: e[:format])
447
- end
448
- name = localized_string elm.at("./name")
449
- Affiliation.new organization: org, description: desc, name: name
450
- end
451
-
452
- def localized_string(elm)
453
- return unless elm
454
-
455
- LocalizedString.new(elm.text, elm[:language], elm[:script])
456
- end
457
-
458
- #
459
- # Parse contact information
460
- #
461
- # @param [Nokogiri::XML::Element] contrib contributor element
462
- #
463
- # @return [Array<Relaton::Bib::Address, Relaton::Bib::Contact>] contacts
464
- #
465
- def parse_contact(contrib)
466
- contrib.xpath("./address|./phone|./email|./uri").map do |c|
467
- parse_address(c) || Contact.new(type: c.name, value: c.text, subtype: c[:type])
468
- end
469
- end
470
-
471
- #
472
- # Parse address
473
- #
474
- # @param [Nokogiri::XML::Element] contact contact element
475
- #
476
- # @return [Relaton::Bib::Address] address
477
- #
478
- def parse_address(contact) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
479
- return unless contact.name == "address"
480
-
481
- Address.new(
482
- street: contact.xpath("./street").map(&:text),
483
- city: contact.at("./city")&.text,
484
- state: contact.at("./state")&.text,
485
- country: contact.at("./country")&.text,
486
- postcode: contact.at("./postcode")&.text,
487
- formatted_address: contact.at("./formattedAddress")&.text,
488
- )
489
- end
490
-
491
- #
492
- # Parse initials
493
- #
494
- # @param [Nokogiri::XML::Element] name person name element
495
- #
496
- # @return [Relaton::Bib::LocalizedString, nil] initials
497
- #
498
- def parse_initials(name)
499
- localized_string name.at("./formatted-initials")
500
- end
501
-
502
- #
503
- # Parse forename
504
- #
505
- # @param [Nokogiri::XML::Element] name person name element
506
- #
507
- # @return [Array<Relaton::Bib::Forename>] forenames
508
- #
509
- def parse_forename(name)
510
- name.xpath("./forename").map do |np|
511
- args = np.attributes.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.to_s }
512
- args[:content] = np.text
513
- Forename.new(**args)
514
- end
515
- end
516
-
517
- #
518
- # Parse name part
519
- #
520
- # @param [Nokogiri::XML::Element] name person name element
521
- # @param [String] part name part
522
- #
523
- # @return [Array<Relaton::Bib::LocalizedString>] name parts
524
- #
525
- def name_part(name, part)
526
- name.xpath("./#{part}").map { |np| localized_string np }
527
- end
528
-
529
- # @param item [Nokogiri::XML::Element]
530
- # @return [Array<Relaton::Bib::ContributionInfo>]
531
- def fetch_contributors(item)
532
- item.xpath("./contributor").map { |c| fetch_contribution_info c }
533
- end
534
-
535
- def fetch_contribution_info(contrib)
536
- entity = get_org(contrib.at("./organization")) || get_person(contrib.at("./person"))
537
- role = contrib.xpath("./role").map do |r|
538
- { type: r[:type], description: r.xpath("./description").map(&:text) }
539
- end
540
- ContributionInfo.new entity: entity, role: role
541
- end
542
-
543
- # @param item [Nokogiri::XML::Element]
544
- # @return [Array<Relaton::Bib::FormattedString>]
545
- def fetch_abstract(item)
546
- item.xpath("./abstract").map do |a|
547
- c = a.children.to_xml(encoding: "utf-8").strip
548
- FormattedString.new(content: c, language: a[:language],
549
- script: a[:script], format: a[:format])
550
- end
551
- end
552
-
553
- # @param item [Nokogiri::XML::Element]
554
- # @return [Array<Relaton::Bib::CopyrightAssociation>]
555
- def fetch_copyright(item)
556
- item.xpath("./copyright").map do |cp|
557
- owner = cp.xpath("owner").map { |o| fetch_contribution_info o }
558
- from = cp.at("from")&.text
559
- to = cp.at("to")&.text
560
- scope = cp.at("scope")&.text
561
- CopyrightAssociation.new(owner: owner, from: from, to: to, scope: scope)
562
- end
563
- end
564
-
565
- # @param item [Nokogiri::XML::Element]
566
- # @return [Arra<Relaton::Bib::Bsource>]
567
- def fetch_link(item)
568
- item.xpath("./uri").map do |l|
569
- Bsource.new(type: l[:type], content: l.text, language: l[:language],
570
- script: l[:script])
571
- end
572
- end
573
-
574
- # @param item [Nokogiri::XML::Element]
575
- # @param klass [Relaton::Bib::DocumentRelation.class, RelatonNist::DocumentRelation.class]
576
- # @return [Array<Relaton::Bib::DocumentRelation>]
577
- def fetch_relations(item, klass = DocumentRelation)
578
- item.xpath("./relation").map do |rel|
579
- klass.new(
580
- type: rel[:type].nil? || rel[:type].empty? ? nil : rel[:type],
581
- description: relation_description(rel),
582
- bibitem: bib_item(item_data(rel.at("./bibitem"))),
583
- locality: localities(rel),
584
- source_locality: source_localities(rel),
585
- )
586
- end
587
- end
588
-
589
- # @param rel [Nokogiri::XML::Element]
590
- # @return [Relaton::Bib::FormattedString, nil]
591
- def relation_description(rel)
592
- d = rel.at "./description"
593
- return unless d
594
-
595
- FormattedString.new(content: d.text, language: d[:language],
596
- script: d[:script], format: d[:format])
597
- end
598
-
599
- #
600
- # Create bibliographic item
601
- #
602
- # @param item_hash [Hash] bibliographic item hash
603
- #
604
- # @return [Relaton::Bib::Item] bibliographic item
605
- #
606
- def bib_item(item_hash)
607
- Item.new(**item_hash)
608
- end
609
-
610
- #
611
- # Parse locality
612
- #
613
- # @param rel [Nokogiri::XML::Element] relation element
614
- #
615
- # @return [Array<Relaton::Bib::Locality, Relaton::Bib::LocalityStack>] localities
616
- #
617
- def localities(rel)
618
- rel.xpath("./locality|./localityStack").map do |lc|
619
- if lc.name == "locality"
620
- locality lc
621
- else
622
- LocalityStack.new(lc.xpath("./locality").map { |l| locality l })
623
- end
624
- end
625
- end
626
-
627
- #
628
- # Create Locality object from Nokogiri::XML::Element
629
- #
630
- # @param loc [Nokogiri::XML::Element]
631
- # @param klass [Relaton::Bib::Locality, Relaton::Bib::LocalityStack]
632
- #
633
- # @return [Relaton::Bib::Locality]
634
- def locality(loc, klass = Locality)
635
- klass.new(
636
- loc[:type],
637
- loc.at("./referenceFrom")&.text,
638
- loc.at("./referenceTo")&.text,
639
- )
640
- end
641
-
642
- # @param rel [Nokogiri::XML::Element]
643
- # @return [Array<Relaton::Bib::SourceLocality, Relaton::Bib::SourceLocalityStack>]
644
- def source_localities(rel)
645
- rel.xpath("./sourceLocality|./sourceLocalityStack").map do |loc|
646
- if loc.name == "sourceLocality"
647
- # src_locs = loc.xapth("./sourceLocality").map { |sl| locality(sl, SourceLocality) }
648
- # SourceLocalityStack.new src_locs
649
- locality loc, SourceLocality
650
- else
651
- sls = loc.xpath("./sourceLocality").map { |l| locality l, SourceLocality }
652
- SourceLocalityStack.new sls
653
- end
654
- end
655
- end
656
-
657
- # @param item [Nokogiri::XML::Element]
658
- # @return [Relaton::Bib::Formattedref, nil]
659
- def fref(item)
660
- ident = item&.at("./formattedref")
661
- return unless ident
662
-
663
- Formattedref.new(
664
- content: ident.children.to_s, format: ident[:format],
665
- language: ident[:language], script: ident[:script]
666
- )
667
- end
668
-
669
- # @param ext [Nokogiri::XML::Element]
670
- # @return [Relaton::Bib::EditorialGroup, nil]
671
- def fetch_editorialgroup(ext)
672
- return unless ext && (eg = ext.at "editorialgroup")
673
-
674
- eg = eg.xpath("technical-committee").map do |tc|
675
- wg = WorkGroup.new(
676
- name: tc.text, number: tc[:number]&.to_i, type: tc[:type],
677
- identifier: tc[:identifier], prefix: tc[:prefix]
678
- )
679
- TechnicalCommittee.new wg
680
- end
681
- EditorialGroup.new eg if eg.any?
682
- end
683
-
684
- def fetch_ics(ext)
685
- return [] unless ext
686
-
687
- ext.xpath("ics").map do |ics|
688
- ICS.new code: ics.at("code")&.text, text: ics.at("text")&.text
689
- end
690
- end
691
-
692
- # @param ext [Nokogiri::XML::Element]
693
- # @return [Relaton::Bib::StructuredIdentifierCollection]
694
- def fetch_structuredidentifier(ext) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
695
- return unless ext
696
-
697
- sids = ext.xpath("structuredidentifier").map do |si|
698
- StructuredIdentifier.new(
699
- type: si[:type],
700
- agency: si.xpath("agency").map(&:text),
701
- class: si.at("class")&.text,
702
- docnumber: si.at("docnumber")&.text,
703
- partnumber: si.at("partnumber")&.text,
704
- edition: si.at("edition")&.text,
705
- version: si.at("version")&.text,
706
- supplementtype: si.at("supplementtype")&.text,
707
- supplementnumber: si.at("supplementnumber")&.text,
708
- language: si.at("language")&.text,
709
- year: si.at("year")&.text,
710
- )
711
- end
712
- StructuredIdentifierCollection.new sids
713
- end
714
- end
715
- end
716
- end