metanorma-standoc 1.10.3 → 1.10.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/asciidoctor/standoc/base.rb +15 -5
  3. data/lib/asciidoctor/standoc/blocks.rb +37 -31
  4. data/lib/asciidoctor/standoc/cleanup.rb +12 -69
  5. data/lib/asciidoctor/standoc/cleanup_block.rb +6 -3
  6. data/lib/asciidoctor/standoc/cleanup_maths.rb +113 -21
  7. data/lib/asciidoctor/standoc/cleanup_reqt.rb +60 -14
  8. data/lib/asciidoctor/standoc/cleanup_section.rb +1 -0
  9. data/lib/asciidoctor/standoc/cleanup_section_names.rb +31 -14
  10. data/lib/asciidoctor/standoc/cleanup_text.rb +70 -0
  11. data/lib/asciidoctor/standoc/converter.rb +2 -0
  12. data/lib/asciidoctor/standoc/isodoc.rng +29 -9
  13. data/lib/asciidoctor/standoc/lists.rb +9 -6
  14. data/lib/asciidoctor/standoc/reqt.rb +39 -27
  15. data/lib/asciidoctor/standoc/reqt.rng +15 -4
  16. data/lib/asciidoctor/standoc/table.rb +22 -20
  17. data/lib/asciidoctor/standoc/validate_section.rb +2 -1
  18. data/lib/isodoc/base.standard.xsl +6003 -0
  19. data/lib/isodoc/pdf_convert.rb +20 -0
  20. data/lib/metanorma/standoc/processor.rb +5 -1
  21. data/lib/metanorma/standoc/version.rb +1 -1
  22. data/lib/metanorma-standoc.rb +1 -0
  23. data/metanorma-standoc.gemspec +1 -1
  24. data/spec/asciidoctor/base_spec.rb +6 -0
  25. data/spec/asciidoctor/blocks_spec.rb +43 -23
  26. data/spec/asciidoctor/cleanup_sections_spec.rb +67 -1
  27. data/spec/asciidoctor/cleanup_spec.rb +148 -21
  28. data/spec/asciidoctor/isobib_cache_spec.rb +8 -8
  29. data/spec/asciidoctor/macros_spec.rb +114 -1
  30. data/spec/asciidoctor/refs_dl_spec.rb +1 -1
  31. data/spec/asciidoctor/refs_spec.rb +218 -442
  32. data/spec/asciidoctor/section_spec.rb +1 -1
  33. data/spec/asciidoctor/validate_spec.rb +4 -0
  34. data/spec/examples/datamodel/address_class_profile.adoc +1 -0
  35. data/spec/examples/datamodel/address_component_profile.adoc +1 -0
  36. data/spec/examples/datamodel/blank_definition_profile.adoc +1 -0
  37. data/spec/examples/datamodel/common_models_diagram.adoc +2 -1
  38. data/spec/examples/datamodel/top_down_diagram.adoc +2 -1
  39. data/spec/fixtures/datamodel_description_sections_tree.xml +326 -0
  40. data/spec/fixtures/test.xmi +9250 -0
  41. data/spec/metanorma/processor_spec.rb +50 -50
  42. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +231 -143
  43. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +152 -0
  44. data/spec/vcr_cassettes/isobib_get_123.yml +51 -35
  45. data/spec/vcr_cassettes/isobib_get_123_1.yml +103 -71
  46. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +112 -80
  47. data/spec/vcr_cassettes/isobib_get_123_2001.yml +51 -35
  48. data/spec/vcr_cassettes/isobib_get_124.yml +51 -35
  49. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +14 -14
  50. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +49 -47
  51. metadata +10 -4
@@ -1,40 +1,42 @@
1
1
  module Asciidoctor
2
2
  module Standoc
3
3
  module Cleanup
4
- def requirement_cleanup(reqt)
5
- requirement_descriptions(reqt)
6
- requirement_inherit(reqt)
4
+ def requirement_cleanup(xmldoc)
5
+ requirement_metadata(xmldoc)
6
+ requirement_descriptions(xmldoc)
7
+ requirement_inherit(xmldoc)
7
8
  end
8
9
 
