metanorma 1.6.1 → 1.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,6 +5,8 @@ require "metanorma-utils"
5
5
  module Metanorma
6
6
  # XML collection renderer
7
7
  class FileLookup
8
+ attr_accessor :files_to_delete, :parent
9
+
8
10
  # hash for each document in collection of document identifier to:
9
11
  # document reference (fileref or id), type of document reference,
10
12
  # and bibdata entry for that file
@@ -18,12 +20,12 @@ module Metanorma
18
20
  @path = path
19
21
  @compile = parent.compile
20
22
  @documents = parent.documents
23
+ @files_to_delete = []
21
24
  read_files
22
25
  end
23
26
 
24
27
  def read_files
25
28
  @xml.xpath(ns("//docref")).each { |d| read_file(d) }
26
- add_section_split
27
29
  end
28
30
 
29
31
  def read_file(docref)
@@ -41,9 +43,10 @@ module Metanorma
41
43
  .attachment_bibitem(identifier).root
42
44
  else
43
45
  file, _filename = targetfile(entry, read: true)
44
- xml = Nokogiri::XML(file)
46
+ xml = Nokogiri::XML(file, &:huge)
45
47
  add_document_suffix(identifier, xml)
46
48
  entry[:anchors] = read_anchors(xml)
49
+ entry[:ids] = read_ids(xml)
47
50
  entry[:bibdata] = xml.at(ns("//bibdata"))
48
51
  end
49
52
  end
@@ -56,66 +59,61 @@ module Metanorma
56
59
  end
57
60
 
58
61
  def add_section_split
59
- #require "debug"; binding.b
60
62
  ret = @files.keys.each_with_object({}) do |k, m|
61
63
  if @files[k][:sectionsplit] == "true" && !@files[k]["attachment"]
62
- s, manifest = sectionsplit(@files[k][:ref])
63
- s.each_with_index do |f1, i|
64
- add_section_split_instance(f1, m, k, i)
65
- end
64
+ s, manifest = sectionsplit(@files[k][:ref], k)
65
+ s.each_with_index { |f1, i| add_section_split_instance(f1, m, k, i) }
66
66
  m["#{k}:index.html"] = add_section_split_cover(manifest, k)
67
+ @files_to_delete << m["#{k}:index.html"][:ref]
67
68
  end
68
69
  m[k] = @files[k]
69
- #require "debug"; binding.b
70
70
  end
71
71
  @files = ret
72
72
  end
73
73
 
74
74
  def add_section_split_cover(manifest, ident)
75
- cover = section_split_cover(manifest, @parent.dir_name_cleanse(ident))
75
+ cover = @sectionsplit.section_split_cover(manifest,
76
+ @parent.dir_name_cleanse(ident))
76
77
  @files[ident][:out_path] = cover
77
78
  { attachment: true, index: false, out_path: cover,
78
79
  ref: File.join(File.dirname(manifest.file), cover) }
79
80
  end
80
81
 
81
- def section_split_cover(col, ident)
82
- dir = File.dirname(col.file)
83
- @compile.collection_setup(nil, dir)
84
- #require "debug";binding.b
85
- CollectionRenderer.new(col, dir,
86
- output_folder: "#{ident}_collection",
87
- format: %i(html),
88
- coverpage: File.join(dir, "cover.html")).coverpage
89
- FileUtils.mv "#{ident}_collection/index.html",
90
- File.join(dir, "#{ident}_index.html")
91
- FileUtils.rm_rf "#{ident}_collection"
92
- "#{ident}_index.html"
93
- end
94
-
95
82
  def add_section_split_instance(file, manifest, key, idx)
96
- presfile = File.join(File.dirname(@files[key][:ref]),
97
- File.basename(file[:url]))
98
- newkey = key("#{key.strip} #{file[:title]}")
83
+ presfile, newkey, xml =
84
+ add_section_split_instance_prep(file, key)
99
85
  manifest[newkey] =
100
86
  { parentid: key, presentationxml: true, type: "fileref",
101
87
  rel_path: file[:url], out_path: File.basename(file[:url]),
102
- anchors: read_anchors(Nokogiri::XML(File.read(presfile))),
88
+ anchors: read_anchors(xml), ids: read_ids(xml),
89
+ sectionsplit_output: true,
103
90
  bibdata: @files[key][:bibdata], ref: presfile }
