module Metanorma
class Requirements
class Modspec < Default
def recommendation_label(elem, type, xrefs)
label = elem.at(ns("./identifier"))&.text
if inject_crossreference_reqt?(elem, label)
number = xrefs.anchor(reqtlabels(elem.document, label), :xref, false)
number.nil? ? type : number
else
type = recommendation_class_label(elem)
super
end
end
def reqtlabels(doc, label)
@reqtlabels ||= doc
.xpath(ns("//requirement | //recommendation | //permission"))
.each_with_object({}) do |r, m|
l = r.at(ns("./label"))&.text and m[l] = r["id"]
end
@reqtlabels[label]
end
# embedded reqts xref to top level reqts via label lookup
def inject_crossreference_reqt?(node, label)
!node.ancestors("requirement, recommendation, permission").empty? &&
reqtlabels(node.document, label)
end
def recommendation_class_label(node)
case node["type"]
when "verification" then @labels["#{node.name}test"]
when "class" then @labels["#{node.name}class"]
when "abstracttest" then @labels["abstracttest"]
when "conformanceclass" then @labels["conformanceclass"]
else
case node.name
when "recommendation" then @labels["recommendation"]
when "requirement" then @labels["requirement"]
when "permission" then @labels["permission"]
end
end
end
def reqt_ids(docxml)
docxml.xpath(ns("//requirement | //recommendation | //permission"))
.each_with_object({}) do |r, m|
id = r.at(ns("./identifier")) or next
m[id.text] = r["id"]
end
end
def reqt_links(docxml)
docxml.xpath(ns("//requirement | //recommendation | //permission"))
.each_with_object({}) do |r, m|
next unless %w(conformanceclass
verification).include?(r["type"])
subj = r.at(ns("./classification[tag = 'target']/value"))
id = r.at(ns("./identifier"))
next unless subj && id
m[subj.text] = { lbl: id.text, id: r["id"] }
end
end
def recommendation_link(docxml, ident)
@reqt_links ||= reqt_links(docxml)
test = @reqt_links[ident&.strip] or return nil
"#{test[:lbl]}"
end
def recommendation_id(docxml, ident)
@reqt_ids ||= reqt_ids(docxml)
test = @reqt_ids[ident&.strip] or return ident&.strip
"#{ident.strip}"
end
end
end
end