relaton-3gpp 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/rake.yml +36 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.rubocop.yml +12 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +21 -0
- data/README.adoc +170 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/rspec +29 -0
- data/bin/setup +8 -0
- data/grammars/3gpp.rng +105 -0
- data/grammars/basicdoc.rng +1131 -0
- data/grammars/biblio.rng +1236 -0
- data/grammars/isodoc.rng +2519 -0
- data/grammars/reqt.rng +205 -0
- data/lib/relaton_3gpp/bibliographic_item.rb +74 -0
- data/lib/relaton_3gpp/bibliography.rb +44 -0
- data/lib/relaton_3gpp/data_fetcher.rb +135 -0
- data/lib/relaton_3gpp/hash_converter.rb +21 -0
- data/lib/relaton_3gpp/parser.rb +244 -0
- data/lib/relaton_3gpp/processor.rb +54 -0
- data/lib/relaton_3gpp/release.rb +65 -0
- data/lib/relaton_3gpp/version.rb +5 -0
- data/lib/relaton_3gpp/xml_parser.rb +58 -0
- data/lib/relaton_3gpp.rb +25 -0
- data/relaton_3gpp.gemspec +50 -0
- metadata +225 -0
data/grammars/reqt.rng
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
3
|
+
<!--
|
4
|
+
Presupposes isodoc.rnc, is included in it
|
5
|
+
include "isodoc.rnc" { }
|
6
|
+
-->
|
7
|
+
<define name="requirement">
|
8
|
+
<element name="requirement">
|
9
|
+
<ref name="RequirementType"/>
|
10
|
+
</element>
|
11
|
+
</define>
|
12
|
+
<define name="recommendation">
|
13
|
+
<element name="recommendation">
|
14
|
+
<ref name="RequirementType"/>
|
15
|
+
</element>
|
16
|
+
</define>
|
17
|
+
<define name="permission">
|
18
|
+
<element name="permission">
|
19
|
+
<ref name="RequirementType"/>
|
20
|
+
</element>
|
21
|
+
</define>
|
22
|
+
<define name="RequirementType">
|
23
|
+
<optional>
|
24
|
+
<attribute name="obligation">
|
25
|
+
<ref name="ObligationType"/>
|
26
|
+
</attribute>
|
27
|
+
</optional>
|
28
|
+
<optional>
|
29
|
+
<attribute name="unnumbered">
|
30
|
+
<data type="boolean"/>
|
31
|
+
</attribute>
|
32
|
+
</optional>
|
33
|
+
<optional>
|
34
|
+
<attribute name="number"/>
|
35
|
+
</optional>
|
36
|
+
<optional>
|
37
|
+
<attribute name="subsequence"/>
|
38
|
+
</optional>
|
39
|
+
<optional>
|
40
|
+
<attribute name="keep-with-next">
|
41
|
+
<data type="boolean"/>
|
42
|
+
</attribute>
|
43
|
+
</optional>
|
44
|
+
<optional>
|
45
|
+
<attribute name="keep-lines-together">
|
46
|
+
<data type="boolean"/>
|
47
|
+
</attribute>
|
48
|
+
</optional>
|
49
|
+
<attribute name="id">
|
50
|
+
<data type="ID"/>
|
51
|
+
</attribute>
|
52
|
+
<optional>
|
53
|
+
<attribute name="filename"/>
|
54
|
+
</optional>
|
55
|
+
<optional>
|
56
|
+
<attribute name="model"/>
|
57
|
+
</optional>
|
58
|
+
<optional>
|
59
|
+
<attribute name="type"/>
|
60
|
+
</optional>
|
61
|
+
<optional>
|
62
|
+
<ref name="reqtitle"/>
|
63
|
+
</optional>
|
64
|
+
<optional>
|
65
|
+
<ref name="label"/>
|
66
|
+
</optional>
|
67
|
+
<zeroOrMore>
|
68
|
+
<ref name="subject"/>
|
69
|
+
</zeroOrMore>
|
70
|
+
<zeroOrMore>
|
71
|
+
<ref name="reqinherit"/>
|
72
|
+
</zeroOrMore>
|
73
|
+
<zeroOrMore>
|
74
|
+
<ref name="classification"/>
|
75
|
+
</zeroOrMore>
|
76
|
+
<zeroOrMore>
|
77
|
+
<choice>
|
78
|
+
<ref name="measurementtarget"/>
|
79
|
+
<ref name="specification"/>
|
80
|
+
<ref name="verification"/>
|
81
|
+
<ref name="import"/>
|
82
|
+
<ref name="description"/>
|
83
|
+
<ref name="component"/>
|
84
|
+
</choice>
|
85
|
+
</zeroOrMore>
|
86
|
+
<optional>
|
87
|
+
<ref name="reqt_references"/>
|
88
|
+
</optional>
|
89
|
+
<zeroOrMore>
|
90
|
+
<choice>
|
91
|
+
<ref name="requirement"/>
|
92
|
+
<ref name="recommendation"/>
|
93
|
+
<ref name="permission"/>
|
94
|
+
</choice>
|
95
|
+
</zeroOrMore>
|
96
|
+
</define>
|
97
|
+
<define name="reqtitle">
|
98
|
+
<element name="title">
|
99
|
+
<ref name="FormattedString"/>
|
100
|
+
</element>
|
101
|
+
</define>
|
102
|
+
<define name="label">
|
103
|
+
<element name="label">
|
104
|
+
<text/>
|
105
|
+
</element>
|
106
|
+
</define>
|
107
|
+
<define name="subject">
|
108
|
+
<element name="subject">
|
109
|
+
<oneOrMore>
|
110
|
+
<ref name="TextElement"/>
|
111
|
+
</oneOrMore>
|
112
|
+
</element>
|
113
|
+
</define>
|
114
|
+
<define name="reqinherit">
|
115
|
+
<element name="inherit">
|
116
|
+
<oneOrMore>
|
117
|
+
<ref name="TextElement"/>
|
118
|
+
</oneOrMore>
|
119
|
+
</element>
|
120
|
+
</define>
|
121
|
+
<define name="measurementtarget">
|
122
|
+
<element name="measurement-target">
|
123
|
+
<ref name="RequirementSubpart"/>
|
124
|
+
</element>
|
125
|
+
</define>
|
126
|
+
<define name="specification">
|
127
|
+
<element name="specification">
|
128
|
+
<ref name="RequirementSubpart"/>
|
129
|
+
</element>
|
130
|
+
</define>
|
131
|
+
<define name="verification">
|
132
|
+
<element name="verification">
|
133
|
+
<ref name="RequirementSubpart"/>
|
134
|
+
</element>
|
135
|
+
</define>
|
136
|
+
<define name="import">
|
137
|
+
<element name="import">
|
138
|
+
<ref name="RequirementSubpart"/>
|
139
|
+
</element>
|
140
|
+
</define>
|
141
|
+
<define name="description">
|
142
|
+
<element name="description">
|
143
|
+
<ref name="RequirementSubpart"/>
|
144
|
+
</element>
|
145
|
+
</define>
|
146
|
+
<define name="component">
|
147
|
+
<element name="component">
|
148
|
+
<attribute name="class"/>
|
149
|
+
<ref name="RequirementSubpart"/>
|
150
|
+
</element>
|
151
|
+
</define>
|
152
|
+
<define name="reqt_references">
|
153
|
+
<element name="references">
|
154
|
+
<oneOrMore>
|
155
|
+
<ref name="bibitem"/>
|
156
|
+
</oneOrMore>
|
157
|
+
</element>
|
158
|
+
</define>
|
159
|
+
<define name="RequirementSubpart">
|
160
|
+
<optional>
|
161
|
+
<attribute name="type"/>
|
162
|
+
</optional>
|
163
|
+
<optional>
|
164
|
+
<attribute name="exclude">
|
165
|
+
<data type="boolean"/>
|
166
|
+
</attribute>
|
167
|
+
</optional>
|
168
|
+
<optional>
|
169
|
+
<attribute name="keep-with-next">
|
170
|
+
<data type="boolean"/>
|
171
|
+
</attribute>
|
172
|
+
</optional>
|
173
|
+
<optional>
|
174
|
+
<attribute name="keep-lines-together">
|
175
|
+
<data type="boolean"/>
|
176
|
+
</attribute>
|
177
|
+
</optional>
|
178
|
+
<oneOrMore>
|
179
|
+
<ref name="BasicBlock"/>
|
180
|
+
</oneOrMore>
|
181
|
+
</define>
|
182
|
+
<define name="ObligationType">
|
183
|
+
<choice>
|
184
|
+
<value>requirement</value>
|
185
|
+
<value>recommendation</value>
|
186
|
+
<value>permission</value>
|
187
|
+
</choice>
|
188
|
+
</define>
|
189
|
+
<define name="classification">
|
190
|
+
<element name="classification">
|
191
|
+
<ref name="classification_tag"/>
|
192
|
+
<ref name="classification_value"/>
|
193
|
+
</element>
|
194
|
+
</define>
|
195
|
+
<define name="classification_tag">
|
196
|
+
<element name="tag">
|
197
|
+
<text/>
|
198
|
+
</element>
|
199
|
+
</define>
|
200
|
+
<define name="classification_value">
|
201
|
+
<element name="value">
|
202
|
+
<text/>
|
203
|
+
</element>
|
204
|
+
</define>
|
205
|
+
</grammar>
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Relaton3gpp
|
2
|
+
class BibliographicItem < RelatonBib::BibliographicItem
|
3
|
+
DOCTYPES = %w[TR TS].freeze
|
4
|
+
DOCSUBTYPES = %w[spec release].freeze
|
5
|
+
RADIOTECHNOLOGIES = %w[2G 3G LTE 5G].freeze
|
6
|
+
|
7
|
+
#
|
8
|
+
# Initialize bibliographic item.
|
9
|
+
#
|
10
|
+
# @param [String] radiotechnology
|
11
|
+
# @param [Boolean] common_ims_spec
|
12
|
+
# @param [Relaton3gpp::Release] release
|
13
|
+
#
|
14
|
+
def initialize(**args) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
15
|
+
@radiotechnology = args.delete(:radiotechnology)
|
16
|
+
if @radiotechnology && !RADIOTECHNOLOGIES.include?(@radiotechnology)
|
17
|
+
warn "[relaton-3gpp] Unknown radiotechnology type: #{@radiotechnology}"
|
18
|
+
warn "[relaton-3gpp] Possible radiotechnology types: #{RADIOTECHNOLOGIES.join ' '}"
|
19
|
+
end
|
20
|
+
@common_ims_spec = args.delete(:common_ims_spec)
|
21
|
+
@release = args.delete(:release)
|
22
|
+
if args[:doctype].nil? then warn "[relaton-3gpp] doctype is missing"
|
23
|
+
elsif !DOCTYPES.include?(args[:doctype])
|
24
|
+
warn "[relaton-3gpp] Unknown doctype: #{args[:doctype]}"
|
25
|
+
warn "[relaton-3gpp] Possible doctypes: #{DOCTYPES.join ' '}"
|
26
|
+
end
|
27
|
+
if args[:docsubtype] && !DOCSUBTYPES.include?(args[:docsubtype])
|
28
|
+
warn "[relaton-3gpp] Unknown docsubtype: #{args[:docsubtype]}"
|
29
|
+
warn "[relaton-3gpp] Possible docsubtypes: #{DOCSUBTYPES.join ' '}"
|
30
|
+
end
|
31
|
+
super(**args)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param opts [Hash]
|
35
|
+
# @option opts [Nokogiri::XML::Builder] :builder XML builder
|
36
|
+
# @option opts [Boolean] :bibdata
|
37
|
+
# @option opts [String] :lang language
|
38
|
+
# @return [String] XML
|
39
|
+
def to_xml(**opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
40
|
+
super do |b|
|
41
|
+
if block_given? then yield b
|
42
|
+
elsif opts[:bibdata] && has_ext_attrs?
|
43
|
+
b.ext do
|
44
|
+
b.doctype doctype if doctype
|
45
|
+
b.subdoctype subdoctype if subdoctype
|
46
|
+
editorialgroup&.to_xml b
|
47
|
+
ics.each { |i| i.to_xml b }
|
48
|
+
b.radiotechnology @radiotechnology if @radiotechnology
|
49
|
+
b.send "common-ims-spec", @common_ims_spec if @common_ims_spec
|
50
|
+
@release&.to_xml b if @release
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def has_ext_attrs? # rubocop:disable Metrics/CyclomaticComplexity
|
57
|
+
doctype || subdoctype || editorialgroup || ics.any? || @radiotechnology ||
|
58
|
+
@common_ims_spec || @release
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Convert to hash.
|
63
|
+
#
|
64
|
+
# @return [Hash
|
65
|
+
#
|
66
|
+
def to_hash
|
67
|
+
hash = super
|
68
|
+
hash["radiotechnology"] = @radiotechnology if @radiotechnology
|
69
|
+
hash["common-ims-spec"] = @common_ims_spec if @common_ims_spec
|
70
|
+
hash["release"] = @release.to_hash if @release
|
71
|
+
hash
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Relaton3gpp
|
4
|
+
# Methods for search IANA standards.
|
5
|
+
module Bibliography
|
6
|
+
# SOURCE = "http://xml2rfc.tools.ietf.org/public/rfc/bibxml-3gpp-new/"
|
7
|
+
SOURCE = "https://raw.githubusercontent.com/relaton/relaton-data-3gpp/main/data/"
|
8
|
+
|
9
|
+
# @param text [String]
|
10
|
+
# @return [RelatonBib::BibliographicItem]
|
11
|
+
def search(text) # rubocop:disable Metrics/MethodLength
|
12
|
+
file = text.sub(/^3GPP\s/, "").gsub(/[\s,:\/]/, "_").squeeze("_").upcase
|
13
|
+
url = "#{SOURCE}#{file}.yaml"
|
14
|
+
resp = Net::HTTP.get_response URI(url)
|
15
|
+
return unless resp.code == "200"
|
16
|
+
|
17
|
+
hash = YAML.safe_load resp.body
|
18
|
+
bib_hash = Relaton3gpp::HashConverter.hash_to_bib(hash)
|
19
|
+
Relaton3gpp::BibliographicItem.new(**bib_hash)
|
20
|
+
rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
|
21
|
+
EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
|
22
|
+
Net::ProtocolError, Errno::ETIMEDOUT => e
|
23
|
+
raise RelatonBib::RequestError, e.message
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param ref [String] the W3C standard Code to look up
|
27
|
+
# @param year [String, NilClass] not used
|
28
|
+
# @param opts [Hash] options
|
29
|
+
# @return [RelatonBib::BibliographicItem]
|
30
|
+
def get(ref, _year = nil, _opts = {})
|
31
|
+
warn "[relaton-3gpp] (\"#{ref}\") fetching..."
|
32
|
+
result = search(ref)
|
33
|
+
unless result
|
34
|
+
warn "[relaton-3gpp] (\"#{ref}\") not found"
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
warn "[relaton-3gpp] (\"#{ref}\") found #{result.docidentifier[0].id}"
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
42
|
+
extend Bibliography
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "net/ftp"
|
3
|
+
require "zip"
|
4
|
+
require "mdb"
|
5
|
+
|
6
|
+
module Relaton3gpp
|
7
|
+
class DataFetcher
|
8
|
+
CURRENT = "current.yaml".freeze
|
9
|
+
#
|
10
|
+
# Data fetcher initializer
|
11
|
+
#
|
12
|
+
# @param [String] output directory to save files
|
13
|
+
# @param [String] format format of output files (xml, yaml, bibxml)
|
14
|
+
#
|
15
|
+
def initialize(output, format)
|
16
|
+
@output = output
|
17
|
+
@format = format
|
18
|
+
@ext = format.sub(/^bib/, "")
|
19
|
+
@files = []
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Initialize fetcher and run fetch
|
24
|
+
#
|
25
|
+
# @param [Strin] output directory to save files, default: "data"
|
26
|
+
# @param [Strin] format format of output files (xml, yaml, bibxml), default: yaml
|
27
|
+
#
|
28
|
+
def self.fetch(output: "data", format: "yaml")
|
29
|
+
t1 = Time.now
|
30
|
+
puts "Started at: #{t1}"
|
31
|
+
FileUtils.mkdir_p output unless Dir.exist? output
|
32
|
+
new(output, format).fetch
|
33
|
+
t2 = Time.now
|
34
|
+
puts "Stopped at: #{t2}"
|
35
|
+
puts "Done in: #{(t2 - t1).round} sec."
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Parse documents
|
40
|
+
#
|
41
|
+
def fetch # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
42
|
+
file = get_file
|
43
|
+
return unless file
|
44
|
+
|
45
|
+
Zip::File.open(file) do |zip_file|
|
46
|
+
enntry = zip_file.glob("status_smg_3GPP.mdb").first
|
47
|
+
File.open("status_smg_3GPP.mdb", "wb") do |f|
|
48
|
+
f.write enntry.get_input_stream.read
|
49
|
+
end
|
50
|
+
end
|
51
|
+
dbs = Mdb.open "status_smg_3GPP.mdb"
|
52
|
+
specs = dbs["Specs_GSM+3G"]
|
53
|
+
specrels = dbs["Specs_GSM+3G_release-info"]
|
54
|
+
releases = dbs["Releases"]
|
55
|
+
dbs["2001-04-25_schedule"].each do |row|
|
56
|
+
fetch_doc row, specs, specrels, releases
|
57
|
+
end
|
58
|
+
File.write CURRENT, @current.to_yaml, encoding: "UTF-8"
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Get file from FTP
|
63
|
+
#
|
64
|
+
# @return [String] file name
|
65
|
+
#
|
66
|
+
def get_file # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
67
|
+
@current = YAML.load_file CURRENT if File.exist? CURRENT
|
68
|
+
@current ||= {}
|
69
|
+
ftp = Net::FTP.new("www.3gpp.org")
|
70
|
+
ftp.resume = true
|
71
|
+
ftp.login
|
72
|
+
ftp.chdir "/Information/Databases/Spec_Status/"
|
73
|
+
d, t, _, file = ftp.list("*.zip").first.split
|
74
|
+
dt = DateTime.strptime("#{d} #{t}", "%m-%d-%y %I:%M%p")
|
75
|
+
return if file == @current["file"] && dt == DateTime.parse(@current["date"])
|
76
|
+
|
77
|
+
ftp.getbinaryfile file
|
78
|
+
@current["file"] = file
|
79
|
+
@current["date"] = dt.to_s
|
80
|
+
file
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# Fetch document
|
85
|
+
#
|
86
|
+
# @param [Hash] row row from mdb
|
87
|
+
# @param [Mdb] dbs mdb
|
88
|
+
#
|
89
|
+
# @return [Relaton3gpp::BibliographicItem, nil] bibliographic item
|
90
|
+
#
|
91
|
+
def fetch_doc(row, specs, specrels, releases)
|
92
|
+
doc = Parser.parse row, specs, specrels, releases
|
93
|
+
save_doc doc
|
94
|
+
rescue StandardError => e
|
95
|
+
warn "Error: #{e.message}"
|
96
|
+
warn "PubID: #{row[:spec]}:#{row[:release]}/#{row[:MAJOR_VERSION_NB]}."\
|
97
|
+
"#{row[:TECHNICAL_VERSION_NB]}.#{row[:EDITORIAL_VERSION_NB]}"
|
98
|
+
warn e.backtrace[0..5].join("\n")
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Save document to file
|
103
|
+
#
|
104
|
+
# @param [RelatonW3c::W3cBibliographicItem, nil] bib bibliographic item
|
105
|
+
#
|
106
|
+
def save_doc(bib) # rubocop:disable Metrics/MethodLength
|
107
|
+
return unless bib
|
108
|
+
|
109
|
+
c = case @format
|
110
|
+
when "xml" then bib.to_xml(bibdata: true)
|
111
|
+
when "yaml" then bib.to_hash.to_yaml
|
112
|
+
else bib.send("to_#{@format}")
|
113
|
+
end
|
114
|
+
file = file_name(bib)
|
115
|
+
if @files.include? file
|
116
|
+
warn "File #{file} already exists. Document: #{bib.docnumber}"
|
117
|
+
else
|
118
|
+
@files << file
|
119
|
+
end
|
120
|
+
File.write file, c, encoding: "UTF-8"
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Generate file name
|
125
|
+
#
|
126
|
+
# @param [RelatonW3c::W3cBibliographicItem] bib bibliographic item
|
127
|
+
#
|
128
|
+
# @return [String] file name
|
129
|
+
#
|
130
|
+
def file_name(bib)
|
131
|
+
name = bib.docnumber.gsub(/[\s,:\/]/, "_").squeeze("_").upcase
|
132
|
+
File.join @output, "#{name}.#{@ext}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Relaton3gpp
|
2
|
+
class HashConverter < RelatonBib::HashConverter
|
3
|
+
class << self
|
4
|
+
def hash_to_bib(args, nested = false)
|
5
|
+
hash = super
|
6
|
+
release_hash_to_bib(hash)
|
7
|
+
hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def release_hash_to_bib(hash)
|
11
|
+
hash[:release] &&= Release.new(**hash[:release])
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param item_hash [Hash]
|
15
|
+
# @return [RelatonBib::BibliographicItem]
|
16
|
+
def bib_item(item_hash)
|
17
|
+
BibliographicItem.new(**item_hash)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|