91
+ @files_to_delete << file[:url]
104
92
  manifest[newkey][:bare] = true unless idx.zero?
105
93
  end
106
94
 
107
- def sectionsplit(file)
108
- #require "debug"; binding.b
109
- @compile.compile(
110
- file, { format: :asciidoc, extension_keys: [:presentation] }
111
- .merge(@parent.compile_options)
112
- )
113
- r = file.sub(/\.xml$/, ".presentation.xml")
114
- xml = Nokogiri::XML(File.read(r))
115
- s = @compile.sectionsplit(xml, File.basename(r), File.dirname(r))
116
- .sort_by { |f| f[:order] }
117
- [s, @compile.collection_manifest(File.basename(r), s, xml, nil,
118
- File.dirname(r))]
95
+ def add_section_split_instance_prep(file, key)
96
+ presfile = File.join(File.dirname(@files[key][:ref]),
97
+ File.basename(file[:url]))
98
+ newkey = key("#{key.strip} #{file[:title]}")
99
+ xml = Nokogiri::XML(File.read(presfile), &:huge)
100
+ [presfile, newkey, xml]
101
+ end
102
+
103
+ def sectionsplit(file, ident)
104
+ @sectionsplit =
105
+ Sectionsplit.new(input: file, base: File.basename(file), dir: File.dirname(file),
106
+ output: file, compile_options: @parent.compile_options,
107
+ fileslookup: self, ident: ident, isodoc: @isodoc)
108
+ coll = @sectionsplit.sectionsplit.sort_by { |f| f[:order] }
109
+ # s = @compile.sectionsplit(file, File.basename(file), File.dirname(file),
110
+ # @parent.compile_options, self, ident)
111
+ # .sort_by { |f| f[:order] }
112
+ # xml = Nokogiri::XML(File.read(file, encoding: "UTF-8")) { |x| x.huge }
113
+ xml = Nokogiri::XML(File.read(file, encoding: "UTF-8"), &:huge)
114
+ [coll, @sectionsplit
115
+ .collection_manifest(File.basename(file), coll, xml, nil,
116
+ File.dirname(file))]
119
117
  end
120
118
 
121
119
  # rel_path is the source file address, determined relative to the YAML.
@@ -220,8 +218,19 @@ module Metanorma
220
218
  ret[val[:type]][val[:value]] = key if val[:value]
221
219
  end
222
220
 
221
+ # Also parse all ids in doc (including ones which won't be xref targets)
222
+ def read_ids(xml)
223
+ ret = {}
224
+ xml.traverse do |x|
225
+ x.text? and next
226
+ /^semantic__/.match?(x.name) and next
227
+ x["id"] and ret[x["id"]] = true
228
+ end
229
+ ret
230
+ end
231
+
223
232
  def key(ident)
224
- @c.decode(ident).gsub(/(\s|[ ])+/, " ")
233
+ @c.decode(ident).gsub(/(\p{Zs})+/, " ").sub(/^metanorma-collection /, "")
225
234
  end
226
235
 
227
236
  def keys
@@ -229,10 +238,8 @@ module Metanorma
229
238
  end
230
239
 
231
240
  def get(ident, attr = nil)
232
- if attr
233
- @files[key(ident)][attr]
234
- else
235
- @files[key(ident)]
241
+ if attr then @files[key(ident)][attr]
242
+ else @files[key(ident)]
236
243
  end
237
244
  end
238
245
 
@@ -69,7 +69,8 @@ module Metanorma
69
69
  pdf-allow-print pdf-allow-print-hq pdf-allow-fill-in-forms
70
70
  fonts font-license-agreement pdf-allow-access-content
71
71
  pdf-encrypt-metadata iso-word-template document-scheme
72
- localize-number iso-word-bg-strip-color modspec-identifier-base).freeze
72
+ localize-number iso-word-bg-strip-color modspec-identifier-base)
73
+ .freeze
73
74
 
74
75
  EMPTY_ADOC_OPTIONS_DEFAULT_TRUE =
