Class: IsoDoc::Ietf::RfcConvert

Inherits:
Convert
  • Object
show all
Includes:
Init
Defined in:
lib/isodoc/ietf/reqt.rb,
lib/isodoc/ietf/front.rb,
lib/isodoc/ietf/lists.rb,
lib/isodoc/ietf/table.rb,
lib/isodoc/ietf/terms.rb,
lib/isodoc/ietf/blocks.rb,
lib/isodoc/ietf/inline.rb,
lib/isodoc/ietf/cleanup.rb,
lib/isodoc/ietf/section.rb,
lib/isodoc/ietf/footnotes.rb,
lib/isodoc/ietf/references.rb,
lib/isodoc/ietf/validation.rb,
lib/isodoc/ietf/rfc_convert.rb,
lib/isodoc/ietf/cleanup_blocks.rb,
lib/isodoc/ietf/cleanup_inline.rb

Constant Summary collapse

OL_STYLE =
{
  arabic: "1",
  roman: "i",
  alphabet: "a",
  roman_upper: "I",
  alphabet_upper: "A",
}.freeze

Instance Method Summary collapse

Methods included from Init

#fileloc, #i18n_init

Constructor Details

#initialize(options) ⇒ RfcConvert

Returns a new instance of RfcConvert.



107
108
109
110
111
112
113
114
# File 'lib/isodoc/ietf/rfc_convert.rb', line 107

def initialize(options)
  super
  @xinclude = options[:usexinclude]
  @format = :rfc
  @suffix = "rfc.xml"
  @isodoc = IsoDoc::PresentationXMLConvert.new({})
  @isodoc.i18n_init("en", "Latn", nil, nil)
end

Instance Method Details

#abstract(isoxml, front) ⇒ Object



221
222
223
224
225
226
227
228
229
230
# File 'lib/isodoc/ietf/front.rb', line 221

def abstract(isoxml, front)
  a = isoxml.at(ns("//preface/abstract | //preface/foreword")) || return
  front.abstract **attr_code(anchor: a["id"]) do |abs|
    a.children.reject do |c1|
      %w(title note).include? c1.name
    end.each do |c1|
      parse(c1, abs)
    end
  end
end

#address(addr, phone, fax, email, uri, out) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
# File 'lib/isodoc/ietf/front.rb', line 134

def address(addr, phone, fax, email, uri, out)
  return unless addr || phone || fax || email || uri

  out.address do |a|
    addr and postal(addr, a)
    phone and a.phone phone.text
    fax and a.facsimile fax.text
    email.each { |e| email(e, a) }
    uri and a.uri uri.text
  end
end

#admitted_term_parse(node, out) ⇒ Object



38
39
40
41
42
43
# File 'lib/isodoc/ietf/terms.rb', line 38

def admitted_term_parse(node, out)
  name = node.at(ns(".//name"))
  out.t do |p|
    name.children.each { |c| parse(c, p) }
  end
end

#admonition_name(node, type) ⇒ Object



142
143
144
145
146
147
148
# File 'lib/isodoc/ietf/blocks.rb', line 142

def admonition_name(node, type)
  name = node&.at(ns("./name")) and return name
  name = Nokogiri::XML::Node.new("name", node.document)
  type && @i18n.admonition[type] or return
  name << @i18n.admonition[type]&.upcase
  name
end

#admonition_name_parse(_node, div, name) ⇒ Object



150
151
152
153
154
# File 'lib/isodoc/ietf/blocks.rb', line 150

def admonition_name_parse(_node, div, name)
  div.t keepWithNext: "true" do |p|
    name.children.each { |n| parse(n, p) }
  end
end

#admonition_parse(node, out) ⇒ Object



156
157
158
159
160
161
162
163
# File 'lib/isodoc/ietf/blocks.rb', line 156

def admonition_parse(node, out)
  type = node["type"]
  name = admonition_name(node, type)
  out.aside anchor: node["id"] do |t|
    admonition_name_parse(node, t, name) if name
    node.children.each { |n| parse(n, t) unless n.name == "name" }
  end
end

#annex(isoxml, out) ⇒ Object



169
170
171
172
173
# File 'lib/isodoc/ietf/section.rb', line 169

def annex(isoxml, out)
  isoxml.xpath(ns("//annex")).each do |c|
    clause_parse(c, out)
  end
end

#annotation_cleanup(docxml) ⇒ Object



136
137
138
139
140
141
142
143
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 136

def annotation_cleanup(docxml)
  docxml.xpath("//reference").each do |r|
    while r.next_element&.name == "aside"
      annotation_cleanup1(r)
    end
  end
  docxml.xpath("//references/aside").each(&:remove)
end

#annotation_cleanup1(ref) ⇒ Object



145
146
147
148
149
150
151
152
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 145

def annotation_cleanup1(ref)
  aside = ref.next_element
  aside.name = "annotation"
  aside.traverse do |n|
    n.name == "t" and n.replace(n.children)
  end
  ref << aside
end

#annotation_parse(node, out) ⇒ Object



84
85
86
87
88
89
90
91
92
93
# File 'lib/isodoc/ietf/blocks.rb', line 84

def annotation_parse(node, out)
  @sourcecode = false
  node.at(ns("./annotation")) or return
  out.t { |p| p << @i18n.key }
  out.dl do |dl|
    node.xpath(ns("./annotation")).each do |a|
      annotation_parse1(a, dl)
    end
  end
end

#annotation_parse1(ann, dlist) ⇒ Object



95
96
97
98
99
100
# File 'lib/isodoc/ietf/blocks.rb', line 95

def annotation_parse1(ann, dlist)
  dlist.dt ann.at(ns("//callout[@target='#{ann['id']}']")).text
  dlist.dd do |dd|
    ann.children.each { |n| parse(n, dd) }
  end
end

#area(_isoxml, front) ⇒ Object



203
204
205
206
207
# File 'lib/isodoc/ietf/front.rb', line 203

def area(_isoxml, front)
  @meta.get[:areas].each do |w|
    front.area w
  end
end

#aside_cleanup(docxml) ⇒ Object



177
178
179
180
181
182
183
184
185
186
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 177

def aside_cleanup(docxml)
  docxml.xpath("//*[aside]").each do |p|
    %w(section).include?(p.name) and next
    insert = p
    p.xpath("./aside").each do |a|
      insert.next = a.remove
      insert = insert.next_element
    end
  end
end

#author(isoxml, front) ⇒ Object



71
72
73
74
75
76
77
78
# File 'lib/isodoc/ietf/front.rb', line 71

def author(isoxml, front)
  isoxml.xpath("//xmlns:bibdata/xmlns:contributor[xmlns:role/@type = " \
    "'author' or xmlns:role/@type = 'editor']").each do |c|
    role = c.at(ns("./role/@type")).text == "editor" ? "editor" : nil
    (c.at("./organization") and org_author(c, role, front)) or
      person_author(c, role, front)
  end
end

#bcp14_parse(node, out) ⇒ Object



34
35
36
37
38
# File 'lib/isodoc/ietf/inline.rb', line 34

def bcp14_parse(node, out)
  out.bcp14 do |e|
    children_parse(node, e)
  end
end

#bibitem_render(ref, bib) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/isodoc/ietf/references.rb', line 68

def bibitem_render(ref, bib)
  bib1 = bib.clone
  @isodoc.prep_for_rendering(bib1)
  bib1.namespace = nil
  ret = @bibrenderer.render(bib1.to_xml, embedded: true)
  ref << if bib1.at(ns("./formattedref")) && !bib1.at(ns("./title"))
           "<front><title>#{ret}</title></front>"
         else
           ret
         end
end

#biblio_abstract_cleanup(xmldoc) ⇒ Object



56
57
58
59
60
61
62
63
64
# File 'lib/isodoc/ietf/cleanup.rb', line 56

def biblio_abstract_cleanup(xmldoc)
  xmldoc.xpath("//abstract[@cleanme]").each do |a|
    a.delete("cleanme")
    ret = reparse_abstract(a)
    a.children = if a.at("./p") then ret
                 else "<t>#{ret}</t>"
                 end
  end
end

#biblio_cleanup(xmldoc) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/isodoc/ietf/cleanup.rb', line 24

def biblio_cleanup(xmldoc)
  biblio_referencegroup_cleanup(xmldoc)
  biblio_abstract_cleanup(xmldoc)
  biblio_date_cleanup(xmldoc)
  biblio_refcontent_cleanup(xmldoc)
  annotation_cleanup(xmldoc)
end

#biblio_date_cleanup(xmldoc) ⇒ Object



45
46
47
48
49
50
51
52
53
54
# File 'lib/isodoc/ietf/cleanup.rb', line 45

