metanorma 1.6.5 → 1.6.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4bbd3fdfd37664da0a7f9e91cbecfcb0f7cdd49c004cf75eaa122c366ea6fba
4
- data.tar.gz: 6b61241e1010ed465995c23447b4828503495d8f4fb2366e64babe0ae6d0726e
3
+ metadata.gz: c329757741717214253fd1ca5cf31cfaa1859c2c35647b5586970cb36595f1a3
4
+ data.tar.gz: c02920016d7294a37d9459e26d9d4e5c4291bc75a94181c1d139ad7f3a2e5215
5
5
  SHA512:
6
- metadata.gz: dc05aa1c9d8aec0e6d45b537e10a130f88e715116f0dd92820e73588ff5a6542a7f2f92099e504654d2ed21e4e95c4bd84c0b260e24f923720b38ae298455f33
7
- data.tar.gz: 870e182c05914d484180fd19360bfe1010cb9b57ed926926d76ba6cde3d9f2adbf2cb98e5d7e44702f2024cd51b52347524b9fb0ac28c0463d01b3d1dfc9d7b6
6
+ metadata.gz: d8fb74a61e67a308fb0523e4512bc4d2e0067d5dadb8cc736114e47781e9b638066a0e438cadeca16a1d210f785eeb544abd526a91483dfd81f6580b9fa051ff
7
+ data.tar.gz: de5e33cc1cfd207c6ad912759a5fc9e8cda3f576eaabd3e2c897662d299d298d37d9db052589990f5aa9f18a9ccd675d870212f0a07b987128d42eec198e5007
@@ -1,8 +1,6 @@
1
1
  module Metanorma
2
2
  # XML collection renderer
3
3
  class CollectionRenderer
4
- # @param bib [Nokogiri::XML::Element]
5
- # @param identifier [String]
6
4
  def update_bibitem(bib, identifier)
7
5
  docid = get_bibitem_docid(bib, identifier) or return
8
6
  newbib = dup_bibitem(docid, bib)
@@ -14,77 +12,90 @@ module Metanorma
14
12
  bib.replace(newbib)
15
13
  end
16
14
 
17
- def get_bibitem_docid(bib, identifier)
18
- # IDs for repo references are untyped by default
19
- docid = bib.at(ns("./docidentifier[not(@type)]")) ||
20
- bib.at(ns("./docidentifier"))
21
- docid &&= docid_prefix(docid)
22
- if @files.get(docid) then docid
23
- else
24
- fail_update_bibitem(docid, identifier)
25
- nil
26
- end
27
- end
28
-
29
- def docid_prefix(docid)
30
- type = docid["type"]
31
- type == "metanorma-collection" and type = nil
32
- @c.decode(@isodoc
33
- .docid_prefix(type, docid.children.to_xml)).gsub(/\s/, " ")
34
- end
35
-
36
- def dup_bibitem(docid, bib)
37
- newbib = @files.get(docid, :bibdata).dup
38
- newbib.name = "bibitem"
39
- newbib["hidden"] = "true"
40
- newbib&.at("./*[local-name() = 'ext']")&.remove
41
- newbib["id"] = bib["id"]
42
- newbib
43
- end
44
-
45
- # Resolves direct links to other files in collection
46
- # (repo(current-metanorma-collection/x),
47
- # and indirect links to other files in collection
48
- # (bibitem[@type = 'internal'] pointing to a file anchor
49
- # in another file in the collection)
15
+ # Resolves references to other files in the collection. Three routines:
16
+ # 1. Eref to a document that has been split into multiple documents
17
+ # (sectionsplit) are resolved to direct eref to the split document
18
+ # 2. Indirect erefs to a file anchor in an unknwon file in the collection
19
+ # (bibitem[@type = 'internal'] ) are resolved to direct eref to the
20
+ # containing document
21
+ # 3. Direct erefs to other files in collection
22
+ # (repo(current-metanorma-collection/x) are resolved to hyperlinks
50
23
  # @param file [String] XML content
51
24
  # @param identifier [String] docid
52
25
  # @param internal_refs [Hash{String=>Hash{String=>String}] schema name to
53
26
  # anchor to filename
54
27
  # @return [String] XML content
55
- def update_xrefs(file, identifier, internal_refs)
28
+ def update_xrefs(file, docid, internal_refs)
56
29
  docxml = file.is_a?(String) ? Nokogiri::XML(file, &:huge) : file
57
30
  supply_repo_ids(docxml)
58
- update_indirect_refs_to_docs(docxml, internal_refs)
59
- ids = @files.get(identifier, :ids)
60
- @files.add_document_suffix(identifier, docxml)
61
- update_direct_refs_to_docs(docxml, identifier)
31
+ @nested or update_indirect_refs_to_docs(docxml, docid, internal_refs)
32
+ @files.add_document_suffix(docid, docxml)
33
+ @nested or update_sectionsplit_refs_to_docs(docxml, internal_refs)
34
+ update_direct_refs_to_docs(docxml, docid)
62
35
  hide_refs(docxml)
63
- @files.get(identifier, :sectionsplit_output) and eref2link(docxml)
64
- svgmap_resolve(datauri_encode(docxml), ids)
36
+ @files.get(docid, :sectionsplit_output) and eref2link(docxml)
37
+ svgmap_resolve(datauri_encode(docxml), @files.get(docid, :ids))
65
38
  docxml.to_xml
66
39
  end
67
40
 
