metanorma-ieee 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rake.yml +13 -0
  3. data/.rubocop.yml +10 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile +11 -0
  6. data/LICENSE +25 -0
  7. data/README.adoc +30 -0
  8. data/Rakefile +8 -0
  9. data/bin/console +14 -0
  10. data/bin/rspec +17 -0
  11. data/bin/setup +8 -0
  12. data/lib/html2doc/ieee.rb +89 -0
  13. data/lib/isodoc/ieee/base_convert.rb +33 -0
  14. data/lib/isodoc/ieee/html/header.html +146 -0
  15. data/lib/isodoc/ieee/html/html_ieee_intro.html +12 -0
  16. data/lib/isodoc/ieee/html/html_ieee_titlepage.html +44 -0
  17. data/lib/isodoc/ieee/html/htmlstyle.css +1027 -0
  18. data/lib/isodoc/ieee/html/htmlstyle.scss +736 -0
  19. data/lib/isodoc/ieee/html/ieee.css +3603 -0
  20. data/lib/isodoc/ieee/html/ieee.scss +3418 -0
  21. data/lib/isodoc/ieee/html/scripts.html +70 -0
  22. data/lib/isodoc/ieee/html/word_ieee_intro.html +70 -0
  23. data/lib/isodoc/ieee/html/word_ieee_titlepage.html +28 -0
  24. data/lib/isodoc/ieee/html/wordstyle.css +5310 -0
  25. data/lib/isodoc/ieee/html/wordstyle.scss +5026 -0
  26. data/lib/isodoc/ieee/html_convert.rb +52 -0
  27. data/lib/isodoc/ieee/i18n-en.yaml +28 -0
  28. data/lib/isodoc/ieee/i18n.rb +19 -0
  29. data/lib/isodoc/ieee/ieee.amendment.xsl +11177 -0
  30. data/lib/isodoc/ieee/ieee.rb +11 -0
  31. data/lib/isodoc/ieee/ieee.standard.xsl +11177 -0
  32. data/lib/isodoc/ieee/init.rb +28 -0
  33. data/lib/isodoc/ieee/metadata.rb +136 -0
  34. data/lib/isodoc/ieee/pdf_convert.rb +24 -0
  35. data/lib/isodoc/ieee/presentation_terms.rb +181 -0
  36. data/lib/isodoc/ieee/presentation_xml_convert.rb +89 -0
  37. data/lib/isodoc/ieee/word_authority.rb +160 -0
  38. data/lib/isodoc/ieee/word_cleanup.rb +134 -0
  39. data/lib/isodoc/ieee/word_convert.rb +75 -0
  40. data/lib/isodoc/ieee/xref.rb +77 -0
  41. data/lib/isodoc/ieee.rb +11 -0
  42. data/lib/metanorma/ieee/basicdoc.rng +1150 -0
  43. data/lib/metanorma/ieee/biblio.rng +1385 -0
  44. data/lib/metanorma/ieee/boilerplate.xml +298 -0
  45. data/lib/metanorma/ieee/cleanup.rb +160 -0
  46. data/lib/metanorma/ieee/converter.rb +81 -0
  47. data/lib/metanorma/ieee/front.rb +120 -0
  48. data/lib/metanorma/ieee/ieee.rng +97 -0
  49. data/lib/metanorma/ieee/isodoc.rng +2776 -0
  50. data/lib/metanorma/ieee/processor.rb +56 -0
  51. data/lib/metanorma/ieee/reqt.rng +226 -0
  52. data/lib/metanorma/ieee/validate.rb +198 -0
  53. data/lib/metanorma/ieee/validate_section.rb +119 -0
  54. data/lib/metanorma/ieee/validate_style.rb +108 -0
  55. data/lib/metanorma/ieee/version.rb +5 -0
  56. data/lib/metanorma/ieee.rb +11 -0
  57. data/lib/metanorma-ieee.rb +8 -0
  58. data/metanorma-itu.gemspec +41 -0
  59. metadata +284 -0