def biblio_date_cleanup(xmldoc)
  xmldoc.xpath("//date[@cleanme]").each do |a|
    a.delete("cleanme")
    d = @c.decode(a.text).gsub(//, "-").sub(/-\d\d\d\d.*$/, "")
    if attrs = date_attr(d)
      attrs.each { |k, v| a[k] = v }
      a.children.remove
    else a.remove end
  end
end

#biblio_list(node, div, _biblio) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/isodoc/ietf/references.rb', line 45

def biblio_list(node, div, _biblio)
  i = 0
  node.xpath(ns("./bibitem | ./note")).each do |b|
    next if implicit_reference(b)

    i += 1 if b.name == "bibitem"
    if b.name == "note" then note_parse(b, div)
    else
      ietf_bibitem(div, b, i)
    end
  end
end

#biblio_refcontent_cleanup(xmldoc) ⇒ Object



66
67
68
69
70
71
72
73
# File 'lib/isodoc/ietf/cleanup.rb', line 66

def biblio_refcontent_cleanup(xmldoc)
  xmldoc.xpath("//refcontent").each do |a|
    val = a.text.strip
    if val.empty? then a.remove
    else a.children = val
    end
  end
end

#biblio_referencegroup_cleanup(xmldoc) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/isodoc/ietf/cleanup.rb', line 32

def biblio_referencegroup_cleanup(xmldoc)
  xmldoc.xpath("//reference[ref-included]").each do |r|
    r.name = "referencegroup"
    r.elements.each do |e|
      if e.name == "ref-included"
        e.name = "reference"
        e["anchor"] ||= "_#{UUIDTools::UUID.random_create}"
      else e.remove
      end
    end
  end
end

#bibliography(docxml, out) ⇒ Object



6
7
8
9
10
11
12
13
14
15
# File 'lib/isodoc/ietf/references.rb', line 6

def bibliography(docxml, out)
  bibliography_prep(docxml)
  docxml.xpath(ns("//bibliography/references | " \
                  "//bibliography/clause[.//references] | " \
                  "//annex/clause[.//references] | " \
                  "//annex/references | " \
                  "//sections/clause[.//references]")).each do |f|
    bibliography1(f, out)
  end
end

#bibliography1(node, out) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/isodoc/ietf/references.rb', line 30

def bibliography1(node, out)
  out.references **attr_code(anchor: node["id"]) do |div|
    title = node.at(ns("./title")) and div.name do |name|
      title.children.each { |n| parse(n, name) }
    end
    node.elements.select do |e|
      %w(references clause).include? e.name
    end.each { |e| bibliography1(e, out) }
    node.elements.reject do |e|
      %w(references title bibitem note).include? e.name
    end.each { |e| parse(e, div) }
    biblio_list(node, div, true)
  end
end

#bibliography_prep(docxml) ⇒ Object



17
18
19
20
21
22
23
24
# File 'lib/isodoc/ietf/references.rb', line 17

def bibliography_prep(docxml)
  docxml.xpath(ns("//references/bibitem/docidentifier")).each do |i|
    i.children = docid_prefix(i["type"], i.text)
  end
  @bibrenderer =
    ::Relaton::Render::Ietf::General.new(language: @lang,
                                         i18nhash: @i18n.get)
end

#boilerplate(isoxml, front) ⇒ Object



245
# File 'lib/isodoc/ietf/front.rb', line 245

def boilerplate(isoxml, front); end

#bookmark_cleanup(docxml) ⇒ Object



60
61
62
# File 'lib/isodoc/ietf/cleanup_inline.rb', line 60

def bookmark_cleanup(docxml)
  docxml.xpath("//bookmark").each(&:remove)
end

#bookmark_parse(node, out) ⇒ Object



181
182
183
# File 'lib/isodoc/ietf/inline.rb', line 181

def bookmark_parse(node, out)
  out.bookmark nil, **attr_code(anchor: node["id"])
end

#br_parse(_node, out) ⇒ Object



79
80
81
# File 'lib/isodoc/ietf/inline.rb', line 79

def br_parse(_node, out)
  out.br
end

#clause(isoxml, out) ⇒ Object



161
162
163
164
165
166
167
# File 'lib/isodoc/ietf/section.rb', line 161

def clause(isoxml, out)
  isoxml.xpath("//xmlns:preface/child::*" \
               "[not(name() = 'abstract' or name() = 'foreword')] " \
               "| //xmlns:sections/child::*").each do |c|
    clause_parse(c, out)
  end
end

#clause_parse(node, out) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/isodoc/ietf/section.rb', line 148

def clause_parse(node, out)
  node.at(ns(".//references")) and return
  out.section **attr_code(
    anchor: node["id"], numbered: node["numbered"],
    removeInRFC: node["removeInRFC"], toc: node["toc"]
  ) do |div|
    clause_parse_title(node, div, node.at(ns("./title")), out)
    node.children.reject { |c1| c1.name == "title" }.each do |c1|
      parse(c1, div)
    end
  end
end

#clause_parse_title(_node, div, clause, _out, _heading_attrs = {}) ⇒ Object



140
141
142
143
144
145
146
# File 'lib/isodoc/ietf/section.rb', line 140

def clause_parse_title(_node, div, clause, _out, _heading_attrs = {})
  return unless clause

  div.name do |n|
    clause&.children&.each { |c2| parse(c2, n) }
  end
end

#cleanup(docxml) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/isodoc/ietf/cleanup.rb', line 7

def cleanup(docxml)
  image_cleanup(docxml)
  figure_cleanup(docxml)
  table_cleanup(docxml)
  footnote_cleanup(docxml)
  sourcecode_cleanup(docxml)
  li_cleanup(docxml)
  deflist_cleanup(docxml)
  cref_cleanup(docxml) # feeds bookmark
  bookmark_cleanup(docxml)
  front_cleanup(docxml)
  u_cleanup(docxml)
  biblio_cleanup(docxml) # feeds aside
  aside_cleanup(docxml)
  docxml
end

#comments(isoxml, out) ⇒ Object



175
176
177
178
179
# File 'lib/isodoc/ietf/section.rb', line 175

def comments(isoxml, out)
  isoxml.xpath(ns("//review")).each do |c|
    review_note_parse(c, out)
  end
end

#common_rfc_pis(node) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/isodoc/ietf/section.rb', line 4

def common_rfc_pis(node)
  rfc_pis = {
    artworkdelimiter: node.at(ns("//pi/artworkdelimiter"))&.text,
    artworklines: node.at(ns("//pi/artworklines"))&.text,
    authorship: node.at(ns("//pi/authorship"))&.text,
    autobreaks: node.at(ns("//pi/autobreaks"))&.text,
    background: node.at(ns("//pi/background"))&.text,
    colonspace: node.at(ns("//pi/colonspace"))&.text,
    comments: node.at(ns("//pi/comments"))&.text,
    docmapping: node.at(ns("//pi/docmapping"))&.text,
    editing: node.at(ns("//pi/editing"))&.text,
    emoticonic: node.at(ns("//pi/emoticonic"))&.text,
    footer: node.at(ns("//pi/footer"))&.text,
    header: node.at(ns("//pi/header"))&.text,
    inline: node.at(ns("//pi/inline"))&.text,
    iprnotified: node.at(ns("//pi/iprnotified"))&.text,
    linkmailto: node.at(ns("//pi/linkmailto"))&.text,
    linefile: node.at(ns("//pi/linefile"))&.text,
    notedraftinprogress: node.at(ns("//pi/notedraftinprogress"))&.text,
    private: node.at(ns("//pi/private"))&.text,
    refparent: node.at(ns("//pi/refparent"))&.text,
    rfcedstyle: node.at(ns("//pi/rfcedstyle"))&.text,
    slides: node.at(ns("//pi/slides"))&.text,
    "text-list-symbols": node.at(ns("//pi/text-list-symbols"))&.text,
    tocappendix: node.at(ns("//pi/tocappendix"))&.text,
    tocindent: node.at(ns("//pi/tocindent"))&.text,
    tocnarrow: node.at(ns("//pi/tocnarrow"))&.text,
    tocompact: node.at(ns("//pi/tocompact"))&.text,
    topblock: node.at(ns("//pi/topblock"))&.text,
    useobject: node.at(ns("//pi/useobject"))&.text,
    strict: node.at(ns("//pi/strict"))&.text || "yes",
    compact: node.at(ns("//pi/compact"))&.text || "yes",
    subcompact: node.at(ns("//pi/subcompact"))&.text || "no",
    toc: node.at(ns("//pi/tocinclude"))&.text,
    tocdepth: node.at(ns("//pi/toc-depth"))&.text || "4",
    symrefs: node.at(ns("//pi/sym-refs"))&.text || "yes",
    sortrefs: node.at(ns("//pi/sort-refs"))&.text || "yes",
  }
  attr_code(rfc_pis)
end

#concept_parse(node, out) ⇒ Object



88
89
90
91
92
93
94
95
# File 'lib/isodoc/ietf/terms.rb', line 88

def concept_parse(node, out)
  ref = node.at(ns("./xref | ./eref | ./termref"))
  render = node.at(ns("./renderterm"))
  !ref && !render and return node.children.each { |n| parse(n, out) }
  !render or concept_render(render, ref, out)
  ref or return
  concept_ref(ref, out)
end

#concept_ref(ref, out) ⇒ Object



104
105
106
107
108
109
# File 'lib/isodoc/ietf/terms.rb', line 104

def concept_ref(ref, out)
  ref or return
  out << "[term defined in "
  parse(ref, out)
  out << "]"
end

#concept_render(render, ref, out) ⇒ Object



97
98
99
100
101
102
# File 'lib/isodoc/ietf/terms.rb', line 97

def concept_render(render, ref, out)
  out.em do |em|
    render.children.each { |n| parse(n, em) }
  end
  ref and out << " "
end

#content_validate(xml, filename) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/isodoc/ietf/validation.rb', line 18

def content_validate(xml, filename)
  #return
  err = []
  err += numbered_sections_check(xml)
  err += toc_sections_check(xml)
  err += references_check(xml)
  err += xref_check(xml)
  err += (xml)
  return if err.empty?

  FileUtils.mv(filename, "#{filename}.err")
  err.each { |e| warn "RFC XML: #{e}" }
  warn "Cannot continue processing"
end

#convert1(docxml, _filename, _dir) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/isodoc/ietf/rfc_convert.rb', line 20

def convert1(docxml, _filename, _dir)
  document_preprocess(docxml)
  ret = noko do |xml|
    xml.rfc **attr_code(rfc_attributes(docxml)) do |html|
      make_link(html, docxml)
      make_front(html, docxml)
      make_middle(html, docxml)
      make_back(html, docxml)
    end
  end.join("\n").sub(/<!DOCTYPE[^>]+>\n/, "")
  set_pis(docxml, Nokogiri::XML(ret))
end

#cref_cleanup(docxml) ⇒ Object



64
65
66
67
# File 'lib/isodoc/ietf/cleanup_inline.rb', line 64

def cref_cleanup(docxml)
  cref_move(docxml)
  cref_unwrap(docxml)
end

#cref_move(docxml) ⇒ Object

do not remove bookmarks until this is done, bookmarks can be cref destination



71
72
73
74
75
76
77
78
79
# File 'lib/isodoc/ietf/cleanup_inline.rb', line 71

def cref_move(docxml)
  docxml.xpath("//cref[@from]").each do |c|
    dest = docxml.at("//*[@anchor = '#{c['from']}']")
    t = dest.at(".//text()[not(ancestor::cref)]") and dest = t
    c.delete("from")
    c.delete("to")
    dest.previous = c
  end
end

#cref_unwrap(docxml) ⇒ Object



81
82
83
84
85
86
87
88
89
# File 'lib/isodoc/ietf/cleanup_inline.rb', line 81

def cref_unwrap(docxml)
  docxml.xpath("//cref").each do |c|
    c.xpath("./t").each do |t|
      t.replace(t.children)
    end
    %w(section abstract).include? c.parent.name or next
    c.wrap("<t></t>")
  end
end

#date(_isoxml, front) ⇒ Object



179
180
181
182
183
184
# File 'lib/isodoc/ietf/front.rb', line 179

def date(_isoxml, front)
  date = @meta.get[:publisheddate] || @meta.get[:circulateddate] || return
  date = date.gsub(/T.*$/, "")
  attr = date_attr(date) || return
  front.date **attr_code(attr)
end

#date_attr(date) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/isodoc/ietf/front.rb', line 186

def date_attr(date)
  date.nil? and return nil
  if date.length == 4 && date =~ /^\d\d\d\d$/ then { year: date }
  elsif /^\d\d\d\d-?\d\d$/.match?(date)
    m = /^(?<year>\d\d\d\d)-(?<month>\d\d)$/.match date
    { month: Date::MONTHNAMES[(m[:month]).to_i], year: m[:year] }
  else
    begin
      d = Date.iso8601 date
      { day: d.day.to_s.gsub(/^0/, ""), year: d.year,
        month: Date::MONTHNAMES[d.month] }
    rescue StandardError
      nil
    end
  end
end

#dd_cleanup(docxml) ⇒ Object



170
171
172
173
174
175
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 170

def dd_cleanup(docxml)
  docxml.xpath("//dd").each do |d|
    d&.first_element_child&.name == "bookmark" and
      d["anchor"] ||= d.first_element_child["anchor"]
  end
end

#definition_parse(node, out) ⇒ Object



12
13
14
# File 'lib/isodoc/ietf/terms.rb', line 12

def definition_parse(node, out)
  node.children.each { |n| parse(n, out) }
end

#deflist_cleanup(docxml) ⇒ Object



154
155
156
157
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 154

def deflist_cleanup(docxml)
  dt_cleanup(docxml)
  dd_cleanup(docxml)
end

#deprecated_term_parse(node, out) ⇒ Object



26
27
28
29
30
31
32
# File 'lib/isodoc/ietf/terms.rb', line 26

def deprecated_term_parse(node, out)
  name = node.at(ns(".//name"))
  out.t do |p|
    p << l10n("#{@i18n.deprecated}: ")
    name.children.each { |c| parse(c, p) }
  end
end

#display_text_parse(node, out) ⇒ Object



40
41
42
# File 'lib/isodoc/ietf/inline.rb', line 40

def display_text_parse(node, out)
  children_parse(node, out)
end

#div_parse(node, out) ⇒ Object



29
30
31
32
33
# File 'lib/isodoc/ietf/reqt.rb', line 29

def div_parse(node, out)
  node.children.each do |n|
    parse(n, out)
  end
end

#dl_attrs(node) ⇒ Object



41
42
43
44
# File 'lib/isodoc/ietf/lists.rb', line 41

def dl_attrs(node)
  attr_code(anchor: node["id"], newline: node["newline"],
            indent: node["indent"], spacing: node["spacing"])
end

#dl_parse(node, out) ⇒ Object



46
47
48
49
50
51
52
53
54
# File 'lib/isodoc/ietf/lists.rb', line 46

def dl_parse(node, out)
  list_title_parse(node, out)
  out.dl **dl_attrs(node) do |v|
    node.elements.select { |n| dt_dd? n }.each_slice(2) do |dt, dd|
      dl_parse1(v, dt, dd)
    end
  end
  dl_parse_notes(node, out)
end

#dl_parse1(dlist, dterm, ddef) ⇒ Object



62
63
64
65
66
67
68
69
# File 'lib/isodoc/ietf/lists.rb', line 62

def dl_parse1(dlist, dterm, ddef)
  dlist.dt **attr_code(anchor: dterm["id"]) do |term|
    dt_parse(dterm, term)
  end
  dlist.dd **attr_code(anchor: ddef["id"]) do |listitem|
    ddef.children.each { |n| parse(n, listitem) }
  end
end

#document_preprocess(docxml) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/isodoc/ietf/rfc_convert.rb', line 33

def document_preprocess(docxml)
  @isodoc.reqt_models = Metanorma::Requirements
    .new({ default: "default", lang: @lang, script: @script,
           locale: @locale, labels: @i18n.get })
  info docxml, nil
  @xrefs.parse docxml
  @isodoc.xrefs = @xrefs
  @isodoc.bibrender = @isodoc.bibrenderer
  @isodoc.reference_names(docxml)
  @isodoc.permission(docxml)
  @isodoc.requirement(docxml)
  @isodoc.recommendation(docxml)
  @isodoc.requirement_render(docxml)
  @xrefs.parse docxml
end

#dt_cleanup(docxml) ⇒ Object



159
160
161
162
163
164
165
166
167
168
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 159

def dt_cleanup(docxml)
  docxml.xpath("//dt").each do |d|
    d.first_element_child&.name == "bookmark" and
      d["anchor"] ||= d.first_element_child["anchor"]
    d.xpath(".//t").each do |t|
      d["anchor"] ||= t["anchor"]
      t.replace(t.children)
    end
  end
end

#dt_parse(dterm, term) ⇒ Object



56
57
58
59
60
# File 'lib/isodoc/ietf/lists.rb', line 56

def dt_parse(dterm, term)
  if dterm.elements.empty? then term << dterm.text
  else dterm.children.each { |n| parse(n, term) }
  end
end

#em_parse(node, out) ⇒ Object



4
5
6
7
8
# File 'lib/isodoc/ietf/inline.rb', line 4

def em_parse(node, out)
  out.em do |e|
    children_parse(node, e)
  end
end

#email(email, out) ⇒ Object



173
174
175
176
177
# File 'lib/isodoc/ietf/front.rb', line 173

def email(email, out)
  ascii = email.text.transliterate
  out.email email.text,
            **attr_code(ascii: ascii == email.text ? nil : ascii)
end

#eref_relative(node) ⇒ Object



154
155
156
157
# File 'lib/isodoc/ietf/inline.rb', line 154

def eref_relative(node)
  node["relative"] ||
    node.at(ns(".//locality[@type = 'anchor']/referenceFrom"))&.text || ""
end

#eref_section(node) ⇒ Object



159
160
161
162
163
164
165
# File 'lib/isodoc/ietf/inline.rb', line 159

def eref_section(node)
  ret = @isodoc.eref_localities(
    node.xpath(ns("./locality | ./localityStack")), nil, node
  ) or return ""
  ret.gsub(%r{</?span[^>]*>}, "").sub(/^,/, "")
    .sub(/^\s*(Sections?|Clauses?)/, "").strip.sub(/,$/, "")
end

#error_parse(node, out) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/isodoc/ietf/rfc_convert.rb', line 68

def error_parse(node, out)
  case node.name
  when "bcp14" then bcp14_parse(node, out) # legacy
  when "concept" then concept_parse(node, out)
  when "display-text" then display_text_parse(node, out)
  when "verbal-definition", "non-verbal-representation",
    "fmt-provision"
    node.elements.each { |n| parse(n, out) }
  else
    text = node.to_xml.gsub(/</, "&lt;").gsub(/>/, "&gt;")
    out.t { |p| p << text }
  end
end

#example_label(node, div, name) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/isodoc/ietf/blocks.rb', line 47

def example_label(node, div, name)
  n = @xrefs.get[node["id"]]
  div.t **attr_code(anchor: node["id"], keepWithNext: "true") do |p|
    lbl = if n.nil? || n[:label].nil? || n[:label].empty?
            @i18n.example
          else l10n("#{@i18n.example} #{n[:label]}")
          end
    p << lbl
    name and !lbl.nil? and p << ": "
    name&.children&.each { |e| parse(e, p) }
  end
end

#example_parse(node, out) ⇒ Object



42
43
44
45
# File 'lib/isodoc/ietf/blocks.rb', line 42

def example_parse(node, out)
  example_label(node, out, node.at(ns("./name")))
  node.elements.each { |n| parse(n, out) unless n.name == "name" }
end

#extract_delims(text) ⇒ Object



57
58
59
60
61
62
63
64
65
66
# File 'lib/isodoc/ietf/rfc_convert.rb', line 57

def extract_delims(text)
  @openmathdelim = "$$"
  @closemathdelim = "$$"
  while %r{#{Regexp.escape(@openmathdelim)}}m.match(text) ||
      %r{#{Regexp.escape(@closemathdelim)}}m.match(text)
    @openmathdelim += "$"
    @closemathdelim += "$"
  end
  [@openmathdelim, @closemathdelim]
end

#figure_cleanup(docxml) ⇒ Object



31
32
33
34
35
36
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 31

def figure_cleanup(docxml)
  figure_postamble(docxml)
  figure_unnest(docxml)
  figure_footnote_cleanup(docxml)
  figure_data_uri(docxml)
end

#figure_data_uri(docxml) ⇒ Object



38
39
40
41
42
43
44
45
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 38

def figure_data_uri(docxml)
  docxml.xpath("//artwork").each do |a|
    %r{^data:image/svg\+xml;base64}.match?(a["src"]) or next
    f = Vectory::Utils::save_dataimage(a["src"])
    a.delete("src")
    a.children = File.read(f).sub(%r{<\?.+\?>}, "")
  end
end

#figure_footnote_cleanup(docxml) ⇒ Object



19
20
21
22
23
24
25
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 19

def figure_footnote_cleanup(docxml)
  docxml.xpath("//figure[descendant::fn]").each do |t|
    t.xpath(".//fn").each do |a|
      t << "<aside>#{a.remove.children}</aside>"
    end
  end
end

#figure_name_parse(_node, div, name) ⇒ Object



176
177
178
179
180
181
# File 'lib/isodoc/ietf/blocks.rb', line 176

def figure_name_parse(_node, div, name)
  name.nil? and return
  div.name do |_n|
    name.children.each { |n| parse(n, div) }
  end
end

#figure_parse(node, out) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/isodoc/ietf/blocks.rb', line 195

def figure_parse(node, out)
  node["class"] == "pseudocode" || node["type"] == "pseudocode" and
    return pseudocode_parse(node, out)
  @in_figure = true
  out.figure **attr_code(anchor: node["id"]) do |div|
    figure_name_parse(node, div, node.at(ns("./name")))
    node.children.each do |n|
      parse(n, div) unless n.name == "name"
    end
  end
  @in_figure = false
end

#figure_postamble(docxml) ⇒ Object



59
60
61
62
63
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 59

def figure_postamble(docxml)
  make_postamble(docxml)
  move_postamble(docxml)
  move_preamble(docxml)
end

#figure_unnest(docxml) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 47

def figure_unnest(docxml)
  docxml.xpath("//figure[descendant::figure]").each do |f|
    insert = f
    f.xpath(".//figure").each do |a|
      title = f.at("./name") and a.children.first.previous = title.remove
      insert.next = a.remove
      insert = insert.next_element
    end
    f.remove
  end
end

#footnote_cleanup(docxml) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/isodoc/ietf/cleanup_inline.rb', line 14

def footnote_cleanup(docxml)
  fn = footnote_refs_cleanup(docxml)
  endnotes = make_endnotes(docxml)
  docxml.xpath("//section[descendant::fn] | " \
               "//abstract[descendant::fn]").each do |s|
    s.xpath(".//fn").each do |f|
      ref = f.at(".//ref") and ref.replace("[#{fn[ref.text]}] ")
      endnotes << f.remove.children
    end
  end
end

#footnote_parse(node, out) ⇒ Object



3
4
5
6
7
8
9
# File 'lib/isodoc/ietf/footnotes.rb', line 3

def footnote_parse(node, out)
  return table_footnote_parse(node, out) if @in_table || @in_figure

  fn = node["reference"]
  out.fnref fn
  make_local_footnote(node, fn, out)
end

#footnote_refs_cleanup(docxml) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/isodoc/ietf/cleanup_inline.rb', line 26

def footnote_refs_cleanup(docxml)
  i = 0
  fn = {}
  docxml.xpath("//fnref").each do |f|
    unless fn[f.text]
      i = i + 1
      fn[f.text] = i.to_s
    end
    f.replace(" [#{fn[f.text]}]")
  end
  fn
end

#formula_parse(node, out) ⇒ Object



119
120
121
122
123
124
125
126
# File 'lib/isodoc/ietf/blocks.rb', line 119

def formula_parse(node, out)
  formula_parse1(node, out)
  formula_where(node.at(ns("./dl")), out)
  node.children.each do |n|
    %w(stem dl).include? n.name and next
    parse(n, out)
  end
end

#formula_parse1(node, out) ⇒ Object



108
109
110
111
112
113
114
115
116
117
# File 'lib/isodoc/ietf/blocks.rb', line 108

def formula_parse1(node, out)
  out.t **attr_code(anchor: node["id"]) do |p|
    parse(node.at(ns("./stem")), p)
    if lbl = @xrefs.anchor(node["id"], :label, false)
      lbl.gsub!(%r{</?span[^>]*>}, "")
      /^\(.+?\)$/.match?(lbl) or lbl = "(#{lbl})"
      p << "    #{lbl}"
    end
  end
end

#formula_where(dlist, out) ⇒ Object



102
103
104
105
106
# File 'lib/isodoc/ietf/blocks.rb', line 102

def formula_where(dlist, out)
  dlist or return
  out.t { |p| p << @i18n.where }
  parse(dlist, out)
end

#front_cleanup(xmldoc) ⇒ Object



83
84
85
86
87
88
89
# File 'lib/isodoc/ietf/cleanup.rb', line 83

def front_cleanup(xmldoc)
  xmldoc.xpath("//title").each { |s| s.children = s.text }
  xmldoc.xpath("//reference/front[not(author)]").each do |f|
    insert = f.at("./seriesInfo[last()]") || f.at("./title")
    insert.next = "<author surname='Unknown'/>"
  end
end

#get_linkend(node) ⇒ Object



129
130
131
132
133
134
135
136
137
138
# File 'lib/isodoc/ietf/inline.rb', line 129

def get_linkend(node)
  no_loc_contents = node.children.reject do |c|
    %w{locality localityStack location}.include? c.name
  end
  contents = no_loc_contents.select { |c| !c.text? || /\S/.match(c) }
    .map { |x| x.name == "display-text" ? x.children : x }.flatten
  !contents.empty? and
    return to_xml(Nokogiri::XML::NodeSet.new(node.document, contents))
  ""
end

#get_table_ancestor_id(node) ⇒ Object



67
68
69
70
71
72
# File 'lib/isodoc/ietf/footnotes.rb', line 67

def get_table_ancestor_id(node)
  table = node.ancestors("table") || node.ancestors("figure")
  return UUIDTools::UUID.random_create.to_s if table.empty?

  table.last["id"]
end

#hr_parse(node, out) ⇒ Object



83
# File 'lib/isodoc/ietf/inline.rb', line 83

def hr_parse(node, out); end

#id_seriesinfo(isoxml, front) ⇒ Object



62
63
64
65
66
67
68
69
# File 'lib/isodoc/ietf/front.rb', line 62

def id_seriesinfo(isoxml, front)
  front.seriesInfo nil,
                   **seriesinfo_attr(isoxml)
                     .merge({ name: "Internet-Draft",
                              asciiName: "Internet-Draft" })
  i = isoxml&.at(ns("//bibdata/series[@type = 'intended']/title"))&.text and
    front.seriesInfo **attr_code(name: "", value: "", status: i)
end

#ietf_bibitem(list, bib, _ordinal) ⇒ Object



58
59
60
61
62
63
64
65
66
# File 'lib/isodoc/ietf/references.rb', line 58

def ietf_bibitem(list, bib, _ordinal)
  uris = bib.xpath(ns("./uri"))
  target = nil
  uris&.each { |u| target = u.text if %w(src HTML).include?(u["type"]) }
  list.reference **attr_code(target: target,
                             anchor: bib["id"]) do |r|
                               bibitem_render(r, bib)
                             end
end

#image_cleanup(docxml) ⇒ Object



49
50
51
52
53
54
55
56
57
58
# File 'lib/isodoc/ietf/cleanup_inline.rb', line 49

def image_cleanup(docxml)
  docxml.xpath("//t[descendant::artwork]").each do |t|
    insert = t
    t.xpath(".//artwork").each_with_index do |a, i|
      insert.next = a.dup
      insert = insert.next
      a.replace("[IMAGE #{i + 1}]")
    end
  end
end

#image_parse(node, out, caption) ⇒ Object



99
100
101
102
# File 'lib/isodoc/ietf/inline.rb', line 99

def image_parse(node, out, caption)
  out.artwork **attr_code(image_parse_attrs(node))
  image_title_parse(out, caption)
end

#image_parse_attrs(node) ⇒ Object



92
93
94
95
96
97
# File 'lib/isodoc/ietf/inline.rb', line 92

def image_parse_attrs(node)
  { src: node["src"], title: node["title"],
    align: node["align"], name: node["filename"],
    anchor: node["id"], type: "svg",
    alt: node["alt"] }
end

#image_title_parse(out, caption) ⇒ Object



104
105
106
107
108
109
110
# File 'lib/isodoc/ietf/inline.rb', line 104

def image_title_parse(out, caption)
  unless caption.nil?
    out.t align: "center", keepWithPrevious: "true" do |p|
      p << caption.to_s
    end
  end
end

#implicit_reference(bib) ⇒ Object



26
27
28
# File 'lib/isodoc/ietf/references.rb', line 26

def implicit_reference(bib)
  bib["hidden"] == "true"
end

#index_parse(node, out) ⇒ Object



175
176
177
178
179
# File 'lib/isodoc/ietf/inline.rb', line 175

def index_parse(node, out)
  out.iref nil, **attr_code(item: node.at(ns("./primary")).text,
                            primary: node["primary"],
                            subitem: node&.at(ns("./secondary"))&.text)
end

#info(isoxml, out) ⇒ Object



22
23
24
25
# File 'lib/isodoc/ietf/front.rb', line 22

def info(isoxml, out)
  @meta.areas isoxml, out
  super
end

#init_file(filename, debug) ⇒ Object



102
103
104
105
# File 'lib/isodoc/ietf/rfc_convert.rb', line 102

def init_file(filename, debug)
  filename = filename.sub(/\.rfc\.xml$/, ".rfc")
  super
end

#ipr_check(xml) ⇒ Object

5.4.2.3. “Copyright Notice” Insertion



192
193
194
195
196
197
198
199
# File 'lib/isodoc/ietf/validation.rb', line 192

def ipr_check(xml)
  xml.root["ipr"] or
    return ["Missing ipr attribute on <rfc> element (:ipr:)"]
  /trust200902$/.match(xml.root["ipr"]) or
    return ["Unknown ipr attribute on <rfc> element (:ipr:): " \
            "#{xml.root['ipr']}"]
  []
end

#keyword(_isoxml, front) ⇒ Object



215
216
217
218
219
# File 'lib/isodoc/ietf/front.rb', line 215

def keyword(_isoxml, front)
  @meta.get[:keywords].each do |kw|
    front.keyword kw
  end
end

#keyword_parse(node, out) ⇒ Object



52
53
54
# File 'lib/isodoc/ietf/inline.rb', line 52

def keyword_parse(node, out)
  children_parse(node, out)
end

#label(sect) ⇒ Object



33
34
35
36
# File 'lib/isodoc/ietf/validation.rb', line 33

def label(sect)
  sect&.at("./name")&.text ||
    sect["name"] || sect["anchor"]
end

#li_cleanup(xmldoc) ⇒ Object



4
5
6
7
8
9
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 4

def li_cleanup(xmldoc)
  xmldoc.xpath("//li[t]").each do |li|
    li.elements.size == 1 or next
    li.children = li.elements[0].children
  end
end

#li_parse(node, out) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/isodoc/ietf/lists.rb', line 71

def li_parse(node, out)
  out.li **attr_code(anchor: node["id"]) do |li|
    if node["uncheckedcheckbox"] == "true"
      li << '<span class="zzMoveToFollowing">' \
            '<input type="checkbox" checked="checked"/></span>'
    elsif node["checkedcheckbox"] == "true"
      li << '<span class="zzMoveToFollowing">' \
            '<input type="checkbox"/></span>'
    end
    node.children.each { |n| parse(n, li) }
  end
end

5.6.3. <link> Processing



165
166
167
168
169
170
171
172
# File 'lib/isodoc/ietf/validation.rb', line 165

def link_check(xml)
  l = xml&.at("//link[@rel = 'convertedFrom']")&.text
  !l || %r{^https://datatracker\.ietf\.org/doc/draft-}.match(l) or
    return ["<link rel='convertedFrom'> (:derived-from: document " \
            "attribute) must start with " \
            "https://datatracker.ietf.org/doc/draft-"]
  []
end

#make_back(out, isoxml) ⇒ Object



132
133
134
135
136
137
138
# File 'lib/isodoc/ietf/section.rb', line 132

def make_back(out, isoxml)
  out.back do |back|
    bibliography isoxml, back
    annex isoxml, back
    comments isoxml, back
  end
end

#make_endnotes(docxml) ⇒ Object



39
40
41
42
43
44
45
46
47
# File 'lib/isodoc/ietf/cleanup_inline.rb', line 39

def make_endnotes(docxml)
  return unless docxml.at("//fn")

  unless endnotes = docxml.at("//back")
    docxml << "<back/>" and endnotes = docxml.at("//back")
  end
  endnotes << "<section><name>Endnotes</name></section>"
  docxml.at("//back/section[last()]")
end

#make_front(out, isoxml) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/isodoc/ietf/front.rb', line 6

def make_front(out, isoxml)
  info(isoxml, out)
  out.front do |front|
    title isoxml, front
    seriesinfo isoxml, front
    author isoxml, front
    date isoxml, front
    area isoxml, front
    workgroup isoxml, front
    keyword isoxml, front
    abstract isoxml, front
    note isoxml, front
    boilerplate isoxml, front
  end
end

#make_generic_footnote_text(node, fnref) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/isodoc/ietf/footnotes.rb', line 20

def make_generic_footnote_text(node, fnref)
  first = node.first_element_child
  noko do |xml|
    xml.fn do |_div|
      xml.t **attr_code(anchor: first ? first["id"] : nil) do |div|
        div.ref fnref
        first.name == "p" and first.children.each { |n| parse(n, div) }
      end
      (first.name == "p" and
        node.elements.drop(1).each { |n| parse(n, xml) }) or
        node.children.each { |n| parse(n, xml) }
    end
  end.join
end


104
105
106
107
108
109
110
111
112
113
# File 'lib/isodoc/ietf/section.rb', line 104

def make_link(out, isoxml)
  links = isoxml
    .xpath(ns("//bibdata/relation[@type = 'includedIn' or " \
              "@type = 'describedBy' or @type = 'derivedFrom' or " \
              "@type = 'instanceOf']")) || return
  links.each do |l|
    out.link href: l&.at(ns("./bibitem/docidentifier"))&.text,
             rel: rel2iana(l["type"])
  end
end

#make_local_footnote(node, fn, out) ⇒ Object



11
12
13
14
15
16
17
18
# File 'lib/isodoc/ietf/footnotes.rb', line 11

def make_local_footnote(node, fn, out)
  return if @seen_footnote.include?(fn)

  @in_footnote = true
  out << make_generic_footnote_text(node, fn)
  @in_footnote = false
  @seen_footnote << fn
end

#make_middle(out, isoxml) ⇒ Object



126
127
128
129
130
# File 'lib/isodoc/ietf/section.rb', line 126

def make_middle(out, isoxml)
  out.middle do |middle|
    clause isoxml, middle
  end
end

#make_postamble(docxml) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 65

def make_postamble(docxml)
  docxml.xpath("//figure").each do |f|
    a = f.at("./artwork | ./sourcecode") || next
    name = f.at("./name")&.remove
    b = a.xpath("./preceding-sibling::*")&.remove
    c = a.xpath("./following-sibling::*")&.remove
    a = a.remove
    name and f << name
    b.empty? or f << "<preamble>#{to_xml(b)}</preamble>"
    a and f << a
    c.empty? or f << "<postamble>#{to_xml(c)}</postamble>"
  end
end


50
51
52
# File 'lib/isodoc/ietf/footnotes.rb', line 50

def make_table_footnote_link(out, _fnid, fnref)
  out << " [#{fnref}]"
end

#make_table_footnote_text(node, _fnid, fnref) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/isodoc/ietf/footnotes.rb', line 54

def make_table_footnote_text(node, _fnid, fnref)
  first = node.first_element_child
  noko do |xml|
    xml.t **attr_code(anchor: first ? first["id"] : nil) do |div|
      div << "[#{fnref}]  "
      first.name == "p" and first.children.each { |n| parse(n, div) }
    end
    (first.name == "p" and
      node.elements.drop(1).each { |n| parse(n, xml) }) or
      node.children.each { |n| parse(n, xml) }
  end.join
end

#make_tr_attr(cell, _row, _totalrows, _header) ⇒ Object



44
45
46
47
# File 'lib/isodoc/ietf/table.rb', line 44

def make_tr_attr(cell, _row, _totalrows, _header)
  attr_code(rowspan: cell["rowspan"], colspan: cell["colspan"],
            align: cell["align"])
end

#metadata_check(xml) ⇒ Object



156
157
158
159
160
161
162
# File 'lib/isodoc/ietf/validation.rb', line 156

def (xml)
  ret = []
  ret += link_check(xml)
  ret += seriesInfo_check(xml)
  ret += ipr_check(xml)
  ret
end

#metadata_init(lang, script, locale, i18n) ⇒ Object



49
50
51
# File 'lib/isodoc/ietf/rfc_convert.rb', line 49

def (lang, script, locale, i18n)
  @meta = Metadata.new(lang, script, locale, i18n)
end

#modification_parse(node, out) ⇒ Object



16
17
18
19
20
# File 'lib/isodoc/ietf/terms.rb', line 16

def modification_parse(node, out)
  para = node.at(ns("./p"))
  out << " -- "
  para.children.each { |n| parse(n, out) }
end

#move_postamble(docxml) ⇒ Object



79
80
81
82
83
84
85
86
87
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 79

def move_postamble(docxml)
  docxml.xpath("//postamble").each do |p|
    insert = p.parent
    p.remove.elements.each do |e|
      insert.next = e
      insert = insert.next_element
    end
  end
end

#move_preamble(docxml) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 89

def move_preamble(docxml)
  docxml.xpath("//preamble").each do |p|
    insert = p.parent
    p.remove.elements.each do |e|
      insert.previous = e
    end
  end
end

#multidef(elem) ⇒ Object



76
77
78
79
80
81
82
83
84
# File 'lib/isodoc/ietf/terms.rb', line 76

def multidef(elem)
  d = elem.at(ns("./definition"))
d = d.replace("<ol><li>#{to_xml(d.children)}</li></ol>").first
elem.xpath(ns("./definition")).each do |f|
  f = f.replace("<li>#{to_xml(f.children)}</li>").first
  d << f
end
d.wrap("<definition></definition>")
end

#note(isoxml, front) ⇒ Object



232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/isodoc/ietf/front.rb', line 232

def note(isoxml, front)
  a = isoxml.at(ns("//preface/abstract/note | //preface/foreword/note")) or
    return
  front.note **attr_code(removeInRFC: a["removeInRFC"]) do |n|
    title = a.at(ns("./name")) and n.name do |t|
      title.children.each { |tt| parse(tt, t) }
    end
    a.children.reject { |c1| c1.name == "name" }.each do |c1|
      parse(c1, n)
    end
  end
end

#note_label(node) ⇒ Object



22
23
24
25
26
27
# File 'lib/isodoc/ietf/blocks.rb', line 22

def note_label(node)
  n = @xrefs.get[node["id"]]
  n.nil? || n[:label].nil? || n[:label].empty? and
    return l10n("#{@i18n.note}: ")
  l10n("#{@i18n.note} #{n[:label]}: ")
end

#note_parse(node, out) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/isodoc/ietf/blocks.rb', line 29

def note_parse(node, out)
  first = node.first_element_child
  out.aside **attr_code(anchor: node["id"] || first["id"]) do |a|
    a.t do |p|
      p << note_label(node)
      first.name == "p" and first.children.each { |n| parse(n, p) }
    end
    (first.name == "p" and
      node.elements.drop(1).each { |n| parse(n, out) }) or
      node.children.each { |n| parse(n, out) }
  end
end

#numbered_sections_check(xml) ⇒ Object

2.46.2. “numbered” Attribute



39
40
41
42
43
44
45
46
# File 'lib/isodoc/ietf/validation.rb', line 39

def numbered_sections_check(xml)
  ret = []
  xml.xpath("//section[@numbered = 'false']").each do |s1|
    ret += numbered_sections_check1(s1)
    ret += numbered_sections_check2(s1)
  end
  ret
end

#numbered_sections_check1(section) ⇒ Object



48
49
50
51
52
53
54
# File 'lib/isodoc/ietf/validation.rb', line 48

def numbered_sections_check1(section)
  section.xpath("./section[not(@numbered) or @numbered = 'true']")
    .each_with_object([]) do |s2, m|
    m << "Numbered section #{label(s2)} under unnumbered section " \
         "#{label(section)}"
  end
end

#numbered_sections_check2(section) ⇒ Object



56
57
58
59
60
61
62
63
# File 'lib/isodoc/ietf/validation.rb', line 56

def numbered_sections_check2(section)
  section.xpath("./following-sibling::*[name() = 'section']" \
                "[not(@numbered) or @numbered = 'true']")
    .each_with_object([]) do |s2, m|
    m << "Numbered section #{label(s2)} following unnumbered " \
         "section #{label(section)}"
  end
end

#ol_attrs(node) ⇒ Object



28
29
30
31
32
33
# File 'lib/isodoc/ietf/lists.rb', line 28

def ol_attrs(node)
  { anchor: node["id"],
    spacing: node["spacing"], indent: node["indent"],
    type: ol_style(node["type"]),
    group: node["group"], start: node["start"] }
end

#ol_parse(node, out) ⇒ Object



35
36
37
38
39
# File 'lib/isodoc/ietf/lists.rb', line 35

def ol_parse(node, out)
  out.ol **attr_code(ol_attrs(node)) do |ol|
    node.children.each { |n| parse(n, ol) }
  end
end

#ol_style(type) ⇒ Object



24
25
26
# File 'lib/isodoc/ietf/lists.rb', line 24

def ol_style(type)
  OL_STYLE[type&.to_sym] || type
end

#omit_docid_prefix(prefix) ⇒ Object



82
83
84
85
86
# File 'lib/isodoc/ietf/rfc_convert.rb', line 82

def omit_docid_prefix(prefix)
  return true if %w(IETF RFC).include?(prefix)

  super
end

#org_author(contrib, role, front) ⇒ Object



114
115
116
117
118
119
120
121
122
123
# File 'lib/isodoc/ietf/front.rb', line 114

def org_author(contrib, role, front)
  front.author **attr_code(role: role) do |a|
    organization(contrib.at(ns("./organization")), a,
                 contrib.document.at(ns("//showOnFrontPage")))
    address(contrib.at(ns(".//address")),
            contrib.at(ns(".//phone[not(@type = 'fax')]")),
            contrib.at(ns(".//phone[@type = 'fax']")),
            contrib.xpath(ns(".//email")), contrib.at(ns(".//uri")), a)
  end
end

#organization(org, out, show) ⇒ Object



125
126
127
128
129
130
131
132
# File 'lib/isodoc/ietf/front.rb', line 125

def organization(org, out, show)
  name = org.at(ns("./name"))&.text
  out.organization name, **attr_code(
    showOnFrontPage: show&.text, ascii: output_if_translit(name),
    asciiAbbrev: output_if_translit(org.at(ns("./abbreviation"))),
    abbrev: org.at(ns("./abbreviation"))
  )
end

#output_if_translit(text) ⇒ Object



27
28
29
30
# File 'lib/isodoc/ietf/front.rb', line 27

def output_if_translit(text)
  text.nil? and return nil
  text.transliterate == text ? nil : text.transliterate
end

#page_break(_out) ⇒ Object



75
# File 'lib/isodoc/ietf/inline.rb', line 75

def page_break(_out); end

#pagebreak_parse(_node, _out) ⇒ Object



77
# File 'lib/isodoc/ietf/inline.rb', line 77

def pagebreak_parse(_node, _out); end

#para_attrs(node) ⇒ Object



4
5
6
7
8
9
# File 'lib/isodoc/ietf/blocks.rb', line 4

def para_attrs(node)
  { keepWithNext: node["keep-with-next"],
    keepWithPrevious: node["keep-with-previous"],
    indent: node["indent"],
    anchor: node["id"] }
end

#para_parse(node, out) ⇒ Object



11
12
13
14
15
16
17
18
19
20
# File 'lib/isodoc/ietf/blocks.rb', line 11

def para_parse(node, out)
  out.t **attr_code(para_attrs(node)) do |p|
    unless @termdomain.empty?
      p << "&lt;#{@termdomain}&gt; "
      @termdomain = ""
    end
    node.children.each { |n| parse(n, p) unless n.name == "note" }
  end
  node.xpath(ns("./note")).each { |n| parse(n, out) }
end

#permission_parse(node, out) ⇒ Object



25
26
27
# File 'lib/isodoc/ietf/reqt.rb', line 25

def permission_parse(node, out)
  recommendation_parse1(node, out)
end

#pers_author_attrs1(ret, full, init, contrib) ⇒ Object



91
92
93
94
95
96
97
98
99
100
# File 'lib/isodoc/ietf/front.rb', line 91

def pers_author_attrs1(ret, full, init, contrib)
  full and ret.merge!(
    attr_code(
      asciiFullname: output_if_translit(full),
      asciiInitials: output_if_translit(init),
      asciiSurname: output_if_translit(contrib&.at(ns("./surname"))),
    ),
  )
  ret
end

#person_author(contrib, role, front) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
# File 'lib/isodoc/ietf/front.rb', line 102

def person_author(contrib, role, front)
  attrs = person_author_attrs(contrib.at(ns("./person/name")), role)
  front.author **attrs do |a|
    org = contrib.at(ns("./person/affiliation/organization")) and
      organization(org, a, contrib.document.at(ns("//showOnFrontPage")))
    address(contrib.xpath(ns(".//address")),
            contrib.at(ns(".//phone[not(@type = 'fax')]")),
            contrib.at(ns(".//phone[@type = 'fax']")),
            contrib.xpath(ns(".//email")), contrib.at(ns(".//uri")), a)
  end
end

#person_author_attrs(contrib, role) ⇒ Object



80
81
82
83
84
85
86
87
88
89
# File 'lib/isodoc/ietf/front.rb', line 80

def person_author_attrs(contrib, role)
  contrib.nil? and return {}
  full = contrib.at(ns("./completename"))&.text
  init = contrib.at(ns("./initial"))&.text ||
    contrib.xpath(ns("./forename"))&.map { |n| n.text[0] }&.join(".")
  init = nil if init.empty?
  ret = attr_code(role: role, fullname: full, initials: init,
                  surname: contrib.at(ns("./surname"))&.text)
  pers_author_attrs1(ret, full, init, contrib)
end

#postal(addr, out) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/isodoc/ietf/front.rb', line 146

def postal(addr, out)
  out.postal do |p|
    if line = addr.at(ns("./formattedAddress"))
      line.xpath(ns(".//br")).each { |br| br.replace("\n") }
      line.text.split("\n").each do |l|
        p.postalLine l, **attr_code(ascii: l.transliterate)
      end
    else
      postal_detailed(addr, p)
    end
  end
end

#postal_detailed(addr, out) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/isodoc/ietf/front.rb', line 159

def postal_detailed(addr, out)
  addr.xpath(ns("./street")).each do |s|
    out.street s.text, **attr_code(ascii: s.text.transliterate)
  end
  s = addr.at(ns("./city")) and
    out.city s.text, **attr_code(ascii: s.text.transliterate)
  s = addr.at(ns("./state")) and
    out.region s.text, **attr_code(ascii: s.text.transliterate)
  s = addr.at(ns("./country")) and
    out.country s.text, **attr_code(ascii: s.text.transliterate)
  s = addr.at(ns("./postcode")) and
    out.code s.text, **attr_code(ascii: s.text.transliterate)
end

#postprocess(result, filename, _dir) ⇒ Object



92
93
94
95
96
97
98
99
100
# File 'lib/isodoc/ietf/rfc_convert.rb', line 92

def postprocess(result, filename, _dir)
  result = from_xhtml(cleanup(to_xhtml(textcleanup(result))))
    .sub(/<!DOCTYPE[^>]+>\n/, "")
    .sub(/(<rfc[^<]+? )lang="[^"]+"/, "\\1")
  File.open(filename, "w:UTF-8") { |f| f.write(result) }
  schema_validate(filename)
  @files_to_delete.each { |f| FileUtils.rm_rf f }
  content_validate(to_xhtml(result), filename)
end

#pre_parse(node, out) ⇒ Object



77
78
79
80
81
82
# File 'lib/isodoc/ietf/blocks.rb', line 77

def pre_parse(node, out)
  out.artwork **attr_code(anchor: node["id"], align: node["align"],
                          alt: node["alt"], type: "ascii-art") do |s|
    s.cdata node.text.sub(/^\n/, "").gsub(/\t/, "    ")
  end
end

#preprocess_termref(elem) ⇒ Object



126
127
128
129
130
131
132
133
# File 'lib/isodoc/ietf/terms.rb', line 126

def preprocess_termref(elem)
  origin = elem.at(ns("./origin"))
  s = termsource_status(elem["status"]) and origin.next = l10n(", #{s}")
  termsource_add_modification_text(elem.at(ns("./modification")))
  while elem&.next_element&.name == "termsource"
    elem << "; #{to_xml(elem.next_element.remove.children)}"
  end
end

#pseudocode_parse(node, out) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
# File 'lib/isodoc/ietf/blocks.rb', line 183

def pseudocode_parse(node, out)
  out.sourcecode **attr_code(
    anchor: node["id"], type: node["lang"], name: node["filename"],
    markers: node["markers"], src: node["src"]
  ) do |s|
    node.children.each do |x|
      %w(name dl).include?(x.name) and next
      parse(x, s)
    end
  end
end

#quote_attribution(node) ⇒ Object



128
129
130
131
132
# File 'lib/isodoc/ietf/blocks.rb', line 128

def quote_attribution(node)
  author = node.at(ns("./author"))&.text
  source = node.at(ns("./source/@uri"))&.text
  attr_code(quotedFrom: author, cite: source)
end

#quote_parse(node, out) ⇒ Object



134
135
136
137
138
139
140
# File 'lib/isodoc/ietf/blocks.rb', line 134

def quote_parse(node, out)
  out.blockquote **quote_attribution(node) do |p|
    node.children.each do |n|
      parse(n, p) unless ["author", "source"].include? n.name
    end
  end
end

#recommendation_name(node, out) ⇒ Object



4
5
6
7
8
# File 'lib/isodoc/ietf/reqt.rb', line 4

def recommendation_name(node, out)
  out.t **{ keepWithNext: "true" } do |p|
    node.children.each { |n| parse(n, p) }
  end
end

#recommendation_parse(node, out) ⇒ Object



10
11
12
# File 'lib/isodoc/ietf/reqt.rb', line 10

def recommendation_parse(node, out)
  recommendation_parse1(node, out)
end

#recommendation_parse1(node, out) ⇒ Object



14
15
16
17
18
19
# File 'lib/isodoc/ietf/reqt.rb', line 14

def recommendation_parse1(node, out)
  recommendation_name(node.at(ns("./fmt-name")), out)
  node.children.each do |n|
    parse(n, out) if %w(name fmt-provision).include?(n.name)
  end
end

#references_check(xml) ⇒ Object

5.4.3 <reference> “target” Insertion

5.4.2.4  "Table of Contents" Insertion


79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/isodoc/ietf/validation.rb', line 79

def references_check(xml)
  ret = []
  xml.xpath("//reference[not(@target)]").each do |s|
    s.xpath(".//seriesInfo[@name = 'RFC' or @name = 'Internet-Draft' " \
            "or @name = 'DOI'][not(@value)]").each do |s1|
      ret << "for reference #{s['anchor']}, the seriesInfo with " \
             "name=#{s1['name']} has been given no value"
    end
  end
  xml.xpath("//references | //section").each do |s|
    s.at("./name") or ret << "Cannot generate table of contents entry " \
                             "for #{label(s)}, as it has no title"
  end
  ret
end

#rel2iana(type) ⇒ Object



115
116
117
118
119
120
121
122
123
124
# File 'lib/isodoc/ietf/section.rb', line 115

def rel2iana(type)
  case type
  when "includedIn" then "item"
  when "describedBy" then "describedby"
  when "derivedFrom" then "convertedfrom"
  when "instanceOf" then "alternate"
  else
    "alternate"
  end
end

#reparse_abstract(abstract) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/isodoc/ietf/cleanup.rb', line 75

def reparse_abstract(abstract)
  a1 = Nokogiri::XML(abstract.dup.to_xml
    .sub("<abstract>", "<abstract xmlns='http://www.example.com'>")).root
  noko do |xml|
    a1.children.each { |n| parse(n, xml) }
  end.join
end

#requirement_parse(node, out) ⇒ Object



21
22
23
# File 'lib/isodoc/ietf/reqt.rb', line 21

def requirement_parse(node, out)
  recommendation_parse1(node, out)
end

#review_note_parse(node, out) ⇒ Object



165
166
167
168
169
170
171
172
173
174
# File 'lib/isodoc/ietf/blocks.rb', line 165

def review_note_parse(node, out)
  out.cref **attr_code(anchor: node["id"], display: node["display"],
                       source: node["reviewer"], from: node["from"]) do |c|
    if name = node.at(ns("./name"))
      name.children.each { |n| parse(n, c) }
      c << " "
    end
    node.children.each { |n| parse(n, c) unless n.name == "name" }
  end
end

#rfc_attributes(docxml) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/isodoc/ietf/section.rb', line 55

def rfc_attributes(docxml)
  # t = Time.now.getutc
  obs = xpath_comma(docxml
    .xpath(ns("//bibdata/relation[@type = 'obsoletes']/bibitem/docidentifier[not(@scope)]")))
  upd = xpath_comma(docxml
    .xpath(ns("//bibdata/relation[@type = 'updates']/bibitem/docidentifier[not(@scope)]")))
  {
    docName: @meta.get[:doctype] == "Internet Draft" ? @meta.get[:docnumber] : nil,
    number: @meta.get[:doctype].casecmp?("rfc") ? @meta.get[:docnumber] : nil,
    category: series2category(
      docxml.at(ns("//bibdata/series[@type = 'intended']/title"))&.text,
    ),
    ipr: docxml.at(ns("//bibdata/ext/ipr"))&.text,
    consensus: docxml.at(ns("//bibdata/ext/consensus"))&.text,
    obsoletes: obs,
    updates: upd,
    indexInclude: docxml.at(ns("//bibdata/ext/indexInclude"))&.text,
    iprExtract: docxml.at(ns("//bibdata/ext/iprExtract"))&.text,
    sortRefs: docxml.at(ns("//bibdata/ext/sortRefs"))&.text,
    symRefs: docxml.at(ns("//bibdata/ext/symRefs"))&.text,
    tocInclude: docxml.at(ns("//bibdata/ext/tocInclude"))&.text,
    tocDepth: docxml.at(ns("//bibdata/ext/tocDepth"))&.text,
    submissionType: docxml.at(ns(
                                "//bibdata/series[@type = 'stream']/title",
                              ))&.text || "IETF",
    "xml:lang": docxml.at(ns("//bibdata/language"))&.text,
    version: "3",
    "xmlns:xi": "http://www.w3.org/2001/XInclude",
  }
end

#rfc_seriesinfo(isoxml, front) ⇒ Object



52
53
54
55
56
57
58
59
60
# File 'lib/isodoc/ietf/front.rb', line 52

def rfc_seriesinfo(isoxml, front)
  front.seriesInfo **seriesinfo_attr(isoxml).merge({ name: "RFC",
                                                     asciiName: "RFC" })
  i = isoxml&.at(ns("//bibdata/series[@type = 'intended']")) and
    front.seriesInfo nil,
                     **attr_code(name: "",
                                 status: i&.at(ns("./title"))&.text,
                                 value: i&.at(ns("./number"))&.text || "")
end

#schema_validate(filename) ⇒ Object



7
8
9
10
11
12
13
14
15
16
# File 'lib/isodoc/ietf/validation.rb', line 7

def schema_validate(filename)
  errors = Jing.new(File.join(File.dirname(__FILE__), "v3.rng"))
    .validate(filename)
  errors.each do |error|
    warn "RFC XML: Line #{'%06d' % error[:line]}:#{error[:column]} " \
         "#{error[:message]}"
  end
rescue Jing::Error => e
  abort "Jing failed with error: #{e}"
end

#semx_admitted_term_parse(node, out) ⇒ Object



34
35
36
# File 'lib/isodoc/ietf/terms.rb', line 34

def semx_admitted_term_parse(node, out)
  admitted_term_parse(node, out)
end

#semx_definition_parse(node, out) ⇒ Object



8
9
10
# File 'lib/isodoc/ietf/terms.rb', line 8

def semx_definition_parse(node, out)
  definition_parse(node, out)
end

#semx_deprecated_term_parse(node, out) ⇒ Object



22
23
24
# File 'lib/isodoc/ietf/terms.rb', line 22

def semx_deprecated_term_parse(node, out)
  deprecated_term_parse(node, out)
end

#semx_eref_parse(node, out) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/isodoc/ietf/inline.rb', line 140

def semx_eref_parse(node, out)
  linkend = node.children.reject do |c|
    %w{locality localityStack}.include? c.name
  end
  # section = "" unless relative.empty?
  out.xref **attr_code(target: node["bibitemid"],
                       section: eref_section(node),
                       relative: eref_relative(node),
                       sectionFormat: node["displayFormat"]) do |l|
    linkend.map(&:text).join.strip.empty? or
      linkend.each { |n| parse(n, l) }
  end
end


85
86
87
88
89
90
# File 'lib/isodoc/ietf/inline.rb', line 85

def semx_link_parse(node, out)
  out.eref **attr_code(target: node["target"],
                       brackets: node["style"]) do |l|
    children_parse(node, l)
  end
end

#semx_origin_parse(node, out) ⇒ Object



167
168
169
170
171
172
173
# File 'lib/isodoc/ietf/inline.rb', line 167

def semx_origin_parse(node, out)
  if t = node.at(ns("./termref"))
    termrefelem_parse(t, out)
  else
    semx_eref_parse(node, out)
  end
end

#semx_stem_parse(node, out) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/isodoc/ietf/inline.rb', line 63

def semx_stem_parse(node, out)
  stem = case node["type"]
         when "MathML"
           a = node.at(ns("./asciimath"))&.remove
           a&.children&.text ||
             Plurimath::Math
               .parse(node.children.to_xml, "mathml").to_asciimath
         else HTMLEntities.new.encode(node.text)
         end
  out << "#{@openmathdelim} #{stem} #{@closemathdelim}"
end

#semx_term_parse(node, out) ⇒ Object



45
46
47
# File 'lib/isodoc/ietf/terms.rb', line 45

def semx_term_parse(node, out)
  term_parse(node, out)
end

#semx_termref_parse(node, out) ⇒ Object



135
136
137
# File 'lib/isodoc/ietf/terms.rb', line 135

def semx_termref_parse(node, out)
  termref_parse(node, out)
end

#semx_xref_parse(node, out) ⇒ Object



122
123
124
125
126
127
# File 'lib/isodoc/ietf/inline.rb', line 122

def semx_xref_parse(node, out)
  out.xref **attr_code(target: node["target"], format: node["format"],
                       relative: node["relative"]) do |l|
                         l << get_linkend(node)
                       end
end

#series2category(series) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
# File 'lib/isodoc/ietf/section.rb', line 86

def series2category(series)
  case series&.downcase
  when "standard", "std", "full-standard" then "std"
  when "informational", "info", "fyi" then "info"
  when "experimental", "exp" then "exp"
  when "bcp" then "bcp"
  when "historic" then "historic"
  else
    "std"
  end
end

#seriesinfo(isoxml, front) ⇒ Object



39
40
41
42
# File 'lib/isodoc/ietf/front.rb', line 39

def seriesinfo(isoxml, front)
  rfc_seriesinfo(isoxml, front) if @meta.get[:doctype] == "Rfc"
  id_seriesinfo(isoxml, front) if @meta.get[:doctype] == "Internet Draft"
end

#seriesinfo_attr(isoxml) ⇒ Object



44
45
46
47
48
49
50
# File 'lib/isodoc/ietf/front.rb', line 44

def seriesinfo_attr(isoxml)
  attr_code(value: @meta.get[:docnumber] || "",
            asciiValue: output_if_translit(@meta.get[:docnumber]),
            status: @meta.get[:stage],
            stream: isoxml&.at(ns("//bibdata/series[@type = 'stream']/" \
                                  "title"))&.text)
end

#seriesInfo_check(xml) ⇒ Object

5.2.2. “seriesInfo” Insertion



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/isodoc/ietf/validation.rb', line 175

def seriesInfo_check(xml)
  ret = []
  xml.root["ipr"] == "none" and return []
  rfcinfo = xml.at("//front//seriesInfo[@name = 'RFC']")
  rfcnumber = xml.root["number"]
  rfcinfo && rfcnumber && rfcnumber != rfcinfo["value"] and
    ret << "Mismatch between <rfc number='#{rfcnumber}'> " \
           "(:docnumber: NUMBER) " \
           "and <seriesInfo name='RFC' value='#{rfcinfo['value']}'> " \
           "(:intended-series: TYPE NUMBER)"
  rfcinfo && !/^\d+$/.match(rfcnumber) and
    ret << "RFC identifier <rfc number='#{rfcnumber}'> " \
           "(:docnumber: NUMBER) must be a number"
  ret
end

#set_pis(node, doc) ⇒ Object



45
46
47
48
49
50
51
52
53
# File 'lib/isodoc/ietf/section.rb', line 45

def set_pis(node, doc)
  rfc_pis = common_rfc_pis(node)
  rfc_pis.each_pair do |k, v|
    pi = Nokogiri::XML::ProcessingInstruction.new(doc, "rfc",
                                                  "#{k}=\"#{v}\"")
    doc.root.add_previous_sibling(pi)
  end
  doc.to_xml
end

#set_termdomain(termdomain) ⇒ Object



4
5
6
# File 'lib/isodoc/ietf/terms.rb', line 4

def set_termdomain(termdomain)
  @termdomain = termdomain
end

#smallcap_parse(node, out) ⇒ Object



48
49
50
# File 'lib/isodoc/ietf/inline.rb', line 48

def smallcap_parse(node, out)
  children_parse(node, out)
end

#source_parse(node, out) ⇒ Object



60
61
62
# File 'lib/isodoc/ietf/blocks.rb', line 60

def source_parse(node, out)
  termref_parse(node, out)
end

#sourcecode_cleanup(docxml) ⇒ Object

for markup in pseudocode



99
100
101
102
103
104
105
106
107
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 99

def sourcecode_cleanup(docxml)
  docxml.xpath("//sourcecode").each do |s|
    s.children = to_xml(s.children).gsub(%r{<br/>\n}, "\n")
      .gsub(%r{\s+(<t[ >])}, "\\1").gsub(%r{</t>\s+}, "</t>")
    sourcecode_remove_markup(s)
    s.children = "<![CDATA[#{@c.decode(to_xml(s.children)
      .sub(/\A\n+/, ''))}]]>"
  end