9
- def requirement_inherit(reqt)
10
- reqt.xpath("//requirement | //recommendation | //permission")
11
- .each do |r|
10
+ REQRECPER = "//requirement | //recommendation | //permission".freeze
11
+
12
+ def requirement_inherit(xmldoc)
13
+ xmldoc.xpath(REQRECPER).each do |r|
12
14
  ins = r.at("./classification") ||
13
15
  r.at("./description | ./measurementtarget | ./specification | "\
14
16
  "./verification | ./import | ./description | ./requirement | "\
15
- "./recommendation | ./permission")
17
+ "./recommendation | ./permission | ./component")
16
18
  r.xpath("./*//inherit").each { |i| ins.previous = i }
17
19
  end
18
20
  end
19
21
 
20
- def requirement_descriptions(reqt)
21
- reqt.xpath("//requirement | //recommendation | //permission")
22
- .each do |r|
22
+ def requirement_descriptions(xmldoc)
23
+ xmldoc.xpath(REQRECPER).each do |r|
23
24
  r.children.each do |e|
24
25
  unless e.element? && (reqt_subpart(e.name) ||
25
26
  %w(requirement recommendation permission).include?(e.name))
26
- t = Nokogiri::XML::Element.new("description", reqt)
27
+ next if e.text.strip.empty?
28
+ t = Nokogiri::XML::Element.new("description", r)
27
29
  e.before(t)
28
30
  t.children = e.remove
29
31
  end
30
32
  end
31
- requirement_cleanup1(r)
33
+ requirement_description_cleanup1(r)
32
34
  end
33
35
  end
34
36
 
35
- def requirement_cleanup1(reqt)
37
+ def requirement_description_cleanup1(reqt)
36
38
  while d = reqt.at("./description[following-sibling::*[1]"\
37
- "[self::description]]")
39
+ "[self::description]]")
38
40
  n = d.next.remove
39
41
  d << n.children
40
42
  end
@@ -42,6 +44,50 @@ module Asciidoctor
42
44
  r.replace("\n")
43
45
  end
44
46
  end
47
+
48
+ def requirement_metadata(xmldoc)
49
+ xmldoc.xpath(REQRECPER).each do |r|
50
+ dl = r&.at("./dl[@metadata = 'true']")&.remove or next
51
+ requirement_metadata1(r, dl)
52
+ end
53
+ end
54
+
55
+ def requirement_metadata1(reqt, dlist)
56
+ unless ins = reqt.at("./title")
57
+ reqt.children.first.previous = " "
58
+ ins = reqt.children.first
59
+ end
60
+ %w(label subject inherit).each do |a|
61
+ ins = reqt_dl_to_elems(ins, reqt, dlist, a)
62
+ end
63
+ reqt_dl_to_classif(ins, reqt, dlist)
64
+ end
65
+
66
+ def reqt_dl_to_elems(ins, reqt, dlist, name)
67
+ if a = reqt.at("./#{name}[last()]")
68
+ ins = a
69
+ end
70
+ dlist.xpath("./dt[text()='#{name}']").each do |e|
71
+ val = e.at("./following::dd/p") || e.at("./following::dd")
72
+ val.name = name
73
+ ins.next = val
74
+ ins = ins.next
75
+ end
76
+ ins
77
+ end
78
+
79
+ def reqt_dl_to_classif(ins, reqt, dlist)
80
+ if a = reqt.at("./classification[last()]")
81
+ ins = a
82
+ end
83
+ dlist.xpath("./dt[text()='classification']").each do |e|
84
+ val = e.at("./following::dd/p") || e.at("./following::dd")
85
+ req_classif_parse(val.text).each do |r|
86
+ ins.next = "<classification><tag>#{r[0]}</tag>"\
87
+ "<value>#{r[1]}</value></classification>"
88
+ end
89
+ end
90
+ end
45
91
  end
46
92
  end
47
93
  end
@@ -114,6 +114,7 @@ module Asciidoctor
114
114
  sections_order_cleanup(xml)
115
115
  sections_level_cleanup(xml)
116
116
  sections_names_cleanup(xml)
