require "metanorma-utils" module IsoDoc module Function module Utils def to_xml(node) self.class.to_xml(node) end def date_range(date) self.class.date_range(date) end def ns(xpath) self.class.ns(xpath) end def start_of_sentence(node) self.class.start_of_sentence(node) end def insert_tab(out, count) tab = %w(Hans Hant).include?(@script) ? " " : "  " [1..count].each { out << tab } end def noko(&block) Metanorma::Utils::noko_html(&block) end def attr_code(attributes) attributes.compact.transform_values do |v| v.is_a?(String) ? HTMLEntities.new.decode(v) : v end end DOCTYPE_HDR = "'.freeze HUGESTRICT = Nokogiri::XML::ParseOptions::HUGE | Nokogiri::XML::ParseOptions::STRICT def to_xhtml(xml) xml = to_xhtml_prep(xml) begin Nokogiri::XML.parse(xml, nil, nil, HUGESTRICT) rescue Nokogiri::XML::SyntaxError => e File.open("#{@filename}.#{@format}.err", "w:UTF-8") do |f| f.write xml end abort "Malformed Output XML for #{@format}: #{e} " \ "(see #{@filename}.#{@format}.err)" end end def numeric_escapes(xml) Metanorma::Utils::numeric_escapes(xml) end def to_xhtml_prep(xml) xml.gsub!(/<\?xml[^>]*>/, "") xml.include?("}, " ") .gsub(%r{]+)?>}, "") .gsub(/<\/?h[123456][^>]*>/, "").gsub(/<\/?b[^>]*>/, "").dup) h1.traverse do |x| if x.name == "span" && x["style"]&.include?("mso-tab-count") x.replace(" ") elsif header_strip_elem?(x) then x.remove elsif x.name == "a" then x.replace(x.children) end end from_xhtml(h1) end def header_strip_elem?(elem) elem.name == "img" || (elem.name == "span" && elem["class"] == "MsoCommentReference") || (elem.name == "a" && elem["class"] == "FootnoteRef") || (elem.name == "span" && elem["style"]&.include?("mso-bookmark")) end def liquid(doc) # unescape HTML escapes in doc doc = doc.split(%r<(\{%|%\})>).each_slice(4).map do |a| a[2] = a[2].gsub(/</, "<").gsub(/>/, ">") if a.size > 2 a.join end.join Liquid::Template.parse(doc) end def empty2nil(str) !str.nil? && str.is_a?(String) && str.empty? and return nil str end def populate_template(docxml, _format = nil) meta = @meta .get .merge(@labels ? { labels: @labels } : {}) .merge(@meta.labels ? { labels: @meta.labels } : {}) .merge(fonts_options || {}) template = liquid(docxml) template.render(meta.map { |k, v| [k.to_s, empty2nil(v)] }.to_h) .gsub("<", "<").gsub(">", ">").gsub("&", "&") end def save_dataimage(uri, _relative_dir = true) %r{^data:(?image|application)/(?[^;]+);(?:charset=[^;]+;)?base64,(?.+)$} =~ uri imgtype = "emf" if emf?("#{imgclass}/#{imgtype}") imgtype = imgtype.sub(/\+[a-z0-9]+$/, "") # svg+xml imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype Tempfile.open(["image", ".#{imgtype}"]) do |f| f.binmode f.write(Base64.strict_decode64(imgdata)) @tempfile_cache << f # persist to the end f.path end end def save_svg(img) Tempfile.open(["image", ".svg"]) do |f| f.write(img.to_xml) @tempfile_cache << f # persist to the end f.path end end def image_localfile(img) img.name == "svg" && !img["src"] and return save_svg(img) case img["src"] when /^data:/ then save_dataimage(img["src"], false) when %r{^([A-Z]:)?/} then img["src"] else File.join(@localdir, img["src"]) end end LABELLED_ANCESTOR_ELEMENTS = %w(example requirement recommendation permission note table figure sourcecode).freeze def labelled_ancestor(elem) #require "debug"; binding.b #!elem.path.gsub(/\[\d+\]/, "").split(%r{/})[1..-1] !elem.ancestors.map(&:name) .intersection(LABELLED_ANCESTOR_ELEMENTS).empty? end def emf?(type) %w(application/emf application/x-emf image/x-emf image/x-mgx-emf application/x-msmetafile image/x-xbitmap image/emf).include? type end def eps?(type) %w(application/postscript image/x-eps).include? type end def cleanup_entities(text, is_xml: true) c = HTMLEntities.new if is_xml text.split(/([<>])/).each_slice(4).map do |a| a[0] = c.encode(c.decode(a[0]), :hexadecimal) a end.join else c.encode(c.decode(text), :hexadecimal) end end def external_path(path) win = !!((RUBY_PLATFORM =~ /(win|w)(32|64)$/) || (RUBY_PLATFORM =~ /mswin|mingw/)) if win path.gsub!(%{/}, "\\") path[/\s/] ? "\"#{path}\"" : path else path end end end end end