Module: Metanorma::Standoc::Ref

Included in:
Cleanup
Defined in:
lib/metanorma/cleanup/ref.rb

Constant Summary collapse

BIBLIO_PUBLISHER_ORG =
"./contributor[role/@type = 'publisher']/organization".freeze

Instance Method Summary collapse

Instance Method Details

#biblio_annex(xmldoc) ⇒ Object



170
171
172
173
174
175
176
177
# File 'lib/metanorma/cleanup/ref.rb', line 170

def biblio_annex(xmldoc)
  xmldoc.xpath("//annex[references/references]").each do |t|
    t.xpath("./clause | ./references | ./terms").size == 1 or next
    r = t.at("./references")
    r.xpath("./references").each { |b| b["normative"] = r["normative"] }
    r.replace(r.elements)
  end
end

#biblio_cleanup(xmldoc) ⇒ Object



140
141
142
143
144
145
146
147
148
# File 'lib/metanorma/cleanup/ref.rb', line 140

def biblio_cleanup(xmldoc)
  biblio_reorder(xmldoc)
  biblio_annex(xmldoc)
  biblio_nested(xmldoc)
  biblio_renumber(xmldoc)
  biblio_linkonly(xmldoc)
  biblio_hidden_inherit(xmldoc)
  biblio_no_ext(xmldoc)
end

#biblio_linkonly(xmldoc) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
# File 'lib/metanorma/cleanup/ref.rb', line 150

def biblio_linkonly(xmldoc)
  xmldoc.at("//xref[@hidden]") or return
  ins = xmldoc.at("//bibliography")
    .add_child("<references hidden='true' normative='true'/>").first
  refs = xmldoc.xpath("//xref[@hidden]").each_with_object([]) do |x, m|
    @refids << x["target"]
    m << { id: x["target"], ref: x["hidden"] }
    x.delete("hidden")
  end
  ins << insert_hidden_bibitems(refs)
end

#biblio_nested(xmldoc) ⇒ Object



179
180
181
182
# File 'lib/metanorma/cleanup/ref.rb', line 179

def biblio_nested(xmldoc)
  biblio_nested_initial_items(xmldoc)
  biblio_nested_sections(xmldoc)
end

#biblio_nested_initial_items(xmldoc) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
# File 'lib/metanorma/cleanup/ref.rb', line 184

def biblio_nested_initial_items(xmldoc)
  xmldoc.xpath("//references[references][bibitem]").each do |t|
    r = t.at("./references")
    ref = t.at("./bibitem")
      .before("<references unnumbered='true'></references>").previous
    (ref.xpath("./following-sibling::*") &
     r.xpath("./preceding-sibling::*")).each do |x|
      ref << x
    end
  end
end

#biblio_nested_sections(xmldoc) ⇒ Object



196
197
198
199
200
201
202
# File 'lib/metanorma/cleanup/ref.rb', line 196

def biblio_nested_sections(xmldoc)
  xmldoc.xpath("//references[references]").each do |t|
    t.name = "clause"
    t.xpath("./references").each { |r| r["normative"] = t["normative"] }
    t.delete("normative")
  end
end

#biblio_renumber(xmldoc) ⇒ Object

default presuppose that all citations in biblio numbered consecutively, but that standards codes are preserved as is: only numeric references are renumbered



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/metanorma/cleanup/ref.rb', line 111

def biblio_renumber(xmldoc)
  i = 0
  xmldoc.xpath("//references[not(@normative = 'true')]" \
               "[not(@hidden = 'true')]").each do |r|
    r.xpath("./bibitem[not(@hidden = 'true')]").each do |b|
      i += 1
      docid = b.at("./docidentifier[@type = 'metanorma']") or next
      /^\[\d+\]$/.match?(docid.text) or next
      docid.children = "[#{i}]"
    end
  end
end

#biblio_reorder(xmldoc) ⇒ Object



9
10
11
12
13
# File 'lib/metanorma/cleanup/ref.rb', line 9

def biblio_reorder(xmldoc)
  xmldoc.xpath("//references[@normative = 'false']").each do |r|
    biblio_reorder1(r)
  end
end

#biblio_reorder1(refs) ⇒ Object



15
16
17
18
19
20
21
22
# File 'lib/metanorma/cleanup/ref.rb', line 15

def biblio_reorder1(refs)
  fold_notes_into_biblio(refs)
  bib = refs.xpath("./bibitem")
  @sort_biblio and bib = sort_biblio(bib)
  insert_sorted_bibitems(refs, bib)
  extract_notes_from_biblio(refs)
  refs.xpath("./references").each { |r| biblio_reorder1(r) }
end

#biblio_standards_ref?(bib) ⇒ Boolean

Whether a bibitem is a standards reference (sorts after the ranked publishers, before non-standard references). Base definition: it has a typed, non-DOI/ISSN/ISBN docidentifier. Flavours may widen this (ISO also treats an untyped docidentifier as a standards reference).

Returns:

  • (Boolean)


103
104
105
106
# File 'lib/metanorma/cleanup/ref.rb', line 103

def biblio_standards_ref?(bib)
  !!bib.at("./docidentifier[@type][not(#{@conv.skip_docid} or " \
           "@type = 'metanorma')]")
end

#insert_hidden_bibitems(bib) ⇒ Object