41
+ def update_sectionsplit_refs_to_docs(docxml, internal_refs)
42
+ Util::gather_citeases(docxml).each do |k, v|
43
+ (@files.get(k) && @files.get(k, :sectionsplit)) or next
44
+ opts = { key: @files.get(k, :indirect_key),
45
+ source_suffix: docxml.root["document_suffix"],
46
+ target_suffix: @files.get(k, :document_suffix) }
47
+ refs = v.each_with_object({}) do |eref, m|
48
+ update_sectionsplit_eref_to_doc(eref, internal_refs, m, opts)
49
+ end
50
+ add_hidden_bibliography(docxml, refs)
51
+ end
52
+ end
53
+
54
+ def update_sectionsplit_eref_to_doc(eref, internal_refs, doclist, opts)
55
+ a = eref.at(ns("./localityStack/locality[@type = 'anchor']/" \
56
+ "referenceFrom")) or return
57
+ doc = internal_refs[opts[:key]]["#{a.text}_#{opts[:target_suffix]}"]
58
+ bibitemid = Metanorma::Utils::to_ncname("#{doc}_#{opts[:source_suffix]}")
59
+ eref["bibitemid"] = bibitemid
60
+ doclist[bibitemid] ||= doc
61
+ doclist
62
+ end
63
+
64
+ def new_hidden_ref(xmldoc)
65
+ ins = xmldoc.at(ns("bibliography")) or
66
+ xmldoc.root << "<bibliography/>" and ins = xmldoc.at(ns("bibliography"))
67
+ ins.at(ns("./referenced[@hidden = 'true']")) or
68
+ ins.add_child("<references hidden='true' normative='false'/>").first
69
+ end
70
+
71
+ def add_hidden_bibliography(xmldoc, refs)
72
+ ins = new_hidden_ref(xmldoc)
73
+ refs.each do |k, v|
74
+ _, url = @files.targetfile_id(v, {})
75
+ ins << <<~XML
76
+ <bibitem id="#{k}">
77
+ <docidentifier type="repository">current-metanorma-collection/#{v}</docidentifier>
78
+ <uri type='citation'>#{url}</uri>
79
+ </bibitem>
80
+ XML
81
+ end
82
+ end
83
+
68
84
  def eref2link(docxml)
69
85
  isodoc = IsoDoc::PresentationXMLConvert.new({})
70
86
  isodoc.bibitem_lookup(docxml)
71
87
  isodoc.eref2link(docxml)
72
88
  end
73
89
 
74
- def hide_refs(docxml)
75
- docxml.xpath(ns("//references[bibitem][not(./bibitem[not(@hidden) or " \
76
- "@hidden = 'false'])]")).each do |f|
77
- f["hidden"] = "true"
78
- end
79
- end
80
-
81
- def supply_repo_ids(docxml)
82
- docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |b|
83
- b.at(ns("./docidentifier[@type = 'repository']")) and next
90
+ def supply_repo_ids(doc)
91
+ doc.xpath(
92
+ ns("//bibitem[not(ancestor::bibitem)]" \
93
+ "[not(./docidentifier[@type = 'repository'])]"),
94
+ ).each do |b|
84
95
  b.xpath(ns("./docidentifier")).each do |docid|
85
- id = @isodoc
86
- .docid_prefix(docid["type"], docid.children.to_xml)
96
+ id = @isodoc.docid_prefix(docid["type"], docid.children.to_xml)
87
97
  @files.get(id) or next
98
+ @files.get(id, :indirect_key) and next # will resolve as indirect key
88
99
  docid.next = "<docidentifier type='repository'>" \
89
100
  "current-metanorma-collection/#{id}</docidentifier>"
90
101
  end
@@ -103,12 +114,11 @@ module Metanorma
103
114
 
104
115
  def svgmap_resolve1(eref, isodoc, _docxml, ids)
105
116
  href = isodoc.eref_target(eref) or return
