Class: Metanorma::Sectionsplit

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

Constant Summary collapse

SPLITSECTIONS =
[["//preface/*", "preface"], ["//sections/*", "sections"],
["//annex", nil],
["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
["//indexsect", nil], ["//colophon", nil]].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Sectionsplit

Returns a new instance of Sectionsplit.



9
10
11
12
13
14
15
16
17
18
19
# File 'lib/metanorma/sectionsplit.rb', line 9

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]
end

Instance Attribute Details

#filecacheObject

Returns the value of attribute filecache.



7
8
9
# File 'lib/metanorma/sectionsplit.rb', line 7

def filecache
  @filecache
end

#keyObject

Returns the value of attribute key.



7
8
9
# File 'lib/metanorma/sectionsplit.rb', line 7

def key
  @key
end

Instance Method Details

#block?(node) ⇒ Boolean

Returns:

  • (Boolean)


80
81
82
83
84
# File 'lib/metanorma/sectionsplit.rb', line 80

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

#build_collectionObject



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

def build_collection
  collection_setup(@base, @dir)
  files = sectionsplit # (@input_filename, @base, @dir, @compile_opts)
  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),
  )
end

#coll_coverObject



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

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

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



36
37
38
39
40
41
# File 'lib/metanorma/sectionsplit.rb', line 36

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



43
44
45
46
47
48
49
# File 'lib/metanorma/sectionsplit.rb', line 43

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



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/metanorma/sectionsplit.rb', line 178

def collectionyaml(files, 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
    },
  }
  Util::recursive_string_keys(ret).to_yaml
end

#conflate_floatingtitles(nodes) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/metanorma/sectionsplit.rb', line 86

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

#copy_repo_items_biblio(ins, section, xml) ⇒ Object



150
151
152
153
154
155
156
157
158
159
# File 'lib/metanorma/sectionsplit_links.rb', line 150

def copy_repo_items_biblio(ins, section, xml)
  bibitems = Util::gather_bibitems(section)
  xml.xpath(ns("//references/bibitem[docidentifier/@type = 'repository']"))
    .each_with_object([]) do |b, m|
      bibitems[b["id"]] or next
      # section.at("//*[@bibitemid = '#{b['id']}']") or next
      ins << b.dup
      m << b["id"]
    end
end

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



151
152
153
154
155
156
157
158
159
160
# File 'lib/metanorma/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)
  xref_process(out, xml, @key)
  outname = "#{file}.xml"
  File.open(File.join(@splitdir, outname), "w:UTF-8") do |f|
    f.write(out)
  end
  outname
end

#emptydoc(xml) ⇒ Object



135
136
137
138
139
140
141
142
143
# File 'lib/metanorma/sectionsplit.rb', line 135

def emptydoc(xml)
  out = xml.dup
  out.xpath(
    ns("//preface | //sections | //annex | //bibliography/clause | " \
       "//bibliography/references[not(@hidden = 'true')] | //indexsect | " \
       "//colophon"),
  ).each(&:remove)
  out
end

#eref_to_internal_eref(section, xml, key) ⇒ Object



93
94
95
96
97
98
99
100
101
102
# File 'lib/metanorma/sectionsplit_links.rb', line 93

def eref_to_internal_eref(section, xml, key)
  bibitems, bibitemids = eref_to_internal_eref_prep(section, xml)
  eref_to_internal_eref_select(section, xml, bibitems)
    .each_with_object([]) do |x, m|
      url = bibitems[x]&.at(ns("./uri[@type = 'citation']"))
      bibitemids[x]&.each do |e|
        id = eref_to_internal_eref1(e, key, url) and m << id
      end
    end
end

#eref_to_internal_eref1(elem, key, url) ⇒ Object



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

def eref_to_internal_eref1(elem, key, url)
  if url
    elem.name = "link"
    elem["target"] = url
    nil
  else
    elem["bibitemid"] = "#{key}_#{elem['bibitemid']}"
    elem << make_anchor(elem["bibitemid"])
    elem["type"] = key
    elem["bibitemid"]
  end
