Class: Metanorma::Collection::Sectionsplit

Inherits:
Object
  • Object
show all
Defined in:
lib/metanorma/collection/sectionsplit/collection.rb,
lib/metanorma/collection/sectionsplit/sectionsplit.rb

Constant Summary collapse

SPLITSECTIONS =
[["//preface/*", "preface"], ["//sections/*", "sections"],
["//annex", nil],
["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
["//indexsect", nil], ["//colophon", nil]].freeze
FN_CAPTIONS =
".//fmt-fn-label/span[@class = 'fmt-caption-label']".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Sectionsplit

Returns a new instance of Sectionsplit.



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 12

def initialize(opts)
  @input_filename = opts[:input]
  @base = opts[:base]
  @output_filename = opts[:output]
  @xml = opts[:xml]
  @dir = opts[:dir]
  @compile_opts = opts[:compile_opts] || {}
  @fileslookup = opts[:fileslookup]
  @ident = opts[:ident]
  @isodoc = opts[:isodoc]
  @isodoc_presxml = opts[:isodoc_presxml]
  @document_suffix = opts[:document_suffix]
end

Instance Attribute Details

#filecacheObject

Returns the value of attribute filecache.



10
11
12
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 10

def filecache
  @filecache
end

#keyObject

Returns the value of attribute key.



10
11
12
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 10

def key
  @key
end

Instance Method Details

#att_dir(file) ⇒ Object



66
67
68
# File 'lib/metanorma/collection/sectionsplit/collection.rb', line 66

def att_dir(file)
  "_#{File.basename(file, '.*')}_attachments"
end

#block?(node) ⇒ Boolean

TODO move to metanorma-utils

Returns:

  • (Boolean)


72
73
74
75
76
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 72

def block?(node)
  %w(p table formula admonition ol ul dl figure quote sourcecode example
     pre note pagebreak hr bookmark requirement recommendation permission
     svgmap inputform toc passthrough review imagemap).include?(node.name)
end

#build_collectionObject



4
5
6
7
8
9
10
11
12
13
14
# File 'lib/metanorma/collection/sectionsplit/collection.rb', line 4

def build_collection
  collection_setup(@base, @dir)
  files = sectionsplit
  input_xml = Nokogiri::XML(File.read(@input_filename,
                                      encoding: "UTF-8"), &:huge)
  collection_manifest(@base, files, input_xml, @xml, @dir).render(
    { format: i(html), output_folder: "#{@output_filename}_collection",
      coverpage: File.join(@dir, "cover.html") }.merge(@compile_opts),
  )
  section_split_attachments(out: "#{@output_filename}_collection")
end

#coll_coverObject



24
25
26
27
28
29
30
31
32
# File 'lib/metanorma/collection/sectionsplit/collection.rb', line 24

def coll_cover
  "    <html><head><meta charset=\"UTF-8\"/></head><body>\n          <h1>{{ doctitle }}</h1>\n          <h2>{{ docnumber }}</h2>\n          <nav>{{ navigation }}</nav>\n        </body></html>\n  COVER\nend\n"

#collection_manifest(filename, files, origxml, _presxml, dir) ⇒ Object



34
35
36
37
38
39
# File 'lib/metanorma/collection/sectionsplit/collection.rb', line 34

def collection_manifest(filename, files, origxml, _presxml, dir)
  File.open(File.join(dir, "#{filename}.html.yaml"), "w:UTF-8") do |f|
    f.write(collectionyaml(files, origxml))
  end
  Metanorma::Collection.parse File.join(dir, "#{filename}.html.yaml")
end

#collection_setup(filename, dir) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/metanorma/collection/sectionsplit/collection.rb', line 16

def collection_setup(filename, dir)
  FileUtils.mkdir_p "#{filename}_collection" if filename
  FileUtils.mkdir_p dir
  File.open(File.join(dir, "cover.html"), "w:UTF-8") do |f|
    f.write(coll_cover)
  end
end

#collectionyaml(files, xml) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/metanorma/collection/sectionsplit/collection.rb', line 41

def collectionyaml(files, xml)
  #warn xml.to_xml
  ret = {
    directives: ["presentation-xml", "bare-after-first"],
    bibdata: {
      title: {
        type: "title-main", language: @lang,
        content: xml.at(ns("//bibdata/title")).text
      },
      type: "collection",
      docid: {
        type: xml.at(ns("//bibdata/docidentifier/@type")).text,
        id: xml.at(ns("//bibdata/docidentifier")).text,
      },
    },
    manifest: {
      level: "collection", title: "Collection",
      docref: files.sort_by { |f| f[:order] }.each.map do |f|
        { fileref: f[:url], identifier: f[:title] }
      end
    },
  }
  ::Metanorma::Util::recursive_string_keys(ret).to_yaml
end

#conflate_floatingtitles(nodes) ⇒ Object



78
79
80
81
82
83
84
85
86
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 78

def conflate_floatingtitles(nodes)
  holdover = false
  nodes.each_with_object([]) do |x, m|
    if holdover then m.last << x
    else m << [x]
    end
    holdover = block?(x)
  end
end

#create_sectionfile(xml, out, file, chunks, parentnode) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 151

def create_sectionfile(xml, out, file, chunks, parentnode)
  ins = out.at(ns("//metanorma-extension")) || out.at(ns("//bibdata"))
  sectionfile_insert(ins, chunks, parentnode)
  sectionfile_fn_filter(sectionfile_review_filter(out))
  Metanorma::Collection::XrefProcess::xref_process(out, xml, @key,
                                                   @ident, @isodoc, true)
  outname = "#{file}.xml"
  File.open(File.join(@splitdir, outname), "w:UTF-8") do |f|
    f.write(out)
  end
  outname
end

#empty_attachments(xml) ⇒ Object



141
142
143
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 141

def empty_attachments(xml)
  xml.dup
end

#empty_doc(xml) ⇒ Object



130
131
132
133
134
135
136
137
138
139
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 130

def empty_doc(xml)
  out = xml.dup
  out.xpath(
    ns("//preface | //sections | //annex | " \
    "//references/bibitem[not(@hidden = 'true')] | " \
    "//indexsect | //colophon"),
  ).each(&:remove)
  ::Metanorma::Collection::Util::hide_refs(out)
  out
end

#ns(xpath) ⇒ Object



26
27
28
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 26

def ns(xpath)
  @isodoc.ns(xpath)
end

#section_split_attachments(out: nil) ⇒ Object



70
71
72
73
74
75
76
77
78
# File 'lib/metanorma/collection/sectionsplit/collection.rb', line 70

def section_split_attachments(out: nil)
  attachments = att_dir(@tmp_filename)
  File.directory?(attachments) or return
  dir = out || File.dirname(@input_filename)
  ret = File.join(dir, att_dir(@output_filename))
  FileUtils.rm_rf ret
  FileUtils.mv attachments, ret
  File.basename(ret)
end

#section_split_cover(col, ident, one_doc_coll) ⇒ Object



80
81
82
83
84
85
86
87
88
89
# File 'lib/metanorma/collection/sectionsplit/collection.rb', line 80

def section_split_cover(col, ident, one_doc_coll)
  dir = File.dirname(col.file)
  collection_setup(nil, dir)
  r = ::Metanorma::Collection::Renderer
    .new(col, dir, output_folder: "#{ident}_collection",
                   format: i(html),
                   coverpage: File.join(dir, "cover.html"))
  r.coverpage
  section_split_cover1(ident, r, dir, one_doc_coll)
end

#section_split_cover1(ident, renderer, dir, _one_doc_coll) ⇒ Object



91
92
93
94
95
96
97
98
# File 'lib/metanorma/collection/sectionsplit/collection.rb', line 91

def section_split_cover1(ident, renderer, dir, _one_doc_coll)
  filename = File.basename("#{ident}_index.html")
  # ident can be a directory with YAML indirection
  dest = File.join(dir, filename)
  FileUtils.mv File.join(renderer.outdir, "index.html"), dest
  FileUtils.rm_rf renderer.outdir
  filename
end

#sectionfile(fulldoc, xml, file, chunks, parentnode) ⇒ Object



145
146
147
148
149
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 145

def sectionfile(fulldoc, xml, file, chunks, parentnode)
  fname = create_sectionfile(fulldoc, xml.dup, file, chunks, parentnode)
  { order: chunks.last["displayorder"].to_i, url: fname,
    title: titlerender(chunks.last) }
end

#sectionfile_fn_filter(xml) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 172

def sectionfile_fn_filter(xml)
  ids = sectionfile_fn_filter_prep(xml)
  xml.root.xpath(ns("./fmt-footnote-container/fmt-fn-body")).each do |f|
    ids.has_key?(f["id"]) or f.remove
  end
  seen = {}
  xml.root.xpath(ns("/fmt-footnote-container/fmt-fn-body"))
    .each_with_index do |fnbody, i|
      sectionfile_fn_filter_renumber(fnbody, i, ids, seen)
    end
  xml
end

#sectionfile_fn_filter_fn_renumber(fnbody, idx, ids, seen) ⇒ Object



200
201
202
203
204
205
206
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 200

def sectionfile_fn_filter_fn_renumber(fnbody, idx, ids, seen)
  ids[fnbody["id"]].each do |f|
    @isodoc_presxml.renumber_document_footnote(f, idx, seen)
    fnlabel = f.at(ns(FN_CAPTIONS)) and
      fnlabel.children = @isodoc_presxml.fn_ref_label(f)
  end
end

#sectionfile_fn_filter_fnbody_renumber(fnbody, _idx, ids) ⇒ Object



208
209
210
211
212
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 208

def sectionfile_fn_filter_fnbody_renumber(fnbody, _idx, ids)
  fnlabel = fnbody.at(ns(FN_CAPTIONS)) or return
  fnbody["reference"] = ids[fnbody["id"]].first["reference"]
  fnlabel.children = @isodoc_presxml.fn_body_label(fnbody)
end

#sectionfile_fn_filter_prep(xml) ⇒ Object

map fmt-fn-body/@id = fn/@target to fn



186
187
188
189
190
191
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 186

def sectionfile_fn_filter_prep(xml)
  xml.xpath(ns("//fn")).each_with_object({}) do |f, m|
    m[f["target"]] ||= []
    m[f["target"]] << f
  end
end

#sectionfile_fn_filter_renumber(fnbody, idx, ids, seen) ⇒ Object



195
196
197
198
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 195

def sectionfile_fn_filter_renumber(fnbody, idx, ids, seen)
  sectionfile_fn_filter_fn_renumber(fnbody, idx, ids, seen)
  sectionfile_fn_filter_fnbody_renumber(fnbody, idx, ids)
end

#sectionfile_insert(ins, chunks, parentnode) ⇒ Object



164
165
166
167
168
169
170
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 164

def sectionfile_insert(ins, chunks, parentnode)
  if parentnode
    ins.next = "<#{parentnode}/>"
    chunks.each { |c| ins.next.add_child(c.dup) }
  else chunks.each { |c| ins.next = c.dup }
  end
end

#sectionfile_review_filter(xml) ⇒ Object



224
225
226
227
228
229
230
231
232
233
234
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 224

def sectionfile_review_filter(xml)
  ids = sectionfile_review_filter_prep(xml)
  xml.root.xpath(ns("./review-container/fmt-review-body")).each do |f|
    ids.has_key?(f["id"]) or f.remove
  end
  xml.root.xpath(ns("./review-container/fmt-review-body"))
    .each_with_index do |fnbody, i|
      sectionfile_review_filter_renumber(fnbody, i, ids)
    end
  xml
end

#sectionfile_review_filter_prep(xml) ⇒ Object

map fmt-review-body/@id = fmt-review-start/end/@target to fmt-review-stary/end



216
217
218
219
220
221
222
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 216

def sectionfile_review_filter_prep(xml)
  xml.xpath(ns("//fmt-review-start | //fmt-review-end"))
    .each_with_object({}) do |f, m|
      m[f["target"]] ||= []
      m[f["target"]] << f
    end
end

#sectionfile_review_filter_renumber(fnbody, _idx, ids) ⇒ Object



236
237
238
239
240
241
242
243
244
245
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 236

def sectionfile_review_filter_renumber(fnbody, _idx, ids)
  ids[fnbody["id"]].each do |f|
    case f.name
    when "fmt-review-start"
      f.children = @isodoc_presxml.comment_bookmark_start_label(f)
    when "fmt-review-end"
      f.children = @isodoc_presxml.comment_bookmark_end_label(f)
    end
  end
end

#sectionsplitObject

Input XML is Semantic XML



37
38
39
40
41
42
43
44
45
46
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 37

def sectionsplit
  xml = sectionsplit_prep(File.read(@input_filename), @base, @dir)
  @key = Metanorma::Collection::XrefProcess::xref_preprocess(xml, @isodoc)
  empty = empty_doc(xml)
  empty1 = empty_attachments(empty)
  @mutex = Mutex.new
  # @pool = Concurrent::FixedThreadPool.new(4)
  @pool = Concurrent::FixedThreadPool.new(1)
  sectionsplit1(xml, empty, empty1, 0)
end

#sectionsplit1(xml, empty, empty1, idx) ⇒ Object

xml is Presentation XML



49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 49

def sectionsplit1(xml, empty, empty1, idx)
  ret = SPLITSECTIONS.each_with_object([]) do |n, m|
    conflate_floatingtitles(xml.xpath(ns(n[0]))).each do |s|
      sectionsplit2(xml, idx.zero? ? empty : empty1, s, n[1],
                    { acc: m, idx: idx })
      idx += 1
    end
  end
  @pool.shutdown
  @pool.wait_for_termination
  ret
end

#sectionsplit2(xml, empty, chunks, parentnode, opt) ⇒ Object



62
63
64
65
66
67
68
69
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 62

def sectionsplit2(xml, empty, chunks, parentnode, opt)
  @pool.post do
    warn "#{@base}.#{opt[:idx]}"
    a = sectionfile(xml, empty, "#{@base}.#{opt[:idx]}", chunks,
                    parentnode)
    @mutex.synchronize { opt[:acc] << a }
  end
end

#sectionsplit_prep(file, filename, dir) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 88

def sectionsplit_prep(file, filename, dir)
  @splitdir = dir
  xml, type = sectionsplit_preprocess_semxml(file, filename)
  flags = { format: :asciidoc, extension_keys: [:presentation],
            type: type }.merge(@compile_opts)
  Compile.new.compile(xml, flags)
  f = File.open(xml.sub(/\.xml$/, ".presentation.xml"), encoding: "utf-8")
  r = Nokogiri::XML(f, &:huge)
  f.close
  r.xpath("//xmlns:svgmap1").each { |x| x.name = "svgmap" }
  r
end

#sectionsplit_preprocess_semxml(file, filename) ⇒ Object



101
102
103
104
105
106
107
108
109
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 101

def sectionsplit_preprocess_semxml(file, filename)
  xml = Nokogiri::XML(file, &:huge)
  type = xml.root["flavor"]
  type ||= xml.root.name.sub("-standard", "").to_sym
  sectionsplit_update_xrefs(xml)
  xml1 = sectionsplit_write_semxml(filename, xml)
  @tmp_filename = xml1
  [xml1, type]
end

#sectionsplit_update_xrefs(xml) ⇒ Object



111
112
113
114
115
116
117
118
119
120
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 111

def sectionsplit_update_xrefs(xml)
  if c = @fileslookup&.parent
    n = c.nested
    c.nested = true # so unresolved erefs are not deleted
    c.update_xrefs(xml, @ident, {})
    c.nested = n
    xml.xpath("//xmlns:svgmap").each { |x| x.name = "svgmap1" }
    # do not process svgmap until after files are split
  end
end

#sectionsplit_write_semxml(filename, xml) ⇒ Object



122
123
124
125
126
127
128
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 122

def sectionsplit_write_semxml(filename, xml)
  outname = Pathname.new("tmp_#{filename}").sub_ext(".xml").to_s
  File.open(outname, "w:UTF-8") do |f|
    f.write(@isodoc.to_xml(xml))
  end
  outname
end

#titlerender(section) ⇒ Object



247
248
249
250
251
252
253
# File 'lib/metanorma/collection/sectionsplit/sectionsplit.rb', line 247

def titlerender(section)
  title = section.at(ns("./fmt-title")) or return "[Untitled]"
  t = title.dup
  t.xpath(ns(".//tab | .//br")).each { |x| x.replace(" ") }
  t.xpath(ns(".//bookmark")).each(&:remove)
  t.xpath(".//text()").map(&:text).join
end