75
76
  %w(data-uri-image suppress-asciimath-dup use-xinclude
@@ -80,7 +81,7 @@ module Metanorma
80
81
  toc-tables toc-recommendations).freeze
81
82
 
82
83
  def attr_name_normalise(name)
83
- name.gsub(/-/, "").sub(/override$/, "_override").sub(/pdf$/, "_pdf")
84
+ name.gsub("-", "").sub(/override$/, "_override").sub(/pdf$/, "_pdf")
84
85
  .to_sym
85
86
  end
86
87
 
@@ -1,31 +1,35 @@
1
1
  require "yaml"
2
+ require_relative "util"
3
+ require_relative "sectionsplit_links"
2
4
 
3
5
  module Metanorma
4
- class Compile
5
- # assume we pass in Presentation XML, but we want to recover Semantic XML
6
- def sectionsplit_convert(input_filename, file, output_filename = nil,
7
- opts = {})
8
- @isodoc = IsoDoc::Convert.new({})
9
- input_filename += ".xml" unless input_filename.match?(/\.xml$/)
10
- File.exist?(input_filename) or
11
- File.open(input_filename, "w:UTF-8") { |f| f.write(file) }
12
- presxml = File.read(input_filename, encoding: "utf-8")
13
- @openmathdelim, @closemathdelim = @isodoc.extract_delims(presxml)
14
- xml, filename, dir = @isodoc.convert_init(presxml, input_filename, false)
15
- build_collection(xml, presxml, output_filename || filename, dir, opts)
6
+ class Sectionsplit
7
+ attr_accessor :filecache
8
+
9
+ def initialize(opts)
10
+ @input_filename = opts[:input]
11
+ @base = opts[:base]
12
+ @output_filename = opts[:output]
13
+ @xml = opts[:xml]
14
+ @dir = opts[:dir]
15
+ @compile_opts = opts[:compile_opts] || {}
16
+ @fileslookup = opts[:fileslookup]
17
+ @ident = opts[:ident]
18
+ @isodoc = opts[:isodoc]
16
19
  end
17
20
 
18
21
  def ns(xpath)
19
22
  @isodoc.ns(xpath)
20
23
  end
21
24
 