end

#sourcecode_parse(node, out) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/isodoc/ietf/blocks.rb', line 64

def sourcecode_parse(node, out)
  b = node.at(ns("./body"))
  out.sourcecode **attr_code(
    anchor: node["id"], type: node["lang"], name: node["filename"],
    markers: node["markers"], src: node["src"]
  ) do |s|
    b&.children&.each do |x|
      parse(x, s)
    end
  end
  annotation_parse(node, out)
end

#sourcecode_remove_markup(node) ⇒ Object



109
110
111
112
113
114
115
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 109

def sourcecode_remove_markup(node)
  node.traverse do |n|
    n.text? and next
    %w(name callout annotation note sourcecode).include? n.name and next
    sourcecode_remove_markup_elem(n)
  end
end

#sourcecode_remove_markup_elem(node) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 117

def sourcecode_remove_markup_elem(node)
  case node.name
  when "br" then node.replace("\n")
  when "t" then node.replace("\n\n#{node.children}")
  when "eref"
    node.replace(node.children.empty? ? node["target"] : node.children)
  when "xref"
    node.children.empty? ? sourcecode_xref(node) : node.replace(node.children)
    # when "relref" then n.replace(n.children.empty? ? n["target"] : n.children)
  else node.replace(node.children)
  end
end

#sourcecode_xref(node) ⇒ Object