end

#eref_to_internal_eref_prep(section, xml) ⇒ Object



104
105
106
107
108
109
# File 'lib/metanorma/sectionsplit_links.rb', line 104

def eref_to_internal_eref_prep(section, xml)
  bibitems = Util::gather_bibitems(xml)
    .delete_if { |_, v| internal_bib?(v) }
  bibitemids = Util::gather_bibitemids(section)
  [bibitems, bibitemids]
end

#eref_to_internal_eref_select(section, _xml, bibitems) ⇒ Object



124
125
126
127
128
129
# File 'lib/metanorma/sectionsplit_links.rb', line 124

def eref_to_internal_eref_select(section, _xml, bibitems)
  refs = Util::gather_bibitemids(section).keys
  refs.uniq.reject do |x|
    b = bibitems[x] and ( indirect_bib?(b) || internal_bib?(b) )
  end
end

#indirect_bib?(bibitem) ⇒ Boolean

Returns:

  • (Boolean)


136
137
138
139
140
141
# File 'lib/metanorma/sectionsplit_links.rb', line 136

def indirect_bib?(bibitem)
  a = bibitem.at(ns("./docidentifier[@type = 'repository']")) or
    return false
  %r{^current-metanorma-collection/}.match?(a.text) and return false
  a.text.include?("/")
end

#insert_indirect_biblio(ins, refs, key, xml) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/metanorma/sectionsplit_links.rb', line 161

