require "metanorma" require "yaml" module IsoDoc::HtmlFunction module Html # assume we pass in Presentation XML, but we want to recover Semantic XML def sectionsplit_convert(input_filename, file, debug, output_filename = nil) input_filename += ".xml" unless input_filename.match?(/\.xml$/) File.exist?(input_filename) or File.open(input_filename, "w:UTF-8") { |f| f.write(file) } presxml = File.read(input_filename, encoding: "utf-8") @openmathdelim, @closemathdelim = extract_delims(presxml) xml, filename, dir = convert_init(presxml, input_filename, debug) build_collection(xml, presxml, output_filename || filename, dir) end def build_collection(xml, presxml, filename, dir) base = File.basename(filename) collection_setup(base, dir) files = sectionsplit(xml, base, dir) collection_manifest(base, files, xml, presxml, dir).render( format: %i(html), output_folder: "#{filename}_collection", coverpage: File.join(dir, "cover.html") ) 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" 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 <html> <head/> <body> <h1>{{ doctitle }}</h1> <h2>{{ docnumber }}</h2> <nav>{{ labels["navigation"] }}</nav> </body> </html> COVER end def sectionsplit(xml, filename, dir) xref_preprocess(xml) out = emptydoc(xml) [["//preface/*", "preface"], ["//sections/*", "sections"], ["//annex", nil], ["//bibliography/*[not(@hidden = 'true')]", "bibliography"], ["//indexsect", nil]].each_with_object([]) do |n, ret| xml.xpath(ns(n[0])).each do |s| ret << sectionfile(out, dir, "#{filename}.#{ret.size}", s, n[1]) end end end def emptydoc(xml) out = xml.dup out.xpath( ns("//preface | //sections | //annex | //bibliography/clause | "\ "//bibliography/references[not(@hidden = 'true')] | //indexsect"), ).each(&:remove) out end def sectionfile(xml, dir, file, chunk, parentnode) fname = create_sectionfile(xml.dup, dir, file, chunk, parentnode) { order: chunk["displayorder"].to_i, url: fname, title: titlerender(chunk) } end def create_sectionfile(out, dir, file, chunk, parentnode) ins = out.at(ns("//misccontainer")) || out.at(ns("//bibdata")) if parentnode ins.next = "<#{parentnode}/>" ins.next.add_child(chunk.dup) else ins.next = chunk.dup end outname = "#{file}.xml" File.open(File.join(dir, outname), "w:UTF-8") { |f| f.write(out) } outname end def xref_preprocess(xml) svg_preprocess(xml) key = (0...8).map { rand(65..90).chr }.join # random string refs = eref_to_internal_eref(xml, key) refs += xref_to_internal_eref(xml, key) xml.root["type"] = key # to force recognition of internal refs ins = new_hidden_ref(xml) copy_repo_items_biblio(ins, xml) insert_indirect_biblio(ins, refs, key) end def svg_preprocess(xml) xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s| m = svgmap_wrap(s) s.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a| next unless /^#/.match? a["href"] a["href"] = a["href"].sub(/^#/, "") m << "<target href='#{a['href']}'>"\ "<xref target='#{a['href']}'/></target>" end end end 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 def make_anchor(anchor) "<localityStack><locality type='anchor'><referenceFrom>"\ "#{anchor}</referenceFrom></locality></localityStack>" end def xref_to_internal_eref(xml, key) xml.xpath(ns("//xref")).each_with_object({}) do |x, m| x["bibitemid"] = "#{key}_#{x['target']}" x << make_anchor(x["target"]) m[x["bibitemid"]] = true x.delete("target") x["type"] = key x.name = "eref" end.keys end def eref_to_internal_eref(xml, key) eref_to_internal_eref_select(xml).each_with_object([]) do |x, m| url = xml.at(ns("//bibitem[@id = '#{x}']/url[@type = 'citation']")) xml.xpath(("//*[@bibitemid = '#{x}']")).each do |e| id = eref_to_internal_eref1(e, key, url) id and m << id end end end 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 def eref_to_internal_eref_select(xml) refs = xml.xpath(("//*/@bibitemid")).map { |x| x.text } # rubocop:disable Style/SymbolProc refs.uniq.reject do |x| xml.at(ns("//bibitem[@id = '#{x}'][@type = 'internal']")) || xml.at(ns("//bibitem[@id = '#{x}']"\ "[docidentifier/@type = 'repository']")) end end # from standoc 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 def copy_repo_items_biblio(ins, xml) xml.xpath(ns("//references/bibitem[docidentifier/@type = 'repository']")) .each do |b| ins << b.dup end end def insert_indirect_biblio(ins, refs, prefix) refs.each do |x| ins << <<~BIBENTRY <bibitem id="#{x}" type="internal"> <docidentifier type="repository">#{x.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier> </bibitem> BIBENTRY end end def recursive_string_keys(hash) case hash when Hash then Hash[ hash.map { |k, v| [k.to_s, recursive_string_keys(v)] } ] when Enumerable then hash.map { |v| recursive_string_keys(v) } else hash 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, }, } recursive_string_keys(ret).to_yaml end end end