130
131
132
133
134
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 130

def sourcecode_xref(node)
  ret = @xrefs.anchor(node["target"], :xref, false)&.gsub(%r{<[^>]+>}, "")
  s = node["section"] and ret += ", Section #{s}"
  node.replace(ret)
end

#span_parse(node, out) ⇒ Object



185
186
187
188
189
190
191
# File 'lib/isodoc/ietf/inline.rb', line 185

def span_parse(node, out)
  if node["class"] == "bcp14"
    bcp14_parse(node, out)
  else
    children_parse(node, out)
  end
end

#strike_parse(node, out) ⇒ Object



44
45
46
# File 'lib/isodoc/ietf/inline.rb', line 44

def strike_parse(node, out)
  children_parse(node, out)
end

#strong_parse(node, out) ⇒ Object



28
29
30
31
32
# File 'lib/isodoc/ietf/inline.rb', line 28

def strong_parse(node, out)
  out.strong do |e|
    children_parse(node, e)
  end
end

#sub_parse(node, out) ⇒ Object



16
17
18
19
20
# File 'lib/isodoc/ietf/inline.rb', line 16

def sub_parse(node, out)
  out.sub do |e|
    children_parse(node, e)
  end
end

#sup_parse(node, out) ⇒ Object



10
11
12
13
14
# File 'lib/isodoc/ietf/inline.rb', line 10