@@ -0,0 +1,56 @@
1
+ require "metanorma/processor"
2
+
3
+ module Metanorma
4
+ module IEEE
5
+ class Processor < Metanorma::Processor
6
+ def initialize
7
+ @short = :ieee
8
+ @input_format = :asciidoc
9
+ @asciidoctor_backend = :ieee
10
+ end
11
+
12
+ def output_formats
13
+ super.merge(
14
+ html: "html",
15
+ doc: "doc",
16
+ pdf: "pdf",
17
+ )
18
+ end
19
+
20
+ def fonts_manifest
21
+ {
22
+ "Arial" => nil,
23
+ "Courier New" => nil,
24
+ "Times New Roman" => nil,
25
+ "Source Han Sans" => nil,
26
+ "Source Han Sans Normal" => nil,
27
+ "STIX Two Math" => nil,
28
+ }
29
+ end
30
+
31
+ def version
32
+ "Metanorma::IEEE #{Metanorma::IEEE::VERSION}"
33
+ end
34
+
35
+ def output(isodoc_node, inname, outname, format, options = {})
36
+ case format
37
+ when :html
38
+ IsoDoc::IEEE::HtmlConvert.new(options).convert(inname, isodoc_node,
39
+ nil, outname)
40
+ when :doc
41
+ IsoDoc::IEEE::WordConvert.new(options).convert(inname, isodoc_node,
42
+ nil, outname)
43
+ when :pdf
44
+ IsoDoc::IEEE::PdfConvert.new(options).convert(inname, isodoc_node,
45
+ nil, outname)
46
+ when :presentation
47
+ IsoDoc::IEEE::PresentationXMLConvert.new(options).convert(
48
+ inname, isodoc_node, nil, outname
49
+ )
50
+ else
51
+ super
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,226 @@
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
+ <attribute name="tag"/>
63
+ </optional>
64
+ <optional>
65
+ <attribute name="multilingual-rendering">
66
+ <ref name="MultilingualRenderingType"/>
67
+ </attribute>
68
+ </optional>
69
+ <optional>
70
+ <ref name="reqtitle"/>
71
+ </optional>
72
+ <optional>
73
+ <ref name="label"/>
74
+ </optional>
75
+ <zeroOrMore>
76
+ <ref name="subject"/>
77
+ </zeroOrMore>
78
+ <zeroOrMore>
79
+ <ref name="reqinherit"/>
80
+ </zeroOrMore>
81
+ <zeroOrMore>
82
+ <ref name="classification"/>
83
+ </zeroOrMore>
84
+ <zeroOrMore>
85
+ <choice>
86
+ <ref name="measurementtarget"/>
87
+ <ref name="specification"/>
88
+ <ref name="verification"/>
89
+ <ref name="import"/>
90
+ <ref name="description"/>
91
+ <ref name="component"/>
92
+ </choice>
93
+ </zeroOrMore>
94
+ <optional>
95
+ <ref name="reqt_references"/>
96
+ </optional>
97
+ <zeroOrMore>
98
+ <choice>
99
+ <ref name="requirement"/>
100
+ <ref name="recommendation"/>
101
+ <ref name="permission"/>
102
+ </choice>
103
+ </zeroOrMore>
104
+ </define>
105
+ <define name="reqtitle">
106
+ <element name="title">
107
+ <ref name="FormattedString"/>
108
+ </element>
109
+ </define>
110
+ <define name="label">
111
+ <element name="label">
112
+ <oneOrMore>
113
+ <ref name="TextElement"/>
114
+ </oneOrMore>
115
+ </element>
116
+ </define>
117
+ <define name="subject">
118
+ <element name="subject">
119
+ <oneOrMore>
120
+ <ref name="TextElement"/>
121
+ </oneOrMore>
122
+ </element>
123
+ </define>
124
+ <define name="reqinherit">
125
+ <element name="inherit">
126
+ <oneOrMore>
127
+ <ref name="TextElement"/>
128
+ </oneOrMore>
129
+ </element>
130
+ </define>
131
+ <define name="measurementtarget">
132
+ <element name="measurement-target">
133
+ <ref name="RequirementSubpart"/>
134
+ </element>
135
+ </define>
136
+ <define name="specification">
137
+ <element name="specification">
138
+ <ref name="RequirementSubpart"/>
139
+ </element>
140
+ </define>
141
+ <define name="verification">
142
+ <element name="verification">
143
+ <ref name="RequirementSubpart"/>
144
+ </element>
145
+ </define>
146
+ <define name="import">
147
+ <element name="import">
148
+ <ref name="RequirementSubpart"/>
149
+ </element>
150
+ </define>
151
+ <define name="description">
152
+ <element name="description">
153
+ <ref name="RequirementSubpart"/>
154
+ </element>
155
+ </define>
156
+ <define name="component">
157
+ <element name="component">
158
+ <attribute name="class"/>
159
+ <ref name="RequirementSubpart"/>
160
+ </element>
161
+ </define>
162
+ <define name="reqt_references">
163
+ <element name="references">
164
+ <oneOrMore>
165
+ <ref name="bibitem"/>
166
+ </oneOrMore>
167
+ </element>
168
+ </define>
169
+ <define name="RequirementSubpart">
170
+ <optional>
171
+ <attribute name="type"/>
172
+ </optional>
173
+ <optional>
174
+ <attribute name="exclude">
175
+ <data type="boolean"/>
176
+ </attribute>
177
+ </optional>
178
+ <optional>
179
+ <attribute name="keep-with-next">
180
+ <data type="boolean"/>
181
+ </attribute>
182
+ </optional>
183
+ <optional>
184
+ <attribute name="keep-lines-together">
185
+ <data type="boolean"/>
186
+ </attribute>
187
+ </optional>
188
+ <optional>
189
+ <attribute name="tag"/>
190
+ </optional>
191
+ <optional>
192
+ <attribute name="multilingual-rendering">
193
+ <ref name="MultilingualRenderingType"/>
194
+ </attribute>
195
+ </optional>
196
+ <oneOrMore>
197
+ <choice>
198
+ <ref name="BasicBlock"/>
199
+ <ref name="component"/>
200
+ </choice>
201
+ </oneOrMore>
202
+ </define>
203
+ <define name="ObligationType">
204
+ <choice>
205
+ <value>requirement</value>
206
+ <value>recommendation</value>
207
+ <value>permission</value>
208
+ </choice>
209
+ </define>
210
+ <define name="classification">
211
+ <element name="classification">
212
+ <ref name="classification_tag"/>
213
+ <ref name="classification_value"/>
214
+ </element>
215
+ </define>
216
+ <define name="classification_tag">
217
+ <element name="tag">
218
+ <text/>
219
+ </element>
220
+ </define>
221
+ <define name="classification_value">
222
+ <element name="value">
223
+ <text/>
224
+ </element>
225
+ </define>
226
+ </grammar>
@@ -0,0 +1,198 @@
1
+ require_relative "validate_section"
2
+ require_relative "validate_style"
3
+
4
+ module Metanorma
5
+ module IEEE
6
+ class Converter < Standoc::Converter
7
+ def validate(doc)
8
+ content_validate(doc)
9
+ schema_validate(formattedstr_strip(doc.dup),
10
+ File.join(File.dirname(__FILE__), "ieee.rng"))
11
+ end
12
+
13
+ def content_validate(doc)
14
+ super
15
+ bibdata_validate(doc.root)
16
+ title_validate(doc.root)
17
+ locality_erefs_validate(doc.root)
18
+ bibitem_validate(doc.root)
19
+ listcount_validate(doc)
20
+ table_style(doc)
21
+ figure_validate(doc)
22
+ end
23
+
24
+ def bibdata_validate(doc)
25
+ doctype_validate(doc)
26
+ # stage_validate(doc)
27
+ # substage_validate(doc)
28
+ end
29
+
30
+ def doctype_validate(xmldoc)
31
+ doctype = xmldoc&.at("//bibdata/ext/doctype")&.text
32
+ %w(standard recommended-practice guide
33
+ amendment technical-corrigendum).include? doctype or
34
+ @log.add("Document Attributes", nil,
35
+ "#{doctype} is not a recognised document type")
36
+ end
37
+
38
+ def title_validate(xml)
39
+ title_validate_type(xml)
40
+ title_validate_capitalisation(xml)
41
+ end
42
+
43
+ # Style Manual 11.3
44
+ def title_validate_type(xml)
45
+ title = xml.at("//bibdata/title") or return
46
+ draft = xml.at("//bibdata//draft")
47
+ type = xml.at("//bibdata/ext/doctype")
48
+ subtype = xml.at("//bibdata/ext/subdoctype")
49
+ target = draft ? "Draft " : ""
50
+ target += subtype ? "#{strict_capitalize_phrase(subtype.text)} " : ""
51
+ target += type ? "#{strict_capitalize_phrase(type.text)} " : ""
52
+ /^#{target}/.match?(title.text) or
53
+ @log.add("Style", title,
54
+ "Expected title to start as: #{target}")
55
+ end
56
+
57
+ def strict_capitalize_phrase(str)
58
+ ret = str.split(/[ -]/).map do |w|
59
+ letters = w.chars
60
+ letters.first.upcase! unless /^[ -]/.match?(w)
61
+ letters.join
62
+ end.join(" ")
63
+ ret = "Trial-Use" if ret == "Trial Use"
64
+ ret
65
+ end
66
+
67
+ # Style Manual 11.3
68
+ def title_validate_capitalisation(xml)
69
+ title = xml.at("//bibdata/title") or return
70
+ found = false
71
+ title.text.split(/[ -]/).each do |w|
72
+ /^[[:upper:]]/.match?(w) or preposition?(w) or
73
+ found = true
74
+ end
75
+ found and @log.add("Style", title,
76
+ "Title contains uncapitalised word other than preposition")
77
+ end
78
+
79
+ def preposition?(word)
80
+ %w(aboard about above across after against along amid among anti around
81
+ as at before behind below beneath beside besides between beyond but
82
+ by concerning considering despite down during except excepting
83
+ excluding following for from in inside into like minus near of off
84
+ on onto opposite outside over past per plus regarding round save
85
+ since than through to toward towards under underneath unlike until
86
+ up upon versus via with within without a an the).include?(word)
87
+ end
88
+
89
+ # Style manual 12.3.2
90
+ def locality_erefs_validate(root)
91
+ root.xpath("//eref[descendant::locality]").each do |t|
92
+ if !/[:-](\d+{4})$/.match?(t["citeas"])
93
+ @log.add("Style", t,
94
+ "undated reference #{t['citeas']} should not contain "\
95
+ "specific elements")
96
+ end
97
+ end
98
+ end
99
+
100
+ def bibitem_validate(root)
101
+ normative_dated_refs(root)
102
+ end
103
+
104
+ # Style manual 12.3.1
105
+ def normative_dated_refs(root)
106
+ root.xpath("//references[@normative = 'true']/bibitem").each do |b|
107
+ b.at(".//date") or
108
+ @log.add("Style", b,
109
+ "Normative reference #{b&.at('./@id')&.text} is not dated.")
110
+ end
111
+ end
112
+
113
+ # Style manual 13.3
114
+ def listcount_validate(doc)
115
+ doc.xpath("//clause | //annex").each do |c|
116
+ next if c.xpath(".//ol").empty?
117
+
118
+ ols = c.xpath(".//ol") -
119
+ c.xpath(".//ul//ol | .//ol//ol | .//clause//ol")
120
+ ols.size > 1 and
121
+ style_warning(c, "More than 1 ordered list in a numbered clause",
122
+ nil)
123
+ end
124
+ end
125
+
126
+ # Style manual 17.1
127
+ def figure_validate(xmldoc)
128
+ xrefs = xrefs(xmldoc)
129
+ figure_name_validate(xmldoc, xrefs)
130
+ table_figure_name_validate(xmldoc, xrefs)
131
+ table_figure_quantity_validate(xmldoc)
132
+ end
133
+
134
+ def xrefs(xmldoc)
135
+ klass = IsoDoc::IEEE::HtmlConvert.new(language: @lang, script: @script)
136
+ xrefs = IsoDoc::IEEE::Xref
137
+ .new(@lang, @script, klass, IsoDoc::IEEE::I18n.new(@lang, @script),
138
+ { hierarchical_assets: @hierarchical_assets })
139
+ xrefs.parse(Nokogiri::XML(xmldoc.to_xml))
140
+ xrefs
141
+ end
142
+
143
+ def image_name_prefix(xmldoc)
144
+ num = xmldoc.at("//bibdata/docnumber") or return
145
+ yr = xmldoc.at("//bibdata/date[@type = 'published']") ||
146
+ xmldoc.at("//bibdata/date[@type = 'issued']") ||
147
+ xmldoc.at("//bibdata/copyright/from")
148
+ yr = yr&.text || Date.now.year
149
+ "#{num.text}-#{yr.sub(/-*$/, '')}"
150
+ end
151
+
152
+ def figure_name_validate(xmldoc, xrefs)
153
+ pref = image_name_prefix(xmldoc)
154
+ (xmldoc.xpath("//figure") - xmldoc.xpath("//table//figure"))
155
+ .each do |f|
156
+ i = f.at("./image") or next
157
+ next if i["src"].start_with?("data:")
158
+
159
+ num = xrefs.anchor(f["id"], :label)
160
+ File.basename(i["src"], ".*") == "#{pref}_fig#{num}" or
161
+ @log.add("Style", i,
162
+ "image name #{i['src']} is expected to be #{pref}_fig#{num}")
163
+ end
164
+ end
165
+
166
+ def table_figure_name_validate(xmldoc, xrefs)
167
+ xmldoc.xpath("//table[.//figure]").each do |t|
168
+ xmldoc.xpath(".//figure").each do |f|
169
+ i = f.at("./image") or next
170
+ next if i["src"].start_with?("data:")
171
+
172
+ num = tablefigurenumber(t, f, xrefs)
173
+ File.basename(i["src"]) == num or
174
+ @log.add("Style", i,
175
+ "image name #{i['src']} is expected to be #{num}")
176
+ end
177
+ end
178
+ end
179
+
180
+ def tablefigurenumber(table, figure, xrefs)
181
+ tab = xrefs.anchor(table["id"], :label)
182
+ td = figure.at("./ancestor::td | ./ancestor::th")
183
+ cols = td.xpath("./preceding-sibling::td | ./preceding-sibling::td")
184
+ rows = td.parent.xpath("./preceding::tr") &
185
+ td.at("./ancestor::table").xpath(".//tr")
186
+ "Tab#{tab}Row#{rows.size + 1}Col#{cols.size + 1}"
187
+ end
188
+
189
+ def table_figure_quantity_validate(xmldoc)
190
+ xmldoc.xpath("//td[.//image] | //th[.//image]").each do |d|
191
+ d.xpath(".//image").size > 1 and
192
+ @log.add("Style", d,
193
+ "More than one image in the table cell")
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,119 @@
1
+ module Metanorma
2
+ module IEEE
3
+ class Converter < Standoc::Converter
4
+ def section_validate(doc)
5
+ doctype = doc&.at("//bibdata/ext/doctype")&.text
6
+ unless %w(amendment technical-corrigendum).include? doctype
7
+ sections_presence_validate(doc.root)
8
+ sections_sequence_validate(doc.root)
9
+ end
10
+ subclause_validate(doc.root)
11
+ onlychild_clause_validate(doc.root)
12
+ super
13
+ end
14
+
15
+ def sections_presence_validate(root)
16
+ root.at("//sections/clause[@type = 'overview']") or
17
+ @log.add("Style", nil, "Overview clause missing")
18
+ root.at("//sections/clause[@type = 'overview']/clause[@type = 'scope']") or
19
+ @log.add("Style", nil, "Scope subclause missing")
20
+ root.at("//sections/clause[@type = 'overview']/clause[@type = 'word-usage']") or
21
+ @log.add("Style", nil, "Word Usage subclause missing")
22
+ root.at("//references[@normative = 'true']") or
23
+ @log.add("Style", nil, "Normative references missing")
24
+ root.at("//terms") or
25
+ @log.add("Style", nil, "Definitions missing")
26
+ end
27
+
28
+ def seqcheck(names, msg, accepted)
29
+ n = names.shift
30
+ return [] if n.nil?
31
+
32
+ test = accepted.map { |a| n.at(a) }
33
+ if test.all?(&:nil?)
34
+ @log.add("Style", nil, msg)
35
+ end
36
+ names
37
+ end
38
+
39
+ # spec of permissible section sequence
40
+ # we skip normative references, it goes to end of list
41
+ SEQ = [
42
+ { msg: "Initial section must be (content) Abstract",
43
+ val: ["./self::abstract"] },
44
+ { msg: "Prefatory material must be followed by (clause) Overview",
45
+ val: ["./self::clause[@type = 'overview']"] },
46
+ { msg: "Normative References must be followed by "\
47
+ "Definitions",
48
+ val: ["./self::terms | .//terms"] },
49
+ ].freeze
50
+
51
+ SECTIONS_XPATH =
52
+ "//preface/abstract | //sections/terms | .//annex | "\
53
+ "//sections/definitions | //sections/clause | "\
54
+ "//references[not(parent::clause)] | "\
55
+ "//clause[descendant::references][not(parent::clause)]".freeze
56
+
57
+ def sections_sequence_validate(root)
58
+ names, n = sections_sequence_validate_start(root)
59
+ names, n = sections_sequence_validate_body(names, n)
60
+ sections_sequence_validate_end(names, n)
61
+ end
62
+
63
+ def sections_sequence_validate_start(root)
64
+ names = root.xpath(SECTIONS_XPATH)
65
+ names = seqcheck(names, SEQ[0][:msg], SEQ[0][:val])
66
+ n = names[0]
67
+ names = seqcheck(names, SEQ[1][:msg], SEQ[1][:val])
68
+ names = seqcheck(names, SEQ[2][:msg], SEQ[2][:val])
69
+ n = names.shift
70
+ n = names.shift if n&.at("./self::definitions")
71
+ [names, n]
72
+ end
73
+
74
+ def sections_sequence_validate_body(names, elem)
75
+ [names, elem]
76
+ end
77
+
78
+ def sections_sequence_validate_end(names, elem)
79
+ while elem&.name == "annex"
80
+ elem = names.shift
81
+ if elem.nil?
82
+ @log.add("Style", nil, "Document must include (references) "\
83
+ "Normative References")
84
+ end
85
+ end
86
+ elem&.at("./self::references[@normative = 'true']") ||
87
+ @log.add("Style", nil, "Document must include (references) "\
88
+ "Normative References")
89
+ elem = names&.shift
90
+ elem&.at("./self::references[@normative = 'false']") ||
91
+ @log.add("Style", elem,
92
+ "Final section must be (references) Bibliography")
93
+ names.empty? ||
94
+ @log.add("Style", elem,
95
+ "There are sections after the final Bibliography")
96
+ end
97
+
98
+ # Style manual 13.1
99
+ def subclause_validate(root)
100
+ root.xpath("//clause/clause/clause/clause/clause/clause")
101
+ .each do |c|
102
+ style_warning(c, "Exceeds the maximum clause depth of 5", nil)
103
+ end
104
+ end
105
+
106
+ # Style manual 13.1
107
+ def onlychild_clause_validate(root)
108
+ root.xpath(Standoc::Utils::SUBCLAUSE_XPATH).each do |c|
109
+ next unless c.xpath("../clause").size == 1
110
+
111
+ title = c.at("./title")
112
+ location = c["id"] || "#{c.text[0..60]}..."
113
+ location += ":#{title.text}" if c["id"] && !title.nil?
114
+ @log.add("Style", nil, "#{location}: subclause is only child")
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end