22
- def build_collection(xml, presxml, filename, dir, opts = {})
23
- base = File.basename(filename)
24
- collection_setup(base, dir)
25
- files = sectionsplit(xml, base, dir)
26
- collection_manifest(base, files, xml, presxml, dir).render(
27
- { format: %i(html), output_folder: "#{filename}_collection",
28
- coverpage: File.join(dir, "cover.html") }.merge(opts),
25
+ def build_collection
26
+ collection_setup(@base, @dir)
27
+ files = sectionsplit #(@input_filename, @base, @dir, @compile_opts)
28
+ input_xml = Nokogiri::XML(File.read(@input_filename,
29
+ encoding: "UTF-8"), &:huge)
30
+ collection_manifest(@base, files, input_xml, @xml, @dir).render(
31
+ { format: %i(html), output_folder: "#{@output_filename}_collection",
32
+ coverpage: File.join(@dir, "cover.html") }.merge(@compile_opts),
29
33
  )
30
34
  end
31
35
 
@@ -46,13 +50,11 @@ module Metanorma
46
50
 
47
51
  def coll_cover
48
52
  <<~COVER
49
- <html><head/>
50
- <body>
53
+ <html><head/><body>
51
54
  <h1>{{ doctitle }}</h1>
52
55
  <h2>{{ docnumber }}</h2>
53
56
  <nav>{{ navigation }}</nav>
54
- </body>
55
- </html>
57
+ </body></html>
56
58
  COVER
57
59
  end
58
60
 
@@ -62,161 +64,91 @@ module Metanorma
62
64
  ["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
63
65
  ["//indexsect", nil], ["//colophon", nil]].freeze
64
66
 
65
- def sectionsplit(xml, filename, dir)
66
- @key = xref_preprocess(xml)
67
- @splitdir = dir
68
- out = emptydoc(xml)
67
+ # Input XML is Semantic
68
+ # def sectionsplit(filename, basename, dir, compile_options, fileslookup = nil, ident = nil)
69
+ def sectionsplit
70
+ xml = sectionsplit_prep(File.read(@input_filename), @base, @dir)
71
+ @key = xref_preprocess(xml, @fileslookup, @ident)
69
72
  SPLITSECTIONS.each_with_object([]) do |n, ret|
70
- xml.xpath(ns(n[0])).each do |s|
71
- ret << sectionfile(xml, out, "#{filename}.#{ret.size}", s, n[1])
72
- end
73
- end
74
- end
75
-
76
- def emptydoc(xml)
77
- out = xml.dup
78
- out.xpath(
79
- ns("//preface | //sections | //annex | //bibliography/clause | " \
80
- "//bibliography/references[not(@hidden = 'true')] | //indexsect" \
81
- "//colophon"),
82
- ).each(&:remove)
83
- out
84
- end
85
-
86
- def sectionfile(fulldoc, xml, file, chunk, parentnode)
87
- fname = create_sectionfile(fulldoc, xml.dup, file, chunk, parentnode)
88
- { order: chunk["displayorder"].to_i, url: fname,
89
- title: titlerender(chunk) }
90
- end
91
-
92
- def create_sectionfile(xml, out, file, chunk, parentnode)
93
- ins = out.at(ns("//misccontainer")) || out.at(ns("//bibdata"))
94
- if parentnode
95
- ins.next = "<#{parentnode}/>"
96
- ins.next.add_child(chunk.dup)
97
- else ins.next = chunk.dup
98
- end
99
- xref_process(out, xml, @key)
100
- outname = "#{file}.xml"
101
- File.open(File.join(@splitdir, outname), "w:UTF-8") { |f| f.write(out) }
102
- outname
103
- end
104
-
105
- def xref_preprocess(xml)
106
- svg_preprocess(xml)
107
- key = (0...8).map { rand(65..90).chr }.join # random string
108
- xml.root["type"] = key # to force recognition of internal refs
109
- key
110
- end
111
-
112
- def xref_process(section, xml, key)
113
- refs = eref_to_internal_eref(section, xml, key)
114
- refs += xref_to_internal_eref(section, key)
115
- ins = new_hidden_ref(section)
116
- copied_refs = copy_repo_items_biblio(ins, section, xml)
117
- insert_indirect_biblio(ins, refs - copied_refs, key)
118
- end
119
-
120
- def svg_preprocess(xml)
121
- xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
122
- m = svgmap_wrap(s)
123
- s.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
124
- next unless /^#/.match? a["href"]
125
-
126
- a["href"] = a["href"].sub(/^#/, "")
127
- m << "<target href='#{a['href']}'>" \
128
- "<xref target='#{a['href']}'/></target>"
73
+ conflate_floatingtitles(xml.xpath(ns(n[0]))).each do |s|
74
+ ret << sectionfile(xml, emptydoc(xml), "#{@base}.#{ret.size}", s, n[1])
129
75
  end
130
76
  end
131
77
  end
132
78
 
133
- def svgmap_wrap(svg)
134
- ret = svg.at("./ancestor::xmlns:svgmap") and return ret
135
- ret = svg.at("./ancestor::xmlns:figure")
136
- ret.wrap("<svgmap/>")
137
- svg.at("./ancestor::xmlns:svgmap")
138
- end
139
-
140
- def make_anchor(anchor)
141
- "<localityStack><locality type='anchor'><referenceFrom>" \
142
- "#{anchor}</referenceFrom></locality></localityStack>"
79
+ def block?(node)
80
+ %w(p table formula admonition ol ul dl figure quote sourcecode example
81
+ pre note pagebrreak hr bookmark requirement recommendation permission
82
+ svgmap inputform toc passthrough review imagemap).include?(node.name)
143
83
  end
144
84
 
145
- def xref_to_internal_eref(xml, key)
146
- xml.xpath(ns("//xref")).each_with_object({}) do |x, m|
147
- x["bibitemid"] = "#{key}_#{x['target']}"
148
- x << make_anchor(x["target"])
149
- m[x["bibitemid"]] = true
150
- x.delete("target")
151
- x["type"] = key
152
- x.name = "eref"
153
- end.keys
154
- end
155
-
156
- def eref_to_internal_eref(section, xml, key)
157
- eref_to_internal_eref_select(section, xml).each_with_object([]) do |x, m|
158
- url = xml.at(ns("//bibitem[@id = '#{x}']/uri[@type = 'citation']"))
159
- section.xpath("//*[@bibitemid = '#{x}']").each do |e|
160
- id = eref_to_internal_eref1(e, key, url)
161
- id and m << id
85
+ def conflate_floatingtitles(nodes)
86
+ holdover = false
87
+ nodes.each_with_object([]) do |x, m|
88
+ if holdover then m.last << x
89
+ else m << [x]
162
90
  end
91
+ holdover = block?(x)
163
92
  end
164
93
  end
165
94
 
166
- def eref_to_internal_eref1(elem, key, url)
167
- if url
168
- elem.name = "link"
169
- elem["target"] = url
170
- nil
171
- else
172
- elem["bibitemid"] = "#{key}_#{elem['bibitemid']}"
173
- elem << make_anchor(elem["bibitemid"])
174
- elem["type"] = key
175
- elem["bibitemid"]
176
- end
95
+ def sectionsplit_prep(file, filename, dir)
96
+ @splitdir = dir
97
+ xml1filename, type = sectionsplit_preprocess_semxml(file, filename)
98
+ Compile.new.compile(
99
+ xml1filename,
100
+ { format: :asciidoc, extension_keys: [:presentation], type: type }
101
+ .merge(@compile_opts),
102
+ )
103
+ Nokogiri::XML(File.read(xml1filename.sub(/\.xml$/, ".presentation.xml"),
104
+ encoding: "utf-8"), &:huge)
177
105
  end
178
106
 
179
- def eref_to_internal_eref_select(section, xml)
180
- refs = section.xpath("//*/@bibitemid").map { |x| x.text } # rubocop:disable Style/SymbolProc
181
- refs.uniq.reject do |x|
182
- xml.at(ns("//bibitem[@id = '#{x}'][@type = 'internal']")) ||
183
- xml.at(ns("//bibitem[@id = '#{x}']" \
184
- "[docidentifier/@type = 'repository']"))
107
+ def sectionsplit_preprocess_semxml(file, filename)
108
+ xml = Nokogiri::XML(file, &:huge)
109
+ type = xml.root.name.sub("-standard", "").to_sym
110
+ @fileslookup&.parent&.update_xrefs(xml, @ident, {})
111
+ xml1 = Tempfile.open([filename, ".xml"], encoding: "utf-8") do |f|
112
+ f.write(@isodoc.to_xml(svg_preprocess(xml)))
113
+ f
185
114
  end
115
+ @filecache ||= []
116
+ @filecache << xml1
117
+ [xml1.path, type]
186
118
  end
187
119
 
188
- # from standoc
189
- def new_hidden_ref(xmldoc)
190
- ins = xmldoc.at("bibliography") or
191
- xmldoc.root << "<bibliography/>" and ins = xmldoc.at("bibliography")
192
- ins.add_child("<references hidden='true' normative='false'/>").first
120
+ def emptydoc(xml)
121
+ out = xml.dup
122
+ out.xpath(
123
+ ns("//preface | //sections | //annex | //bibliography/clause | " \
124
+ "//bibliography/references[not(@hidden = 'true')] | //indexsect | " \
125
+ "//colophon"),
126
+ ).each(&:remove)
127
+ out
193
128
  end
194
129
 
195
- def copy_repo_items_biblio(ins, section, xml)
196
- xml.xpath(ns("//references/bibitem[docidentifier/@type = 'repository']"))
197
- .each_with_object([]) do |b, m|
198
- section.at("//*[@bibitemid = '#{b['id']}']") or next
199
- ins << b.dup
200
- m << b["id"]
201
- end
130
+ def sectionfile(fulldoc, xml, file, chunks, parentnode)
131
+ fname = create_sectionfile(fulldoc, xml.dup, file, chunks, parentnode)
132
+ { order: chunks.last["displayorder"].to_i, url: fname,
133
+ title: titlerender(chunks.last) }
202
134
  end
203
135
 
204
- def insert_indirect_biblio(ins, refs, prefix)
205
- refs.each do |x|
206
- ins << <<~BIBENTRY
207
- <bibitem id="#{x}" type="internal">
208
- <docidentifier type="repository">#{x.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
209
- </bibitem>
210
- BIBENTRY
136
+ def create_sectionfile(xml, out, file, chunks, parentnode)
137
+ ins = out.at(ns("//metanorma-extension")) || out.at(ns("//bibdata"))
138
+ sectionfile_insert(ins, chunks, parentnode)
139
+ xref_process(out, xml, @key)
140
+ outname = "#{file}.xml"
141
+ File.open(File.join(@splitdir, outname), "w:UTF-8") do |f|
142
+ f.write(out)
211
143
  end
144
+ outname
212
145
  end
213
146
 
214
- def recursive_string_keys(hash)
215
- case hash
216
- when Hash then hash.map { |k, v| [k.to_s, recursive_string_keys(v)] }.to_h
217
- when Enumerable then hash.map { |v| recursive_string_keys(v) }
218
- else
219
- hash
147
+ def sectionfile_insert(ins, chunks, parentnode)
148
+ if parentnode
149
+ ins.next = "<#{parentnode}/>"
150
+ chunks.each { |c| ins.next.add_child(c.dup) }
151
+ else chunks.each { |c| ins.next = c.dup }
220
152
  end
221
153
  end
222
154
 
@@ -249,7 +181,20 @@ module Metanorma
249
181
  end
250
182
  },
251
183
  }