def insert_indirect_biblio(ins, refs, key, xml)
  refs.empty? and return
  internal_bibitems, external_bibitems = insert_indirect_biblio_prep(xml)
  refs.compact.reject do |x|
    #external_bibitems[x.sub(/^#{key}_/, "")]
  end.each do |x|
    ins << if b = internal_bibitems[x.sub(/^#{key}_/, "")]
             b.dup.tap { |m| m["id"] = x }
           else new_indirect_bibitem(x, key)
           end
  end
end

#insert_indirect_biblio_prep(xml) ⇒ Object



174
175
176
177
178
179
# File 'lib/metanorma/sectionsplit_links.rb', line 174

def insert_indirect_biblio_prep(xml)
  bibitems = Util::gather_bibitems(xml)
  internal_bibitems = bibitems.select { |_, v| internal_bib?(v) }
  external_bibitems = bibitems.reject { |_, v| internal_bib?(v) }
  [internal_bibitems, external_bibitems]
end

#internal_bib?(bibitem) ⇒ Boolean

Returns:

  • (Boolean)


131
132
133
134
# File 'lib/metanorma/sectionsplit_links.rb', line 131

def internal_bib?(bibitem)
  bibitem["type"] == "internal" ||
    bibitem.at(ns("./docidentifier[@type = 'repository']"))
end

#make_anchor(anchor) ⇒ Object



49
50
51
52
# File 'lib/metanorma/sectionsplit_links.rb', line 49

def make_anchor(anchor)
  "<localityStack><locality type='anchor'><referenceFrom>" \
    "#{anchor}</referenceFrom></locality></localityStack>"
end

#new_hidden_ref(xmldoc) ⇒ Object

from standoc



144
145
146
147
148
# File 'lib/metanorma/sectionsplit_links.rb', line 144

def new_hidden_ref(xmldoc)
  ins = xmldoc.at("bibliography") or
    xmldoc.root << "<bibliography/>" and ins = xmldoc.at("bibliography")
  ins.add_child("<references hidden='true' normative='false'/>").first
end

#new_indirect_bibitem(ident, prefix) ⇒ Object



181
182
183
184
185
186
187
# File 'lib/metanorma/sectionsplit_links.rb', line 181

def new_indirect_bibitem(ident, prefix)
  <<~BIBENTRY
    <bibitem id="#{ident}" type="internal">
    <docidentifier type="repository">#{ident.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
    </bibitem>
  BIBENTRY
end

#ns(xpath) ⇒ Object



21
22
23
# File 'lib/metanorma/sectionsplit.rb', line 21

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

#section_split_cover(col, ident, one_doc_coll) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/metanorma/sectionsplit.rb', line 202

def section_split_cover(col, ident, one_doc_coll)
  dir = File.dirname(col.file)
  collection_setup(nil, dir)
  CollectionRenderer.new(col, dir,
                         output_folder: "#{ident}_collection",
                         format: %i(html),
                         coverpage: File.join(dir, "cover.html")).coverpage
  #filename = one_doc_coll ? "#{ident}_index.html" : "index.html"
  filename = "#{ident}_index.html"
  FileUtils.mv "#{ident}_collection/index.html", File.join(dir, filename)
  FileUtils.rm_rf "#{ident}_collection"
  filename
end

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



145
146
147
148
149
# File 'lib/metanorma/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_insert(ins, chunks, parentnode) ⇒ Object



162
163
164
165
166
167
168
# File 'lib/metanorma/sectionsplit.rb', line 162

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

#sectionsplitObject

Input XML is Semantic def sectionsplit(filename, basename, dir, compile_options, fileslookup = nil, ident = nil)



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

def sectionsplit
  xml = sectionsplit_prep(File.read(@input_filename), @base, @dir)
  @key = xref_preprocess(xml, @fileslookup, @ident)
  SPLITSECTIONS.each_with_object([]) do |n, ret|
    conflate_floatingtitles(xml.xpath(ns(n[0]))).each do |s|
      ret << sectionfile(xml, emptydoc(xml), "#{@base}.#{ret.size}", s,
                         n[1])
    end
  end
end

#sectionsplit_prep(file, filename, dir) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/metanorma/sectionsplit.rb', line 96

def sectionsplit_prep(file, filename, dir)
  @splitdir = dir
  xml1filename, type = sectionsplit_preprocess_semxml(file, filename)
  Compile.new.compile(
    xml1filename,
    { format: :asciidoc, extension_keys: [:presentation], type: type }
   .merge(@compile_opts),
  )
  Nokogiri::XML(File.read(xml1filename.sub(/\.xml$/, ".presentation.xml"),
                          encoding: "utf-8"), &:huge)
end

#sectionsplit_preprocess_semxml(file, filename) ⇒ Object



108
109
110
111
112
113
114
115
116
# File 'lib/metanorma/sectionsplit.rb', line 108

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

#sectionsplit_update_xrefs(xml) ⇒ Object



118
119
120
121
122
123
124
125
# File 'lib/metanorma/sectionsplit.rb', line 118

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
  end
end

#sectionsplit_write_semxml(filename, xml) ⇒ Object



127
128
129
130
131
132
133
# File 'lib/metanorma/sectionsplit.rb', line 127

def sectionsplit_write_semxml(filename, xml)
  Tempfile.open([filename, ".xml"], encoding: "utf-8") do |f|
    # f.write(@isodoc.to_xml(svg_preprocess(xml)))
    f.write(@isodoc.to_xml(xml))
    f
  end
end

#svg_preprocess(xml, doc_suffix) ⇒ Object



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

def svg_preprocess(xml, doc_suffix)
  suffix = doc_suffix.nil? || doc_suffix.blank? ? "" : "_#{doc_suffix}"
  xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
    m = svgmap_wrap(s)
    svg_xrefs(s, m, suffix)
  end
  xml
end

#svg_xrefs(svg, svgmap, suffix) ⇒ Object



40
41
42
43
44
45
46
47
# File 'lib/metanorma/sectionsplit_links.rb', line 40

def svg_xrefs(svg, svgmap, suffix)
  svg.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
    /^#/.match? a["href"] or next
    a["href"] = a["href"].sub(/^#/, "")
    svgmap << "<target href='#{a['href']}'>" \
              "<xref target='#{a['href']}#{suffix}'/></target>"
  end
end

#svgmap_wrap(svg) ⇒ Object



33
34
35
36
37
38
# File 'lib/metanorma/sectionsplit_links.rb', line 33

def svgmap_wrap(svg)
  ret = svg.at("./ancestor::xmlns:svgmap") and return ret
  ret = svg.at("./ancestor::xmlns:figure")
  ret.wrap("<svgmap/>")
  svg.at("./ancestor::xmlns:svgmap")
end

#titlerender(section) ⇒ Object



170
171
172
173
174
175
176
# File 'lib/metanorma/sectionsplit.rb', line 170

def titlerender(section)
  title = section.at(ns("./title")) or return "[Untitled]"
  t = title.dup
  t.xpath(ns(".//tab | .//br")).each { |x| x.replace(" ") }
  t.xpath(ns(".//strong")).each { |x| x.replace(x.children) }
  t.children.to_xml
end

#xref_prefix_key(xref, key, indirect) ⇒ Object



83
84
85
86
87
88
89
90
91
# File 'lib/metanorma/sectionsplit_links.rb', line 83

def xref_prefix_key(xref, key, indirect)
  if b = indirect[xref["target"]]
    t = b.at(ns("./docidentifier[@type = 'repository']"))
    xref["type"] = t.text.sub(%r{/.*$}, "")
  else
    xref["target"] = "#{key}_#{xref['target']}"
    xref["type"] = key
  end
end

#xref_preprocess(xml, _fileslookup, _identifier) ⇒ Object



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

def xref_preprocess(xml, _fileslookup, _identifier)
  key = (0...8).map { rand(65..90).chr }.join # random string
  xml.root["type"] = key # to force recognition of internal refs
  # bookmarks etc as new id elements introduced in Presentation XML:
  # add doc suffix
  Metanorma::Utils::anchor_attributes.each do |(tag_name, attribute_name)|
    Util::add_suffix_to_attributes(xml, xml.root["document_suffix"],
                                   tag_name, attribute_name, @isodoc)
  end
  key
end

#xref_process(section, xml, key) ⇒ Object



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

def xref_process(section, xml, key)
  svg_preprocess(section, Metanorma::Utils::to_ncname(@ident))
  refs = eref_to_internal_eref(section, xml, key)
  refs += xref_to_internal_eref(section, xml, key)
  ins = new_hidden_ref(section)
  copied_refs = copy_repo_items_biblio(ins, section, xml)
  insert_indirect_biblio(ins, refs - copied_refs, key, xml)
end

#xref_to_internal_eref(section, xml, key) ⇒ Object



54
55
56
57
58
59
60
61
62
# File 'lib/metanorma/sectionsplit_links.rb', line 54

def xref_to_internal_eref(section, xml, key)
  bibitems, indirect = xref_to_internal_eref_prep(section, xml)
  section.xpath(ns("//xref")).each_with_object({}) do |x, m|
    xref_prefix_key(x, key, indirect)
    x["bibitemid"] = x["target"]
    m[x["bibitemid"]] = true
    xref_to_internal_eref_anchor(x, key, bibitems, xml.root["document_suffix"])
  end.keys
end

#xref_to_internal_eref_anchor(xref, key, bibitems, document_suffix) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
# File 'lib/metanorma/sectionsplit_links.rb', line 71

def xref_to_internal_eref_anchor(xref, key, bibitems, document_suffix)
  t = xref["target"]
  if d = bibitems[t]&.at(ns("./docidentifier[@type = 'repository']"))
    m = %r{^([^/]+)}.match(d.text) and
      t.sub!(%r(#{m[0]}_), "")
  end
  t.sub!(%r{^#{key}_}, "")
  xref << make_anchor(t.sub(%r(_#{document_suffix}$), ""))
  xref.delete("target")
  xref.name = "eref"
end

#xref_to_internal_eref_prep(section, xml) ⇒ Object



64
65
66
67
68
69
# File 'lib/metanorma/sectionsplit_links.rb', line 64

def xref_to_internal_eref_prep(section, xml)
  bibitems = Util::gather_bibitems(section)
  indirect_bibitems = Util::gather_bibitems(xml)
    .select { |_, v| indirect_bib?(v) }
  [bibitems, indirect_bibitems]
end