def sup_parse(node, out)
  out.sup do |e|
    children_parse(node, e)
  end
end

#svg_parse(node, out) ⇒ Object



112
113
114
115
116
117
118
119
120
# File 'lib/isodoc/ietf/inline.rb', line 112

def svg_parse(node, out)
  if node.parent.name == "image" then super
  else
    out.artwork **attr_code(image_parse_attrs(node)) do |x|
      out = x
      super
    end
  end
end

#table_attrs(node) ⇒ Object



4
5
6
# File 'lib/isodoc/ietf/table.rb', line 4

def table_attrs(node)
  attr_code(anchor: node["id"], align: node["align"])
end

#table_cleanup(docxml) ⇒ Object



27
28
29
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 27

def table_cleanup(docxml)
  table_footnote_cleanup(docxml)
end

#table_footnote_cleanup(docxml) ⇒ Object



11
12
13
14
15
16
17
# File 'lib/isodoc/ietf/cleanup_blocks.rb', line 11

def table_footnote_cleanup(docxml)
  docxml.xpath("//table[descendant::fn]").each do |t|
    t.xpath(".//fn").each do |a|
      t << "<aside>#{a.remove.children}</aside>"
    end
  end
end

#table_footnote_parse(node, out) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/isodoc/ietf/footnotes.rb', line 35

def table_footnote_parse(node, out)
  fn = node["reference"]
  tid = get_table_ancestor_id(node)
  make_table_footnote_link(out, tid + fn, fn)
  # do not output footnote text if we have already seen it for this table
  return if @seen_footnote.include?(tid + fn)

  @in_footnote = true
  out.fn do |a|
    a << make_table_footnote_text(node, tid + fn, fn)
  end
  @in_footnote = false
  @seen_footnote << (tid + fn)
end

#table_parse(node, out) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
# File 'lib/isodoc/ietf/table.rb', line 8

def table_parse(node, out)
  @in_table = true
  out.table **table_attrs(node) do |t|
    table_title_parse(node, t)
    thead_parse(node, t)
    tbody_parse(node, t)
    tfoot_parse(node, t)
  end
  table_parse_tail(node, out)
  @in_table = false
end

#table_parse_tail(node, out) ⇒ Object



20
21
22
23
24
# File 'lib/isodoc/ietf/table.rb', line 20

def table_parse_tail(node, out)
  (dl = node.at(ns("./dl"))) && parse(dl, out)
  node.xpath(ns("./source")).each { |n| parse(n, out) }
  node.xpath(ns("./note")).each { |n| parse(n, out) }
end

#table_title_parse(node, out) ⇒ Object



