require "asciidoctor/standoc/utils" require_relative "./validate_section.rb" require "nokogiri" require "jing" require "iev" module Asciidoctor module Standoc module Validate SOURCELOCALITY = "./termsource/origin//locality[@type = 'clause']/"\ "referenceFrom".freeze def init_iev return nil if @no_isobib return @iev if @iev @iev = Iev::Db.new(@iev_globalname, @iev_localname) unless @no_isobib @iev end def iev_validate(xmldoc) xmldoc.xpath("//term").each do |t| /^IEC 60050-/.match(t&.at("./termsource/origin/@citeas")&.text) && loc = t.xpath(SOURCELOCALITY)&.text or next @iev = init_iev or return iev = @iev.fetch(loc, xmldoc&.at("//language")&.text || "en") or next pref = t.xpath("./preferred").inject([]) do |m, x| m << x&.text&.downcase end pref.include?(iev.downcase) or @log.add("Bibliography", t, %(Term "#{pref[0]}" does not match ) + %(IEV #{loc} "#{iev}")) end end def content_validate(doc) section_validate(doc) norm_ref_validate(doc) repeat_id_validate(doc.root) iev_validate(doc.root) end def norm_ref_validate(doc) found = false doc.xpath("//references[@normative = 'true']/bibitem").each do |b| next unless docid = b.at("./docidentifier[@type = 'metanorma']") next unless /^\[\d+\]$/.match(docid.text) @log.add("Bibliography", b, "Numeric reference in normative references") found = true end if found clean_exit abort("Numeric reference in normative references") end end def repeat_id_validate1(ids, x) if ids[x["id"]] @log.add("Anchors", x, "Anchor #{x['id']} has already been used "\ "at line #{ids[x['id']]}") raise StandardError.new "Error: multiple instances of same ID" else ids[x["id"]] = x.line end ids end def repeat_id_validate(doc) ids = {} begin doc.xpath("//*[@id]").each do |x| ids = repeat_id_validate1(ids, x) end rescue StandardError => e clean_exit abort(e.message) end end def schema_validate(doc, schema) Tempfile.open(["tmp", ".xml"], :encoding => 'UTF-8') do |f| begin f.write(doc.to_xml) f.close errors = Jing.new(schema).validate(f.path) warn "Syntax Valid!" if errors.none? errors.each do |e| @log.add("Metanorma XML Syntax", "XML Line #{"%06d" % e[:line]}:#{e[:column]}", e[:message]) end rescue Jing::Error => e clean_exit abort "Jing failed with error: #{e}" ensure f.close! end end end # RelaxNG cannot cope well with wildcard attributes. So we strip # any attributes from FormattedString instances (which can contain # xs:any markup, and are signalled with @format) before validation. def formattedstr_strip(doc) doc.xpath("//*[@format] | //stem | //bibdata//description | "\ "//formattedref | //bibdata//note | //bibdata/abstract | "\ "//bibitem/abstract | //bibitem/note | //misc-container").each do |n| n.elements.each do |e| e.traverse do |e1| e1.element? and e1.each { |k, _v| e1.delete(k) } end end end doc end def validate(doc) content_validate(doc) schema_validate(formattedstr_strip(doc.dup), File.join(File.dirname(__FILE__), "isodoc.rng")) end end end end