106
- return if href == "##{eref['bibitemid']}" ||
107
- (href =~ /^#/ && !ids[href.sub(/^#/, "")])
108
-
117
+ href == "##{eref['bibitemid']}" ||
118
+ (href =~ /^#/ && !ids[href.sub(/^#/, "")]) and return
109
119
  eref["target"] = href.strip
110
120
  eref.name = "link"
111
- eref&.elements&.remove
121
+ eref.elements&.remove
112
122
  end
113
123
 
114
124
  # repo(current-metanorma-collection/ISO 17301-1:2016)
@@ -117,60 +127,83 @@ module Metanorma
117
127
  # Preferably with anchor, and is a job to realise dynamic lookup
118
128
  # of localities.
119
129
  def update_direct_refs_to_docs(docxml, identifier)
120
- @ncnames = {}
121
- erefs = Util::gather_citeases(docxml)
122
- erefs1 = Util::gather_bibitemids(docxml)
130
+ erefs, erefs1 = update_direct_refs_to_docs_prep(docxml)
123
131
  docxml.xpath(ns("//bibitem")).each do |b|
124
132
  docid = b.at(ns("./docidentifier[@type = 'repository']")) or next
125
- unless %r{^current-metanorma-collection/}.match(docid.text)
126
- erefs1[b["id"]]&.each { |x| strip_eref(x) }
127
- next
128
- end
133
+ strip_unresolved_repo_erefs(identifier, docid, erefs1, b) or next
129
134
  update_bibitem(b, identifier)
130
135
  docid = docid_to_citeas(b) or next
131
136
  erefs[docid] and update_anchors(b, docid, erefs[docid])
132
137
  end
133
138
  end
134
139
 
135
- def strip_eref(eref)
136
- eref.xpath(ns("./locality | ./localityStack")).each(&:remove)
137
- eref.replace(eref.children)
138
- end
139
-
140
- def docid_to_citeas(bib)
141
- docid = bib.at(ns("./docidentifier[@primary = 'true']")) ||
142
- bib.at(ns("./docidentifier")) or return
143
- docid_prefix(docid)
140
+ def update_direct_refs_to_docs_prep(docxml)
141
+ @ncnames = {}
142
+ [Util::gather_citeases(docxml), Util::gather_bibitemids(docxml)]
144
143
  end
145
144
 
146
- def collect_erefs(docxml)
147
- docxml.xpath(ns("//eref"))
148
- .each_with_object({ citeas: {}, bibitemid: {} }) do |i, m|
149
- m[:citeas][i["citeas"]] = true
150
- m[:bibitemid][i["bibitemid"]] = true
151
- end
145
+ # strip erefs if they are repository erefs, but do not point to a document
146
+ # within the current collection. This can happen if a collection consists
147
+ # of many documents, but not all are included in the current collection.
148
+ # Do not do this if this is a sectionsplit collection or a nested manifest.
149
+ # Return false if bibitem is not to be further processed
150
+ def strip_unresolved_repo_erefs(_document_id, bib_docid, erefs, bibitem)
151
+ %r{^current-metanorma-collection/(?!Missing:)}.match?(bib_docid.text) and
152
+ return true
153
+ @nested and return false
154
+ erefs[bibitem["id"]]&.each { |x| x.parent and strip_eref(x) }
155
+ false
152
156
  end
153
157
 
154
158
  # Resolve erefs to a container of ids in another doc,
155
159
  # to an anchor eref (direct link)
156
- def update_indirect_refs_to_docs(docxml, internal_refs)
157
- bibitems = Util::gather_bibitems(docxml)
158
- erefs = Util::gather_bibitemids(docxml)
160
+ def update_indirect_refs_to_docs(docxml, _docidentifier, internal_refs)
161
+ bibitems, erefs = update_indirect_refs_to_docs_prep(docxml)
159
162
  internal_refs.each do |schema, ids|
160
163
  ids.each do |id, file|
161
- update_indirect_refs_to_docs1(docxml, "#{schema}_#{id}",
164
+ k = indirect_ref_key(schema, id, docxml)
165
+ update_indirect_refs_to_docs1(docxml, k,
162
166
  file, bibitems, erefs)
163
167
  end
164
168
  end
165
169
  end
166
170
 
171
+ def update_indirect_refs_to_docs_prep(docxml)
172
+ bibitems = Util::gather_bibitems(docxml)
173
+ erefs = Util::gather_bibitemids(docxml)
174
+ @updated_anchors = {}
175
+ [bibitems, erefs]
176
+ end
177
+
178
+ def indirect_ref_key(schema, id, docxml)
179
+ /^#{schema}_/.match?(id) and return id
180
+ ret = "#{schema}_#{id}"
181
+ (k = docxml.root["type"]) && k != schema and
182
+ ret = "#{ret}_#{docxml.root['document_suffix']}"
183
+ ret
184
+ end
185
+
167
186
  def update_indirect_refs_to_docs1(_docxml, key, file, bibitems, erefs)
168
187
  erefs[key]&.each do |e|
169
188
  e["citeas"] = file
170
- a = e.at(ns(".//locality[@type = 'anchor']/referenceFrom")) and
171
- a.children = "#{a.text}_#{Metanorma::Utils::to_ncname(file)}"
189
+ update_indirect_refs_to_docs_anchor(e, file)
172
190
  end
173
- docid = bibitems[key]&.at(ns("./docidentifier[@type = 'repository']")) or
191
+ update_indirect_refs_to_docs_docid(bibitems[key], file)
192
+ end
193
+
194
+ def update_indirect_refs_to_docs_anchor(eref, file)
195
+ a = eref.at(ns(".//locality[@type = 'anchor']/referenceFrom")) or return
196
+ suffix = file
197
+ @files.get(file) && p = @files.get(file, :parentid) and
198
+ suffix = "#{p}_#{suffix}"
199
+ existing = a.text
200
+ anchor = Metanorma::Utils::to_ncname("#{existing}_#{suffix}")
201
+ @updated_anchors[existing] or a.children = anchor
202
+ @updated_anchors[anchor] = true
203
+ end
204
+
205
+ def update_indirect_refs_to_docs_docid(bibitem, file)
206
+ docid = bibitem&.at(ns("./docidentifier[@type = 'repository']")) or
174
207
  return
175
208
  docid.children = "current-metanorma-collection/#{file}"
176
209
  docid.previous =
@@ -183,8 +216,11 @@ module Metanorma
183
216
  erefs.each do |e|
184
217
  if @files.get(docid) then update_anchor_loc(bib, e, docid)
185
218
  else
186
- e << "<strong>** Unresolved reference to document #{docid} " \
187
- "from eref</strong>"
219
+ msg = "<strong>** Unresolved reference to document #{docid} " \
220
+ "from eref</strong>"
221
+ e << msg
222
+ strip_eref(e)
223
+ @log&.add("Cross-References", e, msg)
188
224
  end
189
225
  end
190
226
  end
@@ -195,10 +231,9 @@ module Metanorma
195
231
  @ncnames[docid] ||= Metanorma::Utils::to_ncname(docid)
196
232
  ref = loc.at("./xmlns:referenceFrom") or return
197
233
  anchor = "#{ref.text}_#{@ncnames[docid]}"
198
- return unless @files.get(docid, :anchors).inject([]) do |m, (_, x)|
234
+ @files.get(docid, :anchors).inject([]) do |m, (_, x)|
199
235
  m += x.values
200
- end.include?(anchor)
201
-
236
+ end.include?(anchor) or return
202
237
  ref.content = anchor
203
238
  end
204
239
 
@@ -213,55 +248,5 @@ module Metanorma
213
248
  ins << "<locality type='anchor'><referenceFrom>#{anchor.sub(/^_/, '')}" \
214
249
  "</referenceFrom></locality>"
215
250
  end
216
-
217
- # gather internal bibitem references
218
- def gather_internal_refs
219
- @files.keys.each_with_object({}) do |i, refs|
220
- @files.get(i, :attachment) and next
221
- file, = @files.targetfile_id(i, read: true)
222
- gather_internal_refs1(file, refs)
223
- end
224
- end
225
-
226
- def gather_internal_refs1(file, refs)
227
- Nokogiri::XML(file, &:huge)
228
- .xpath(ns("//bibitem[@type = 'internal']/" \
229
- "docidentifier[@type = 'repository']")).each do |d|
230
- a = d.text.split(%r{/}, 2)
231
- a.size > 1 or next
232
- refs[a[0]] ||= {}
233
- refs[a[0]][a[1]] = true
234
- end
235
- end
236
-
237
- # resolve file location for the target of each internal reference
238
- def locate_internal_refs
239
- refs = gather_internal_refs
240
- @files.keys.reject { |k| @files.get(k, :attachment) }.each do |ident|
241
- locate_internal_refs1(refs, ident, @isodoc.docid_prefix("", ident.dup))
242
- end
243
- refs.each do |schema, ids|
244
- ids.each do |id, key|
245
- key == true and refs[schema][id] = "Missing:#{schema}:#{id}"
246
- end
247
- end
248
- refs
249
- end
250
-
251
- def locate_internal_refs1(refs, identifier, ident)
252
- t = locate_internal_refs1_prep(ident)
253
- refs.each do |schema, ids|
254
- ids.keys.select { |id| t[id] }.each do |id|
255
- t[id].at("./ancestor-or-self::*[@type = '#{schema}']") and
256
- refs[schema][id] = identifier
257
- end
258
- end
259
- end
260
-
261
- def locate_internal_refs1_prep(ident)
262
- file, _filename = @files.targetfile_id(ident, read: true)
263
- xml = Nokogiri::XML(file, &:huge)
264
- xml.xpath("//*[@id]").each_with_object({}) { |i, x| x[i["id"]] = i }
265
- end
266
251
  end
267
252
  end
@@ -75,5 +75,82 @@ module Metanorma
75
75
  end
76
76
  end
77
77
  end
78
+
79
+ # gather internal bibitem references
80
+ def gather_internal_refs
81
+ @files.keys.each_with_object({}) do |i, refs|
82
+ @files.get(i, :attachment) and next
83
+ file, = @files.targetfile_id(i, read: true)
84
+ gather_internal_refs1(file, i, refs)
85
+ end
86
+ end
87
+
88
+ def gather_internal_refs1(file, ident, refs)
89
+ f = Nokogiri::XML(file, &:huge)
90
+ !@files.get(ident, :sectionsplit) and
91
+ gather_internal_refs_indirect(f, refs)
92
+ key = @files.get(ident, :indirect_key) and
93
+ gather_internal_refs_sectionsplit(f, ident, key, refs)
94
+ end
95
+
96
+ def gather_internal_refs_indirect(doc, refs)
97
+ doc.xpath(ns("//bibitem[@type = 'internal']/" \
98
+ "docidentifier[@type = 'repository']")).each do |d|
99
+ a = d.text.split(%r{/}, 2)
100
+ a.size > 1 or next
101
+ refs[a[0]] ||= {}
102
+ refs[a[0]][a[1]] = false
103
+ end
104
+ end
105
+
106
+ def gather_internal_refs_sectionsplit(_doc, ident, key, refs)
107
+ refs[key] ||= {}
108
+ @files.get(ident, :ids).each_key do |k|
109
+ refs[key][k] = false
110
+ end
111
+ end
112
+
113
+ def populate_internal_refs(refs)
114
+ @files.keys.reject do |k|
115
+ @files.get(k, :attachment) || @files.get(k, :sectionsplit)
116
+ end.each do |ident|
117
+ locate_internal_refs1(refs, ident, @isodoc.docid_prefix("", ident.dup))
118
+ end
119
+ refs
120
+ end
121
+
122
+ # resolve file location for the target of each internal reference
123
+ def locate_internal_refs
124
+ refs = populate_internal_refs(gather_internal_refs)
125
+ refs.each do |schema, ids|
126
+ ids.each do |id, key|
127
+ key and next
128
+ refs[schema][id] = "Missing:#{schema}:#{id}"
129
+ @log&.add("Cross-References", nil, refs[schema][id])
130
+ end
131
+ end
132
+ refs
133
+ end
134
+
135
+ def locate_internal_refs1(refs, identifier, ident)
136
+ t = locate_internal_refs1_prep(ident)
137
+ refs.each do |schema, ids|
138
+ ids.keys.select { |id| t[id] }.each do |id|
139
+ t[id].at("./ancestor-or-self::*[@type = '#{schema}']") and
140
+ refs[schema][id] = identifier
141
+ end
142
+ end
143
+ end
144
+
145
+ def locate_internal_refs1_prep(ident)
146
+ file, = @files.targetfile_id(ident, read: true)
147
+ xml = Nokogiri::XML(file, &:huge)
148
+ r = xml.root["document_suffix"]
149
+ xml.xpath("//*[@id]").each_with_object({}) do |i, x|
150
+ /^semantic_/.match?(i.name) and next
151
+ x[i["id"]] = i
152
+ r and x[i["id"].sub(/_#{r}$/, "")] = i
153
+ end
154
+ end
78
155
  end
79
156
  end
@@ -66,10 +66,9 @@ module Metanorma
66
66
  # @return [Hash<String, Metanorma::Document>]
67
67
  def documents(dir = "")
68
68
  docs = @docref.each_with_object({}) do |dr, m|
69
- next m unless dr["fileref"]
70
-
69
+ dr["fileref"] or next m
71
70
  m[dr["identifier"]] = Document.parse_file(
72
- File.join(dir, dr["fileref"]),
71
+ rel_path_resolve(dir, dr["fileref"]),
73
72
  dr["attachment"], dr["identifier"], dr["index"]
74
73
  )
75
74
  m
@@ -77,6 +76,11 @@ module Metanorma
77
76
  @manifest.reduce(docs) { |mem, mnf| mem.merge mnf.documents(dir) }
78
77
  end
79
78
 
79
+ def rel_path_resolve(dir, path)
80
+ p = Pathname.new(path)
81
+ p.absolute? ? path : File.join(dir, path)
82
+ end
83
+
80
84
  # @param builder [Nokogiri::XML::Builder]
81
85
  def to_xml(builder)
82
86
  builder.manifest do |b|
@@ -10,8 +10,62 @@ module Metanorma
10
10
  path.basename.to_s.gsub(clean_regex, fallback_sym))
11
11
  end
12
12
 
13
+ def dup_bibitem(docid, bib)
14
+ newbib = @files.get(docid, :bibdata).dup
15
+ newbib.name = "bibitem"
16
+ newbib["hidden"] = "true"
17
+ newbib&.at("./*[local-name() = 'ext']")&.remove
18
+ newbib["id"] = bib["id"]
19
+ newbib
20
+ end
21
+
22
+ def get_bibitem_docid(bib, identifier)
23
+ # IDs for repo references are untyped by default
24
+ docid = bib.at(ns("./docidentifier[not(@type)]")) ||
25
+ bib.at(ns("./docidentifier"))
26
+ docid &&= docid_prefix(docid)
27
+ if @files.get(docid) then docid
28
+ else
29
+ fail_update_bibitem(docid, identifier)
30
+ nil
31
+ end
32
+ end
33
+
34
+ def hide_refs(docxml)
35
+ docxml.xpath(ns("//references[bibitem][not(./bibitem[not(@hidden) or " \
36
+ "@hidden = 'false'])]")).each do |f|
37
+ f["hidden"] = "true"
38
+ end
39
+ end
40
+
41
+ def strip_eref(eref)
42
+ eref.xpath(ns("./locality | ./localityStack")).each(&:remove)
43
+ eref.replace(eref.children)
44
+ end
45
+
46
+ def docid_to_citeas(bib)
47
+ docid = bib.at(ns("./docidentifier[@primary = 'true']")) ||
48
+ bib.at(ns("./docidentifier")) or return
49
+ docid_prefix(docid)
50
+ end
51
+
52
+ def collect_erefs(docxml)
53
+ docxml.xpath(ns("//eref"))
54
+ .each_with_object({ citeas: {}, bibitemid: {} }) do |i, m|
55
+ m[:citeas][i["citeas"]] = true
56
+ m[:bibitemid][i["bibitemid"]] = true
57
+ end
58
+ end
59
+
13
60
  private
14
61
 
62
+ def docid_prefix(docid)
63
+ type = docid["type"]
64
+ type == "metanorma-collection" and type = nil
65
+ @c.decode(@isodoc
66
+ .docid_prefix(type, docid.children.to_xml)).gsub(/\s/, " ")
67
+ end
68
+
15
69
  def create_non_existing_directory(output_directory)
16
70
  !File.exist?(output_directory) and
17
71
  FileUtils.mkdir_p(output_directory)
@@ -92,8 +146,11 @@ module Metanorma
92
146
  "prefatory-content": isodoc_builder(@xml.at(ns("//prefatory-content"))),
93
147
  "final-content": isodoc_builder(@xml.at(ns("//final-content"))),
94
148
  doctitle: m.at(ns("../bibdata/title"))&.text,
95
- docnumber: m.at(ns("../bibdata/docidentifier"))&.text
96
- }.each { |k, v| v and @isodoc.meta.set(k, v) }
149
+ docnumber: m.at(ns("../bibdata/docidentifier"))&.text }.each do |k, v|
150
+ v and @isodoc.meta.set(
151
+ k, v
152
+ )
153
+ end
97
154
  end
98
155
 
99
156
  def isodoc_builder(node)
@@ -11,7 +11,7 @@ module Metanorma
11
11
  class CollectionRenderer
12
12
  FORMATS = %i[html xml doc pdf].freeze
13
13
 
14
- attr_accessor :isodoc
14
+ attr_accessor :isodoc, :nested
15
15
  attr_reader :xml, :compile, :compile_options, :documents
16
16
 
17
17
  # This is only going to render the HTML collection
@@ -49,6 +49,9 @@ module Metanorma
49
49
  @compile = Compile.new
50
50
  @c = HTMLEntities.new
51
51
  @files_to_delete = []
52
+ @nested = options[:nested] # if false, this is the root instance of Renderer
53
+ # if true, then this is not the last time Renderer will be run
54
+ # (e.g. this is sectionsplit)
52
55
 
53
56
  # list of files in the collection
54
57
  @files = Metanorma::FileLookup.new(folder, self)
@@ -39,17 +39,16 @@ module Metanorma
39
39
  @files[i] = entry
40
40
  end
41
41
 
42
- def bibdata_process(entry, identifier)
42
+ def bibdata_process(entry, ident)
43
43
  if entry[:attachment]
44
- entry[:bibdata] = Metanorma::Document
45
- .attachment_bibitem(identifier).root
44
+ entry[:bibdata] = Metanorma::Document.attachment_bibitem(ident).root
46
45
  else
47
46
  file, _filename = targetfile(entry, read: true)
48
47
  xml = Nokogiri::XML(file, &:huge)
49
- add_document_suffix(identifier, xml)
50
- entry[:anchors] = read_anchors(xml)
51
- entry[:ids] = read_ids(xml)
52
- entry[:bibdata] = xml.at(ns("//bibdata"))
48
+ add_document_suffix(ident, xml)
49
+ entry.merge!(anchors: read_anchors(xml), ids: read_ids(xml),
50
+ bibdata: xml.at(ns("//bibdata")),
51
+ document_suffix: xml.root["document_suffix"])
53
52
  end
54
53
  end
55
54
 
@@ -84,19 +83,15 @@ module Metanorma
84
83
  end
85
84
  end
86
85
 
87
- def add_suffix_to_attributes(doc, suffix, tag_name, attribute_name)
88
- doc.xpath(ns("//#{tag_name}[@#{attribute_name}]")).each do |elem|
89
- elem.attributes[attribute_name].value =
90
- "#{elem.attributes[attribute_name].value}_#{suffix}"
91
- end
92
- end
93
-
94
86
  def add_document_suffix(identifier, doc)
95
87
  document_suffix = Metanorma::Utils::to_ncname(identifier)
96
88
  Metanorma::Utils::anchor_attributes.each do |(tag_name, attribute_name)|
97
- add_suffix_to_attributes(doc, document_suffix, tag_name, attribute_name)
89
+ Util::add_suffix_to_attributes(doc, document_suffix, tag_name,
90
+ attribute_name, @isodoc)
98
91
  end
99
92
  url_in_css_styles(doc, document_suffix)
93
+ doc.root["document_suffix"] ||= ""
94
+ doc.root["document_suffix"] += document_suffix
100
95
  end
101
96
 
102
97
  # update relative URLs, url(#...), in CSS in @style attrs (including SVG)
@@ -4,16 +4,30 @@ module Metanorma
4
4
  def add_section_split
5
5
  ret = @files.keys.each_with_object({}) do |k, m|
6
6
  if @files[k][:sectionsplit] == "true" && !@files[k]["attachment"]
7
- s, manifest = sectionsplit(@files[k][:ref], @files[k][:out_path], k)
8
- s.each_with_index { |f1, i| add_section_split_instance(f1, m, k, i) }
9
- m["#{k}:index.html"] = add_section_split_cover(manifest, k)
10
- @files_to_delete << m["#{k}:index.html"][:ref]
7
+ process_section_split_instance(k, m)
8
+ cleanup_section_split_instance(k, m)
11
9
  end
12
10
  m[k] = @files[k]
13
11
  end
14
12
  @files = ret
15
13
  end
16
14
 
15
+ def process_section_split_instance(key, manifest)
16
+ s, sectionsplit_manifest = sectionsplit(@files[key][:ref],
17
+ @files[key][:out_path], key)
18
+ s.each_with_index do |f1, i|
19
+ add_section_split_instance(f1, manifest, key, i)
20
+ end
21
+ manifest["#{key}:index.html"] =
22
+ add_section_split_cover(sectionsplit_manifest, key)
23
+ end
24
+
25
+ def cleanup_section_split_instance(key, manifest)
26
+ @files_to_delete << manifest["#{key}:index.html"][:ref]
27
+ #@files[key].delete(:ids).delete(:anchors)
28
+ @files[key][:indirect_key] = @sectionsplit.key
29
+ end
30
+
17
31
  def add_section_split_cover(manifest, ident)
18
32
  cover = @sectionsplit
19
33
  .section_split_cover(manifest, @parent.dir_name_cleanse(ident),
@@ -57,7 +71,7 @@ module Metanorma
57
71
  def sectionsplit(file, outfile, ident)
58
72
  @sectionsplit = Sectionsplit
59
73
  .new(input: file, base: outfile, dir: File.dirname(file),
60
- output: outfile, compile_options: @parent.compile_options,
74
+ output: outfile, compile_opts: @parent.compile_options,
61
75
  fileslookup: self, ident: ident, isodoc: @isodoc)
62
76
  coll = @sectionsplit.sectionsplit.sort_by { |f| f[:order] }
63
77
  xml = Nokogiri::XML(File.read(file, encoding: "UTF-8"), &:huge)
@@ -4,7 +4,7 @@ require_relative "sectionsplit_links"
4
4
 
5
5
  module Metanorma
6
6
  class Sectionsplit
7
- attr_accessor :filecache
7
+ attr_accessor :filecache, :key
8
8
 
9
9
  def initialize(opts)
10
10
  @input_filename = opts[:input]
@@ -24,7 +24,7 @@ module Metanorma
24
24
 
25
25
  def build_collection
26
26
  collection_setup(@base, @dir)
27
- files = sectionsplit #(@input_filename, @base, @dir, @compile_opts)
27
+ files = sectionsplit # (@input_filename, @base, @dir, @compile_opts)
28
28
  input_xml = Nokogiri::XML(File.read(@input_filename,
29
29
  encoding: "UTF-8"), &:huge)
30
30
  collection_manifest(@base, files, input_xml, @xml, @dir).render(
@@ -50,7 +50,7 @@ module Metanorma
50
50
 
51
51
  def coll_cover
52
52
  <<~COVER
53
- <html><head/><body>
53
+ <html><head><meta charset="UTF-8"/></head><body>
54
54
  <h1>{{ doctitle }}</h1>
55
55
  <h2>{{ docnumber }}</h2>
56
56
  <nav>{{ navigation }}</nav>
@@ -71,7 +71,8 @@ module Metanorma
71
71
  @key = xref_preprocess(xml, @fileslookup, @ident)
72
72
  SPLITSECTIONS.each_with_object([]) do |n, ret|
73
73
  conflate_floatingtitles(xml.xpath(ns(n[0]))).each do |s|
74
- ret << sectionfile(xml, emptydoc(xml), "#{@base}.#{ret.size}", s, n[1])
74
+ ret << sectionfile(xml, emptydoc(xml), "#{@base}.#{ret.size}", s,
75
+ n[1])
75
76
  end
76
77
  end
77
78
  end
@@ -107,17 +108,30 @@ module Metanorma
107
108
  def sectionsplit_preprocess_semxml(file, filename)
108
109
  xml = Nokogiri::XML(file, &:huge)
109
110
  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.write(@isodoc.to_xml((xml)))
114
- f
115
- end
111
+ sectionsplit_update_xrefs(xml)
112
+ xml1 = sectionsplit_write_semxml(filename, xml)
116
113
  @filecache ||= []
117
114
  @filecache << xml1
118
115
  [xml1.path, type]
119
116
  end
120
117
 
118
+ def sectionsplit_update_xrefs(xml)
119
+ if c = @fileslookup&.parent
120
+ n = c.nested
121
+ c.nested = true # so unresolved erefs are not deleted
122
+ c.update_xrefs(xml, @ident, {})
123
+ c.nested = n
124
+ end
125
+ end
126
+
127
+ def sectionsplit_write_semxml(filename, xml)
128
+ Tempfile.open([filename, ".xml"], encoding: "utf-8") do |f|
129
+ # f.write(@isodoc.to_xml(svg_preprocess(xml)))
130
+ f.write(@isodoc.to_xml(xml))
131
+ f
132
+ end
133
+ end
134
+
121
135
  def emptydoc(xml)
122
136
  out = xml.dup
123
137
  out.xpath(
@@ -3,27 +3,29 @@ module Metanorma
3
3
  def xref_preprocess(xml, _fileslookup, _identifier)
4
4
  key = (0...8).map { rand(65..90).chr }.join # random string
5
5
  xml.root["type"] = key # to force recognition of internal refs
6
+ # bookmarks etc as new id elements introduced in Presentation XML:
7
+ # add doc suffix
8
+ Metanorma::Utils::anchor_attributes.each do |(tag_name, attribute_name)|
9
+ Util::add_suffix_to_attributes(xml, xml.root["document_suffix"],
10
+ tag_name, attribute_name, @isodoc)
11
+ end
6
12
  key
7
13
  end
8
14
 
9
15
  def xref_process(section, xml, key)
10
16
  svg_preprocess(section, Metanorma::Utils::to_ncname(@ident))
11
17
  refs = eref_to_internal_eref(section, xml, key)
12
- refs += xref_to_internal_eref(section, key)
18
+ refs += xref_to_internal_eref(section, xml, key)
13
19
  ins = new_hidden_ref(section)
14
20
  copied_refs = copy_repo_items_biblio(ins, section, xml)
15
- insert_indirect_biblio(ins, refs - copied_refs, key)
21
+ insert_indirect_biblio(ins, refs - copied_refs, key, xml)
16
22
  end
17
23
 
18
- def svg_preprocess(xml, document_suffix)
24
+ def svg_preprocess(xml, doc_suffix)
25
+ suffix = doc_suffix.nil? || doc_suffix.blank? ? "" : "_#{doc_suffix}"
19
26
  xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
20
27
  m = svgmap_wrap(s)
21
- s.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
22
- /^#/.match? a["href"] or next
23
- a["href"] = a["href"].sub(/^#/, "")
24
- m << "<target href='#{a['href']}'>" \
25
- "<xref target='#{a['href']}_#{document_suffix}'/></target>"
26
- end
28
+ svg_xrefs(s, m, suffix)
27
29
  end
28
30
  xml
29
31
  end
@@ -35,33 +37,75 @@ module Metanorma
35
37
  svg.at("./ancestor::xmlns:svgmap")
36
38
  end
37
39
 
40
+ def svg_xrefs(svg, svgmap, suffix)
41
+ svg.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
42
+ /^#/.match? a["href"] or next
43
+ a["href"] = a["href"].sub(/^#/, "")
44
+ svgmap << "<target href='#{a['href']}'>" \
45
+ "<xref target='#{a['href']}#{suffix}'/></target>"
46
+ end
47
+ end
48
+
38
49
  def make_anchor(anchor)
39
50
  "<localityStack><locality type='anchor'><referenceFrom>" \
40
51
  "#{anchor}</referenceFrom></locality></localityStack>"
41
52
  end
42
53
 
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"])
54
+ def xref_to_internal_eref(section, xml, key)
55
+ bibitems, indirect = xref_to_internal_eref_prep(section, xml)
56
+ section.xpath(ns("//xref")).each_with_object({}) do |x, m|
57
+ xref_prefix_key(x, key, indirect)
58
+ x["bibitemid"] = x["target"]
47
59
  m[x["bibitemid"]] = true
48
- x.delete("target")
49
- x["type"] = key
50
- x.name = "eref"
60
+ xref_to_internal_eref_anchor(x, key, bibitems, xml.root["document_suffix"])
51
61
  end.keys
52
62
  end
53
63
 
64
+ def xref_to_internal_eref_prep(section, xml)
65
+ bibitems = Util::gather_bibitems(section)
66
+ indirect_bibitems = Util::gather_bibitems(xml)
67
+ .select { |_, v| indirect_bib?(v) }
68
+ [bibitems, indirect_bibitems]
69
+ end
70
+
71
+ def xref_to_internal_eref_anchor(xref, key, bibitems, document_suffix)
72
+ t = xref["target"]
73
+ if d = bibitems[t]&.at(ns("./docidentifier[@type = 'repository']"))
74
+ m = %r{^([^/]+)}.match(d.text) and
75
+ t.sub!(%r(#{m[0]}_), "")
76
+ end
77
+ t.sub!(%r{^#{key}_}, "")
78
+ xref << make_anchor(t.sub(%r(_#{document_suffix}$), ""))
79
+ xref.delete("target")
80
+ xref.name = "eref"
81
+ end
82
+
83
+ def xref_prefix_key(xref, key, indirect)
84
+ if b = indirect[xref["target"]]
85
+ t = b.at(ns("./docidentifier[@type = 'repository']"))
86
+ xref["type"] = t.text.sub(%r{/.*$}, "")
87
+ else
88
+ xref["target"] = "#{key}_#{xref['target']}"
89
+ xref["type"] = key
90
+ end
91
+ end
92
+
54
93
  def eref_to_internal_eref(section, xml, key)
55
- bibitems = Util::gather_bibitems(xml)
56
- bibitemids = Util::gather_bibitemids(section)
94
+ bibitems, bibitemids = eref_to_internal_eref_prep(section, xml)
57
95
  eref_to_internal_eref_select(section, xml, bibitems)
58
96
  .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
97
+ url = bibitems[x]&.at(ns("./uri[@type = 'citation']"))
98
+ bibitemids[x]&.each do |e|
99
+ id = eref_to_internal_eref1(e, key, url) and m << id
100
+ end
63
101
  end
64
- end
102
+ end
103
+
104
+ def eref_to_internal_eref_prep(section, xml)
105
+ bibitems = Util::gather_bibitems(xml)
106
+ .delete_if { |_, v| internal_bib?(v) }
107
+ bibitemids = Util::gather_bibitemids(section)
108
+ [bibitems, bibitemids]
65
109
  end
66
110
 
67
111
  def eref_to_internal_eref1(elem, key, url)
@@ -80,11 +124,22 @@ module Metanorma
80
124
  def eref_to_internal_eref_select(section, _xml, bibitems)
81
125
  refs = Util::gather_bibitemids(section).keys
82
126
  refs.uniq.reject do |x|
83
- b = bibitems[x] and (b["type"] == "internal" ||
84
- b.at(ns("./docidentifier/@type = 'repository']")))
127
+ b = bibitems[x] and ( indirect_bib?(b) || internal_bib?(b) )
85
128
  end
86
129
  end
87
130
 
131
+ def internal_bib?(bibitem)
132
+ bibitem["type"] == "internal" ||
133
+ bibitem.at(ns("./docidentifier[@type = 'repository']"))
134
+ end
135
+
136
+ def indirect_bib?(bibitem)
137
+ a = bibitem.at(ns("./docidentifier[@type = 'repository']")) or
138
+ return false
139
+ %r{^current-metanorma-collection/}.match?(a.text) and return false
140
+ a.text.include?("/")
141
+ end
142
+
88
143
  # from standoc
89
144
  def new_hidden_ref(xmldoc)
90
145
  ins = xmldoc.at("bibliography") or
@@ -96,21 +151,39 @@ module Metanorma
96
151
  bibitems = Util::gather_bibitems(section)
97
152
  xml.xpath(ns("//references/bibitem[docidentifier/@type = 'repository']"))
98
153
  .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
154
+ bibitems[b["id"]] or next
155
+ # section.at("//*[@bibitemid = '#{b['id']}']") or next
156
+ ins << b.dup
157
+ m << b["id"]
158
+ end
104
159
  end
105
160
 
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
161
+ def insert_indirect_biblio(ins, refs, key, xml)
162
+ refs.empty? and return
163
+ internal_bibitems, external_bibitems = insert_indirect_biblio_prep(xml)
164
+ refs.compact.reject do |x|
165
+ #external_bibitems[x.sub(/^#{key}_/, "")]
166
+ end.each do |x|
167
+ ins << if b = internal_bibitems[x.sub(/^#{key}_/, "")]
168
+ b.dup.tap { |m| m["id"] = x }
169
+ else new_indirect_bibitem(x, key)
170
+ end
113
171
  end
114
172
  end
173
+
174
+ def insert_indirect_biblio_prep(xml)
175
+ bibitems = Util::gather_bibitems(xml)
176
+ internal_bibitems = bibitems.select { |_, v| internal_bib?(v) }
177
+ external_bibitems = bibitems.reject { |_, v| internal_bib?(v) }
178
+ [internal_bibitems, external_bibitems]
179
+ end
180
+
181
+ def new_indirect_bibitem(ident, prefix)
182
+ <<~BIBENTRY
183
+ <bibitem id="#{ident}" type="internal">
184
+ <docidentifier type="repository">#{ident.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
185
+ </bibitem>
186
+ BIBENTRY
187
+ end
115
188
  end
116
189
  end
@@ -60,6 +60,15 @@ module Metanorma
60
60
  end
61
61
  end
62
62
 
63
+ def self.add_suffix_to_attributes(doc, suffix, tag_name, attr_name, isodoc)
64
+ (suffix.nil? || suffix.empty?) and return
65
+ doc.xpath(isodoc.ns("//#{tag_name}[@#{attr_name}]")).each do |elem|
66
+ a = elem.attributes[attr_name].value
67
+ /_#{suffix}$/.match?(a) or
68
+ elem.attributes[attr_name].value = "#{a}_#{suffix}"
69
+ end
70
+ end
71
+
63
72
  class DisambigFiles
64
73
  def initialize
65
74
  @seen_filenames = []
@@ -1,3 +1,3 @@
1
1
  module Metanorma
2
- VERSION = "1.6.5".freeze
2
+ VERSION = "1.6.6".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.5
4
+ version: 1.6.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-23 00:00:00.000000000 Z
11
+ date: 2023-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor