metanorma-ietf 2.4.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/asciidoctor/ietf/isodoc.rng +23 -9
- data/lib/asciidoctor/ietf/reqt.rng +15 -4
- data/lib/isodoc/ietf/blocks.rb +181 -174
- data/lib/isodoc/ietf/references.rb +139 -129
- data/lib/isodoc/ietf/validation.rb +158 -157
- data/lib/metanorma/ietf/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: def69cf551c6c50fcb28fcdf04ab02e0d3d9cf83ba3dcd81114c41f71860599f
|
4
|
+
data.tar.gz: 5afc33bb93c93fbc86565d984562a3a61ed02b700e0a1e66a70f47289ef230c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a2c6f8d47d875c1fb896d1fffdc5d5f789c05a679ab474ae7dfbc52795b9df47eb4763164f08c2da964c0de53ad51f91233ea230a8bce9553a31986f19bf4cd
|
7
|
+
data.tar.gz: eb7fbd7913907b01e95f07bd2b28058b1d8c953f5f9b8b8a9c81a6c1638319fbb2ce8f593a3d83970b5ea748fbf34b7d0ba60b73ea5fa8f9c1a41e3076aec6ac
|
@@ -32,6 +32,18 @@
|
|
32
32
|
<ref name="DocumentType"/>
|
33
33
|
</element>
|
34
34
|
</define>
|
35
|
+
<define name="section-title">
|
36
|
+
<element name="title">
|
37
|
+
<zeroOrMore>
|
38
|
+
<ref name="TextElement"/>
|
39
|
+
</zeroOrMore>
|
40
|
+
</element>
|
41
|
+
<zeroOrMore>
|
42
|
+
<element name="variant-title">
|
43
|
+
<ref name="TypedTitleString"/>
|
44
|
+
</element>
|
45
|
+
</zeroOrMore>
|
46
|
+
</define>
|
35
47
|
<define name="hyperlink">
|
36
48
|
<element name="link">
|
37
49
|
<attribute name="target">
|
@@ -158,15 +170,17 @@
|
|
158
170
|
<data type="boolean"/>
|
159
171
|
</attribute>
|
160
172
|
</optional>
|
161
|
-
<
|
162
|
-
<
|
163
|
-
<
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
173
|
+
<optional>
|
174
|
+
<attribute name="type">
|
175
|
+
<choice>
|
176
|
+
<value>roman</value>
|
177
|
+
<value>alphabet</value>
|
178
|
+
<value>arabic</value>
|
179
|
+
<value>roman_upper</value>
|
180
|
+
<value>alphabet_upper</value>
|
181
|
+
</choice>
|
182
|
+
</attribute>
|
183
|
+
</optional>
|
170
184
|
<oneOrMore>
|
171
185
|
<ref name="li"/>
|
172
186
|
</oneOrMore>
|
@@ -64,9 +64,9 @@
|
|
64
64
|
<optional>
|
65
65
|
<ref name="label"/>
|
66
66
|
</optional>
|
67
|
-
<
|
67
|
+
<zeroOrMore>
|
68
68
|
<ref name="subject"/>
|
69
|
-
</
|
69
|
+
</zeroOrMore>
|
70
70
|
<zeroOrMore>
|
71
71
|
<ref name="reqinherit"/>
|
72
72
|
</zeroOrMore>
|
@@ -80,6 +80,7 @@
|
|
80
80
|
<ref name="verification"/>
|
81
81
|
<ref name="import"/>
|
82
82
|
<ref name="description"/>
|
83
|
+
<ref name="component"/>
|
83
84
|
</choice>
|
84
85
|
</zeroOrMore>
|
85
86
|
<optional>
|
@@ -105,12 +106,16 @@
|
|
105
106
|
</define>
|
106
107
|
<define name="subject">
|
107
108
|
<element name="subject">
|
108
|
-
<
|
109
|
+
<oneOrMore>
|
110
|
+
<ref name="TextElement"/>
|
111
|
+
</oneOrMore>
|
109
112
|
</element>
|
110
113
|
</define>
|
111
114
|
<define name="reqinherit">
|
112
115
|
<element name="inherit">
|
113
|
-
<
|
116
|
+
<oneOrMore>
|
117
|
+
<ref name="TextElement"/>
|
118
|
+
</oneOrMore>
|
114
119
|
</element>
|
115
120
|
</define>
|
116
121
|
<define name="measurementtarget">
|
@@ -138,6 +143,12 @@
|
|
138
143
|
<ref name="RequirementSubpart"/>
|
139
144
|
</element>
|
140
145
|
</define>
|
146
|
+
<define name="component">
|
147
|
+
<element name="component">
|
148
|
+
<attribute name="class"/>
|
149
|
+
<ref name="RequirementSubpart"/>
|
150
|
+
</element>
|
151
|
+
</define>
|
141
152
|
<define name="reqt_references">
|
142
153
|
<element name="references">
|
143
154
|
<oneOrMore>
|
data/lib/isodoc/ietf/blocks.rb
CHANGED
@@ -1,229 +1,236 @@
|
|
1
|
-
module IsoDoc
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
1
|
+
module IsoDoc
|
2
|
+
module Ietf
|
3
|
+
class RfcConvert < ::IsoDoc::Convert
|
4
|
+
def para_attrs(node)
|
5
|
+
{ keepWithNext: node["keep-with-next"],
|
6
|
+
keepWithPrevious: node["keep-with-previous"],
|
7
|
+
anchor: node["id"] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def para_parse(node, out)
|
11
|
+
out.t **attr_code(para_attrs(node)) do |p|
|
12
|
+
unless @termdomain.empty?
|
13
|
+
p << "<#{@termdomain}> "
|
14
|
+
@termdomain = ""
|
15
|
+
end
|
16
|
+
node.children.each { |n| parse(n, p) unless n.name == "note" }
|
14
17
|
end
|
15
|
-
node.
|
18
|
+
node.xpath(ns("./note")).each { |n| parse(n, out) }
|
16
19
|
end
|
17
|
-
node.xpath(ns("./note")).each { |n| parse(n, out) }
|
18
|
-
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
# NOTE ignoring "bare" attribute, which is tantamount to "empty"
|
22
|
+
def ul_attrs(node)
|
23
|
+
{ anchor: node["id"],
|
24
|
+
empty: node["nobullet"],
|
25
|
+
spacing: node["spacing"] }
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
def ul_parse(node, out)
|
29
|
+
out.ul **attr_code(ul_attrs(node)) do |ul|
|
30
|
+
node.children.each { |n| parse(n, ul) }
|
31
|
+
end
|
30
32
|
end
|
31
|
-
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
OL_STYLE = {
|
35
|
+
arabic: "1",
|
36
|
+
roman: "i",
|
37
|
+
alphabet: "a",
|
38
|
+
roman_upper: "I",
|
39
|
+
alphabet_upper: "A",
|
40
|
+
}.freeze
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
def ol_style(type)
|
43
|
+
OL_STYLE[type&.to_sym] || type
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
def ol_attrs(node)
|
47
|
+
{ anchor: node["id"],
|
48
|
+
spacing: node["spacing"],
|
49
|
+
type: ol_style(node["type"]),
|
50
|
+
group: node["group"],
|
51
|
+
start: node["start"] }
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
def ol_parse(node, out)
|
55
|
+
out.ol **attr_code(ol_attrs(node)) do |ol|
|
56
|
+
node.children.each { |n| parse(n, ol) }
|
57
|
+
end
|
56
58
|
end
|
57
|
-
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
60
|
+
def dl_attrs(node)
|
61
|
+
attr_code(anchor: node["id"],
|
62
|
+
newline: node["newline"],
|
63
|
+
indent: node["indent"],
|
64
|
+
spacing: node["spacing"])
|
65
|
+
end
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
def dt_parse(dt, term)
|
68
|
+
if dt.elements.empty?
|
69
|
+
term << dt.text
|
70
|
+
else
|
71
|
+
dt.children.each { |n| parse(n, term) }
|
72
|
+
end
|
71
73
|
end
|
72
|
-
end
|
73
74
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
75
|
+
def note_label(node)
|
76
|
+
n = @xrefs.get[node["id"]]
|
77
|
+
return l10n("#{@i18n.note}: ") if n.nil? || n[:label].nil? ||
|
78
|
+
n[:label].empty?
|
78
79
|
|
79
|
-
|
80
|
-
|
80
|
+
l10n("#{@i18n.note} #{n[:label]}: ")
|
81
|
+
end
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
83
|
+
def note_parse(node, out)
|
84
|
+
first = node.first_element_child
|
85
|
+
out.aside **attr_code(anchor: node["id"] || first["id"]) do |a|
|
86
|
+
a.t do |p|
|
87
|
+
p << note_label(node)
|
88
|
+
first.name == "p" and first.children.each { |n| parse(n, p) }
|
89
|
+
end
|
90
|
+
first.name == "p" and
|
91
|
+
node.elements.drop(1).each { |n| parse(n, out) } or
|
92
|
+
node.children.each { |n| parse(n, out) }
|
88
93
|
end
|
89
|
-
first.name == "p" and
|
90
|
-
node.elements.drop(1).each { |n| parse(n, out) } or
|
91
|
-
node.children.each { |n| parse(n, out) }
|
92
94
|
end
|
93
|
-
end
|
94
95
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
96
|
+
def example_parse(node, out)
|
97
|
+
example_label(node, out, node.at(ns("./name")))
|
98
|
+
node.elements.each { |n| parse(n, out) unless n.name == "name" }
|
99
|
+
end
|
99
100
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
101
|
+
def example_label(node, div, name)
|
102
|
+
n = @xrefs.get[node["id"]]
|
103
|
+
div.t **attr_code(anchor: node["id"], keepWithNext: "true") do |p|
|
104
|
+
lbl = if n.nil? || n[:label].nil? || n[:label].empty?
|
105
|
+
@i18n.example
|
106
|
+
else
|
107
|
+
l10n("#{@i18n.example} #{n[:label]}")
|
108
|
+
end
|
109
|
+
p << lbl
|
110
|
+
name and !lbl.nil? and p << ": "
|
111
|
+
name and name.children.each { |n| parse(n, p) }
|
112
|
+
end
|
108
113
|
end
|
109
|
-
end
|
110
114
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
115
|
+
def sourcecode_parse(node, out)
|
116
|
+
out.sourcecode **attr_code(
|
117
|
+
anchor: node["id"], type: node["lang"], name: node["filename"],
|
118
|
+
markers: node["markers"], src: node["src"]
|
119
|
+
) do |s|
|
120
|
+
node.children.each { |x| parse(x, s) unless x.name == "name" }
|
121
|
+
end
|
117
122
|
end
|
118
|
-
end
|
119
123
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
+
def pre_parse(node, out)
|
125
|
+
out.artwork **attr_code(anchor: node["id"], align: node["align"],
|
126
|
+
alt: node["alt"], type: "ascii-art") do |s|
|
127
|
+
s.cdata node.text.sub(/^\n/, "").gsub(/\t/, " ")
|
128
|
+
end
|
124
129
|
end
|
125
|
-
end
|
126
130
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
131
|
+
def annotation_parse(node, out)
|
132
|
+
@sourcecode = false
|
133
|
+
@annotation = true
|
134
|
+
node.at("./preceding-sibling::*[local-name() = 'annotation']") or
|
135
|
+
out << "\n\n"
|
136
|
+
callout = node.at(ns("//callout[@target='#{node['id']}']"))
|
137
|
+
out << "\n<#{callout.text}> "
|
138
|
+
out << node&.children&.text&.strip
|
139
|
+
@annotation = false
|
140
|
+
end
|
137
141
|
|
138
|
-
|
139
|
-
|
142
|
+
def formula_where(dl, out)
|
143
|
+
return unless dl
|
140
144
|
|
141
|
-
|
142
|
-
|
143
|
-
|
145
|
+
out.t { |p| p << @i18n.where }
|
146
|
+
parse(dl, out)
|
147
|
+
end
|
144
148
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
149
|
+
def formula_parse1(node, out)
|
150
|
+
out.t **attr_code(anchor: node["id"]) do |p|
|
151
|
+
parse(node.at(ns("./stem")), p)
|
152
|
+
lbl = @xrefs.anchor(node["id"], :label, false)
|
153
|
+
lbl.nil? or
|
154
|
+
p << " (#{lbl})"
|
155
|
+
end
|
151
156
|
end
|
152
|
-
end
|
153
157
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
158
|
+
def formula_parse(node, out)
|
159
|
+
formula_parse1(node, out)
|
160
|
+
formula_where(node.at(ns("./dl")), out)
|
161
|
+
node.children.each do |n|
|
162
|
+
next if %w(stem dl).include? n.name
|
159
163
|
|
160
|
-
|
164
|
+
parse(n, out)
|
165
|
+
end
|
161
166
|
end
|
162
|
-
end
|
163
167
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
168
|
+
def quote_attribution(node)
|
169
|
+
author = node&.at(ns("./author"))&.text
|
170
|
+
source = node&.at(ns("./source/@uri"))&.text
|
171
|
+
attr_code(quotedFrom: author, cite: source)
|
172
|
+
end
|
169
173
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
+
def quote_parse(node, out)
|
175
|
+
out.blockquote **quote_attribution(node) do |p|
|
176
|
+
node.children.each do |n|
|
177
|
+
parse(n, p) unless ["author", "source"].include? n.name
|
178
|
+
end
|
174
179
|
end
|
175
180
|
end
|
176
|
-
end
|
177
181
|
|
178
|
-
|
179
|
-
|
180
|
-
|
182
|
+
def admonition_name_parse(_node, div, name)
|
183
|
+
div.t **{ keepWithNext: "true" } do |p|
|
184
|
+
name.children.each { |n| parse(n, p) }
|
185
|
+
end
|
181
186
|
end
|
182
|
-
end
|
183
187
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
188
|
+
def admonition_parse(node, out)
|
189
|
+
type = node["type"]
|
190
|
+
name = admonition_name(node, type)
|
191
|
+
out.aside **{ anchor: node["id"] } do |t|
|
192
|
+
admonition_name_parse(node, t, name) if name
|
193
|
+
node.children.each { |n| parse(n, t) unless n.name == "name" }
|
194
|
+
end
|
190
195
|
end
|
191
|
-
end
|
192
196
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
197
|
+
def review_note_parse(node, out)
|
198
|
+
out.cref **attr_code(anchor: node["id"], display: node["display"],
|
199
|
+
source: node["reviewer"]) do |c|
|
200
|
+
name = node.at(ns("./name")) and c.name do |div|
|
201
|
+
name.children.each { |n| parse(n, div) }
|
202
|
+
end
|
203
|
+
node.children.each { |n| parse(n, c) unless n.name == "name" }
|
198
204
|
end
|
199
|
-
node.children.each { |n| parse(n, c) unless n.name == "name" }
|
200
205
|
end
|
201
|
-
end
|
202
206
|
|
203
|
-
|
204
|
-
|
207
|
+
def figure_name_parse(_node, div, name)
|
208
|
+
return if name.nil?
|
205
209
|
|
206
|
-
|
207
|
-
|
210
|
+
div.name do |_n|
|
211
|
+
name.children.each { |n| parse(n, div) }
|
212
|
+
end
|
208
213
|
end
|
209
|
-
end
|
210
214
|
|
211
|
-
|
212
|
-
|
213
|
-
|
215
|
+
def pseudocode_parse(node, out)
|
216
|
+
sourcecode_parse(node, out)
|
217
|
+
end
|
214
218
|
|
215
|
-
|
216
|
-
|
217
|
-
|
219
|
+
def figure_parse(node, out)
|
220
|
+
return pseudocode_parse(node, out) if node["class"] == "pseudocode" ||
|
221
|
+
node["type"] == "pseudocode"
|
218
222
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
223
|
+
@in_figure = true
|
224
|
+
out.figure **attr_code(anchor: node["id"]) do |div|
|
225
|
+
figure_name_parse(node, div, node.at(ns("./name")))
|
226
|
+
node.children.each do |n|
|
227
|
+
parse(n, div) unless n.name == "name"
|
228
|
+
end
|
224
229
|
end
|
230
|
+
@in_figure = false
|
225
231
|
end
|
226
|
-
|
232
|
+
|
233
|
+
def toc_parse(_node, _out); end
|
227
234
|
end
|
228
235
|
end
|
229
236
|
end
|
@@ -1,164 +1,174 @@
|
|
1
|
-
module IsoDoc
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
isoxml
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
module IsoDoc
|
2
|
+
module Ietf
|
3
|
+
class RfcConvert < ::IsoDoc::Convert
|
4
|
+
# TODO displayreference will be implemented as combination of autofetch and user-provided citations
|
5
|
+
|
6
|
+
def bibliography(isoxml, out)
|
7
|
+
isoxml.xpath(ns("//references/bibitem/docidentifier")).each do |i|
|
8
|
+
i.children = docid_prefix(i["type"], i.text)
|
9
|
+
end
|
10
|
+
isoxml.xpath(ns("//bibliography/references | "\
|
11
|
+
"//bibliography/clause[.//references] | "\
|
12
|
+
"//annex/clause[.//references] | "\
|
13
|
+
"//annex/references | "\
|
14
|
+
"//sections/clause[.//references]")).each do |f|
|
15
|
+
bibliography1(f, out)
|
16
|
+
end
|
15
17
|
end
|
16
|
-
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
def bibliography1(node, out)
|
20
|
+
out.references **attr_code(anchor: node["id"]) do |div|
|
21
|
+
title = node.at(ns("./title")) and div.name do |name|
|
22
|
+
title.children.each { |n| parse(n, name) }
|
23
|
+
end
|
24
|
+
node.elements.select do |e|
|
25
|
+
%w(references clause).include? e.name
|
26
|
+
end.each { |e| bibliography1(e, out) }
|
27
|
+
node.elements.reject do |e|
|
28
|
+
%w(references title bibitem note).include? e.name
|
29
|
+
end.each { |e| parse(e, div) }
|
30
|
+
biblio_list(node, div, true)
|
22
31
|
end
|
23
|
-
f.elements.select do |e|
|
24
|
-
%w(references clause).include? e.name
|
25
|
-
end.each { |e| bibliography1(e, out) }
|
26
|
-
f.elements.reject do |e|
|
27
|
-
%w(references title bibitem note).include? e.name
|
28
|
-
end.each { |e| parse(e, div) }
|
29
|
-
biblio_list(f, div, true)
|
30
32
|
end
|
31
|
-
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
def biblio_list(node, div, biblio)
|
35
|
+
i = 0
|
36
|
+
node.xpath(ns("./bibitem | ./note")).each do |b|
|
37
|
+
next if implicit_reference(b)
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
i += 1 if b.name == "bibitem"
|
40
|
+
if b.name == "note" then note_parse(b, div)
|
41
|
+
elsif ietf?(b) then ietf_bibitem_entry(div, b, i)
|
42
|
+
else
|
43
|
+
nonstd_bibitem(div, b, i, biblio)
|
44
|
+
end
|
43
45
|
end
|
44
46
|
end
|
45
|
-
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
docidentifiers = b.xpath(ns("./docidentifier"))
|
66
|
-
id = render_identifier(bibitem_ref_code(b))
|
67
|
-
!id[1].nil? and id[1] != "(NO ID)" and
|
68
|
-
r.refcontent id[1]
|
69
|
-
docidentifiers&.each do |u|
|
70
|
-
if %w(DOI IETF).include? u["type"]
|
71
|
-
r.seriesInfo nil, **attr_code(value: u.text.sub(/^DOI /, ""),
|
72
|
-
name: u["type"])
|
48
|
+
def nonstd_bibitem(list, bib, _ordinal, _bibliography)
|
49
|
+
uris = bib.xpath(ns("./uri"))
|
50
|
+
target = nil
|
51
|
+
uris&.each { |u| target = u.text if u["type"] == "src" }
|
52
|
+
list.reference **attr_code(target: target,
|
53
|
+
anchor: bib["id"]) do |r|
|
54
|
+
nonstd_bibitem_front(r, bib)
|
55
|
+
uris&.each do |u|
|
56
|
+
r.format nil, **attr_code(target: u.text, type: u["type"])
|
57
|
+
end
|
58
|
+
docidentifiers = bib.xpath(ns("./docidentifier"))
|
59
|
+
id = render_identifier(bibitem_ref_code(bib))
|
60
|
+
!id[1].nil? && id[1] != "(NO ID)" and r.refcontent id[1]
|
61
|
+
docidentifiers&.each do |u|
|
62
|
+
if %w(DOI IETF).include? u["type"]
|
63
|
+
r.seriesInfo nil, **attr_code(value: u.text.sub(/^DOI /, ""),
|
64
|
+
name: u["type"])
|
65
|
+
end
|
73
66
|
end
|
74
67
|
end
|
75
68
|
end
|
76
|
-
end
|
77
69
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
70
|
+
def nonstd_bibitem_front(ref, bib)
|
71
|
+
ref.front do |f|
|
72
|
+
relaton_to_title(bib, f)
|
73
|
+
relaton_to_author(bib, f)
|
74
|
+
relaton_to_date(bib, f)
|
75
|
+
relaton_to_keyword(bib, f)
|
76
|
+
relaton_to_abstract(bib, f)
|
77
|
+
end
|
82
78
|
end
|
83
|
-
end
|
84
79
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
role = a.at(ns("./role[@type = 'editor']")) ? "editor" : nil
|
92
|
-
p = a&.at(ns("./person/name")) and
|
93
|
-
relaton_person_to_author(p, role, f) or
|
94
|
-
relaton_org_to_author(a&.at(ns("./organization")), role, f)
|
80
|
+
def relaton_to_title(bib, node)
|
81
|
+
title = bib&.at(ns("./title")) || bib&.at(ns("./formattedref")) or
|
82
|
+
return
|
83
|
+
node.title do |t|
|
84
|
+
title.children.each { |n| parse(n, t) }
|
85
|
+
end
|
95
86
|
end
|
96
|
-
end
|
97
87
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
88
|
+
def relaton_to_author(bib, node)
|
89
|
+
auths = bib.xpath(ns("./contributor[xmlns:role/@type = 'author' or "\
|
90
|
+
"xmlns:role/@type = 'editor']"))
|
91
|
+
auths.empty? and
|
92
|
+
auths = bib.xpath(ns("./contributor[xmlns:role/@type = "\
|
93
|
+
"'publisher']"))
|
94
|
+
auths.each do |a|
|
95
|
+
role = a.at(ns("./role[@type = 'editor']")) ? "editor" : nil
|
96
|
+
p = a&.at(ns("./person/name")) and
|
97
|
+
relaton_person_to_author(p, role, node) or
|
98
|
+
relaton_org_to_author(a&.at(ns("./organization")), role, node)
|
99
|
+
end
|
100
|
+
end
|
110
101
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
102
|
+
def relaton_person_to_author(pers, role, node)
|
103
|
+
full = pers&.at(ns("./completename"))&.text
|
104
|
+
surname = pers&.at(ns("./surname"))&.text
|
105
|
+
initials = pers&.xpath(ns("./initial"))&.map do |i|
|
106
|
+
i.text
|
107
|
+
end&.join(" ") ||
|
108
|
+
pers&.xpath(ns("./forename"))&.map { |i| i.text[0] }&.join(" ")
|
109
|
+
initials = nil if initials.empty?
|
110
|
+
node.author nil, **attr_code(
|
111
|
+
fullname: full,
|
112
|
+
asciiFullname: full&.transliterate,
|
113
|
+
role: role, surname: surname,
|
114
|
+
initials: initials,
|
115
|
+
asciiSurname: full ? surname&.transliterate : nil,
|
116
|
+
asciiInitials: full ? initials&.transliterate : nil
|
117
|
+
)
|
117
118
|
end
|
118
|
-
end
|
119
119
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
120
|
+
def relaton_org_to_author(org, _role, node)
|
121
|
+
name = org&.at(ns("./name"))&.text
|
122
|
+
abbrev = org&.at(ns("./abbreviation"))&.text
|
123
|
+
node.author do |_a|
|
124
|
+
node.organization name, **attr_code(ascii: name&.transliterate,
|
125
|
+
abbrev: abbrev)
|
126
|
+
end
|
127
|
+
end
|
125
128
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
+
def relaton_to_date(bib, node)
|
130
|
+
date = bib.at(ns("./date[@type = 'published']")) ||
|
131
|
+
bib.at(ns("./date[@type = 'issued']")) ||
|
132
|
+
bib.at(ns("./date[@type = 'circulated']"))
|
133
|
+
return unless date
|
129
134
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
135
|
+
attr = date_attr(date&.at(ns("./on | ./from"))&.text) || return
|
136
|
+
node.date **attr_code(attr)
|
137
|
+
end
|
138
|
+
|
139
|
+
def relaton_to_keyword(bib, node)
|
140
|
+
bib.xpath(ns("./keyword")).each do |k|
|
141
|
+
node.keyword do |keyword|
|
142
|
+
k.children.each { |n| parse(n, keyword) }
|
143
|
+
end
|
134
144
|
end
|
135
145
|
end
|
136
|
-
end
|
137
146
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
147
|
+
def relaton_to_abstract(bib, node)
|
148
|
+
bib.xpath(ns("./abstract")).each do |k|
|
149
|
+
node.abstract do |abstract|
|
150
|
+
if k.at(ns("./p"))
|
151
|
+
k.children.each { |n| parse(n, abstract) }
|
152
|
+
else
|
153
|
+
abstract.t do |t|
|
154
|
+
k.children.each { |n| parse(n, t) }
|
155
|
+
end
|
146
156
|
end
|
147
157
|
end
|
148
158
|
end
|
149
159
|
end
|
150
|
-
end
|
151
160
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
161
|
+
def ietf_bibitem_entry(div, bib, _idx)
|
162
|
+
url = bib&.at(ns("./uri[@type = 'xml']"))&.text
|
163
|
+
div << "<xi:include href='#{url}'/>"
|
164
|
+
end
|
156
165
|
|
157
|
-
|
158
|
-
|
166
|
+
def ietf?(bib)
|
167
|
+
return false if !@xinclude
|
159
168
|
|
160
|
-
|
161
|
-
|
169
|
+
url = bib.at(ns("./uri[@type = 'xml']")) or return false
|
170
|
+
/xml2rfc\.tools\.ietf\.org/.match(url)
|
171
|
+
end
|
162
172
|
end
|
163
173
|
end
|
164
174
|
end
|
@@ -1,191 +1,192 @@
|
|
1
1
|
require "jing"
|
2
2
|
require "fileutils"
|
3
3
|
|
4
|
-
module IsoDoc
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
errors = Jing.new(File.join(File.dirname(__FILE__), "v3.rng"))
|
9
|
-
validate(filename)
|
4
|
+
module IsoDoc
|
5
|
+
module Ietf
|
6
|
+
class RfcConvert < ::IsoDoc::Convert
|
7
|
+
def schema_validate(filename)
|
8
|
+
errors = Jing.new(File.join(File.dirname(__FILE__), "v3.rng"))
|
9
|
+
.validate(filename)
|
10
10
|
errors.each do |error|
|
11
|
-
warn "RFC XML: Line #{
|
12
|
-
|
11
|
+
warn "RFC XML: Line #{'%06d' % error[:line]}:#{error[:column]} "\
|
12
|
+
"#{error[:message]}"
|
13
13
|
end
|
14
14
|
rescue Jing::Error => e
|
15
15
|
abort "Jing failed with error: #{e}"
|
16
16
|
end
|
17
|
-
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
FileUtils.mv(filename, "#{filename}.err")
|
28
|
-
err.each { |e| warn "RFC XML: #{e}" }
|
29
|
-
warn "Cannot continue processing"
|
30
|
-
end
|
18
|
+
def content_validate(xml, filename)
|
19
|
+
err = []
|
20
|
+
err += numbered_sections_check(xml)
|
21
|
+
err += toc_sections_check(xml)
|
22
|
+
err += references_check(xml)
|
23
|
+
err += xref_check(xml)
|
24
|
+
err += metadata_check(xml)
|
25
|
+
return if err.empty?
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
FileUtils.mv(filename, "#{filename}.err")
|
28
|
+
err.each { |e| warn "RFC XML: #{e}" }
|
29
|
+
warn "Cannot continue processing"
|
30
|
+
end
|
36
31
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
xml.xpath("//section[@numbered = 'false']").each do |s1|
|
41
|
-
s1.xpath("./section[not(@numbered) or @numbered = 'true']").
|
42
|
-
each do |s2|
|
43
|
-
ret << "Numbered section #{label(s2)} under unnumbered section "\
|
44
|
-
"#{label(s1)}"
|
45
|
-
end
|
46
|
-
s1.xpath("./following-sibling::*[name() = 'section']"\
|
47
|
-
"[not(@numbered) or @numbered = 'true']").each do |s2|
|
48
|
-
ret << "Numbered section #{label(s2)} following unnumbered section "\
|
49
|
-
"#{label(s1)}"
|
50
|
-
end
|
32
|
+
def label(sect)
|
33
|
+
sect&.at("./name")&.text ||
|
34
|
+
sect["name"] || sect["anchor"]
|
51
35
|
end
|
52
|
-
ret
|
53
|
-
end
|
54
36
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
"section #{label(
|
37
|
+
# 2.46.2. "numbered" Attribute
|
38
|
+
def numbered_sections_check(xml)
|
39
|
+
ret = []
|
40
|
+
xml.xpath("//section[@numbered = 'false']").each do |s1|
|
41
|
+
s1.xpath("./section[not(@numbered) or @numbered = 'true']")
|
42
|
+
.each do |s2|
|
43
|
+
ret << "Numbered section #{label(s2)} under unnumbered section "\
|
44
|
+
"#{label(s1)}"
|
45
|
+
end
|
46
|
+
s1.xpath("./following-sibling::*[name() = 'section']"\
|
47
|
+
"[not(@numbered) or @numbered = 'true']").each do |s2|
|
48
|
+
ret << "Numbered section #{label(s2)} following unnumbered "\
|
49
|
+
"section #{label(s1)}"
|
50
|
+
end
|
62
51
|
end
|
52
|
+
ret
|
63
53
|
end
|
64
|
-
ret
|
65
|
-
end
|
66
54
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
"
|
74
|
-
|
75
|
-
"name=#{s1['name']} has been given no value"
|
55
|
+
# 5.2.7. Section "toc" attribute
|
56
|
+
def toc_sections_check(xml)
|
57
|
+
ret = []
|
58
|
+
xml.xpath("//section[@toc = 'exclude']").each do |s1|
|
59
|
+
s1.xpath(".//section[@toc = 'include']").each do |s2|
|
60
|
+
ret << "Section #{label(s2)} with toc=include is included in "\
|
61
|
+
"section #{label(s1)} with toc=exclude"
|
62
|
+
end
|
76
63
|
end
|
64
|
+
ret
|
77
65
|
end
|
78
|
-
xml.xpath("//references | //section").each do |s|
|
79
|
-
s.at("./name") or ret << "Cannot generate table of contents entry "\
|
80
|
-
"for #{label(s)}, as it has no title"
|
81
|
-
end
|
82
|
-
ret
|
83
|
-
end
|
84
66
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
if x["format"] == "title" && t.name == "reference"
|
96
|
-
t.at("./front/title") or
|
97
|
-
ret << "reference #{t['anchor']} has been referenced by #{x.name} "\
|
98
|
-
"with format=title, but the reference has no title"
|
99
|
-
end
|
100
|
-
if x["format"] == "counter" && !%w(section table figure li
|
101
|
-
reference references t dt).include?(t.name)
|
102
|
-
ret << "#{x.to_xml} with format=counter is only allowed for "\
|
103
|
-
"clauses, tables, figures, list entries, definition terms, "\
|
104
|
-
"paragraphs, bibliographies, and bibliographic entries"
|
105
|
-
end
|
106
|
-
if x["format"] == "counter" && t.name == "reference" && !x["section"]
|
107
|
-
ret << "reference #{t['anchor']} has been referenced by xref "\
|
108
|
-
"#{x.to_xml} with format=counter, which requires a "\
|
109
|
-
"section attribute"
|
110
|
-
end
|
111
|
-
if x["format"] == "counter" && t.name == "li" && t.parent.name != "ol"
|
112
|
-
ret << "#{x.to_xml} with format=counter refers to an unnumbered "\
|
113
|
-
"list entry"
|
114
|
-
end
|
115
|
-
if x["format"] == "title" && %w(u author contact).include?(t.name)
|
116
|
-
ret << "#{x.to_xml} with format=title cannot reference a "\
|
117
|
-
"<#{t.name}> element"
|
118
|
-
end
|
119
|
-
if x["relative"] && !x["section"]
|
120
|
-
ret << "#{x.to_xml} with relative attribute requires a section "\
|
121
|
-
"attribute"
|
122
|
-
end
|
123
|
-
if (x["section"]) && t.name != "reference"
|
124
|
-
ret << "#{x.to_xml} has a section attribute, but #{x['target']} "\
|
125
|
-
"points to a #{t.name}"
|
67
|
+
# 5.4.3 <reference> "target" Insertion
|
68
|
+
# 5.4.2.4 "Table of Contents" Insertion
|
69
|
+
def references_check(xml)
|
70
|
+
ret = []
|
71
|
+
xml.xpath("//reference[not(@target)]").each do |s|
|
72
|
+
s.xpath(".//seriesInfo[@name = 'RFC' or @name = 'Internet-Draft' "\
|
73
|
+
"or @name = 'DOI'][not(@value)]").each do |s1|
|
74
|
+
ret << "for reference #{s['anchor']}, the seriesInfo with "\
|
75
|
+
"name=#{s1['name']} has been given no value"
|
76
|
+
end
|
126
77
|
end
|
127
|
-
|
128
|
-
ret << "
|
129
|
-
|
78
|
+
xml.xpath("//references | //section").each do |s|
|
79
|
+
s.at("./name") or ret << "Cannot generate table of contents entry "\
|
80
|
+
"for #{label(s)}, as it has no title"
|
130
81
|
end
|
131
|
-
|
132
|
-
|
133
|
-
|
82
|
+
ret
|
83
|
+
end
|
84
|
+
|
85
|
+
# 5.4.8.2. "derivedContent" Insertion (without Content)
|
86
|
+
def xref_check(xml)
|
87
|
+
ret = []
|
88
|
+
xml.xpath("//xref | //relref").each do |x|
|
89
|
+
t = xml.at(".//*[@anchor = '#{x['target']}']") ||
|
90
|
+
xml.at(".//*[@pn = '#{x['target']}']") or
|
91
|
+
ret << "#{x.name} target #{x['target']} does not exist in the document"
|
92
|
+
next unless t
|
93
|
+
|
94
|
+
x.delete("relative") if x["relative"] && x["relative"].empty?
|
95
|
+
x.delete("section") if x["section"] && x["section"].empty?
|
96
|
+
if x["format"] == "title" && t.name == "reference"
|
97
|
+
t.at("./front/title") or
|
98
|
+
ret << "reference #{t['anchor']} has been referenced by #{x.name} "\
|
99
|
+
"with format=title, but the reference has no title"
|
100
|
+
end
|
101
|
+
if x["format"] == "counter" && !%w(section table figure li
|
102
|
+
reference references t dt).include?(t.name)
|
103
|
+
ret << "#{x.to_xml} with format=counter is only allowed for "\
|
104
|
+
"clauses, tables, figures, list entries, definition terms, "\
|
105
|
+
"paragraphs, bibliographies, and bibliographic entries"
|
106
|
+
end
|
107
|
+
if x["format"] == "counter" && t.name == "reference" && !x["section"]
|
108
|
+
ret << "reference #{t['anchor']} has been referenced by xref "\
|
109
|
+
"#{x.to_xml} with format=counter, which requires a "\
|
110
|
+
"section attribute"
|
111
|
+
end
|
112
|
+
if x["format"] == "counter" && t.name == "li" && t.parent.name != "ol"
|
113
|
+
ret << "#{x.to_xml} with format=counter refers to an unnumbered "\
|
114
|
+
"list entry"
|
115
|
+
end
|
116
|
+
if x["format"] == "title" && %w(u author contact).include?(t.name)
|
117
|
+
ret << "#{x.to_xml} with format=title cannot reference a "\
|
118
|
+
"<#{t.name}> element"
|
119
|
+
end
|
120
|
+
if x["relative"] && !x["section"]
|
121
|
+
ret << "#{x.to_xml} with relative attribute requires a section "\
|
122
|
+
"attribute"
|
123
|
+
end
|
124
|
+
if (x["section"]) && t.name != "reference"
|
125
|
+
ret << "#{x.to_xml} has a section attribute, but #{x['target']} "\
|
126
|
+
"points to a #{t.name}"
|
127
|
+
end
|
128
|
+
if (x["relative"]) && t.name != "reference"
|
129
|
+
ret << "#{x.to_xml} has a relative attribute, but #{x['target']} "\
|
130
|
+
"points to a #{t.name}"
|
131
|
+
end
|
132
|
+
if !x["relative"] && x["section"] && !t.at(".//seriesInfo[@name = 'RFC' or @name = "\
|
133
|
+
"'Internet-Draft']")
|
134
134
|
ret << "#{x.to_xml} must use a relative attribute, "\
|
135
|
-
|
135
|
+
"since it does not point to a RFC or Internet-Draft reference"
|
136
136
|
end
|
137
|
-
|
138
|
-
|
139
|
-
unless t.at(".//seriesInfo[@name = 'RFC' or @name = "\
|
140
|
-
"'Internet-Draft']") || t["target"]
|
137
|
+
if x["relative"] && !(t.at(".//seriesInfo[@name = 'RFC' or @name = "\
|
138
|
+
"'Internet-Draft']") || t["target"])
|
141
139
|
ret << "need an explicit target= URL attribute in the reference "\
|
142
|
-
|
140
|
+
"pointed to by #{x.to_xml}"
|
143
141
|
end
|
144
142
|
end
|
143
|
+
ret
|
145
144
|
end
|
146
|
-
ret
|
147
|
-
end
|
148
145
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
146
|
+
def metadata_check(xml)
|
147
|
+
ret = []
|
148
|
+
ret += link_check(xml)
|
149
|
+
ret += seriesInfo_check(xml)
|
150
|
+
ret += ipr_check(xml)
|
151
|
+
ret
|
152
|
+
end
|
156
153
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
154
|
+
# 5.6.3. <link> Processing
|
155
|
+
def link_check(xml)
|
156
|
+
l = xml&.at("//link[@rel = 'convertedFrom']")&.text
|
157
|
+
!l || %r{^https://datatracker\.ietf\.org/doc/draft-}.match(l) or
|
158
|
+
return ["<link rel='convertedFrom'> (:derived-from: document "\
|
159
|
+
"attribute) must start with "\
|
160
|
+
"https://datatracker.ietf.org/doc/draft-"]
|
161
|
+
[]
|
162
|
+
end
|
166
163
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
164
|
+
# 5.2.2. "seriesInfo" Insertion
|
165
|
+
def seriesInfo_check(xml)
|
166
|
+
ret = []
|
167
|
+
xml.root["ipr"] == "none" and return []
|
168
|
+
rfcinfo = xml.at("//seriesInfo[@name = 'RFC']")
|
169
|
+
rfcnumber = xml.root["number"]
|
170
|
+
rfcinfo && rfcnumber && rfcnumber != rfcinfo["value"] and
|
171
|
+
ret << "Mismatch between <rfc number='#{rfcnumber}'> "\
|
172
|
+
"(:docnumber: NUMBER) "\
|
173
|
+
"and <seriesInfo name='RFC' value='#{rfcinfo['value']}'> "\
|
174
|
+
"(:intended-series: TYPE NUMBER)"
|
175
|
+
rfcinfo && !/^\d+$/.match(rfcnumber) and
|
176
|
+
ret << "RFC identifier <rfc number='#{rfcnumber}'> "\
|
177
|
+
"(:docnumber: NUMBER) must be a number"
|
178
|
+
ret
|
179
|
+
end
|
182
180
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
181
|
+
# 5.4.2.3. "Copyright Notice" Insertion
|
182
|
+
def ipr_check(xml)
|
183
|
+
xml.root["ipr"] or
|
184
|
+
return ["Missing ipr attribute on <rfc> element (:ipr:)"]
|
185
|
+
/trust200902$/.match(xml.root["ipr"]) or
|
186
|
+
return ["Unknown ipr attribute on <rfc> element (:ipr:): "\
|
187
|
+
"#{xml.root['ipr']}"]
|
188
|
+
[]
|
189
|
+
end
|
189
190
|
end
|
190
191
|
end
|
191
192
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metanorma-ietf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-08-
|
11
|
+
date: 2021-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: isodoc
|