metanorma-standoc 2.3.3 → 2.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -53,7 +53,8 @@ module Metanorma
53
53
  end
54
54
 
55
55
  PREFACE_CLAUSE_NAMES =
56
- %w(abstract foreword introduction misc-container acknowledgements).freeze
56
+ %w(abstract foreword introduction misc-container
57
+ acknowledgements).freeze
57
58
 
58
59
  MAIN_CLAUSE_NAMES =
59
60
  ["normative references", "terms and definitions", "scope",
@@ -0,0 +1,261 @@
1
+ module Metanorma
2
+ module Standoc
3
+ module Cleanup
4
+ class SpansToBibitem
5
+ include ::Metanorma::Standoc::Utils
6
+
7
+ attr_reader :err, :out
8
+
9
+ def initialize(bib)
10
+ @bib = bib
11
+ @err = []
12
+ @spans = spans_preprocess(extract_content(bib))
13
+ end
14
+
15
+ def extract_content(bib)
16
+ extract_docid(bib) + extract_spans(bib)
17
+ end
18
+
19
+ def extract_spans(bib)
20
+ bib.xpath("./formattedref//span").each_with_object([]) do |s, m|
21
+ s.at("./ancestor::span") and next
22
+ extract_spans1(s, m)
23
+ end
24
+ end
25
+
26
+ def extract_spans1(span, acc)
27
+ keys = span["class"].split(".", 2)
28
+ acc << { key: keys[0], type: keys[1],
29
+ val: span.children.to_xml }
30
+ (span["class"] == "type" and span.remove) or
31
+ span.replace(span.children)
32
+ end
33
+
34
+ def extract_docid(bib)
35
+ bib.xpath("./docidentifier").each_with_object([]) do |d, m|
36
+ m << { key: "docid", type: d["type"], val: d.text }
37
+ d.remove unless bib.at("./title")
38
+ end
39
+ end
40
+
41
+ def empty_span_hash
42
+ { contrib: [], docid: [], uri: [], date: [], extent: {}, in: {} }
43
+ end
44
+
45
+ def spans_preprocess(spans)
46
+ ret = empty_span_hash
47
+ spans.each { |s| span_preprocess1(s, ret) }
48
+ host_rearrange(ret)
49
+ end
50
+
51
+ def span_preprocess1(span, ret)
52
+ case span[:key]
53
+ when "uri", "docid"
54
+ val = link_unwrap(Nokogiri::XML.fragment(span[:val])).to_xml
55
+ ret[span[:key].to_sym] << { type: span[:type], val: val }
56
+ when "date"
57
+ ret[span[:key].to_sym] << { type: span[:type] || "published",
58
+ val: span[:val] }
59
+ when "pages", "volume", "issue"
60
+ ret[:extent][span[:key].to_sym] ||= []
61
+ ret[:extent][span[:key].to_sym] << span[:val]
62
+ when "pubplace", "title", "type", "series"
63
+ ret[span[:key].to_sym] = span[:val]
64
+ when "in_title"
65
+ ret[:in][:title] = span[:val]
66
+ when "publisher"
67
+ ret[:contrib] << { role: "publisher", entity: "organization",
68
+ name: span[:val] }
69
+ when "surname", "initials", "givenname", "formatted-initials"
70
+ ret[:contrib] = spans_preprocess_contrib(span, ret[:contrib])
71
+ when "fullname"
72
+ ret[:contrib] = spans_preprocess_fullname(span, ret[:contrib])
73
+ when "organization"
74
+ ret[:contrib] = spans_preprocess_org(span, ret[:contrib])
75
+ when "in_surname", "in_initials", "in_givenname",
76
+ "in_formatted-initials"
77
+ ret[:in][:contrib] ||= []
78
+ span[:key].sub!(/^in_/, "")
79
+ ret[:in][:contrib] =
80
+ spans_preprocess_contrib(span, ret[:in][:contrib])
81
+ when "in_fullname"
82
+ ret[:in][:contrib] ||= []
83
+ span[:key].sub!(/^in_/, "")
84
+ ret[:in][:contrib] =
85
+ spans_preprocess_fullname(span, ret[:in][:contrib])
86
+ when "in_organization"
87
+ ret[:in][:contrib] ||= []
88
+ span[:key].sub!(/^in_/, "")
89
+ ret[:in][:contrib] =
90
+ spans_preprocess_org(span, ret[:in][:contrib])
91
+ else
92
+ msg = "unrecognised key '#{span[:key]}' in " \
93
+ "`span:#{span[:key]}[#{span[:val]}]`"
94
+ @err << { msg: msg }
95
+ end
96
+ end
97
+
98
+ def host_rearrange(ret)
99
+ ret[:in][:title] or return ret
100
+ ret[:in].merge!(empty_span_hash, { type: "misc" }) do |_, old, _|
101
+ old
102
+ end
103
+ %i(series).each do |k|
104
+ ret[:in][k] = ret[k]
105
+ ret.delete(k)
106
+ end
107
+ /^in/.match?(ret[:type]) and ret[:in][:type] =
108
+ ret[:type].sub(/^in/, "")
109
+ ret
110
+ end
111
+
112
+ def spans_preprocess_contrib(span, contrib)
113
+ span[:key] == "initials" and span[:key] = "formatted-initials"
114
+ spans_preprocess_new_contrib?(span, contrib) and
115
+ contrib << { role: span[:type] || "author", entity: "person" }
116
+ if multiple_givennames?(span, contrib)
117
+ contrib[-1][:givenname] = [contrib[-1][:givenname],
118
+ span[:val]].flatten
119
+ else contrib[-1][span[:key].to_sym] = span[:val]
120
+ end
121
+ contrib
122
+ end
123
+
124
+ def spans_preprocess_new_contrib?(span, contrib)
125
+ contrib.empty? ||
126
+ (span[:key] == "surname" && contrib[-1][:surname]) ||
127
+ contrib[-1][:role] != (span[:type] || "author")
128
+ end
129
+
130
+ def multiple_givennames?(span, contrib)
131
+ (%w(formatted-initials givenname).include?(span[:key]) &&
132
+ (contrib[-1][:"formatted-initials"] || contrib[-1][:givenname])) or
133
+ return false
134
+ if contrib[-1][:"formatted-initials"]
135
+ contrib[-1][:givenname] = contrib[-1][:"formatted-initials"]
136
+ contrib[-1].delete(:"formatted-initials")
137
+ end
138
+ true
139
+ end
140
+
141
+ def spans_preprocess_fullname(span, contrib)
142
+ name = span[:val].gsub(/\.(?=\p{Alpha})/, ". ").split(/ /)
143
+ out = { role: span[:type] || "author", entity: "person",
144
+ surname: name[-1] }
145
+ if name.size > 1 && name[0..-2].all? { |x| /\.$/.match?(x) }
146
+ out[:"formatted-initials"] = name[0..-2].join(" ")
147
+ else out[:givenname] = name[0..-2]
148
+ end
149
+ contrib << out
150
+ contrib
151
+ end
152
+
153
+ def spans_preprocess_org(span, contrib)
154
+ contrib << { role: span[:type] || "author", entity: "organization",
155
+ name: span[:val] }
156
+ contrib
157
+ end
158
+
159
+ def convert
160
+ ret = spans_to_bibitem(@spans)
161
+ @out = Nokogiri::XML("<bibitem>#{ret}</bibitem>").root
162
+ @spans[:type] and @out["type"] = @spans[:type]
163
+ self
164
+ end
165
+
166
+ def spans_to_bibitem(spans)
167
+ ret = ""
168
+ spans[:title] and ret += "<title>#{spans[:title]}</title>"
169
+ ret += spans_to_bibitem_docid(spans)
170
+ spans[:contrib].each do |s|
171
+ ret += span_to_contrib(s, spans[:title])
172
+ end
173
+ spans[:series] and
174
+ ret += "<series><title>#{spans[:series]}</title></series>"
175
+ spans[:pubplace] and ret += "<place>#{spans[:pubplace]}</place>"
176
+ ret += spans_to_bibitem_host(spans)
177
+ ret += spans_to_bibitem_extent(spans[:extent])
178
+ ret
179
+ end
180
+
181
+ def spans_to_bibitem_host(spans)
182
+ spans[:in].empty? and return ""
183
+ ret =
184
+ "<relation type='includedIn'><bibitem type='#{spans[:in][:type]}'>"
185
+ spans[:in].delete(:type)
186
+ ret + "#{spans_to_bibitem(spans[:in])}</bibitem></relation>"
187
+ end
188
+
189
+ def spans_to_bibitem_docid(spans)
190
+ ret = ""
191
+ spans[:uri].each { |s| ret += span_to_docid(s, "uri") }
192
+ spans[:docid].each { |s| ret += span_to_docid(s, "docidentifier") }
193
+ spans[:date].each { |s| ret += span_to_date(s) }
194
+ ret
195
+ end
196
+
197
+ def spans_to_bibitem_extent(spans)
198
+ ret = ""
199
+ { volume: "volume", issue: "issue", pages: "page" }.each do |k, v|
200
+ spans[k]&.each { |s| ret += span_to_extent(s, v) }
201
+ end
202
+ ret.empty? and return ""
203
+ "<extent>#{ret}</extent>"
204
+ end
205
+
206
+ def span_to_extent(span, key)
207
+ values = span.split(/[-–]/)
208
+ ret = "<locality type='#{key}'>" \
209
+ "<referenceFrom>#{values[0]}</referenceFrom>"
210
+ values[1] and
211
+ ret += "<referenceTo>#{values[1]}</referenceTo>"
212
+ "#{ret}</locality>"
213
+ end
214
+
215
+ def span_to_docid(span, key)
216
+ if span[:type]
217
+ "<#{key} type='#{span[:type]}'>#{span[:val]}</#{key}>"
218
+ else "<#{key}>#{span[:val]}</#{key}>"
219
+ end
220
+ end
221
+
222
+ def span_to_date(span)
223
+ val = if /[-–](?=\d{4})/.match?(span[:val])
224
+ from, to = span[:val].split(/[-–](?=\d{4})/, 2)
225
+ "<from>#{from}</from><to>#{to}</to>"
226
+ else "<on>#{span[:val]}</on>"
227
+ end
228
+ type = span[:type] ? " type='#{span[:type]}'" : ""
229
+ "<date#{type}>#{val}</date>"
230
+ end
231
+
232
+ def span_to_contrib(span, title)
233
+ e = if span[:entity] == "organization"
234
+ "<organization><name>#{span[:name]}</name></organization>"
235
+ else span_to_person(span, title)
236
+ end
237
+ "<contributor><role type='#{span[:role]}'/>#{e}</contributor>"
238
+ end
239
+
240
+ def validate_span_to_person(span, title)
241
+ span[:surname] and return
242
+ msg = "Missing surname: issue with bibliographic markup " \
243
+ "in \"#{title}\": #{span}"
244
+ @err << { msg: msg, fatal: true }
245
+ end
246
+
247
+ def span_to_person(span, title)
248
+ validate_span_to_person(span, title)
249
+ pre = (span[:"formatted-initials"] and
250
+ "<formatted-initials>" \
251
+ "#{span[:"formatted-initials"]}</formatted-initials>") ||
252
+ Array(span[:givenname]).map do |x|
253
+ "<forename>#{x}</forename>"
254
+ end.join
255
+ "<person><name>#{pre}<surname>#{span[:surname]}</surname></name>" \
256
+ "</person>"
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
@@ -60,6 +60,14 @@ module Metanorma
60
60
  "<expression><name>#{elem}</name></expression>"
61
61
  end
62
62
 
63
+ def link_unwrap(para)
64
+ elems = para.elements
65
+ if elems.size == 1 && elems[0].name == "link"
66
+ para.at("./link").replace(elems[0]["target"].strip)
67
+ end
68
+ para
69
+ end
70
+
63
71
  class EmptyAttr
64
72
  def attr(_any_attribute)
65
73
  nil
@@ -13,9 +13,8 @@ module Metanorma
13
13
  "referenceFrom".freeze
14
14
 
15
15
  def init_iev
16
- return nil if @no_isobib
17
- return @iev if @iev
18
-
16
+ @no_isobib and return nil
17
+ @iev and return @iev
19
18
  @iev = Iev::Db.new(@iev_globalname, @iev_localname) unless @no_isobib
20
19
  @iev
21
20
  end
@@ -43,6 +42,8 @@ module Metanorma
43
42
  end
44
43
 
45
44
  def content_validate(doc)
45
+ nested_asset_validate_basic(doc)
46
+ nested_note_validate(doc)
46
47
  xref_validate(doc)
47
48
  section_validate(doc)
48
49
  norm_ref_validate(doc)
@@ -57,12 +58,36 @@ module Metanorma
57
58
  clean_abort(@fatalerror.join("\n"), doc)
58
59
  end
59
60
 
61
+ def nested_asset_validate_basic(doc)
62
+ a = "//formula | //example | //figure | //termnote | //termexample | " \
63
+ "//table"
64
+ doc.xpath("#{a} | //note").each do |m|
65
+ m.xpath(a.gsub(%r{//}, ".//")).each do |n|
66
+ nested_asset_report(m, n, doc)
67
+ end
68
+ end
69
+ end
70
+
71
+ def nested_note_validate(doc)
72
+ doc.xpath("//termnote | //note").each do |m|
73
+ m.xpath(".//note").each do |n|
74
+ nested_asset_report(m, n, doc)
75
+ end
76
+ end
77
+ end
78
+
79
+ def nested_asset_report(outer, inner, _doc)
80
+ outer.name == "figure" && inner.name == "figure" and return
81
+ err = "There is an instance of #{inner.name} nested within #{outer.name}"
82
+ @log.add("Syntax", inner, err)
83
+ @fatalerror << "#{err}:\n#{inner.to_xml}"
84
+ end
85
+
60
86
  def norm_ref_validate(doc)
61
87
  found = false
62
88
  doc.xpath("//references[@normative = 'true']/bibitem").each do |b|
63
- next unless docid = b.at("./docidentifier[@type = 'metanorma']")
64
- next unless /^\[\d+\]$/.match?(docid.text)
65
-
89
+ docid = b.at("./docidentifier[@type = 'metanorma']") or next
90
+ /^\[\d+\]$/.match?(docid.text) or next
66
91
  @log.add("Bibliography", b,
67
92
  "Numeric reference in normative references")
68
93
  found = true
@@ -106,8 +131,7 @@ module Metanorma
106
131
  @log.add("Anchors", elem, "Anchor #{elem['id']} has already been " \
107
132
  "used at line #{ids[elem['id']]}")
108
133
  @fatalerror << "Multiple instances of same ID: #{elem['id']}"
109
- else
110
- ids[elem["id"]] = elem.line
134
+ else ids[elem["id"]] = elem.line
111
135
  end
112
136
  ids
113
137
  end
@@ -166,8 +190,7 @@ module Metanorma
166
190
  def xref_validate(doc)
167
191
  ids = doc.xpath("//*/@id").each_with_object({}) { |x, m| m[x.text] = 1 }
168
192
  doc.xpath("//xref/@target | //xref/@to").each do |x|
169
- next if ids[x.text]
170
-
193
+ ids[x.text] and next
171
194
  @log.add("Anchors", x.parent,
172
195
  "Crossreference target #{x.text} is undefined")
173
196
  end
@@ -19,6 +19,6 @@ module Metanorma
19
19
  end
20
20
 
21
21
  module Standoc
22
- VERSION = "2.3.3".freeze
22
+ VERSION = "2.3.4".freeze
23
23
  end
24
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma-standoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.3
4
+ version: 2.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-22 00:00:00.000000000 Z
11
+ date: 2022-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -475,7 +475,6 @@ files:
475
475
  - lib/metanorma/standoc/cleanup.rb
476
476
  - lib/metanorma/standoc/cleanup_amend.rb
477
477
  - lib/metanorma/standoc/cleanup_asciibib.rb
478
- - lib/metanorma/standoc/cleanup_biblio.rb
479
478
  - lib/metanorma/standoc/cleanup_block.rb
480
479
  - lib/metanorma/standoc/cleanup_boilerplate.rb
481
480
  - lib/metanorma/standoc/cleanup_footnotes.rb
@@ -511,6 +510,7 @@ files:
511
510
  - lib/metanorma/standoc/macros_note.rb
512
511
  - lib/metanorma/standoc/macros_plantuml.rb
513
512
  - lib/metanorma/standoc/macros_terms.rb
513
+ - lib/metanorma/standoc/merge_bibitems.rb
514
514
  - lib/metanorma/standoc/processor.rb
515
515
  - lib/metanorma/standoc/ref.rb
516
516
  - lib/metanorma/standoc/ref_sect.rb
@@ -519,6 +519,7 @@ files:
519
519
  - lib/metanorma/standoc/reqt.rb
520
520
  - lib/metanorma/standoc/reqt.rng
521
521
  - lib/metanorma/standoc/section.rb
522
+ - lib/metanorma/standoc/spans_to_bibitem.rb
522
523
  - lib/metanorma/standoc/table.rb
523
524
  - lib/metanorma/standoc/term_lookup_cleanup.rb
524
525
  - lib/metanorma/standoc/terms.rb
@@ -1,243 +0,0 @@
1
- module Metanorma
2
- module Standoc
3
- module Cleanup
4
- def formattedref_spans(xmldoc)
5
- xmldoc.xpath("//bibitem[formattedref//span]").each do |b|
6
- spans = spans_preprocess(extract_content(b), b)
7
- ret = spans_to_bibitem(spans)
8
- spans[:type] and b["type"] = spans[:type]
9
- b << ret
10
- end
11
- end
12
-
13
- def extract_content(bib)
14
- extract_docid(bib) + extract_spans(bib)
15
- end
16
-
17
- def extract_spans(bib)
18
- bib.xpath("./formattedref//span").each_with_object([]) do |s, m|
19
- next if s.at("./ancestor::span")
20
-
21
- extract_spans1(s, m)
22
- end
23
- end
24
-
25
- def extract_spans1(span, acc)
26
- keys = span["class"].split(".", 2)
27
- acc << { key: keys[0], type: keys[1],
28
- val: span.children.to_xml }
29
- (span["class"] == "type" and span.remove) or span.replace(span.children)
30
- end
31
-
32
- def extract_docid(bib)
33
- bib.xpath("./docidentifier").each_with_object([]) do |d, m|
34
- m << { key: "docid", type: d["type"], val: d.text }
35
- d.remove
36
- end
37
- end
38
-
39
- def empty_span_hash
40
- { contrib: [], docid: [], uri: [], date: [], extent: {}, in: {} }
41
- end
42
-
43
- def spans_preprocess(spans, bib)
44
- ret = empty_span_hash
45
- spans.each { |s| span_preprocess1(s, ret, bib) }
46
- host_rearrange(ret)
47
- end
48
-
49
- def span_preprocess1(span, ret, bib)
50
- case span[:key]
51
- when "uri", "docid"
52
- val = link_unwrap(Nokogiri::XML.fragment(span[:val])).to_xml
53
- ret[span[:key].to_sym] << { type: span[:type], val: val }
54
- when "date"
55
- ret[span[:key].to_sym] << { type: span[:type] || "published",
56
- val: span[:val] }
57
- when "pages", "volume", "issue"
58
- ret[:extent][span[:key].to_sym] ||= []
59
- ret[:extent][span[:key].to_sym] << span[:val]
60
- when "pubplace", "title", "type", "series"
61
- ret[span[:key].to_sym] = span[:val]
62
- when "in_title"
63
- ret[:in][:title] = span[:val]
64
- when "publisher"
65
- ret[:contrib] << { role: "publisher", entity: "organization",
66
- name: span[:val] }
67
- when "surname", "initials", "givenname", "formatted-initials"
68
- ret[:contrib] = spans_preprocess_contrib(span, ret[:contrib])
69
- when "fullname"
70
- ret[:contrib] = spans_preprocess_fullname(span, ret[:contrib])
71
- when "organization"
72
- ret[:contrib] = spans_preprocess_org(span, ret[:contrib])
73
- when "in_surname", "in_initials", "in_givenname",
74
- "in_formatted-initials"
75
- ret[:in][:contrib] ||= []
76
- span[:key].sub!(/^in_/, "")
77
- ret[:in][:contrib] =
78
- spans_preprocess_contrib(span, ret[:in][:contrib])
79
- when "in_fullname"
80
- ret[:in][:contrib] ||= []
81
- span[:key].sub!(/^in_/, "")
82
- ret[:in][:contrib] =
83
- spans_preprocess_fullname(span, ret[:in][:contrib])
84
- when "in_organization"
85
- ret[:in][:contrib] ||= []
86
- span[:key].sub!(/^in_/, "")
87
- ret[:in][:contrib] =
88
- spans_preprocess_org(span, ret[:in][:contrib])
89
- else
90
- msg = "unrecognised key '#{span[:key]}' in `span:#{span[:key]}[#{span[:val]}]`"
91
- @log.add("Bibliography", bib, msg)
92
- end
93
- end
94
-
95
- def host_rearrange(ret)
96
- ret[:in][:title] or return ret
97
- ret[:in].merge!(empty_span_hash, { type: "misc" }) { |_, old, _| old }
98
-
99
- %i(series).each do |k|
100
- ret[:in][k] = ret[k]
101
- ret.delete(k)
102
- end
103
- /^in/.match?(ret[:type]) and ret[:in][:type] =
104
- ret[:type].sub(/^in/, "")
105
- ret
106
- end
107
-
108
- def spans_preprocess_contrib(span, contrib)
109
- span[:key] = "formatted-initials" if span[:key] == "initials"
110
-
111
- spans_preprocess_new_contrib?(span, contrib) and
112
- contrib << { role: span[:type] || "author", entity: "person" }
113
- if span[:key] == "givenname" && contrib[-1][span[:key].to_sym]
114
- contrib[-1][span[:key].to_sym] =
115
- Array(contrib[-1][span[:key].to_sym]) + span[:val]
116
- else
117
- contrib[-1][span[:key].to_sym] = span[:val]
118
- end
119
- contrib
120
- end
121
-
122
- def spans_preprocess_new_contrib?(span, contrib)
123
- contrib.empty? ||
124
- (if span[:key] == "surname" then contrib[-1][:surname]
125
- else (contrib[-1][:"formatted-initials"] || contrib[-1][:givenname])
126
- end) ||
127
- contrib[-1][:role] != (span[:type] || "author")
128
- end
129
-
130
- def spans_preprocess_fullname(span, contrib)
131
- name = span[:val].gsub(/\.(?=\p{Alpha})/, ". ").split(/ /)
132
- out = { role: span[:type] || "author", entity: "person",
133
- surname: name[-1] }
134
- if name.size > 1 && name[0..-2].all? { |x| /\.$/.match?(x) }
135
- out[:"formatted-initials"] = name[0..-2].join(" ")
136
- else
137
- out[:givenname] = name[0..-2]
138
- end
139
- contrib << out
140
- contrib
141
- end
142
-
143
- def spans_preprocess_org(span, contrib)
144
- contrib << { role: span[:type] || "author", entity: "organization",
145
- name: span[:val] }
146
- contrib
147
- end
148
-
149
- def spans_to_bibitem(spans)
150
- ret = ""
151
- spans[:title] and ret += "<title>#{spans[:title]}</title>"
152
- ret += spans_to_bibitem_docid(spans)
153
- spans[:contrib].each { |s| ret += span_to_contrib(s, spans[:title]) }
154
- spans[:series] and
155
- ret += "<series><title>#{spans[:series]}</title></series>"
156
- spans[:pubplace] and ret += "<place>#{spans[:pubplace]}</place>"
157
- ret += spans_to_bibitem_host(spans)
158
- ret + spans_to_bibitem_extent(spans[:extent])
159
- end
160
-
161
- def spans_to_bibitem_host(spans)
162
- return "" if spans[:in].empty?
163
-
164
- ret =
165
- "<relation type='includedIn'><bibitem type='#{spans[:in][:type]}'>"
166
- spans[:in].delete(:type)
167
- ret + "#{spans_to_bibitem(spans[:in])}</bibitem></relation>"
168
- end
169
-
170
- def spans_to_bibitem_docid(spans)
171
- ret = ""
172
- spans[:uri].each { |s| ret += span_to_docid(s, "uri") }
173
- spans[:docid].each { |s| ret += span_to_docid(s, "docidentifier") }
174
- spans[:date].each { |s| ret += span_to_date(s) }
175
- ret
176
- end
177
-
178
- def spans_to_bibitem_extent(spans)
179
- ret = ""
180
- { volume: "volume", issue: "issue", pages: "page" }.each do |k, v|
181
- spans[k]&.each { |s| ret += span_to_extent(s, v) }
182
- end
183
- return "" if ret.empty?
184
-
185
- "<extent>#{ret}</extent>"
186
- end
187
-
188
- def span_to_extent(span, key)
189
- values = span.split(/[-–]/)
190
- ret = "<locality type='#{key}'>" \
191
- "<referenceFrom>#{values[0]}</referenceFrom>"
192
- values[1] and
193
- ret += "<referenceTo>#{values[1]}</referenceTo>"
194
- "#{ret}</locality>"
195
- end
196
-
197
- def span_to_docid(span, key)
198
- if span[:type]
199
- "<#{key} type='#{span[:type]}'>#{span[:val]}</#{key}>"
200
- else
201
- "<#{key}>#{span[:val]}</#{key}>"
202
- end
203
- end
204
-
205
- def span_to_date(span)
206
- val = if /[-–](?=\d{4})/.match?(span[:val])
207
- from, to = span[:val].split(/[-–](?=\d{4})/, 2)
208
- "<from>#{from}</from><to>#{to}</to>"
209
- else
210
- "<on>#{span[:val]}</on>"
211
- end
212
- type = span[:type] ? " type='#{span[:type]}'" : ""
213
- "<date#{type}>#{val}</date>"
214
- end
215
-
216
- def span_to_contrib(span, title)
217
- e = if span[:entity] == "organization"
218
- "<organization><name>#{span[:name]}</name></organization>"
219
- else span_to_person(span, title)
220
- end
221
- "<contributor><role type='#{span[:role]}'/>#{e}</contributor>"
222
- end
223
-
224
- def validate_span_to_person(span, title)
225
- span[:surname] and return
226
- msg = "Missing surname: issue with bibliographic markup " \
227
- "in \"#{title}\": #{span}"
228
- @log.add("Bibliography", nil, msg)
229
- @fatalerror << msg
230
- end
231
-
232
- def span_to_person(span, title)
233
- validate_span_to_person(span, title)
234
- pre = (span[:"formatted-initials"] and
235
- "<formatted-initials>" \
236
- "#{span[:"formatted-initials"]}</formatted-initials>") ||
237
- Array(span[:givenname]).map { |x| "<forename>#{x}</forename>" }.join
238
- "<person><name>#{pre}<surname>#{span[:surname]}</surname></name>" \
239
- "</person>"
240
- end
241
- end
242
- end
243
- end