252
- recursive_string_keys(ret).to_yaml
184
+ Util::recursive_string_keys(ret).to_yaml
185
+ end
186
+
187
+ def section_split_cover(col, ident)
188
+ dir = File.dirname(col.file)
189
+ collection_setup(nil, dir)
190
+ CollectionRenderer.new(col, dir,
191
+ output_folder: "#{ident}_collection",
192
+ format: %i(html),
193
+ coverpage: File.join(dir, "cover.html")).coverpage
194
+ FileUtils.mv "#{ident}_collection/index.html",
195
+ File.join(dir, "#{ident}_index.html")
196
+ FileUtils.rm_rf "#{ident}_collection"
197
+ "#{ident}_index.html"
253
198
  end
254
199
  end
255
200
  end
@@ -0,0 +1,116 @@
1
+ module Metanorma
2
+ class Sectionsplit
3
+ def xref_preprocess(xml, fileslookup, identifier)
4
+ key = (0...8).map { rand(65..90).chr }.join # random string
5
+ xml.root["type"] = key # to force recognition of internal refs
6
+ key
7
+ end
8
+
9
+ def xref_process(section, xml, key)
10
+ refs = eref_to_internal_eref(section, xml, key)
11
+ refs += xref_to_internal_eref(section, key)
12
+ ins = new_hidden_ref(section)
13
+ copied_refs = copy_repo_items_biblio(ins, section, xml)
14
+ insert_indirect_biblio(ins, refs - copied_refs, key)
15
+ end
16
+
17
+ def svg_preprocess(xml)
18
+ xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
19
+ m = svgmap_wrap(s)
20
+ s.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
21
+ next unless /^#/.match? a["href"]
22
+
23
+ a["href"] = a["href"].sub(/^#/, "")
24
+ m << "<target href='#{a['href']}'>" \
25
+ "<xref target='#{a['href']}'/></target>"
26
+ end
27
+ end
28
+ xml
29
+ end
30
+
31
+ def svgmap_wrap(svg)
32
+ ret = svg.at("./ancestor::xmlns:svgmap") and return ret
33
+ ret = svg.at("./ancestor::xmlns:figure")
34
+ ret.wrap("<svgmap/>")
35
+ svg.at("./ancestor::xmlns:svgmap")
36
+ end
37
+
38
+ def make_anchor(anchor)
39
+ "<localityStack><locality type='anchor'><referenceFrom>" \
40
+ "#{anchor}</referenceFrom></locality></localityStack>"
41
+ end
42
+
43
+ def xref_to_internal_eref(xml, key)
44
+ xml.xpath(ns("//xref")).each_with_object({}) do |x, m|
45
+ x["bibitemid"] = "#{key}_#{x['target']}"
46
+ x << make_anchor(x["target"])
47
+ m[x["bibitemid"]] = true
48
+ x.delete("target")
49
+ x["type"] = key
50
+ x.name = "eref"
51
+ end.keys
52
+ end
53
+
54
+ def eref_to_internal_eref(section, xml, key)
55
+ bibitems = Util::gather_bibitems(xml)
56
+ bibitemids = Util::gather_bibitemids(section)
57
+ eref_to_internal_eref_select(section, xml, bibitems)
58
+ .each_with_object([]) do |x, m|
59
+ url = bibitems[x]&.at(ns("./uri[@type = 'citation']"))
60
+ bibitemids[x]&.each do |e|
61
+ id = eref_to_internal_eref1(e, key, url)
62
+ id and m << id
63
+ end
64
+ end
65
+ end
66
+
67
+ def eref_to_internal_eref1(elem, key, url)
68
+ if url
69
+ elem.name = "link"
70
+ elem["target"] = url
71
+ nil
72
+ else
73
+ elem["bibitemid"] = "#{key}_#{elem['bibitemid']}"
74
+ elem << make_anchor(elem["bibitemid"])
75
+ elem["type"] = key
76
+ elem["bibitemid"]
77
+ end
78
+ end
79
+
80
+ def eref_to_internal_eref_select(section, _xml, bibitems)
81
+ refs = Util::gather_bibitemids(section).keys
82
+ refs.uniq.reject do |x|
83
+ b = bibitems[x] and (b["type"] == "internal" ||
84
+ b.at(ns("./docidentifier/@type = 'repository']")))
85
+ end
86
+ end
87
+
88
+ # from standoc
89
+ def new_hidden_ref(xmldoc)
90
+ ins = xmldoc.at("bibliography") or
91
+ xmldoc.root << "<bibliography/>" and ins = xmldoc.at("bibliography")
92
+ ins.add_child("<references hidden='true' normative='false'/>").first
93
+ end
94
+
95
+ def copy_repo_items_biblio(ins, section, xml)
96
+ bibitems = Util::gather_bibitems(section)
97
+ xml.xpath(ns("//references/bibitem[docidentifier/@type = 'repository']"))
98
+ .each_with_object([]) do |b, m|
99
+ bibitems[b["id"]] or next
100
+ # section.at("//*[@bibitemid = '#{b['id']}']") or next
101
+ ins << b.dup
102
+ m << b["id"]
103
+ end
104
+ end
105
+
106
+ def insert_indirect_biblio(ins, refs, prefix)
107
+ refs.each do |x|
108
+ ins << <<~BIBENTRY
109
+ <bibitem id="#{x}" type="internal">
110
+ <docidentifier type="repository">#{x.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
111
+ </bibitem>
112
+ BIBENTRY
113
+ end
114
+ end
115
+ end
116
+ end
@@ -29,6 +29,37 @@ module Metanorma
29
29
  end
30
30
  end
31
31
 
32
+ def self.recursive_string_keys(hash)
33
+ case hash
34
+ when Hash then hash.map { |k, v| [k.to_s, recursive_string_keys(v)] }.to_h
35
+ when Enumerable then hash.map { |v| recursive_string_keys(v) }
36
+ else
37
+ hash
38
+ end
39
+ end
40
+
41
+ def self.gather_bibitems(xml)
42
+ xml.xpath("//xmlns:bibitem[@id]").each_with_object({}) do |b, m|
43
+ m[b["id"]] = b
44
+ end
45
+ end
46
+
47
+ def self.gather_bibitemids(xml)
48
+ xml.xpath("//*[@bibitemid]").each_with_object({}) do |e, m|
49
+ /^semantic__/.match?(e.name) and next
50
+ m[e["bibitemid"]] ||= []
51
+ m[e["bibitemid"]] << e
52
+ end
53
+ end
54
+
55
+ def self.gather_citeases(xml)
56
+ xml.xpath("//*[@citeas]").each_with_object({}) do |e, m|
57
+ /^semantic__/.match?(e.name) and next
58
+ m[e["citeas"]] ||= []
59
+ m[e["citeas"]] << e
60
+ end
61
+ end
62
+
32
63
  class DisambigFiles
33
64
  def initialize
34
65
  @seen_filenames = []
@@ -1,3 +1,3 @@
1
1
  module Metanorma
2
- VERSION = "1.6.1".freeze
2
+ VERSION = "1.6.3".freeze
3
3
  end