require "nokogiri"
require "twitter_cldr"
require_relative "render_contributors"
require_relative "render_dates"
module Iso690Render
def self.render(bib, embedded = false)
docxml = Nokogiri::XML(bib)
docxml.remove_namespaces!
parse(docxml.root, embedded)
end
def self.title(doc)
doc&.at("./title")&.text
end
def self.medium(doc)
doc&.at("./medium")&.text
end
def self.blank?(x)
x.nil? || x.empty?
end
=begin
def self.edition(doc)
x = doc.at("./edition")
return "" unless x
return x.text unless /^\d+$/.match x.text
x.text.to_i.localize.to_rbnf_s("SpelloutRules", "spellout-ordinal")
end
=end
def self.is_nist(doc)
publisher = doc&.at("./contributor[role/@type = 'publisher']/organization/name")&.text
abbr = doc&.at("./contributor[role/@type = 'publisher']/organization/abbreviation")&.text
publisher == "NIST" || abbr == "NIST" ||
publisher == "National Institute of Standards and Technology"
end
def self.placepub(doc)
place = doc&.at("./place")&.text
publisher = doc&.at("./contributor[role/@type = 'publisher']/organization/name")&.text
abbr = doc&.at("./contributor[role/@type = 'publisher']/organization/abbreviation")&.text
series = series_title(doc)
series == "NIST Federal Information Processing Standards" and
return "U.S. Department of Commerce, Washington, D.C."
is_nist(doc) and
return "National Institute of Standards and Technology, Gaithersburg, MD"
ret = ""
ret += place if place
ret += ": " if place && publisher
ret += publisher if publisher
ret
end
def self.series_title(doc)
s = doc.at("./series[@type = 'main']") || doc.at("./series[not(@type)]") || doc.at("./series")
s&.at("./title")&.text
end
def self.series(doc, type)
s = doc.at("./series[@type = 'main']") || doc.at("./series[not(@type)]") || doc.at("./series")
return "" unless s
f = s.at("./formattedref") and return f.text
t = s.at("./title")
a = s.at("./abbreviation")
n = s.at("./number")
p = s.at("./partnumber")
dn = doc.at("./docnumber")
rev = doc&.at(".//edition")&.text&.sub(/^Revision /, "")
ret = ""
if t
title = included(type) ? wrap(t.text, " ", "") : wrap(t.text, " ", "")
ret += title
ret += " (#{a.text.sub(/^NIST /, "")})" if a
end
if n || p
ret += " #{n.text}" if n
ret += ".#{p.text}" if p
elsif dn && is_nist(doc)
ret += " #{dn.text}"
ret += " Rev. #{rev}" if rev
end
ret
end
def self.standardidentifier(doc)
ret = []
doc.xpath("./docidentifier").each do |id|
next if %w(nist-mr nist-long metanorma rfc-anchor).include? id["type"]
ret << standardidentifier1(id)
end
ret.join(". ")
end
def self.standardidentifier1(id)
r = ""
r += "#{id['type']} " if id["type"] and !%w(ISO IEC NIST).include? id["type"]
r += id.text
r
end
def self.uri(doc)
uri = doc.at("./uri[@type = 'doi']") || doc.at("./uri[@type = 'uri']") || doc.at("./uri")
uri&.text
end
def self.accessLocation(doc)
s = doc.at("./accessLocation") or return ""
s.text
end
def self.included(type)
["article", "inbook", "incollection", "inproceedings"].include? type
end
def self.wrap(text, startdelim = " ", enddelim = ".")
return "" if blank?(text)
"#{startdelim}#{text}#{enddelim}"
end
def self.type(doc)
type = doc.at("./@type") and return type&.text
doc.at("./includedIn") and return "inbook"
"book"
end
def self.extent2(type, from, to)
ret = ""
case type
when "page" then type = to ? "pp." : "p."
when "volume" then type = to ? "Vols." : "Vol."
end
ret += "#{type} "
ret += from.text if from
ret += "–#{to.text}" if to
ret
end
def self.extent1(localities)
ret = []
localities.each do |l|
ret << extent2(l["type"] || "page", l.at("./referenceFrom"), l.at("./referenceTo"))
end
ret.join(", ")
end
def self.extent(localities)
ret = []
ret1 = ""
localities.each do |l|
if %w(localityStack).include? l.name
ret << ret1
ret1 = ""
ret << extent1(l.children)
else
ret1 += extent1([l])
end
end
ret << ret1
ret.reject { |c| c.empty? }.join("; ")
end
def self.draft(doc)
return nil unless is_nist(doc)
dr = doc&.at("./status/stage")&.text
iter = doc&.at("./status/iteration")&.text
return nil unless /^draft/.match(dr)
iterord = iter_ordinal(doc)
status = status_print(dr)
status = "#{iterord} #{status}" if iterord
status
end
def self.iter_ordinal(isoxml)
docstatus = isoxml.at(("./status/stage"))&.text
return nil unless docstatus == "draft-public"
iter = isoxml.at(("./status/iteration"))&.text || "1"
return "Initial" if iter == "1"
return "Final" if iter.downcase == "final"
iter.to_i.localize.to_rbnf_s("SpelloutRules", "spellout-ordinal").capitalize
end
def self.status_print(status)
case status
when "draft-internal" then "Internal Draft"
when "draft-wip" then "Work-in-Progress Draft"
when "draft-prelim" then "Preliminary Draft"
when "draft-public" then "Public Draft"
when "draft-approval" then "Approval Draft"
when "final" then "Final"
when "final-review" then "Under Review"
end
end
# converting bibitem to +
def self.parse(doc, embedded = false)
f = doc.at("./formattedref") and
return embedded ? f.children.to_xml : doc.to_xml
ret = ""
type = type(doc)
container = doc.at("./relation[@type='includedIn']")
if container && !date(doc) && date(container&.at("./bibitem"))
doc << ( container&.at("./bibitem/date[@type = 'issued' or @type = 'published' or "\
"@type = 'circulated']")&.remove )
end
dr = draft(doc)
cr = creatornames(doc)
# NIST has seen fit to completely change rendering based on the type of publication.
if series_title(doc) == "NIST Federal Information Processing Standards"
cr = "National Institute of Standards and Technology"
end
pub = placepub(doc)
ret += wrap(cr, "", "")
if dr
mdy = MMMddyyyy(date(doc)) and ret += wrap(mdy, " (", ")")
else
yr = year(date(doc)) and ret += wrap(yr, " (", ")")
end
ret += included(type) ? wrap(title(doc), " ", "") : wrap(title(doc), " ", "")
ret += wrap(medium(doc), " [", "]")
#ret += wrap(edition(doc), "", " edition.")
if cr != pub
ret += wrap(pub, " (", ")")
end
if cr != pub && pub && !pub.empty? && (dr || !blank?(series(doc, type)))
ret += ","
end
if dr
ret += " Draft (#{dr})"
end
ret += wrap(series(doc, type), " ", "")
ret += wrap(date(doc), ", ", "")
ret += wrap(standardidentifier(doc), ". ", "") unless is_nist(doc)
ret += wrap(uri(doc), ". ", "")
ret += wrap(accessLocation(doc), ". At: ", "")
if container
ret += wrap(parse(container.at("./bibitem"), true), ". In: ", "")
locality = doc.xpath("./extent")
ret += wrap(extent(locality), ", " , "")
else
ret += wrap(extent(doc.xpath("./extent")), ", ", "")
end
if !embedded
ret += "."
end
embedded ? ret : "#{ret}#{doc.xpath('./docidentifier').to_xml}"
end
end