162
163
164
165
166
167
168
# File 'lib/metanorma/cleanup/ref.rb', line 162

def insert_hidden_bibitems(bib)
  refs = bib.each_with_object([]) do |b, m|
    m << @conv
      .reference1code(%(<ref id="#{b[:id]}">[#{b[:ref]}]</ref>), nil)
  end
  @conv.reference_populate(refs)
end

#insert_sorted_bibitems(refs, bib) ⇒ Object



24
25
26
27
28
29
30
31
# File 'lib/metanorma/cleanup/ref.rb', line 24

def insert_sorted_bibitems(refs, bib)
  insert = refs.at("./bibitem")&.previous_element
  refs.xpath("./bibitem").each(&:remove)
  bib.reverse_each do |b|
    (insert and insert.next = b.to_xml) or
      refs.children.first.add_previous_sibling b.to_xml
  end
end

#normref_cleanup(xmldoc) ⇒ Object



132
133
134
135
136
137
138
# File 'lib/metanorma/cleanup/ref.rb', line 132

def normref_cleanup(xmldoc)
  r = xmldoc.at(self.class::NORM_REF) || return
  preface = ((r.xpath("./title/following-sibling::*") & # intersection
              r.xpath("./bibitem[1]/preceding-sibling::*")) -
  r.xpath("./note[@type = 'boilerplate']/descendant-or-self::*"))
  preface.each(&:remove)
end

#publisher_org_match?(org, entry) ⇒ Boolean

A table entry matches a publisher organization on its abbreviation (case-insensitive, since AsciiDoc lowercases attribute-derived abbrevs) or on any of its names (name may be a single string or an array; the latter lets a flavour list, e.g., a Japanese and an English publisher name for the same rank).

Returns:

  • (Boolean)


91
92
93
94
95
96
97
# File 'lib/metanorma/cleanup/ref.rb', line 91

def publisher_org_match?(org, entry)
  abbr = org.at("./abbreviation")&.text&.strip
  name = org.at("./name")&.text&.strip
  names = Array(entry[:name]).map { |n| n.to_s.strip }.reject(&:empty?)
  (!entry[:abbrev].to_s.empty? && abbr&.casecmp?(entry[:abbrev])) ||
    (!name.to_s.empty? && names.include?(name))
end

#publisher_sort_match(bib, table) ⇒ Object

lowest-ranked table entry whose publisher appears on the bibitem



79
80
81
82
83
84
# File 'lib/metanorma/cleanup/ref.rb', line 79

def publisher_sort_match(bib, table)
  orgs = bib.xpath(BIBLIO_PUBLISHER_ORG)
  table.sort_by { |e| e[:rank] }.find do |e|
    orgs.any? { |o| publisher_org_match?(o, e) }
  end
end

#publisher_sort_rank(bib, table) ⇒ Object

Configurable publisher sort ranking, shared by every flavour's bibliography sort. table is the flavour's default ordering, an array of { abbrev:, name:, rank: }. A per-document / metanorma-taste override (:sort-biblio-: : attributes, captured into @publisher_sort_config) REPLACES the flavour default when present.

A matched publisher gets its configured rank; an unmatched standards reference sorts immediately after the ranked publishers, and a non-standard reference last. With no override and the flavour's own default table, this reproduces the flavour's historical hardcoded ranks.



50
51
52
53
54
55
56
57
58
# File 'lib/metanorma/cleanup/ref.rb', line 50

def publisher_sort_rank(bib, table)
  table = publisher_sort_table(table)
  if (entry = publisher_sort_match(bib, table))
    return entry[:rank]
  end

  maxrank = table.map { |e| e[:rank] }.max || 0
  biblio_standards_ref?(bib) ? maxrank + 1 : maxrank + 2
end

#publisher_sort_second(bib, table) ⇒ Object

Secondary sort token: the co-publisher(s) other than the matched primary. Deterministic when several co-publishers exist (returns the smallest token), which reproduces e.g. JIS's "JIS+IEC before JIS+ISO, JIS+IEC+ISO alongside JIS+IEC" ordering.



64
65
66
67
68
69
70
71
# File 'lib/metanorma/cleanup/ref.rb', line 64

def publisher_sort_second(bib, table)
  entry = publisher_sort_match(bib, publisher_sort_table(table))
  entry or return ""
  bib.xpath(BIBLIO_PUBLISHER_ORG)
    .reject { |o| publisher_org_match?(o, entry) }
    .map { |o| (o.at("./abbreviation") || o.at("./name"))&.text&.strip }
    .compact.reject(&:empty?).min || ""
end

#publisher_sort_table(default_table) ⇒ Object



73
74
75
76
# File 'lib/metanorma/cleanup/ref.rb', line 73

def publisher_sort_table(default_table)
  cfg = @publisher_sort_config
  cfg && !cfg.empty? ? cfg : default_table
end

#ref_cleanup(xmldoc) ⇒ Object

move ref before p



125
126
127
128
129
130
# File 'lib/metanorma/cleanup/ref.rb', line 125

def ref_cleanup(xmldoc)
  xmldoc.xpath("//p/ref").each do |r|
    parent = r.parent
    parent.previous = r.remove
  end
end

#sort_biblio(bib) ⇒ Object



33
34
35
# File 'lib/metanorma/cleanup/ref.rb', line 33

def sort_biblio(bib)
  bib
end