require"metanorma/standoc/utils"require_relative"./validate_section"require_relative"./validate_table"require"nokogiri"require"jing"require"iev"require"pngcheck"require"png"moduleMetanormamoduleStandocmoduleValidateSOURCELOCALITY="./origin//locality[@type = 'clause']/"\"referenceFrom".freezedefinit_ievreturnnilif@no_isobibreturn@ievif@iev@iev=Iev::Db.new(@iev_globalname,@iev_localname)unless@no_isobib@ievenddefiev_validate(xmldoc)@iev=init_ievorreturnxmldoc.xpath("//term").eachdo|t|t.xpath(".//termsource").eachdo|src|(/^IEC 60050-/.match(src&.at("./origin/@citeas")&.text)&&loc=src.xpath(SOURCELOCALITY)&.text)ornextiev_validate1(t,loc,xmldoc)endendenddefiev_validate1(term,loc,xmldoc)iev=@iev.fetch(loc,xmldoc&.at("//language")&.text||"en")orreturnpref=term.xpath("./preferred//name").inject([])do|m,x|m<<x&.text&.downcaseendpref.include?(iev.downcase)or@log.add("Bibliography",term,%(Term "#{pref[0]}" does not match )+%(IEV #{loc} "#{iev}"))enddefcontent_validate(doc)@fatalerror=[]xref_validate(doc)section_validate(doc)norm_ref_validate(doc)repeat_id_validate(doc.root)iev_validate(doc.root)concept_validate(doc,"concept","refterm")concept_validate(doc,"related","preferred//name")table_validate(doc)requirement_validate(doc)image_validate(doc)@fatalerror.empty?orclean_abort(@fatalerror.join("\n"),doc)enddefnorm_ref_validate(doc)found=falsedoc.xpath("//references[@normative = 'true']/bibitem").eachdo|b|nextunlessdocid=b.at("./docidentifier[@type = 'metanorma']")nextunless/^\[\d+\]$/.match?(docid.text)@log.add("Bibliography",b,"Numeric reference in normative references")found=trueendfoundand@fatalerror<<"Numeric reference in normative references"enddefconcept_validate(doc,tag,refterm)found=falsedoc.xpath("//#{tag}/xref").eachdo|x|nextifdoc.at("//term[@id = '#{x['target']}']")nextifdoc.at("//definitions//dt[@id = '#{x['target']}']")@log.add("Anchors",x,"#{tag.capitalize}#{x&.at("../#{refterm}")&.text} is "\"pointing to #{x['target']}, which is not a term or symbol")found=trueendfoundand@fatalerror<<"#{tag.capitalize} not cross-referencing term or symbol"enddefrepeat_id_validate1(ids,elem)ifids[elem["id"]]@log.add("Anchors",elem,"Anchor #{elem['id']} has already been "\"used at line #{ids[elem['id']]}")@fatalerror<<"Multiple instances of same ID: #{elem['id']}"elseids[elem["id"]]=elem.lineendidsenddefrepeat_id_validate(doc)ids={}doc.xpath("//*[@id]").eachdo|x|ids=repeat_id_validate1(ids,x)endenddefschema_validate(doc,schema)Tempfile.open(["tmp",".xml"],encoding: "UTF-8")do|f|schema_validate1(f,doc,schema)rescueJing::Error=>eclean_abort("Jing failed with error: #{e}",doc)ensuref.close!endenddefschema_validate1(file,doc,schema)file.write(doc.to_xml)file.closeerrors=Jing.new(schema,encoding: "UTF-8").validate(file.path)warn"Syntax Valid!"iferrors.none?errors.eachdo|e|@log.add("Metanorma XML Syntax","XML Line #{'%06d'%e[:line]}:#{e[:column]}",e[:message])endendSVG_NS="http://www.w3.org/2000/svg".freezeWILDCARD_ATTRS="//*[@format] | //stem | //bibdata//description | "\"//formattedref | //bibdata//note | //bibdata/abstract | "\"//bibitem/abstract | //bibitem/note | //misc-container".freeze# 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.defformattedstr_strip(doc)doc.xpath(WILDCARD_ATTRS,"m"=>SVG_NS).eachdo|n|n.elements.eachdo|e|e.traversedo|e1|e1.element?ande1.each{|k,_v|e1.delete(k)}endendenddoc.xpath("//m:svg","m"=>SVG_NS).each{|n|n.replace("<svg/>")}docend# manually check for xref/@target, xref/@to integritydefxref_validate(doc)ids=doc.xpath("//*/@id").each_with_object({}){|x,m|m[x.text]=1}doc.xpath("//xref/@target | //xref/@to").eachdo|x|nextifids[x.text]@log.add("Anchors",x.parent,"Crossreference target #{x.text} is undefined")endenddefimage_validate(doc)doc.xpath("//image[@mimetype = 'image/png']").eachdo|i|d=Metanorma::Utils::datauri(i["src"],@localdir)# d.chars.to_a.each_slice(80).to_a.map { |s| s.join }.each { |s| warn s }png_validate1(i,Base64.strict_decode64(d.sub(/^.+?base64,/,"")))endenddefpng_validate1(img,buffer)PngCheck.check_buffer(buffer)rescuePngCheck::CorruptPngError=>e@log.add("Images",img.parent,"Corrupt PNG image")@fatalerror<<"Exception #{e.message}"enddefvalidate(doc)content_validate(doc)schema_validate(formattedstr_strip(doc.dup),File.join(File.dirname(__FILE__),"isodoc.rng"))endendendend