relaton-cen 1.8.pre1
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 +46 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +21 -0
- data/README.adoc +203 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/rspec +29 -0
- data/bin/setup +8 -0
- data/grammars/basicdoc.rng +1131 -0
- data/grammars/biblio.rng +1235 -0
- data/grammars/isodoc.rng +1870 -0
- data/grammars/isostandard.rng +478 -0
- data/grammars/reqt.rng +165 -0
- data/lib/relaton_cen.rb +16 -0
- data/lib/relaton_cen/cen_bibliography.rb +111 -0
- data/lib/relaton_cen/committees.yaml +66 -0
- data/lib/relaton_cen/hit.rb +14 -0
- data/lib/relaton_cen/hit_collection.rb +60 -0
- data/lib/relaton_cen/processor.rb +38 -0
- data/lib/relaton_cen/scrapper.rb +198 -0
- data/lib/relaton_cen/version.rb +5 -0
- data/lib/relaton_cen/xml_parser.rb +28 -0
- data/relaton_cen.gemspec +46 -0
- metadata +185 -0
data/grammars/reqt.rng
ADDED
@@ -0,0 +1,165 @@
|
|
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="subsequence"/>
|
35
|
+
</optional>
|
36
|
+
<attribute name="id">
|
37
|
+
<data type="ID"/>
|
38
|
+
</attribute>
|
39
|
+
<optional>
|
40
|
+
<attribute name="filename"/>
|
41
|
+
</optional>
|
42
|
+
<optional>
|
43
|
+
<ref name="reqtitle"/>
|
44
|
+
</optional>
|
45
|
+
<optional>
|
46
|
+
<ref name="label"/>
|
47
|
+
</optional>
|
48
|
+
<optional>
|
49
|
+
<ref name="subject"/>
|
50
|
+
</optional>
|
51
|
+
<optional>
|
52
|
+
<ref name="reqinherit"/>
|
53
|
+
</optional>
|
54
|
+
<zeroOrMore>
|
55
|
+
<ref name="classification"/>
|
56
|
+
</zeroOrMore>
|
57
|
+
<zeroOrMore>
|
58
|
+
<choice>
|
59
|
+
<ref name="measurementtarget"/>
|
60
|
+
<ref name="specification"/>
|
61
|
+
<ref name="verification"/>
|
62
|
+
<ref name="import"/>
|
63
|
+
<ref name="description"/>
|
64
|
+
</choice>
|
65
|
+
</zeroOrMore>
|
66
|
+
<optional>
|
67
|
+
<ref name="reqt_references"/>
|
68
|
+
</optional>
|
69
|
+
<zeroOrMore>
|
70
|
+
<choice>
|
71
|
+
<ref name="requirement"/>
|
72
|
+
<ref name="recommendation"/>
|
73
|
+
<ref name="permission"/>
|
74
|
+
</choice>
|
75
|
+
</zeroOrMore>
|
76
|
+
</define>
|
77
|
+
<define name="reqtitle">
|
78
|
+
<element name="title">
|
79
|
+
<ref name="FormattedString"/>
|
80
|
+
</element>
|
81
|
+
</define>
|
82
|
+
<define name="label">
|
83
|
+
<element name="label">
|
84
|
+
<text/>
|
85
|
+
</element>
|
86
|
+
</define>
|
87
|
+
<define name="subject">
|
88
|
+
<element name="subject">
|
89
|
+
<text/>
|
90
|
+
</element>
|
91
|
+
</define>
|
92
|
+
<define name="reqinherit">
|
93
|
+
<element name="inherit">
|
94
|
+
<text/>
|
95
|
+
</element>
|
96
|
+
</define>
|
97
|
+
<define name="measurementtarget">
|
98
|
+
<element name="measurement-target">
|
99
|
+
<ref name="RequirementSubpart"/>
|
100
|
+
</element>
|
101
|
+
</define>
|
102
|
+
<define name="specification">
|
103
|
+
<element name="specification">
|
104
|
+
<ref name="RequirementSubpart"/>
|
105
|
+
</element>
|
106
|
+
</define>
|
107
|
+
<define name="verification">
|
108
|
+
<element name="verification">
|
109
|
+
<ref name="RequirementSubpart"/>
|
110
|
+
</element>
|
111
|
+
</define>
|
112
|
+
<define name="import">
|
113
|
+
<element name="import">
|
114
|
+
<ref name="RequirementSubpart"/>
|
115
|
+
</element>
|
116
|
+
</define>
|
117
|
+
<define name="description">
|
118
|
+
<element name="description">
|
119
|
+
<ref name="RequirementSubpart"/>
|
120
|
+
</element>
|
121
|
+
</define>
|
122
|
+
<define name="reqt_references">
|
123
|
+
<element name="references">
|
124
|
+
<oneOrMore>
|
125
|
+
<ref name="bibitem"/>
|
126
|
+
</oneOrMore>
|
127
|
+
</element>
|
128
|
+
</define>
|
129
|
+
<define name="RequirementSubpart">
|
130
|
+
<optional>
|
131
|
+
<attribute name="type"/>
|
132
|
+
</optional>
|
133
|
+
<optional>
|
134
|
+
<attribute name="exclude">
|
135
|
+
<data type="boolean"/>
|
136
|
+
</attribute>
|
137
|
+
</optional>
|
138
|
+
<oneOrMore>
|
139
|
+
<ref name="BasicBlock"/>
|
140
|
+
</oneOrMore>
|
141
|
+
</define>
|
142
|
+
<define name="ObligationType">
|
143
|
+
<choice>
|
144
|
+
<value>requirement</value>
|
145
|
+
<value>recommendation</value>
|
146
|
+
<value>permission</value>
|
147
|
+
</choice>
|
148
|
+
</define>
|
149
|
+
<define name="classification">
|
150
|
+
<element name="classification">
|
151
|
+
<ref name="classification_tag"/>
|
152
|
+
<ref name="classification_value"/>
|
153
|
+
</element>
|
154
|
+
</define>
|
155
|
+
<define name="classification_tag">
|
156
|
+
<element name="tag">
|
157
|
+
<text/>
|
158
|
+
</element>
|
159
|
+
</define>
|
160
|
+
<define name="classification_value">
|
161
|
+
<element name="value">
|
162
|
+
<text/>
|
163
|
+
</element>
|
164
|
+
</define>
|
165
|
+
</grammar>
|
data/lib/relaton_cen.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "digest/md5"
|
4
|
+
require_relative "relaton_cen/version"
|
5
|
+
require "relaton_cen/cen_bibliography"
|
6
|
+
|
7
|
+
module RelatonCen
|
8
|
+
# Returns hash of XML greammar
|
9
|
+
# @return [String]
|
10
|
+
def self.grammar_hash
|
11
|
+
gem_path = File.expand_path "..", __dir__
|
12
|
+
grammars_path = File.join gem_path, "grammars", "*"
|
13
|
+
grammars = Dir[grammars_path].sort.map { |gp| File.read gp }.join
|
14
|
+
Digest::MD5.hexdigest grammars
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mechanize"
|
4
|
+
require "relaton_iso_bib"
|
5
|
+
require "relaton_cen/scrapper"
|
6
|
+
require "relaton_cen/hit_collection"
|
7
|
+
require "relaton_cen/hit"
|
8
|
+
require "relaton_cen/xml_parser"
|
9
|
+
|
10
|
+
module RelatonCen
|
11
|
+
# Class methods for search Cenelec standards.
|
12
|
+
class CenBibliography
|
13
|
+
class << self
|
14
|
+
# @param text [String]
|
15
|
+
# @return [RelatonCen::HitCollection]
|
16
|
+
def search(text, year = nil)
|
17
|
+
/^CEN\s(?<code>.+)/ =~ text
|
18
|
+
HitCollection.new code, year
|
19
|
+
rescue Mechanize::ResponseCodeError => e
|
20
|
+
raise RelatonBib::RequestError, e.message
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param code [String] the CEN standard Code to look up
|
24
|
+
# @param year [String] the year the standard was published (optional)
|
25
|
+
# @param opts [Hash] options; restricted to :all_parts if all-parts
|
26
|
+
# reference is required
|
27
|
+
# @return [RelatonBib::BibliographicItem, nil]
|
28
|
+
def get(code, year = nil, opts = {}) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
29
|
+
# if year.nil?
|
30
|
+
code1, year1 = code.split ":"
|
31
|
+
# unless code1.nil?
|
32
|
+
code = code1
|
33
|
+
year ||= year1
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
|
37
|
+
ret = bib_get1(code, year, opts)
|
38
|
+
return nil if ret.nil?
|
39
|
+
|
40
|
+
# ret = ret.to_most_recent_reference unless year || opts[:keep_year]
|
41
|
+
# ret = ret.to_all_parts if opts[:all_parts]
|
42
|
+
ret
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def fetch_ref_err(code, year, missed_years) # rubocop:disable Metrics/MethodLength
|
48
|
+
id = year ? "#{code}:#{year}" : code
|
49
|
+
warn "[relaton-cen] WARNING: no match found online for #{id}. "\
|
50
|
+
"The code must be exactly like it is on the standards website."
|
51
|
+
unless missed_years.empty?
|
52
|
+
warn "[relaton-cen] (There was no match for #{year}, though there "\
|
53
|
+
"were matches found for #{missed_years.join(', ')}.)"
|
54
|
+
end
|
55
|
+
# if /\d-\d/.match? code
|
56
|
+
# warn "[relaton-cen] The provided document part may not exist, or "\
|
57
|
+
# "the document may no longer be published in parts."
|
58
|
+
# else
|
59
|
+
# warn "[relaton-cen] If you wanted to cite all document parts for "\
|
60
|
+
# "the reference, use \"#{code} (all parts)\".\nIf the document "\
|
61
|
+
# "is not a standard, use its document type abbreviation (TS, TR, "]
|
62
|
+
# "PAS, Guide)."
|
63
|
+
# end
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param code [String]
|
68
|
+
# @return [RelatonCen::HitCollection]
|
69
|
+
def search_filter(code) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
70
|
+
%r{^CEN\s(?<code1>[^-:]+)(?:-(?<part1>\d+))?} =~ code
|
71
|
+
warn "[relaton-cen] (\"#{code}\") fetching..."
|
72
|
+
result = search(code)
|
73
|
+
result.select do |i|
|
74
|
+
%r{^(?<code2>[^:-]+)(?:-(?<part2>\d+))?} =~ i.hit[:code]
|
75
|
+
code2.include?(code1) && (!part1 || part1 = part2)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Sort through the results from Isobib, fetching them three at a time,
|
80
|
+
# and return the first result that matches the code,
|
81
|
+
# matches the year (if provided), and which # has a title (amendments do not).
|
82
|
+
# Only expects the first page of results to be populated.
|
83
|
+
# Does not match corrigenda etc (e.g. ISO 3166-1:2006/Cor 1:2007)
|
84
|
+
# If no match, returns any years which caused mismatch, for error reporting
|
85
|
+
def isobib_results_filter(result, year)
|
86
|
+
missed_years = []
|
87
|
+
result.each do |r|
|
88
|
+
/:(?<pyear>\d{4})/ =~ r.hit[:code]
|
89
|
+
if !year || year == pyear
|
90
|
+
ret = r.fetch
|
91
|
+
return { ret: ret } if ret
|
92
|
+
end
|
93
|
+
|
94
|
+
missed_years << pyear
|
95
|
+
end
|
96
|
+
{ years: missed_years }
|
97
|
+
end
|
98
|
+
|
99
|
+
def bib_get1(code, year, _opts)
|
100
|
+
result = search_filter(code) || return
|
101
|
+
ret = isobib_results_filter(result, year)
|
102
|
+
if ret[:ret]
|
103
|
+
warn "[relaton-cen] (\"#{code}\") found #{ret[:ret].docidentifier.first&.id}"
|
104
|
+
ret[:ret]
|
105
|
+
else
|
106
|
+
fetch_ref_err(code, year, ret[:years])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
ASD-STAN: Aerospace
|
2
|
+
CEN/CLC/ETSI/SMCG: CEN-CENELEC-ETSI Coordination Group on Smart Meters
|
3
|
+
CEN/CLC/ETSI/JWG eAcc: eAccessibility
|
4
|
+
CEN/CLC/ETSI/SEG-CG: CEN-CENELEC-ETSI Coordination Group on Smart Grids
|
5
|
+
CEN/CLC/ETSI/SF-SSCC: CEN-CENELEC-ETSI Sector Forum on Smart and Sustainable Cities and Communities
|
6
|
+
CEN/CLC/Guides: Group for CEN-CENELEC Guides
|
7
|
+
CEN/CLC/JTC 1: Criteria for conformity assessment bodies
|
8
|
+
CEN/CLC/JTC 2: Power Engineering
|
9
|
+
CEN/CLC/JTC 3: Quality management and corresponding general aspects for medical devices
|
10
|
+
CEN/CLC/JTC 4: Services for fire safety and security systems
|
11
|
+
CEN/CLC/JTC 5: Space
|
12
|
+
CEN/CLC/JTC 6: Hydrogen in energy systems
|
13
|
+
CEN/CLC/JTC 10: Energy-related products - Material Efficiency Aspects for Ecodesign
|
14
|
+
CEN/CLC/JTC 11: Accessibility in the built environment
|
15
|
+
CEN/CLC/JTC 12: Design for All
|
16
|
+
CEN/CLC/JTC 13: Cybersecurity and Data Protection
|
17
|
+
CEN/CLC/JTC 14: Energy management and energy efficiency in the framework of energy transition
|
18
|
+
CEN/CLC/JTC 15: Energy measurement plan for organizations
|
19
|
+
CEN/CLC/JTC 16: CEN/CENELEC Joint Technical Committee on Active Implantable Medical Devices
|
20
|
+
CEN/CLC/JTC 17: Gas Appliances with Combined Heat and Power
|
21
|
+
CEN/CLC/JTC 18: Non automatic weighing instruments (NAWI)
|
22
|
+
CEN/CLC/JTC 19: Blockchain and Distributed Ledger Technologies
|
23
|
+
CEN/CLC/JTC 20: Hyperloop systems
|
24
|
+
CEN/CLC/JTC 21: Artificial Intelligence
|
25
|
+
CEN/CLC/WS 017: Development of a GALILEO enabled label
|
26
|
+
CEN/CLC/WS 018: Assessment of the resilience of transport infrastructure to potentially disruptive events
|
27
|
+
CEN/CLC/WS SEA-TITAN: Modular and cross-cutting Power Take-Off units for wave energy converters. Recommendations and laboratory testing
|
28
|
+
CEN/CLC/WS SEP2: Industry Best Practices and an Industry Code of Conduct for Licensing of Standard Essential Patents in the field of 5G and Internet of Things
|
29
|
+
CEN/CLC/WS HECTOS: CEN-CENELEC Workshop on Guidelines on evaluation systems and schemes for physical security products
|
30
|
+
CEN/CLC/WS INACHUS: Urban search and rescue (USaR) robotic platform technical and procedural interoperability
|
31
|
+
CEN/CLC/WS Monsoon: Predictive management of data intensive industrial processes
|
32
|
+
CEN/CLC/WS REEMAIN: CEN/CENELEC Workshop on REEMAIN Methodology for Resource and Energy Efficiency Manufacturing
|
33
|
+
CEN/CLC/WS SEP-IoT: Workshop on Best Practices and a Code of Conduct for Licensing Industry Standard Essential Patents in 5G and the Internet of Things (IoT), including the Industrial Internet
|
34
|
+
CEN/CLC/WS ZONeSEC: Interoperability of security systems for the surveillance of widezones
|
35
|
+
CEN/CLC/WS EINSTEIN: Good Practice Thermal Energy Audits (GPTEA)
|
36
|
+
CEN/CLC/WS WiseGRID: Reference model for distribution application for microgrids
|
37
|
+
CEN/CLC/WS EFPFInterOp: European Connected Factory Platform for Agile Manufacturing Interoperability
|
38
|
+
CEN/CLC/WS ZDMterm: Zero Defects in Digital Manufacturing Terminology
|
39
|
+
CEN/SS C20: Explosives and firework
|
40
|
+
CEN/SS S08: Air quality
|
41
|
+
CEN/SS S12: Gas analysis
|
42
|
+
CEN/Guides: Group for CEN Guides
|
43
|
+
CEN/SS A03: Postal services
|
44
|
+
CEN/SS A07: Translation and Interpretation services
|
45
|
+
CEN/SS A08: Funeral services
|
46
|
+
CEN/SS A10: Services of Real Estate Agents
|
47
|
+
CEN/SS A11: Security services
|
48
|
+
CEN/SS A99: Services - Undetermined
|
49
|
+
CEN/SS B02: Structures
|
50
|
+
CEN/SS B09: Energy Performance of Buildings Directive (EPBD)
|
51
|
+
CEN/SS B99: Building and construction - Undetermined
|
52
|
+
CEN/SS C01: Food Products
|
53
|
+
CEN/SS C10: Starch
|
54
|
+
CEN/SS F01: Technical drawings
|
55
|
+
CEN/SS F02: Units and symbols
|
56
|
+
CEN/SS F05: Measuring Instruments
|
57
|
+
CEN/SS F12: Information Processing Systems
|
58
|
+
CEN/SS F16: Graphical symbols
|
59
|
+
CEN/SS F17: Administrative documents
|
60
|
+
CEN/SS F20: Quality assurance
|
61
|
+
CEN/SS F23: Energy
|
62
|
+
CEN/SS H10: Sewing machines
|
63
|
+
CEN/SS H22: Smokers' lighters
|
64
|
+
CEN/SS H99: Products for household and leisure use - Undetermined
|
65
|
+
|
66
|
+
TC 459: ECISS - European Committee for Iron and Steel Standardization
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "relaton_cen/hit"
|
4
|
+
|
5
|
+
module RelatonCen
|
6
|
+
# Page of hit collection.
|
7
|
+
class HitCollection < RelatonBib::HitCollection
|
8
|
+
DOMAIN = "https://standards.cen.eu/dyn/www/"
|
9
|
+
|
10
|
+
# @return [Mechanize]
|
11
|
+
attr_reader :agent
|
12
|
+
|
13
|
+
# @param ref [String]
|
14
|
+
# @param year [String]
|
15
|
+
def initialize(ref, year = nil) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
16
|
+
super ref, year
|
17
|
+
@agent = Mechanize.new
|
18
|
+
agent.user_agent_alias = "Mac Safari"
|
19
|
+
if !ref || ref.empty?
|
20
|
+
@array = []
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
search_page = agent.get "#{DOMAIN}f?p=204:105:0:::::"
|
25
|
+
form = search_page.at "//form"
|
26
|
+
req_body = form.xpath("//input").map do |f|
|
27
|
+
next if f[:name].empty? || f[:name] == "f11"
|
28
|
+
|
29
|
+
val = case f[:value]
|
30
|
+
when "LANGUAGE_LIST" then 0
|
31
|
+
when "STAND_REF" then ref
|
32
|
+
else
|
33
|
+
case f[:name]
|
34
|
+
when "p_request" then "S1-S2-S3-S4-S5-S6"
|
35
|
+
when "f10" then ""
|
36
|
+
else f[:value]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
if f[:name] == "f10" then "f10=#{f[:value]}&f11=#{val}"
|
40
|
+
else "#{f[:name]}=#{val}"
|
41
|
+
end
|
42
|
+
end.compact.join("&")
|
43
|
+
resp = agent.post form[:action], req_body
|
44
|
+
@array = hits resp
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# @param resp [Mechanize::Page]
|
50
|
+
# @return [Array<RelatonCen::Hit>]
|
51
|
+
def hits(resp)
|
52
|
+
resp.xpath("//table[@class='dashlist']/tbody/tr/td[2]").map do |h|
|
53
|
+
ref = h.at("strong/a")
|
54
|
+
code = ref.text.strip
|
55
|
+
url = ref[:href]
|
56
|
+
Hit.new({ code: code, url: url }, self)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "relaton/processor"
|
2
|
+
|
3
|
+
module RelatonCen
|
4
|
+
class Processor < Relaton::Processor
|
5
|
+
def initialize
|
6
|
+
@short = :relaton_cen
|
7
|
+
@prefix = "CEN"
|
8
|
+
@defaultprefix = %r{^CEN\s}
|
9
|
+
@idtype = "CEN"
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param code [String]
|
13
|
+
# @param date [String, NilClass] year
|
14
|
+
# @param opts [Hash]
|
15
|
+
# @return [RelatonBib::BibliographicItem]
|
16
|
+
def get(code, date, opts)
|
17
|
+
::RelatonCen::CenBibliography.get(code, date, opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param xml [String]
|
21
|
+
# @return [RelatonBib::BibliographicItem]
|
22
|
+
def from_xml(xml)
|
23
|
+
::RelatonCen::XMLParser.from_xml xml
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param hash [Hash]
|
27
|
+
# @return [RelatonBib::BibliographicItem]
|
28
|
+
def hash_to_bib(hash)
|
29
|
+
::RelatonIsoBib::IsoBibliographicItem.from_hash hash
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns hash of XML grammar
|
33
|
+
# @return [String]
|
34
|
+
def grammar_hash
|
35
|
+
@grammar_hash ||= ::RelatonIsoBib.grammar_hash
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|