26
27
28
29
30
31
# File 'lib/isodoc/ietf/table.rb', line 26

def table_title_parse(node, out)
  name = node.at(ns("./name")) || return
  out.name do |p|
    name.children.each { |n| parse(n, p) }
  end
end

#term_parse(node, out) ⇒ Object



49
50
51
52
53
54
55
56
57
58
# File 'lib/isodoc/ietf/terms.rb', line 49

def term_parse(node, out)
  if domain = node.at(ns("./domain"))
    set_termdomain(domain.text)
    domain["hidden"] = "true"
  end
  name = node.at(ns(".//name"))
  out.name do |p|
    name.children.each { |n| parse(n, p) }
  end
end

#termdef_parse(node, out) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/isodoc/ietf/terms.rb', line 64

def termdef_parse(node, out)
  if domain = node.at(ns("./domain"))
    set_termdomain(domain.text)
    domain["hidden"] = "true"
  else
    set_termdomain("")
  end
  node.xpath(ns("./definition")).size > 1 and
    multidef(node)
  clause_parse(node, out)
end

#termdocsource_parse(_node, _out) ⇒ Object



86
# File 'lib/isodoc/ietf/terms.rb', line 86

def termdocsource_parse(_node, _out); end

#termnote_parse(node, out) ⇒ Object