117
+ sections_variant_title_cleanup(xml)
117
118
  change_clauses(xml)
118
119
  end
119
120
 
@@ -37,39 +37,56 @@ module Asciidoctor
37
37
  end
38
38
 
39
39
  def section_names_refs_cleanup(xml)
40
- replace_title(xml, "//references[@normative = 'true']",
40
+ replace_title(xml, "//bibliography/references[@normative = 'true']",
41
41
  @i18n&.normref, true)
42
- replace_title(xml, "//references[@normative = 'false']",
42
+ replace_title(xml, "//bibliography/references[@normative = 'false']",
43
43
  @i18n&.bibliography, true)
44
44
  end
45
45
 
46
46
  NO_SYMABBR = "[.//definitions[not(@type)]]".freeze
47
47
  SYMABBR = "[.//definitions[@type = 'symbols']]"\
48
- "[.//definitions[@type = 'abbreviated_terms']]".freeze
48
+ "[.//definitions[@type = 'abbreviated_terms']]".freeze
49
49
  SYMnoABBR = "[.//definitions[@type = 'symbols']]"\
50
- "[not(.//definitions[@type = 'abbreviated_terms'])]".freeze
50
+ "[not(.//definitions[@type = 'abbreviated_terms'])]".freeze
51
51
  ABBRnoSYM = "[.//definitions[@type = 'abbreviated_terms']]"\
52
- "[not(.//definitions[@type = 'symbols'])]".freeze
52
+ "[not(.//definitions[@type = 'symbols'])]".freeze
53
53
 
54
- def section_names_terms_cleanup(x)
55
- replace_title(x, "//definitions[@type = 'symbols']", @i18n&.symbols)
56
- replace_title(x, "//definitions[@type = 'abbreviated_terms']",
54
+ def section_names_terms_cleanup(xml)
55
+ replace_title(xml, "//definitions[@type = 'symbols']", @i18n&.symbols)
56
+ replace_title(xml, "//definitions[@type = 'abbreviated_terms']",
57
57
  @i18n&.abbrev)
58
- replace_title(x, "//definitions[not(@type)]", @i18n&.symbolsabbrev)
59
- replace_title(x, "//terms#{SYMnoABBR} | //clause[.//terms]#{SYMnoABBR}",
58
+ replace_title(xml, "//definitions[not(@type)]", @i18n&.symbolsabbrev)
59
+ replace_title(xml, "//terms#{SYMnoABBR} | //clause[.//terms]#{SYMnoABBR}",
60
60
  @i18n&.termsdefsymbols, true)
61
- replace_title(x, "//terms#{ABBRnoSYM} | //clause[.//terms]#{ABBRnoSYM}",
61
+ replace_title(xml, "//terms#{ABBRnoSYM} | //clause[.//terms]#{ABBRnoSYM}",
62
62
  @i18n&.termsdefabbrev, true)
63
- replace_title(x, "//terms#{SYMABBR} | //clause[.//terms]#{SYMABBR}",
63
+ replace_title(xml, "//terms#{SYMABBR} | //clause[.//terms]#{SYMABBR}",
64
64
  @i18n&.termsdefsymbolsabbrev, true)
65
- replace_title(x, "//terms#{NO_SYMABBR} | //clause[.//terms]#{NO_SYMABBR}",
65
+ replace_title(xml, "//terms#{NO_SYMABBR} | //clause[.//terms]#{NO_SYMABBR}",
66
66
  @i18n&.termsdefsymbolsabbrev, true)
67
67
  replace_title(
68
- x,
68
+ xml,
69
69
  "//terms[not(.//definitions)] | //clause[.//terms][not(.//definitions)]",
70
70
  @i18n&.termsdef, true
71
71
  )
72
72
  end
73
+
74
+ SECTION_CONTAINERS = %w(foreword introduction acknowledgements abstract
75
+ clause clause references terms definitions annex
76
+ appendix).freeze
77
+
78
+ def sections_variant_title_cleanup(xml)
79
+ path = SECTION_CONTAINERS.map { |x| "./ancestor::#{x}" }.join(" | ")
80
+ xml.xpath("//p[@variant_title]").each do |p|
81
+ p.xpath("(#{path})[last()]").each do |sect|
82
+ p.name = "variant-title"
83
+ p.delete("id")
84
+ if ins = sect.at("./title") then ins.next = p
85
+ else sect.children.first.previous = p
86
+ end
87
+ end
88
+ end
89
+ end
73
90
  end
74
91
  end
75
92
  end
@@ -0,0 +1,70 @@
1
+ module Asciidoctor
2
+ module Standoc
3
+ module Cleanup
4
+ def textcleanup(result)
5
+ text = result.flatten.map { |l| l.sub(/\s*$/, "") } * "\n"
6
+ !@keepasciimath and text = asciimath2mathml(text)
7
+ text = text.gsub(/\s+<fn /, "<fn ")
8
+ text.gsub(%r{<passthrough\s+formats="metanorma">([^<]*)
9
+ </passthrough>}mx) { HTMLEntities.new.decode($1) }
10
+ end
11
+
12
+ IGNORE_DUMBQUOTES = "//pre | //pre//* | //tt | //tt//* | "\
13
+ "//sourcecode | //sourcecode//* | //bibdata//* | //stem | "\
14
+ "//stem//* | //figure[@class = 'pseudocode'] | "\
15
+ "//figure[@class = 'pseudocode']//*".freeze
16
+
17
+ def smartquotes_cleanup(xmldoc)
18
+ xmldoc.xpath("//date").each { |d| Metanorma::Utils::endash_date(d) }
19
+ if @smartquotes then smartquotes_cleanup1(xmldoc)
20
+ else dumbquote_cleanup(xmldoc)
21
+ end
22
+ end
23
+
24
+ def smartquotes_cleanup1(xmldoc)
25
+ uninterrupt_quotes_around_xml(xmldoc)
26
+ dumb2smart_quotes(xmldoc)
27
+ end
28
+
29
+ # "abc<tag/>", def => "abc",<tag/> def
30
+ def uninterrupt_quotes_around_xml(xmldoc)
31
+ xmldoc.xpath("//*[following::text()[1]"\
32
+ "[starts-with(., '\"') or starts-with(., \"'\")]]")
33
+ .each do |x|
34
+ next if !x.ancestors("pre, tt, sourcecode, stem, figure").empty?
35
+ uninterrupt_quotes_around_xml1(x)
36
+ end
37
+ end
38
+
39
+ def uninterrupt_quotes_around_xml1(elem)
40
+ prev = elem.at(".//preceding::text()[1]") or return
41
+ /\S$/.match?(prev.text) or return
42
+ foll = elem.at(".//following::text()[1]")
43
+ m = /^(["'][[:punct:]]*)(\s|$)/.match(HTMLEntities.new.decode(foll&.text)) or return
44
+ foll.content = foll.text.sub(/^(["'][[:punct:]]*)/, "")
45
+ prev.content = "#{prev.text}#{m[1]}"
46
+ end
47
+
48
+ def dumb2smart_quotes(xmldoc)
49
+ (xmldoc.xpath("//*[child::text()]") - xmldoc.xpath(IGNORE_DUMBQUOTES))
50
+ .each do |x|
51
+ x.children.each do |n|
52
+ next unless n.text?
53
+
54
+ /[-'"(<>]|\.\.|\dx/.match(n) or next
55
+
56
+ n.replace(Metanorma::Utils::smartformat(n.text))
57
+ end
58
+ end
59
+ end
60
+
61
+ def dumbquote_cleanup(xmldoc)
62
+ xmldoc.traverse do |n|
63
+ next unless n.text?
64
+
65
+ n.replace(n.text.gsub(/(?<=\p{Alnum})\u2019(?=\p{Alpha})/, "'")) # .
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -27,6 +27,7 @@ module Asciidoctor
27
27
  preprocessor Metanorma::Plugin::Datastruct::Yaml2TextPreprocessor
28
28
  preprocessor Metanorma::Plugin::Lutaml::LutamlPreprocessor
29
29
  preprocessor Metanorma::Plugin::Lutaml::LutamlUmlAttributesTablePreprocessor
30
+ preprocessor Metanorma::Plugin::Lutaml::LutamlUmlDatamodelDescriptionPreprocessor
30
31
  inline_macro Asciidoctor::Standoc::AltTermInlineMacro
31
32
  inline_macro Asciidoctor::Standoc::DeprecatedTermInlineMacro
32
33
  inline_macro Asciidoctor::Standoc::DomainTermInlineMacro
@@ -48,6 +49,7 @@ module Asciidoctor
48
49
  inline_macro Asciidoctor::Standoc::FormSelectMacro
49
50
  inline_macro Asciidoctor::Standoc::FormOptionMacro
50
51
  inline_macro Asciidoctor::Standoc::ToCInlineMacro
52
+ inline_macro Metanorma::Plugin::Lutaml::LutamlFigureInlineMacro
51
53
  block_macro Metanorma::Plugin::Lutaml::LutamlDiagramBlockMacro
52
54
  block Asciidoctor::Standoc::ToDoAdmonitionBlock
53
55
  treeprocessor Asciidoctor::Standoc::ToDoInlineAdmonitionBlock
@@ -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
- <attribute name="type">
162
- <choice>
163
- <value>roman</value>
164
- <value>alphabet</value>
165
- <value>arabic</value>
166
- <value>roman_upper</value>
167
- <value>alphabet_upper</value>
168
- </choice>
169
- </attribute>
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>
@@ -1011,8 +1025,14 @@
1011
1025
  <ref name="imagemap"/>
1012
1026
  <ref name="svgmap"/>
1013
1027
  <ref name="inputform"/>
1028
+ <ref name="toc"/>
1014
1029
  </choice>
1015
1030
  </define>
1031
+ <define name="toc">
1032
+ <element name="toc">
1033
+ <ref name="ul"/>
1034
+ </element>
1035
+ </define>
1016
1036
  <define name="inputform">
1017
1037
  <element name="form">
1018
1038
  <attribute name="id">
@@ -31,7 +31,7 @@ module Asciidoctor
31
31
  c = node.attr?("checked")
32
32
  attr_code(
33
33
  uncheckedcheckbox: node.attr?("checkbox") ? !c : nil,
34
- checkedcheckbox: node.attr?("checkbox") ? c : nil
34
+ checkedcheckbox: node.attr?("checkbox") ? c : nil,
35
35
  )
36
36
  end
37
37
 
@@ -52,12 +52,14 @@ module Asciidoctor
52
52
  return "roman" if style == "lowerroman"
53
53
  return "roman_upper" if style == "upperroman"
54
54
  return "alphabet_upper" if style == "upperalpha"
55
+
55
56
  style
56
57
  end
57
58
 
58
59
  def ol_attrs(node)
59
- attr_code(keep_attrs(node).merge(id: Metanorma::Utils::anchor_or_uuid(node),
60
- type: olist_style(node.style)))
60
+ attr_code(keep_attrs(node)
61
+ .merge(id: Metanorma::Utils::anchor_or_uuid(node),
62
+ type: olist_style(node.style)))
61
63
  end
62
64
 
63
65
  def olist(node)
@@ -89,9 +91,10 @@ module Asciidoctor
89
91
  end
90
92
 
91
93
  def dl_attrs(node)
92
- attr_code(keep_attrs(node).
93
- merge(id: Metanorma::Utils::anchor_or_uuid(node),
94
- key: node.option?("key") ? "true" : nil))
94
+ attr_code(keep_attrs(node)
95
+ .merge(id: Metanorma::Utils::anchor_or_uuid(node),
96
+ metadata: node.option?("metadata") ? "true" : nil,
97
+ key: node.option?("key") ? "true" : nil))
95
98
  end
96
99
 
97
100
  def dlist(node)
@@ -6,20 +6,23 @@ require "base64"
6
6
  module Asciidoctor
7
7
  module Standoc
8
8
  module Blocks
9
- def reqt_subpart(x)
9
+ def reqt_subpart(name)
10
10
  %w(specification measurement-target verification import label
11
- subject inherit classification title).include? x
11
+ component subject inherit classification title).include? name
12
12
  end
13
13
 
14
- def reqt_subpart_attrs(node)
15
- attr_code(keep_attrs(node).merge(exclude: node.option?("exclude"),
16
- type: node.attr("type")))
14
+ def reqt_subpart_attrs(node, name)
15
+ klass = node.attr("class") || "component"
16
+ attr_code(keep_attrs(node)
17
+ .merge(exclude: node.option?("exclude"),
18
+ type: node.attr("type"),
19
+ class: name == "component" ? klass : nil))
17
20
  end
18
21
 
19
22
  def requirement_subpart(node)
20
23
  name = node.role || node.attr("style")
21
24
  noko do |xml|
22
- xml.send name, **reqt_subpart_attrs(node) do |o|
25
+ xml.send name, **reqt_subpart_attrs(node, name) do |o|
23
26
  o << node.content
24
27
  end
25
28
  end
@@ -30,14 +33,15 @@ module Asciidoctor
30
33
  HTMLEntities.new.decode(classif).split(/;\s*/).each do |c|
31
34
  c1 = c.split(/:\s*/)
32
35
  next unless c1.size == 2
33
- c1[1].split(/,\s*/).each { |v| ret << [ c1[0], v ] }
36
+
37
+ c1[1].split(/,\s*/).each { |v| ret << [c1[0], v] }
34
38
  end
35
39
  ret
36
40
  end
37
41
 
38
- def requirement_classification(classif, ex)
42
+ def requirement_classification(classif, out)
39
43
  req_classif_parse(classif).each do |r|
40
- ex.classification do |c|
44
+ out.classification do |c|
41
45
  c.tag { |t| t << r[0] }
42
46
  c.value { |v| v << r[1] }
43
47
  end
@@ -46,29 +50,37 @@ module Asciidoctor
46
50
 
47
51
  def reqt_attrs(node)
48
52
  attr_code(keep_attrs(node).merge(id_unnum_attrs(node)).merge(
49
- id: Metanorma::Utils::anchor_or_uuid(node),
50
- unnumbered: node.option?("unnumbered") ? "true" : nil,
51
- number: node.attr("number"),
52
- subsequence: node.attr("subsequence"),
53
- obligation: node.attr("obligation"),
54
- filename: node.attr("filename"),
55
- type: node.attr("type"),
56
- model: node.attr("model"),
57
- ))
53
+ id: Metanorma::Utils::anchor_or_uuid(node),
54
+ unnumbered: node.option?("unnumbered") ? "true" : nil,
55
+ number: node.attr("number"),
56
+ subsequence: node.attr("subsequence"),
57
+ obligation: node.attr("obligation"),
58
+ filename: node.attr("filename"),
59
+ type: node.attr("type"),
60
+ model: node.attr("model"),
61
+ ))
62
+ end
63
+
64
+ def requirement_elems(node, out)
65
+ node.title and out.title { |t| t << node.title }
66
+ a = node.attr("label") and out.label do |l|
67
+ l << a
68
+ end
69
+ a = node.attr("subject") and csv_split(a)&.each do |subj|
70
+ out.subject { |s| s << subj }
71
+ end
72
+ a = HTMLEntities.new.decode(node.attr("inherit")) and
73
+ csv_split(a)&.each do |i|
74
+ out.inherit { |inh| inh << i }
75
+ end
76
+ classif = node.attr("classification") and
77
+ requirement_classification(classif, out)
58
78
  end
59
79
 
60
80
  def requirement(node, obligation)
61
- classif = node.attr("classification")
62
81
  noko do |xml|
63
82
  xml.send obligation, **reqt_attrs(node) do |ex|
64
- node.title and ex.title { |t| t << node.title }
65
- node.attr("label") and ex.label { |l| l << node.attr("label") }
66
- node.attr("subject") and ex.subject { |s| s << node.attr("subject") }
67
- i = HTMLEntities.new.decode(node.attr("inherit"))
68
- i&.split(/;\s*/)&.each do |i|
69
- ex.inherit { |inh| inh << i }
70
- end
71
- requirement_classification(classif, ex) if classif
83
+ requirement_elems(node, ex)
72
84
  wrap_in_para(node, ex)
73
85
  end
74
86
  end.join("\n")