relaton-ietf 1.9.0 → 1.9.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/README.adoc +15 -0
- data/lib/relaton_ietf/committee.rb +8 -0
- data/lib/relaton_ietf/ietf_bibliographic_item.rb +2 -2
- data/lib/relaton_ietf/scrapper.rb +354 -347
- data/lib/relaton_ietf/version.rb +1 -1
- data/lib/relaton_ietf/xml_parser.rb +1 -1
- data/lib/relaton_ietf.rb +1 -0
- data/relaton_ietf.gemspec +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ed659b3ac3a91f53fa5872cb839be97adeba30e6eba56f211f140e55b5836d8
|
4
|
+
data.tar.gz: 8b1c58e40158c126f11ab25c92ca99230a3e00064b8d0fb20ad250c51c01e7b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 163f11e5a49d8dd44d6592c1741281b8756f505ac49feb59d3a508ec2ad7340498db0a5d71a1ccfbbc8c4de385ee967388119238f0c4f94641a839623fe19c65
|
7
|
+
data.tar.gz: 0a86ac885aca2d200e5d64cdee74e0b4b5e6d42f77a5e9fb60c233e77e19c176137ebc8220a7397e56e6564edcd58c09933553810a4265597fbc7e64c02a173b
|
data/README.adoc
CHANGED
@@ -90,6 +90,21 @@ item.to_xml bibdata: true
|
|
90
90
|
</bibdata>"
|
91
91
|
----
|
92
92
|
|
93
|
+
=== Typed links
|
94
|
+
|
95
|
+
IETF documents may have `src`, `xml`, and `doi` link type.
|
96
|
+
|
97
|
+
* `src` - web pulication
|
98
|
+
* `xml` - BibXML publication
|
99
|
+
* `doi` - DOI reference
|
100
|
+
|
101
|
+
[source,ruby]
|
102
|
+
----
|
103
|
+
item.link
|
104
|
+
=> [#<RelatonBib::TypedUri:0x00007fe8b287a120 @content=#<Addressable::URI:0x7e4 URI:https://raw.githubusercontent.com/relaton/relaton-data-ietf/master/data/reference.RFC.8341.xml>, @type="xml">,
|
105
|
+
#<RelatonBib::TypedUri:0x00007fe8b2237ec0 @content=#<Addressable::URI:0x7f8 URI:https://www.rfc-editor.org/info/rfc8341>, @type="src">]
|
106
|
+
----
|
107
|
+
|
93
108
|
=== Parse a file locally
|
94
109
|
|
95
110
|
[source,ruby]
|
@@ -21,7 +21,7 @@ module RelatonIetf
|
|
21
21
|
# @return [RelatonIetf::IetfBibliographicItem]
|
22
22
|
def self.from_hash(hash)
|
23
23
|
item_hash = ::RelatonIetf::HashConverter.hash_to_bib(hash)
|
24
|
-
new
|
24
|
+
new(**item_hash)
|
25
25
|
end
|
26
26
|
|
27
27
|
# @param opts [Hash]
|
@@ -32,7 +32,7 @@ module RelatonIetf
|
|
32
32
|
# @return [String] XML
|
33
33
|
def to_xml(**opts)
|
34
34
|
opts[:date_format] ||= :short
|
35
|
-
super
|
35
|
+
super(**opts)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -5,365 +5,372 @@ require "relaton_bib"
|
|
5
5
|
require "relaton_ietf/ietf_bibliographic_item"
|
6
6
|
|
7
7
|
module RelatonIetf
|
8
|
-
# rubocop:disable Metrics/ModuleLength
|
9
|
-
|
10
8
|
# Scrapper module
|
11
9
|
module Scrapper
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
class << self
|
16
|
-
# @param text [String]
|
17
|
-
# @param is_relation [TrueClass, FalseClass]
|
18
|
-
# @return [RelatonIetf::IetfBibliographicItem]
|
19
|
-
def scrape_page(text, is_relation: false)
|
20
|
-
# Remove initial "IETF " string if specified
|
21
|
-
ref = text.gsub(/^IETF /, "")
|
22
|
-
/^(?:RFC|BCP|FYI|STD)\s(?<num>\d+)/ =~ ref
|
23
|
-
ref.sub! /(?<=^(?:RFC|BCP|FYI|STD)\s)(\d+)/, num.rjust(4, "0") if num
|
24
|
-
rfc_item ref, is_relation
|
25
|
-
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
|
26
|
-
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
|
27
|
-
Net::ProtocolError, SocketError
|
28
|
-
raise RelatonBib::RequestError, "No document found for #{ref} reference"
|
29
|
-
end
|
30
|
-
|
31
|
-
# @param reference [Nokogiri::XML::Element, nil]
|
32
|
-
# @param is_relation [TrueClass, FalseClass]
|
33
|
-
# @param url [String, NilClass]
|
34
|
-
# @param ver [String, NilClass] Internet Draft version
|
35
|
-
# @return [RelatonIetf::IetfBibliographicItem]
|
36
|
-
def fetch_rfc(reference, is_relation: false, url: nil, ver: nil) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
37
|
-
return unless reference
|
38
|
-
|
39
|
-
ietf_item(
|
40
|
-
is_relation: is_relation,
|
41
|
-
id: reference[:anchor],
|
42
|
-
type: "standard",
|
43
|
-
docid: docids(reference, ver),
|
44
|
-
status: status(reference),
|
45
|
-
language: [language(reference)],
|
46
|
-
link: link(reference, url, ver),
|
47
|
-
title: titles(reference),
|
48
|
-
formattedref: formattedref(reference),
|
49
|
-
abstract: abstracts(reference),
|
50
|
-
contributor: contributors(reference),
|
51
|
-
relation: relations(reference),
|
52
|
-
date: dates(reference),
|
53
|
-
series: series(reference),
|
54
|
-
place: ["Fremont, CA"],
|
55
|
-
keyword: reference.xpath("front/keyword").map(&:text),
|
56
|
-
doctype: doctype(reference[:anchor]),
|
57
|
-
)
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
# @param anchor [String]
|
63
|
-
# @return [String]
|
64
|
-
def doctype(anchor)
|
65
|
-
anchor&.include?("I-D") ? "internet-draft" : "rfc"
|
66
|
-
end
|
67
|
-
|
68
|
-
# @param reference [Nokogiri::XML::Element]
|
69
|
-
# @param url [String]
|
70
|
-
# @param ver [String, NilClass] Internet Draft version
|
71
|
-
# @return [Array<Hash>]
|
72
|
-
def link(reference, url, ver)
|
73
|
-
l = []
|
74
|
-
l << { type: "xml", content: url } if url
|
75
|
-
l << { type: "src", content: reference[:target] } if reference[:target]
|
76
|
-
if /^I-D/.match? reference[:anchor]
|
77
|
-
reference.xpath("format").each do |f|
|
78
|
-
c = ver ? f[:target].sub(/(?<=-)\d{2}(?=\.)/, ver) : f[:target]
|
79
|
-
l << { type: f[:type], content: c }
|
80
|
-
end
|
81
|
-
end
|
82
|
-
l
|
83
|
-
end
|
84
|
-
|
85
|
-
# @param attrs [Hash]
|
86
|
-
# @return [RelatonIetf::IetfBibliographicItem]
|
87
|
-
def ietf_item(**attrs)
|
88
|
-
attrs[:fetched] = Date.today.to_s unless attrs.delete(:is_relation)
|
89
|
-
attrs[:script] = ["Latn"]
|
90
|
-
RelatonIetf::IetfBibliographicItem.new **attrs
|
91
|
-
end
|
92
|
-
|
93
|
-
# @param ref [String]
|
94
|
-
# @param is_relation [Boolen, nil]
|
95
|
-
# @return [RelatonIetf::IetfBibliographicItem]
|
96
|
-
def rfc_item(ref, is_relation)
|
97
|
-
/(?<=-)(?<ver>\d{2})$/ =~ ref
|
98
|
-
if /^I-D/.match? ref
|
99
|
-
ref.sub! /-\d{2}/, "" if ver
|
100
|
-
ref.sub! /(?<=I-D\.)draft-/, ""
|
101
|
-
end
|
102
|
-
|
103
|
-
uri = "#{GH_URL}#{ref.sub(/\s|\u00a0/, '.')}.xml"
|
104
|
-
doc = Nokogiri::XML get_page(uri)
|
105
|
-
r = doc.at("/referencegroup", "/reference")
|
106
|
-
fetch_rfc r, is_relation: is_relation, url: uri, ver: ver
|
107
|
-
end
|
108
|
-
|
109
|
-
# @param reference [Nokogiri::XML::Element]
|
110
|
-
# @return [Hash]
|
111
|
-
def relations(reference)
|
112
|
-
reference.xpath("reference").map do |ref|
|
113
|
-
{ type: "includes", bibitem: fetch_rfc(ref, is_relation: true) }
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
# @param uri [String]
|
118
|
-
# @return [String] HTTP response body
|
119
|
-
def get_page(uri)
|
120
|
-
res = Net::HTTP.get_response(URI(uri))
|
121
|
-
return unless res.code == "200"
|
122
|
-
|
123
|
-
# raise RelatonBib::RequestError, "No document found at #{uri}"
|
124
|
-
# end
|
125
|
-
|
126
|
-
res.body
|
127
|
-
end
|
128
|
-
|
129
|
-
# @param reference [Nokogiri::XML::Element]
|
130
|
-
# @return [String]
|
131
|
-
def language(reference)
|
132
|
-
reference[:lang] || "en"
|
133
|
-
end
|
10
|
+
extend RelatonBib::BibXMLParser
|
11
|
+
extend Scrapper
|
134
12
|
|
135
|
-
|
136
|
-
# @return [Array<Hash>]
|
137
|
-
def titles(reference)
|
138
|
-
reference.xpath("./front/title").map do |title|
|
139
|
-
{ content: title.text, language: language(reference), script: "Latn" }
|
140
|
-
end
|
141
|
-
end
|
13
|
+
FLAVOR = "IETF"
|
142
14
|
|
143
|
-
|
144
|
-
# @return [RelatonBib::FormattedRef, nil]
|
145
|
-
def formattedref(reference)
|
146
|
-
return if reference.at "./fornt/title"
|
147
|
-
|
148
|
-
cont = (reference[:anchor] || reference[:docName] || reference[:number])
|
149
|
-
if cont
|
150
|
-
RelatonBib::FormattedRef.new(
|
151
|
-
content: cont, language: language(reference), script: "Latn",
|
152
|
-
)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
# @param reference [Nokogiri::XML::Element]
|
157
|
-
# @return [Array<RelatonBib::FormattedString>]
|
158
|
-
def abstracts(ref)
|
159
|
-
ref.xpath("./front/abstract").map do |a|
|
160
|
-
RelatonBib::FormattedString.new(
|
161
|
-
content: a.text.gsub(/\\n\\t{2,4}/, " ").strip,
|
162
|
-
language: language(ref), script: "Latn"
|
163
|
-
)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# @param reference [Nokogiri::XML::Element]
|
168
|
-
# @return [Array<Hash>]
|
169
|
-
def contributors(reference)
|
170
|
-
persons(reference) + organizations(reference)
|
171
|
-
end
|
172
|
-
|
173
|
-
# @param reference [Nokogiri::XML::Element]
|
174
|
-
# @return [Array<Hash{Symbol=>RelatonBib::Person,Symbol=>Array<String>}>]
|
175
|
-
def persons(reference)
|
176
|
-
reference.xpath("./front/author[@surname]|./front/author[@fullname]")
|
177
|
-
.map do |author|
|
178
|
-
entity = RelatonBib::Person.new(
|
179
|
-
name: full_name(author, reference),
|
180
|
-
affiliation: [affiliation(author)],
|
181
|
-
contact: contacts(author.at("./address")),
|
182
|
-
)
|
183
|
-
{ entity: entity, role: [contributor_role(author)] }
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
# @param reference [Nokogiri::XML::Element]
|
188
|
-
# @return [Array<Hash{Symbol=>RelatonBib::Organization,
|
189
|
-
# Symbol=>Array<String>}>]
|
190
|
-
def organizations(reference)
|
191
|
-
publisher = { entity: new_org, role: [type: "publisher"] }
|
192
|
-
orgs = reference.xpath("./seriesinfo").reduce([publisher]) do |mem, si|
|
193
|
-
next mem unless si[:stream]
|
194
|
-
|
195
|
-
mem << { entity: new_org(si[:stream], nil), role: [type: "author"] }
|
196
|
-
end
|
197
|
-
orgs + reference.xpath(
|
198
|
-
"front/author[not(@surname)][not(@fullname)]/organization",
|
199
|
-
).map do |org|
|
200
|
-
{ entity: new_org(org.text, nil), role: [type: "author"] }
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
# @param author [Nokogiri::XML::Element]
|
205
|
-
# @param ref [Nokogiri::XML::Element]
|
206
|
-
# @return [RelatonBib::FullName]
|
207
|
-
def full_name(author, ref)
|
208
|
-
lang = language ref
|
209
|
-
RelatonBib::FullName.new(
|
210
|
-
completename: localized_string(author[:fullname], lang),
|
211
|
-
initial: [localized_string(author[:initials], lang)].compact,
|
212
|
-
surname: localized_string(author[:surname], lang),
|
213
|
-
)
|
214
|
-
end
|
215
|
-
|
216
|
-
# @param content [String]
|
217
|
-
# @param lang [String]
|
218
|
-
# @return [RelatonBib::LocalizedString]
|
219
|
-
def localized_string(content, lang)
|
220
|
-
return unless content
|
221
|
-
|
222
|
-
RelatonBib::LocalizedString.new(content, lang)
|
223
|
-
end
|
224
|
-
|
225
|
-
# @param postal [Nokogiri::XML::Element]
|
226
|
-
# @return [Array<RelatonBib::Address, RelatonBib::Phone>]
|
227
|
-
def contacts(addr)
|
228
|
-
contacts = []
|
229
|
-
return contacts unless addr
|
230
|
-
|
231
|
-
postal = addr.at("./postal")
|
232
|
-
contacts << address(postal) if postal
|
233
|
-
add_contact(contacts, "phone", addr.at("./phone"))
|
234
|
-
add_contact(contacts, "email", addr.at("./email"))
|
235
|
-
add_contact(contacts, "uri", addr.at("./uri"))
|
236
|
-
contacts
|
237
|
-
end
|
238
|
-
|
239
|
-
# @param postal [Nokogiri::XML::Element]
|
240
|
-
# @rerurn [RelatonBib::Address]
|
241
|
-
def address(postal) # rubocop:disable Metrics/CyclomaticComplexity
|
242
|
-
RelatonBib::Address.new(
|
243
|
-
street: [(postal.at("./postalLine") || postal.at("./street"))&.text],
|
244
|
-
city: postal.at("./city")&.text,
|
245
|
-
postcode: postal.at("./code")&.text,
|
246
|
-
country: postal.at("./country")&.text,
|
247
|
-
state: postal.at("./region")&.text,
|
248
|
-
)
|
249
|
-
end
|
250
|
-
|
251
|
-
# @param type [String] allowed "phone", "email" or "uri"
|
252
|
-
# @param value [String]
|
253
|
-
def add_contact(contacts, type, value)
|
254
|
-
return unless value
|
255
|
-
|
256
|
-
contacts << RelatonBib::Contact.new(type: type, value: value.text)
|
257
|
-
end
|
258
|
-
|
259
|
-
# @param author [Nokogiri::XML::Element]
|
260
|
-
# @return [RelatonBib::Affiliation]
|
261
|
-
def affiliation(author)
|
262
|
-
organization = author.at("./organization")
|
263
|
-
org = if organization.nil? || organization&.text&.empty?
|
264
|
-
new_org
|
265
|
-
else
|
266
|
-
new_org organization.text, organization[:abbrev]
|
267
|
-
end
|
268
|
-
RelatonBib::Affiliation.new organization: org
|
269
|
-
end
|
270
|
-
|
271
|
-
# @param name [String]
|
272
|
-
# @param abbr [String]
|
273
|
-
# @return [RelatonBib::Organization]
|
274
|
-
def new_org(name = "Internet Engineering Task Force", abbr = "IETF")
|
275
|
-
RelatonBib::Organization.new name: name, abbreviation: abbr
|
276
|
-
end
|
277
|
-
|
278
|
-
# @param author [Nokogiri::XML::Document]
|
279
|
-
# @return [Hash]
|
280
|
-
def contributor_role(author)
|
281
|
-
{ type: author[:role] || "author" }
|
282
|
-
end
|
15
|
+
GH_URL = "https://raw.githubusercontent.com/relaton/relaton-data-ietf/master/data/reference."
|
283
16
|
|
284
|
-
|
285
|
-
|
286
|
-
|
17
|
+
# @param text [String]
|
18
|
+
# @param is_relation [TrueClass, FalseClass]
|
19
|
+
# @return [RelatonIetf::IetfBibliographicItem]
|
20
|
+
def scrape_page(text, is_relation: false)
|
21
|
+
# Remove initial "IETF " string if specified
|
22
|
+
ref = text.gsub(/^IETF /, "")
|
23
|
+
/^(?:RFC|BCP|FYI|STD)\s(?<num>\d+)/ =~ ref
|
24
|
+
ref.sub!(/(?<=^(?:RFC|BCP|FYI|STD)\s)(\d+)/, num.rjust(4, "0")) if num
|
25
|
+
rfc_item ref, is_relation
|
26
|
+
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
|
27
|
+
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
|
28
|
+
Net::ProtocolError, SocketError
|
29
|
+
raise RelatonBib::RequestError, "No document found for #{ref} reference"
|
30
|
+
end
|
287
31
|
|
288
|
-
|
32
|
+
# @param reference [Nokogiri::XML::Element, nil]
|
33
|
+
# @param is_relation [Boolean] don't add fetched date for relation
|
34
|
+
# @param url [String, NilClass]
|
35
|
+
# @param ver [String, NilClass] Internet Draft version
|
36
|
+
# @return [RelatonBib::tfBibliographicItem]
|
37
|
+
# def fetch_rfc(reference, is_relation: false, url: nil, ver: nil) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
38
|
+
# return unless reference
|
39
|
+
|
40
|
+
# hash = {
|
41
|
+
# id: reference[:anchor],
|
42
|
+
# type: "standard",
|
43
|
+
# docid: docids(reference, ver),
|
44
|
+
# status: status(reference),
|
45
|
+
# language: [language(reference)],
|
46
|
+
# script: ["Latn"],
|
47
|
+
# link: link(reference, url, ver),
|
48
|
+
# title: titles(reference),
|
49
|
+
# formattedref: formattedref(reference),
|
50
|
+
# abstract: abstracts(reference),
|
51
|
+
# contributor: contributors(reference),
|
52
|
+
# relation: relations(reference),
|
53
|
+
# date: dates(reference),
|
54
|
+
# series: series(reference),
|
55
|
+
# keyword: reference.xpath("front/keyword").map(&:text),
|
56
|
+
# doctype: doctype(reference[:anchor]),
|
57
|
+
# }
|
58
|
+
# hash[:fetched] = Date.today.to_s unless is_relation
|
59
|
+
# bib_item(**hash)
|
60
|
+
# end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# @param anchor [String]
|
65
|
+
# @return [String]
|
66
|
+
# def doctype(anchor)
|
67
|
+
# anchor&.include?("I-D") ? "internet-draft" : "rfc"
|
68
|
+
# end
|
69
|
+
|
70
|
+
# @param reference [Nokogiri::XML::Element]
|
71
|
+
# @param url [String]
|
72
|
+
# @param ver [String, NilClass] Internet Draft version
|
73
|
+
# @return [Array<Hash>]
|
74
|
+
# def link(reference, url, ver)
|
75
|
+
# l = []
|
76
|
+
# l << { type: "xml", content: url } if url
|
77
|
+
# l << { type: "src", content: reference[:target] } if reference[:target]
|
78
|
+
# if /^I-D/.match? reference[:anchor]
|
79
|
+
# reference.xpath("format").each do |f|
|
80
|
+
# c = ver ? f[:target].sub(/(?<=-)\d{2}(?=\.)/, ver) : f[:target]
|
81
|
+
# l << { type: f[:type], content: c }
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# l
|
85
|
+
# end
|
86
|
+
|
87
|
+
# @param attrs [Hash]
|
88
|
+
# @return [RelatonIetf::IetfBibliographicItem]
|
89
|
+
def bib_item(**attrs)
|
90
|
+
unless attrs.delete(:is_relation)
|
91
|
+
attrs[:fetched] = Date.today.to_s
|
92
|
+
attrs[:place] = ["Fremont, CA"]
|
289
93
|
end
|
94
|
+
RelatonIetf::IetfBibliographicItem.new(**attrs)
|
95
|
+
end
|
290
96
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
d = [date[:year], month(date[:month]),
|
301
|
-
(date[:day] || 1)].compact.join "-"
|
302
|
-
date = Time.parse(d).strftime "%Y-%m-%d"
|
303
|
-
[RelatonBib::BibliographicDate.new(type: "published", on: date)]
|
97
|
+
# @param ref [String]
|
98
|
+
# @param is_relation [Boolen, nil]
|
99
|
+
# @return [RelatonIetf::IetfBibliographicItem]
|
100
|
+
def rfc_item(ref, is_relation)
|
101
|
+
/(?<=-)(?<ver>\d{2})$/ =~ ref
|
102
|
+
if /^I-D/.match? ref
|
103
|
+
ref.sub!(/-\d{2}/, "") if ver
|
104
|
+
ref.sub!(/(?<=I-D\.)draft-/, "")
|
304
105
|
end
|
305
106
|
|
306
|
-
#
|
307
|
-
#
|
308
|
-
#
|
309
|
-
#
|
310
|
-
|
311
|
-
|
312
|
-
# @return [Array<RelatonBib::DocumentIdentifier>]
|
313
|
-
#
|
314
|
-
def docids(reference, ver) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity,Metrics/AbcSize
|
315
|
-
id = (reference[:anchor] || reference[:docName] || reference[:number])
|
316
|
-
ret = []
|
317
|
-
if id
|
318
|
-
ret << RelatonBib::DocumentIdentifier.new(
|
319
|
-
type: "IETF", id: id.sub(/^(RFC)/, "\\1 "),
|
320
|
-
)
|
321
|
-
end
|
322
|
-
if (id = reference[:anchor])
|
323
|
-
ret << RelatonBib::DocumentIdentifier.new(type: "rfc-anchor", id: id)
|
324
|
-
end
|
325
|
-
ret + reference.xpath("./seriesInfo").map do |si|
|
326
|
-
next unless ["DOI", "Internet-Draft"].include? si[:name]
|
327
|
-
|
328
|
-
id = si[:value]
|
329
|
-
id.sub! /(?<=-)\d{2}$/, ver if ver && si[:name] == "Internet-Draft"
|
330
|
-
RelatonBib::DocumentIdentifier.new(id: id, type: si[:name])
|
331
|
-
end.compact
|
332
|
-
end
|
107
|
+
uri = "#{GH_URL}#{ref.sub(/\s|\u00a0/, '.')}.xml"
|
108
|
+
# doc = Nokogiri::XML get_page(uri)
|
109
|
+
# r = doc.at("/referencegroup", "/reference")
|
110
|
+
# fetch_rfc r, is_relation: is_relation, url: uri, ver: ver
|
111
|
+
parse get_page(uri), url: uri, is_relation: is_relation, ver: ver
|
112
|
+
end
|
333
113
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
)
|
351
|
-
end.compact
|
352
|
-
end
|
114
|
+
# @param reference [Nokogiri::XML::Element]
|
115
|
+
# @return [Hash]
|
116
|
+
# def relations(reference)
|
117
|
+
# reference.xpath("reference").map do |ref|
|
118
|
+
# { type: "includes", bibitem: fetch_rfc(ref, is_relation: true) }
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
|
122
|
+
# @param uri [String]
|
123
|
+
# @return [String] HTTP response body
|
124
|
+
def get_page(uri)
|
125
|
+
res = Net::HTTP.get_response(URI(uri))
|
126
|
+
return unless res.code == "200"
|
127
|
+
|
128
|
+
res.body
|
129
|
+
end
|
353
130
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
# @return [RelatonBib::DocumentStatus]
|
359
|
-
#
|
360
|
-
def status(reference)
|
361
|
-
st = reference.at("./seriesinfo[@status]")
|
362
|
-
return unless st
|
363
|
-
|
364
|
-
RelatonBib::DocumentStatus.new(stage: st[:status])
|
365
|
-
end
|
131
|
+
# @param [RelatonBib::WorkGroup]
|
132
|
+
# @return [RelatonIetf::Committee]
|
133
|
+
def committee(wgr)
|
134
|
+
Committee.new wgr
|
366
135
|
end
|
136
|
+
|
137
|
+
# @param reference [Nokogiri::XML::Element]
|
138
|
+
# @return [String]
|
139
|
+
# def language(reference)
|
140
|
+
# reference[:lang] || "en"
|
141
|
+
# end
|
142
|
+
|
143
|
+
# @param reference [Nokogiri::XML::Element]
|
144
|
+
# @return [Array<Hash>]
|
145
|
+
# def titles(reference)
|
146
|
+
# reference.xpath("./front/title").map do |title|
|
147
|
+
# { content: title.text, language: language(reference), script: "Latn" }
|
148
|
+
# end
|
149
|
+
# end
|
150
|
+
|
151
|
+
# @param reference [Nokogiri::XML::Element]
|
152
|
+
# @return [RelatonBib::FormattedRef, nil]
|
153
|
+
# def formattedref(reference)
|
154
|
+
# return if reference.at "./front/title"
|
155
|
+
|
156
|
+
# cont = (reference[:anchor] || reference[:docName] || reference[:number])
|
157
|
+
# if cont
|
158
|
+
# RelatonBib::FormattedRef.new(
|
159
|
+
# content: cont, language: language(reference), script: "Latn",
|
160
|
+
# )
|
161
|
+
# end
|
162
|
+
# end
|
163
|
+
|
164
|
+
# @param reference [Nokogiri::XML::Element]
|
165
|
+
# @return [Array<RelatonBib::FormattedString>]
|
166
|
+
# def abstracts(ref)
|
167
|
+
# ref.xpath("./front/abstract").map do |a|
|
168
|
+
# RelatonBib::FormattedString.new(
|
169
|
+
# content: a.text.gsub(/\\n\\t{2,4}/, " ").strip,
|
170
|
+
# language: language(ref), script: "Latn"
|
171
|
+
# )
|
172
|
+
# end
|
173
|
+
# end
|
174
|
+
|
175
|
+
# @param reference [Nokogiri::XML::Element]
|
176
|
+
# @return [Array<Hash>]
|
177
|
+
# def contributors(reference)
|
178
|
+
# persons(reference) + organizations(reference)
|
179
|
+
# end
|
180
|
+
|
181
|
+
# @param reference [Nokogiri::XML::Element]
|
182
|
+
# @return [Array<Hash{Symbol=>RelatonBib::Person,Symbol=>Array<String>}>]
|
183
|
+
# def persons(reference)
|
184
|
+
# reference.xpath("./front/author[@surname]|./front/author[@fullname]")
|
185
|
+
# .map do |author|
|
186
|
+
# entity = RelatonBib::Person.new(
|
187
|
+
# name: full_name(author, reference),
|
188
|
+
# affiliation: [affiliation(author)],
|
189
|
+
# contact: contacts(author.at("./address")),
|
190
|
+
# )
|
191
|
+
# { entity: entity, role: [contributor_role(author)] }
|
192
|
+
# end
|
193
|
+
# end
|
194
|
+
|
195
|
+
# @param reference [Nokogiri::XML::Element]
|
196
|
+
# @return [Array<Hash{Symbol=>RelatonBib::Organization,
|
197
|
+
# Symbol=>Array<String>}>]
|
198
|
+
# def organizations(reference)
|
199
|
+
# publisher = { entity: new_org, role: [type: "publisher"] }
|
200
|
+
# orgs = reference.xpath("./seriesinfo").reduce([publisher]) do |mem, si|
|
201
|
+
# next mem unless si[:stream]
|
202
|
+
|
203
|
+
# mem << { entity: new_org(si[:stream], nil), role: [type: "author"] }
|
204
|
+
# end
|
205
|
+
# orgs + reference.xpath(
|
206
|
+
# "front/author[not(@surname)][not(@fullname)]/organization",
|
207
|
+
# ).map do |org|
|
208
|
+
# { entity: new_org(org.text, nil), role: [type: "author"] }
|
209
|
+
# end
|
210
|
+
# end
|
211
|
+
|
212
|
+
# @param author [Nokogiri::XML::Element]
|
213
|
+
# @param ref [Nokogiri::XML::Element]
|
214
|
+
# @return [RelatonBib::FullName]
|
215
|
+
# def full_name(author, ref)
|
216
|
+
# lang = language ref
|
217
|
+
# RelatonBib::FullName.new(
|
218
|
+
# completename: localized_string(author[:fullname], lang),
|
219
|
+
# initial: [localized_string(author[:initials], lang)].compact,
|
220
|
+
# surname: localized_string(author[:surname], lang),
|
221
|
+
# )
|
222
|
+
# end
|
223
|
+
|
224
|
+
# @param content [String]
|
225
|
+
# @param lang [String]
|
226
|
+
# @return [RelatonBib::LocalizedString]
|
227
|
+
# def localized_string(content, lang)
|
228
|
+
# return unless content
|
229
|
+
|
230
|
+
# RelatonBib::LocalizedString.new(content, lang)
|
231
|
+
# end
|
232
|
+
|
233
|
+
# @param postal [Nokogiri::XML::Element]
|
234
|
+
# @return [Array<RelatonBib::Address, RelatonBib::Phone>]
|
235
|
+
# def contacts(addr)
|
236
|
+
# contacts = []
|
237
|
+
# return contacts unless addr
|
238
|
+
|
239
|
+
# postal = addr.at("./postal")
|
240
|
+
# contacts << address(postal) if postal
|
241
|
+
# add_contact(contacts, "phone", addr.at("./phone"))
|
242
|
+
# add_contact(contacts, "email", addr.at("./email"))
|
243
|
+
# add_contact(contacts, "uri", addr.at("./uri"))
|
244
|
+
# contacts
|
245
|
+
# end
|
246
|
+
|
247
|
+
# @param postal [Nokogiri::XML::Element]
|
248
|
+
# @rerurn [RelatonBib::Address]
|
249
|
+
# def address(postal) # rubocop:disable Metrics/CyclomaticComplexity
|
250
|
+
# RelatonBib::Address.new(
|
251
|
+
# street: [(postal.at("./postalLine") || postal.at("./street"))&.text],
|
252
|
+
# city: postal.at("./city")&.text,
|
253
|
+
# postcode: postal.at("./code")&.text,
|
254
|
+
# country: postal.at("./country")&.text,
|
255
|
+
# state: postal.at("./region")&.text,
|
256
|
+
# )
|
257
|
+
# end
|
258
|
+
|
259
|
+
# @param type [String] allowed "phone", "email" or "uri"
|
260
|
+
# @param value [String]
|
261
|
+
# def add_contact(contacts, type, value)
|
262
|
+
# return unless value
|
263
|
+
|
264
|
+
# contacts << RelatonBib::Contact.new(type: type, value: value.text)
|
265
|
+
# end
|
266
|
+
|
267
|
+
# @param author [Nokogiri::XML::Element]
|
268
|
+
# @return [RelatonBib::Affiliation]
|
269
|
+
# def affiliation(author)
|
270
|
+
# organization = author.at("./organization")
|
271
|
+
# org = if organization.nil? || organization&.text&.empty?
|
272
|
+
# new_org
|
273
|
+
# else
|
274
|
+
# new_org organization.text, organization[:abbrev]
|
275
|
+
# end
|
276
|
+
# RelatonBib::Affiliation.new organization: org
|
277
|
+
# end
|
278
|
+
|
279
|
+
# @param name [String]
|
280
|
+
# @param abbr [String]
|
281
|
+
# @return [RelatonBib::Organization]
|
282
|
+
# def new_org(name = "Internet Engineering Task Force", abbr = "IETF")
|
283
|
+
# RelatonBib::Organization.new name: name, abbreviation: abbr
|
284
|
+
# end
|
285
|
+
|
286
|
+
# @param author [Nokogiri::XML::Document]
|
287
|
+
# @return [Hash]
|
288
|
+
# def contributor_role(author)
|
289
|
+
# { type: author[:role] || "author" }
|
290
|
+
# end
|
291
|
+
|
292
|
+
# def month(mon)
|
293
|
+
# return 1 if !mon || mon.empty?
|
294
|
+
# return mon if /^\d+$/.match? mon
|
295
|
+
|
296
|
+
# Date::MONTHNAMES.index(mon)
|
297
|
+
# end
|
298
|
+
|
299
|
+
#
|
300
|
+
# Extract date from reference.
|
301
|
+
#
|
302
|
+
# @param reference [Nokogiri::XML::Element]
|
303
|
+
# @return [Array<RelatonBib::BibliographicDate>] published data.
|
304
|
+
#
|
305
|
+
# def dates(reference)
|
306
|
+
# return unless (date = reference.at "./front/date")
|
307
|
+
|
308
|
+
# d = [date[:year], month(date[:month]),
|
309
|
+
# (date[:day] || 1)].compact.join "-"
|
310
|
+
# date = Time.parse(d).strftime "%Y-%m-%d"
|
311
|
+
# [RelatonBib::BibliographicDate.new(type: "published", on: date)]
|
312
|
+
# end
|
313
|
+
|
314
|
+
#
|
315
|
+
# Extract document identifiers from reference
|
316
|
+
#
|
317
|
+
# @param reference [Nokogiri::XML::Element]
|
318
|
+
# @param ver [String, NilClass] Internet Draft version
|
319
|
+
#
|
320
|
+
# @return [Array<RelatonBib::DocumentIdentifier>]
|
321
|
+
#
|
322
|
+
# def docids(reference, ver) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity,Metrics/AbcSize
|
323
|
+
# id = (reference[:anchor] || reference[:docName] || reference[:number])
|
324
|
+
# ret = []
|
325
|
+
# if id
|
326
|
+
# ret << RelatonBib::DocumentIdentifier.new(
|
327
|
+
# type: "IETF", id: id.sub(/^(RFC)/, "\\1 "),
|
328
|
+
# )
|
329
|
+
# end
|
330
|
+
# if (id = reference[:anchor])
|
331
|
+
# ret << RelatonBib::DocumentIdentifier.new(type: "rfc-anchor", id: id)
|
332
|
+
# end
|
333
|
+
# names = ["DOI", "Internet-Draft"]
|
334
|
+
# ret + reference.xpath("./seriesInfo").map do |si|
|
335
|
+
# next unless names.include? si[:name]
|
336
|
+
|
337
|
+
# id = si[:value]
|
338
|
+
# id.sub!(/(?<=-)\d{2}$/, ver) if ver && si[:name] == "Internet-Draft"
|
339
|
+
# RelatonBib::DocumentIdentifier.new(id: id, type: si[:name])
|
340
|
+
# end.compact
|
341
|
+
# end
|
342
|
+
|
343
|
+
#
|
344
|
+
# Extract series form reference
|
345
|
+
# @param reference [Nokogiri::XML::Element]
|
346
|
+
#
|
347
|
+
# @return [Array<RelatonBib::Series>]
|
348
|
+
#
|
349
|
+
# def series(reference)
|
350
|
+
# reference.xpath("./seriesInfo").map do |si|
|
351
|
+
# next if si[:name] == "DOI" || si[:stream] || si[:status]
|
352
|
+
|
353
|
+
# RelatonBib::Series.new(
|
354
|
+
# title: RelatonBib::TypedTitleString.new(
|
355
|
+
# content: si[:name], language: language(reference), script: "Latn",
|
356
|
+
# ),
|
357
|
+
# number: si[:value],
|
358
|
+
# type: "main",
|
359
|
+
# )
|
360
|
+
# end.compact
|
361
|
+
# end
|
362
|
+
|
363
|
+
#
|
364
|
+
# extract status
|
365
|
+
# @param reference [Nokogiri::XML::Element]
|
366
|
+
#
|
367
|
+
# @return [RelatonBib::DocumentStatus]
|
368
|
+
#
|
369
|
+
# def status(reference)
|
370
|
+
# st = reference.at("./seriesinfo[@status]")
|
371
|
+
# return unless st
|
372
|
+
|
373
|
+
# RelatonBib::DocumentStatus.new(stage: st[:status])
|
374
|
+
# end
|
367
375
|
end
|
368
|
-
# rubocop:enable Metrics/ModuleLength
|
369
376
|
end
|
data/lib/relaton_ietf/version.rb
CHANGED
data/lib/relaton_ietf.rb
CHANGED
data/relaton_ietf.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: relaton-ietf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.9.
|
4
|
+
version: 1.9.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-
|
11
|
+
date: 2021-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: equivalent-xml
|
@@ -126,16 +126,16 @@ dependencies:
|
|
126
126
|
name: relaton-bib
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - "
|
129
|
+
- - ">="
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 1.9.
|
131
|
+
version: 1.9.5
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- - "
|
136
|
+
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 1.9.
|
138
|
+
version: 1.9.5
|
139
139
|
description: "RelatonIetf: retrieve IETF Standards for bibliographic use \nusing the
|
140
140
|
BibliographicItem model.\n\nFormerly known as rfcbib.\n"
|
141
141
|
email:
|
@@ -163,6 +163,7 @@ files:
|
|
163
163
|
- grammars/reqt.rng
|
164
164
|
- lib/relaton/provider_ietf.rb
|
165
165
|
- lib/relaton_ietf.rb
|
166
|
+
- lib/relaton_ietf/committee.rb
|
166
167
|
- lib/relaton_ietf/hash_converter.rb
|
167
168
|
- lib/relaton_ietf/ietf_bibliographic_item.rb
|
168
169
|
- lib/relaton_ietf/ietf_bibliography.rb
|