require "yaml"
require_relative "util"
require_relative "sectionsplit_links"
module Metanorma
class Sectionsplit
attr_accessor :filecache
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
def ns(xpath)
@isodoc.ns(xpath)
end
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
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
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
def coll_cover
<<~COVER
{{ doctitle }}
{{ docnumber }}
COVER
end
SPLITSECTIONS =
[["//preface/*", "preface"], ["//sections/*", "sections"],
["//annex", nil],
["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
["//indexsect", nil], ["//colophon", nil]].freeze
# Input XML is Semantic
# def sectionsplit(filename, basename, dir, compile_options, fileslookup = nil, ident = nil)
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
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
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
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
def sectionsplit_preprocess_semxml(file, filename)
xml = Nokogiri::XML(file, &:huge)
type = xml.root.name.sub("-standard", "").to_sym
@fileslookup&.parent&.update_xrefs(xml, @ident, {})
xml1 = 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
@filecache ||= []
@filecache << xml1
[xml1.path, type]
end
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
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
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
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
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
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
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"
FileUtils.mv "#{ident}_collection/index.html", File.join(dir, filename)
FileUtils.rm_rf "#{ident}_collection"
filename
end
end
end