metanorma 1.6.1 → 1.6.3

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.
@@ -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