60
61
62
# File 'lib/isodoc/ietf/terms.rb', line 60

def termnote_parse(node, out)
  note_parse(node, out)
end

#termref_parse(elem, out) ⇒ Object



139
140
141
142
143
144
145
# File 'lib/isodoc/ietf/terms.rb', line 139

def termref_parse(elem, out)
  preprocess_termref(elem)
  elem.children = l10n("[#{@i18n.source}: #{to_xml(elem.children).strip}]")
  out.t do |p|
    elem.children.each { |n| parse(n, p) }
  end
end

#termsource_add_modification_text(mod) ⇒ Object



118
119
120
121
122
123
124
# File 'lib/isodoc/ietf/terms.rb', line 118

def termsource_add_modification_text(mod)
  mod or return
  mod.text.strip.empty? or mod.previous = " &#x2014; "
  mod.elements.size == 1 and
    mod.elements[0].replace(mod.elements[0].children)
  mod.replace(mod.children)
end

#termsource_status(status) ⇒ Object



111
112
113
114
115
116
# File 'lib/isodoc/ietf/terms.rb', line 111

def termsource_status(status)
  case status
  when "modified" then @i18n.modified
  when "adapted" then @i18n.adapted
  end
end

#text_parse(node, out) ⇒ Object



56
57
58
59
60
61
# File 'lib/isodoc/ietf/inline.rb', line 56

def text_parse(node, out)
  return if node.nil? || node.text.nil?

  text = node.to_s
  out << text
end

#textcleanup(docxml) ⇒ Object



88
89
90
# File 'lib/isodoc/ietf/rfc_convert.rb', line 88

def textcleanup(docxml)
  passthrough_cleanup(docxml)
end

#title(_isoxml, front) ⇒ Object



32
33
34
35
36
37
# File 'lib/isodoc/ietf/front.rb', line 32

def title(_isoxml, front)
  title = @meta.get[:doctitle] or return
  front.title title, **attr_code(abbrev: @meta.get[:docabbrev],
                                 ascii: @meta.get[:docascii] ||
                                 output_if_translit(title))
end

#toc_parse(_node, _out) ⇒ Object



208
# File 'lib/isodoc/ietf/blocks.rb', line 208

def toc_parse(_node, _out); end

#toc_sections_check(xml) ⇒ Object

5.2.7. Section “toc” attribute



66
67
68
69
70
71
72
73
74
75
# File 'lib/isodoc/ietf/validation.rb', line 66

def toc_sections_check(xml)
  ret = []
  xml.xpath("//section[@toc = 'exclude']").each do |s1|
    s1.xpath(".//section[@toc = 'include']").each do |s2|
      ret << "Section #{label(s2)} with toc=include is included in " \
             "section #{label(s1)} with toc=exclude"
    end
  end
  ret
end

#tr_parse(node, out, ord, totalrows, header) ⇒ Object



33
34
35
36
37
38
39
40
41
42
# File 'lib/isodoc/ietf/table.rb', line 33

def tr_parse(node, out, ord, totalrows, header)
  out.tr do |r|
    node.elements.each do |td|
      attrs = make_tr_attr(td, ord, totalrows - 1, header)
      r.send td.name, **attrs do |entry|
        td.children.each { |n| parse(n, entry) }
      end
    end
  end
end

#tt_parse(node, out) ⇒ Object



22
23
24
25
26
# File 'lib/isodoc/ietf/inline.rb', line 22

def tt_parse(node, out)
  out.tt do |e|
    children_parse(node, e)
  end
end

#u_cleanup(xmldoc) ⇒ Object



4
5
6
7
8
9
10
11
12
# File 'lib/isodoc/ietf/cleanup_inline.rb', line 4

def u_cleanup(xmldoc)
  xmldoc.traverse do |n|
    n.text? or next
    %w(t blockquote li dd preamble td th annotation)
      .include? n.parent.name or next
    n.replace(@c.encode(n.text, :basic).gsub(/[\u0080-\uffff]/,
                                             "<u>\\0</u>"))
  end
end

#ul_attrs(node) ⇒ Object



4
5
6
7
8
# File 'lib/isodoc/ietf/lists.rb', line 4

def ul_attrs(node)
  { anchor: node["id"], empty: node["nobullet"],
    indent: node["indent"], bare: node["bare"],
    spacing: node["spacing"] }
end

#ul_parse(node, out) ⇒ Object



10
11
12
13
14
# File 'lib/isodoc/ietf/lists.rb', line 10

def ul_parse(node, out)
  out.ul **attr_code(ul_attrs(node)) do |ul|
    node.children.each { |n| parse(n, ul) }
  end
end

#workgroup(_isoxml, front) ⇒ Object



209
210
211
212
213
# File 'lib/isodoc/ietf/front.rb', line 209

def workgroup(_isoxml, front)
  @meta.get[:wg].each do |w|
    front.workgroup w
  end
end

#xpath_comma(xpath) ⇒ Object



98
99
100
101
102
# File 'lib/isodoc/ietf/section.rb', line 98

def xpath_comma(xpath)
  return nil if xpath.empty?

  xpath.map(&:text).join(", ")
end

#xref_check(xml) ⇒ Object

5.4.8.2. “derivedContent” Insertion (without Content)



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/isodoc/ietf/validation.rb', line 96

def xref_check(xml)
  ret = []
  xml.xpath("//xref | //relref").each do |x|
    t = xml.at(".//*[@anchor = '#{x['target']}']") ||
      xml.at(".//*[@pn = '#{x['target']}']") or
      ret << "#{x.name} target #{x['target']} does not exist in the document"
    next unless t

    x.delete("relative") if x["relative"] && x["relative"].empty?
    x.delete("section") if x["section"] && x["section"].empty?
    if x["format"] == "title" && t.name == "reference"
      t.at("./front/title") or
        ret << "reference #{t['anchor']} has been referenced by #{x.name} " \
               "with format=title, but the reference has no title"
    end
    if x["format"] == "counter" && !%w(section table figure li
                                       reference references t dt).include?(t.name)
      ret << "#{x.to_xml} with format=counter is only allowed for " \
             "clauses, tables, figures, list entries, definition terms, " \
             "paragraphs, bibliographies, and bibliographic entries"
    end
    if x["format"] == "counter" && t.name == "reference" && !x["section"]
      ret << "reference #{t['anchor']} has been referenced by xref " \
             "#{x.to_xml} with format=counter, which requires a " \
             "section attribute"
    end
    if x["format"] == "counter" && t.name == "li" && t.parent.name != "ol"
      ret << "#{x.to_xml} with format=counter refers to an unnumbered " \
             "list entry"
    end
    if x["format"] == "title" && %w(u author contact).include?(t.name)
      ret << "#{x.to_xml} with format=title cannot reference a " \
             "<#{t.name}> element"
    end
    if x["relative"] && !x["section"]
      ret << "#{x.to_xml} with relative attribute requires a section " \
             "attribute"
    end
    if (x["section"]) && t.name != "reference"
      ret << "#{x.to_xml} has a section attribute, but #{x['target']} " \
             "points to a #{t.name}"
    end
    if (x["relative"]) && t.name != "reference"
      ret << "#{x.to_xml} has a relative attribute, but #{x['target']} " \
             "points to a #{t.name}"
    end
    if !x["relative"] && x["section"] && !t.at(".//seriesInfo[@name = 'RFC' or @name = " \
                                               "'Internet-Draft']")
      ret << "#{x.to_xml} must use a relative attribute, " \
             "since it does not point to a RFC or Internet-Draft reference"
    end
    if x["relative"] && !(t.at(".//seriesInfo[@name = 'RFC' or @name = " \
                               "'Internet-Draft']") || t["target"])
      ret << "need an explicit target= URL attribute in the reference " \
             "pointed to by #{x.to_xml}"
    end
  end
  ret
end

#xref_init(lang, script, klass, i18n, options) ⇒ Object



53
54
55
# File 'lib/isodoc/ietf/rfc_convert.rb', line 53

def xref_init(lang, script, klass, i18n, options)
  @xrefs = Xref.new(lang, script, klass, i18n, options)
end