isodoc 1.0.24 → 1.0.29

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +14 -4
  3. data/.github/workflows/ubuntu.yml +19 -5
  4. data/.github/workflows/windows.yml +14 -4
  5. data/isodoc.gemspec +1 -1
  6. data/lib/isodoc-yaml/i18n-en.yaml +3 -1
  7. data/lib/isodoc-yaml/i18n-fr.yaml +3 -1
  8. data/lib/isodoc-yaml/i18n-zh-Hans.yaml +3 -1
  9. data/lib/isodoc/convert.rb +1 -0
  10. data/lib/isodoc/function/blocks.rb +43 -49
  11. data/lib/isodoc/function/{blocks_example.rb → blocks_example_note.rb} +57 -2
  12. data/lib/isodoc/function/cleanup.rb +16 -2
  13. data/lib/isodoc/function/i18n.rb +1 -0
  14. data/lib/isodoc/function/inline.rb +79 -77
  15. data/lib/isodoc/function/inline_simple.rb +72 -0
  16. data/lib/isodoc/function/lists.rb +12 -6
  17. data/lib/isodoc/function/references.rb +51 -39
  18. data/lib/isodoc/function/reqt.rb +13 -4
  19. data/lib/isodoc/function/section.rb +19 -8
  20. data/lib/isodoc/function/table.rb +3 -4
  21. data/lib/isodoc/function/terms.rb +1 -1
  22. data/lib/isodoc/function/to_word_html.rb +23 -13
  23. data/lib/isodoc/function/utils.rb +13 -6
  24. data/lib/isodoc/function/xref_counter.rb +43 -9
  25. data/lib/isodoc/function/xref_gen.rb +2 -1
  26. data/lib/isodoc/function/xref_gen_seq.rb +11 -10
  27. data/lib/isodoc/function/xref_sect_gen.rb +24 -24
  28. data/lib/isodoc/headlesshtml_convert.rb +5 -0
  29. data/lib/isodoc/html_convert.rb +5 -0
  30. data/lib/isodoc/html_function/footnotes.rb +3 -3
  31. data/lib/isodoc/html_function/html.rb +16 -1
  32. data/lib/isodoc/html_function/postprocess.rb +6 -5
  33. data/lib/isodoc/metadata.rb +10 -3
  34. data/lib/isodoc/metadata_date.rb +19 -7
  35. data/lib/isodoc/pdf_convert.rb +5 -0
  36. data/lib/isodoc/version.rb +1 -1
  37. data/lib/isodoc/word_convert.rb +5 -0
  38. data/lib/isodoc/word_function/body.rb +13 -51
  39. data/lib/isodoc/word_function/footnotes.rb +3 -3
  40. data/lib/isodoc/word_function/inline.rb +75 -0
  41. data/lib/isodoc/word_function/postprocess.rb +13 -2
  42. data/lib/isodoc/word_function/table.rb +3 -3
  43. data/lib/isodoc/xslfo_convert.rb +5 -0
  44. data/spec/assets/i18n.yaml +4 -1
  45. data/spec/assets/odf.emf +0 -0
  46. data/spec/assets/odf.svg +4 -0
  47. data/spec/assets/odf1.svg +4 -0
  48. data/spec/isodoc/blocks_spec.rb +274 -51
  49. data/spec/isodoc/cleanup_spec.rb +317 -25
  50. data/spec/isodoc/footnotes_spec.rb +20 -5
  51. data/spec/isodoc/i18n_spec.rb +12 -12
  52. data/spec/isodoc/inline_spec.rb +299 -4
  53. data/spec/isodoc/lists_spec.rb +8 -8
  54. data/spec/isodoc/metadata_spec.rb +112 -3
  55. data/spec/isodoc/postproc_spec.rb +39 -21
  56. data/spec/isodoc/ref_spec.rb +121 -52
  57. data/spec/isodoc/section_spec.rb +236 -207
  58. data/spec/isodoc/table_spec.rb +28 -28
  59. data/spec/isodoc/terms_spec.rb +57 -13
  60. data/spec/isodoc/xref_spec.rb +218 -71
  61. metadata +10 -5
@@ -60,8 +60,12 @@ module IsoDoc::Function
60
60
  %w(label title subject classification tag value inherit).include? n.name
61
61
  end
62
62
 
63
+ def reqt_attrs(node, klass)
64
+ attr_code(class: klass, id: node["id"], style: keep_style(node))
65
+ end
66
+
63
67
  def recommendation_parse(node, out)
64
- out.div **{ class: "recommend" } do |t|
68
+ out.div **reqt_attrs(node, "recommend") do |t|
65
69
  recommendation_name(node, t, @recommendation_lbl)
66
70
  recommendation_attributes(node, out)
67
71
  node.children.each do |n|
@@ -71,7 +75,7 @@ module IsoDoc::Function
71
75
  end
72
76
 
73
77
  def requirement_parse(node, out)
74
- out.div **{ class: "require" } do |t|
78
+ out.div **reqt_attrs(node, "require") do |t|
75
79
  recommendation_name(node, t, @requirement_lbl)
76
80
  recommendation_attributes(node, out)
77
81
  node.children.each do |n|
@@ -81,7 +85,7 @@ module IsoDoc::Function
81
85
  end
82
86
 
83
87
  def permission_parse(node, out)
84
- out.div **{ class: "permission" } do |t|
88
+ out.div **reqt_attrs(node, "permission") do |t|
85
89
  recommendation_name(node, t, @permission_lbl)
86
90
  recommendation_attributes(node, out)
87
91
  node.children.each do |n|
@@ -90,9 +94,14 @@ module IsoDoc::Function
90
94
  end
91
95
  end
92
96
 
97
+ def reqt_component_attrs(node)
98
+ attr_code(class: "requirement-" + node.name,
99
+ style: keep_style(node))
100
+ end
101
+
93
102
  def requirement_component_parse(node, out)
94
103
  return if node["exclude"] == "true"
95
- out.div **{ class: "requirement-" + node.name } do |div|
104
+ out.div **reqt_component_attrs(node) do |div|
96
105
  node.children.each do |n|
97
106
  parse(n, div)
98
107
  end
@@ -16,6 +16,7 @@ module IsoDoc::Function
16
16
  clausedelimspace(out)
17
17
  end
18
18
  c1&.children&.each { |c2| parse(c2, b) }
19
+ clausedelimspace(out) if /\S/.match(c1&.text)
19
20
  end
20
21
  end
21
22
  end
@@ -109,20 +110,29 @@ module IsoDoc::Function
109
110
  num
110
111
  end
111
112
 
112
- def terms_defs_title(f)
113
- symbols = f.at(ns(".//definitions"))
114
- return @termsdefsymbols_lbl if symbols
115
- @termsdef_lbl
116
- end
117
-
118
113
  TERM_CLAUSE = "//sections/terms | "\
119
114
  "//sections/clause[descendant::terms]".freeze
120
115
 
116
+ def term_def_title(title)
117
+ case title&.text
118
+ when "Terms, definitions, symbols and abbreviated terms"
119
+ @labels["termsdefsymbolsabbrev"]
120
+ when "Terms, definitions and symbols"
121
+ @labels["termsdefsymbols"]
122
+ when "Terms, definitions and abbreviated terms"
123
+ @labels["termsdefabbrev"]
124
+ when "Terms and definitions"
125
+ @labels["termsdef"]
126
+ else
127
+ title
128
+ end
129
+ end
130
+
121
131
  def terms_defs(isoxml, out, num)
122
132
  f = isoxml.at(ns(TERM_CLAUSE)) or return num
123
133
  out.div **attr_code(id: f["id"]) do |div|
124
134
  num = num + 1
125
- clause_name(num, terms_defs_title(f), div, nil)
135
+ clause_name(num, term_def_title(f&.at(ns("./title"))), div, nil)
126
136
  f.elements.each do |e|
127
137
  parse(e, div) unless %w{title source}.include? e.name
128
138
  end
@@ -198,7 +208,8 @@ module IsoDoc::Function
198
208
 
199
209
  def preface(isoxml, out)
200
210
  title_attr = { class: "IntroTitle" }
201
- isoxml.xpath(ns("//preface/clause")).each do |f|
211
+ isoxml.xpath(ns("//preface/clause | //preface/terms | //preface/definitions | "\
212
+ "//preface/references")).each do |f|
202
213
  page_break(out)
203
214
  out.div **{ class: "Section3", id: f["id"] } do |div|
204
215
  clause_name(nil, f&.at(ns("./title")), div, title_attr)
@@ -44,12 +44,12 @@ module IsoDoc::Function
44
44
  end
45
45
  end
46
46
 
47
- def make_table_attr(node)
47
+ def table_attrs(node)
48
48
  width = node["width"] ? "width:#{node['width']};" : nil
49
49
  attr_code(
50
50
  id: node["id"],
51
51
  class: "MsoISOTable",
52
- style: "border-width:1px;border-spacing:0;#{width}",
52
+ style: "border-width:1px;border-spacing:0;#{width}#{keep_style(node)}",
53
53
  title: node["alt"]
54
54
  )
55
55
  end
@@ -66,7 +66,7 @@ module IsoDoc::Function
66
66
  def table_parse(node, out)
67
67
  @in_table = true
68
68
  table_title_parse(node, out)
69
- out.table **make_table_attr(node) do |t|
69
+ out.table **table_attrs(node) do |t|
70
70
  tcaption(node, t)
71
71
  thead_parse(node, t)
72
72
  tbody_parse(node, t)
@@ -91,7 +91,6 @@ module IsoDoc::Function
91
91
  style += <<~STYLE
92
92
  border-top:#{row.zero? ? "#{SW} 1.5pt;" : 'none;'}
93
93
  border-bottom:#{SW} #{rowmax == totalrows ? '1.5' : '1.0'}pt;
94
- padding:0;
95
94
  STYLE
96
95
  header and scope = (td["colspan"] ? "colgroup" : "col")
97
96
  !header and td.name == "th" and scope =
@@ -40,7 +40,7 @@ module IsoDoc::Function
40
40
  end
41
41
 
42
42
  def termnote_parse(node, out)
43
- out.div **{ class: "Note" } do |div|
43
+ out.div **note_attrs(node) do |div|
44
44
  first = node.first_element_child
45
45
  div.p do |p|
46
46
  p << "#{anchor(node['id'], :label) || '???'}: "
@@ -21,7 +21,7 @@ module IsoDoc::Function
21
21
  filename = filepath.sub_ext('').to_s
22
22
  dir = "#{filename}_files"
23
23
  unless debug
24
- Dir.mkdir(dir) unless File.exists?(dir)
24
+ Dir.mkdir(dir, 0777) unless File.exists?(dir)
25
25
  FileUtils.rm_rf "#{dir}/*"
26
26
  end
27
27
  @filename = filename
@@ -79,7 +79,7 @@ module IsoDoc::Function
79
79
 
80
80
  def make_body3(body, docxml)
81
81
  body.div **{ class: "main-section" } do |div3|
82
- boilerplate docxml, div3
82
+ boilerplate docxml, div3
83
83
  abstract docxml, div3
84
84
  foreword docxml, div3
85
85
  introduction docxml, div3
@@ -102,6 +102,7 @@ module IsoDoc::Function
102
102
  @meta.relations isoxml, out
103
103
  @meta.version isoxml, out
104
104
  @meta.url isoxml, out
105
+ @meta.keywords isoxml, out
105
106
  @meta.get
106
107
  end
107
108
 
@@ -109,8 +110,15 @@ module IsoDoc::Function
109
110
  out.p(**{ class: "zzSTDTitle1" }) { |p| p << @meta.get[:doctitle] }
110
111
  end
111
112
 
113
+ def middle_admonitions(isoxml, out)
114
+ isoxml.xpath(ns("//sections/note | //sections/admonition")).each do |x|
115
+ parse(x, out)
116
+ end
117
+ end
118
+
112
119
  def middle(isoxml, out)
113
120
  middle_title(out)
121
+ middle_admonitions(isoxml, out)
114
122
  i = scope isoxml, out, 0
115
123
  i = norm_ref isoxml, out, i
116
124
  i = terms_defs isoxml, out, i
@@ -120,20 +128,20 @@ module IsoDoc::Function
120
128
  bibliography isoxml, out
121
129
  end
122
130
 
123
- def boilerplate(node, out)
124
- boilerplate = node.at(ns("//boilerplate")) or return
125
- out.div **{class: "authority"} do |s|
126
- boilerplate.children.each do |n|
127
- if n.name == "title"
128
- s.h1 do |h|
129
- n.children.each { |nn| parse(nn, h) }
130
- end
131
- else
132
- parse(n, s)
131
+ def boilerplate(node, out)
132
+ boilerplate = node.at(ns("//boilerplate")) or return
133
+ out.div **{class: "authority"} do |s|
134
+ boilerplate.children.each do |n|
135
+ if n.name == "title"
136
+ s.h1 do |h|
137
+ n.children.each { |nn| parse(nn, h) }
133
138
  end
139
+ else
140
+ parse(n, s)
134
141
  end
135
142
  end
136
143
  end
144
+ end
137
145
 
138
146
  def parse(node, out)
139
147
  if node.text?
@@ -157,7 +165,7 @@ module IsoDoc::Function
157
165
  when "clause" then clause_parse(node, out)
158
166
  when "xref" then xref_parse(node, out)
159
167
  when "eref" then eref_parse(node, out)
160
- when "origin" then eref_parse(node, out)
168
+ when "origin" then origin_parse(node, out)
161
169
  when "link" then link_parse(node, out)
162
170
  when "ul" then ul_parse(node, out)
163
171
  when "ol" then ol_parse(node, out)
@@ -210,6 +218,8 @@ module IsoDoc::Function
210
218
  when "license-statement" then license_parse(node, out)
211
219
  when "legal-statement" then legal_parse(node, out)
212
220
  when "feedback-statement" then feedback_parse(node, out)
221
+ when "passthrough" then passthrough_parse(node, out)
222
+ when "variant" then variant_parse(node, out)
213
223
  else
214
224
  error_parse(node, out)
215
225
  end
@@ -49,7 +49,12 @@ module IsoDoc::Function
49
49
  /^(\&[^ \t\r\n#;]+;)/.match(t) ?
50
50
  HTMLEntities.new.encode(HTMLEntities.new.decode(t), :hexadecimal) : t
51
51
  end.join("")
52
- Nokogiri::XML.parse(xml)
52
+ begin
53
+ Nokogiri::XML.parse(xml) { |config| config.strict }
54
+ rescue Nokogiri::XML::SyntaxError => e
55
+ File.open("#{@filename}.#{@format}.err", "w:UTF-8") { |f| f.write xml }
56
+ abort "Malformed Output XML for #{@format}: #{e} (see #{@filename}.#{@format}.err)"
57
+ end
53
58
  end
54
59
 
55
60
  def to_xhtml_fragment(xml)
@@ -64,7 +69,7 @@ module IsoDoc::Function
64
69
 
65
70
  CLAUSE_ANCESTOR =
66
71
  ".//ancestor::*[local-name() = 'annex' or "\
67
- "local-name() = 'acknowledgements' or "\
72
+ "local-name() = 'acknowledgements' or local-name() = 'term' or "\
68
73
  "local-name() = 'appendix' or local-name() = 'foreword' or "\
69
74
  "local-name() = 'introduction' or local-name() = 'terms' or "\
70
75
  "local-name() = 'clause' or local-name() = 'references']/@id".freeze
@@ -78,7 +83,7 @@ module IsoDoc::Function
78
83
  ".//ancestor::*[local-name() = 'annex' or "\
79
84
  "local-name() = 'foreword' or local-name() = 'appendix' or "\
80
85
  "local-name() = 'introduction' or local-name() = 'terms' or "\
81
- "local-name() = 'acknowledgements' or "\
86
+ "local-name() = 'acknowledgements' or local-name() = 'term' or "\
82
87
  "local-name() = 'clause' or local-name() = 'references' or "\
83
88
  "local-name() = 'figure' or local-name() = 'formula' or "\
84
89
  "local-name() = 'table' or local-name() = 'example']/@id".freeze
@@ -110,12 +115,13 @@ module IsoDoc::Function
110
115
  end
111
116
 
112
117
  def header_strip(h)
113
- h = h.to_s.gsub(%r{<br/>}, " ").sub(/<\/?h[123456][^>]*>/, "")
118
+ h = h.to_s.gsub(%r{<br\s*/>}, " ").gsub(/<\/?h[123456][^>]*>/, "").
119
+ gsub(/<\/?b[^>]*>/, "")
114
120
  h1 = to_xhtml_fragment(h.dup)
115
121
  h1.traverse do |x|
116
122
  x.replace(" ") if x.name == "span" && /mso-tab-count/.match(x["style"])
117
123
  x.remove if x.name == "span" && x["class"] == "MsoCommentReference"
118
- x.remove if x.name == "a" && x["epub:type"] == "footnote"
124
+ x.remove if x.name == "a" && x["class"] == "FootnoteRef"
119
125
  x.remove if x.name == "span" && /mso-bookmark/.match(x["style"])
120
126
  x.replace(x.children) if x.name == "a"
121
127
  end
@@ -141,7 +147,7 @@ module IsoDoc::Function
141
147
  end
142
148
 
143
149
  def populate_template(docxml, _format = nil)
144
- meta = @meta.get.merge(@labels || {})
150
+ meta = @meta.get.merge(@labels || {}).merge(@meta.labels || {})
145
151
  template = liquid(docxml)
146
152
  template.render(meta.map { |k, v| [k.to_s, empty2nil(v)] }.to_h).
147
153
  gsub('&lt;', '&#x3c;').gsub('&gt;', '&#x3e;').gsub('&amp;', '&#x26;')
@@ -149,6 +155,7 @@ module IsoDoc::Function
149
155
 
150
156
  def save_dataimage(uri, relative_dir = true)
151
157
  %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
158
+ imgtype.sub!(/\+[a-z0-9]+$/, "") # svg+xml
152
159
  imgtype = "png" unless /^[a-z0-9]+$/.match imgtype
153
160
  Tempfile.open(["image", ".#{imgtype}"]) do |f|
154
161
  f.binmode
@@ -15,26 +15,60 @@ module IsoDoc::Function
15
15
  @num = 0
16
16
  @letter = ""
17
17
  @subseq = ""
18
+ @letter_override = nil
19
+ @number_override = nil
20
+ end
21
+
22
+ def new_subseq_increment(node)
23
+ @subseq = node["subsequence"]
24
+ @num += 1
25
+ @letter = node["subsequence"] ? "a" : ""
26
+ if node["number"]
27
+ /^(?<n>\d*)(?<a>[a-z]*)$/ =~ node["number"]
28
+ if n || a
29
+ @letter_override = @letter = a if a
30
+ @number_override = @num = n.to_i if n
31
+ else
32
+ @letter_override = node["number"]
33
+ @letter = @letter_override if /^[a-z]$/.match(@letter_override)
34
+ end
35
+ end
36
+ end
37
+
38
+ def sequence_increment(node)
39
+ if node["number"]
40
+ @number_override = node["number"]
41
+ @num = @number_override.to_i if /^\d+$/.match(@number_override)
42
+ else
43
+ @num += 1
44
+ end
45
+ end
46
+
47
+ def subsequence_increment(node)
48
+ if node["number"]
49
+ @letter_override = node["number"]
50
+ @letter = @letter_override if /^[a-z]$/.match(@letter_override)
51
+ else
52
+ @letter = (@letter.ord + 1).chr.to_s
53
+ end
18
54
  end
19
55
 
20
56
  def increment(node)
21
57
  return self if node["unnumbered"]
58
+ @letter_override = nil
59
+ @number_override = nil
22
60
  if node["subsequence"] != @subseq
23
- @subseq = node["subsequence"]
24
- @num += 1
25
- @letter = node["subsequence"] ? "a" : ""
61
+ new_subseq_increment(node)
62
+ elsif @letter.empty?
63
+ sequence_increment(node)
26
64
  else
27
- if @letter.empty?
28
- @num += 1
29
- else
30
- @letter = (@letter.ord + 1).chr.to_s
31
- end
65
+ subsequence_increment(node)
32
66
  end
33
67
  self
34
68
  end
35
69
 
36
70
  def print
37
- "#{@num}#{@letter}"
71
+ "#{@number_override || @num}#{@letter_override || @letter}"
38
72
  end
39
73
 
40
74
  def listlabel(depth)
@@ -40,6 +40,7 @@ module IsoDoc::Function
40
40
 
41
41
  SECTIONS_XPATH =
42
42
  "//foreword | //introduction | //acknowledgements | //preface/clause | "\
43
+ "//preface/terms | preface/definitions | preface/references | "\
43
44
  "//sections/terms | //annex | "\
44
45
  "//sections/clause | //sections/definitions | "\
45
46
  "//bibliography/references | //bibliography/clause".freeze
@@ -68,7 +69,7 @@ module IsoDoc::Function
68
69
  "not(self::xmlns:terms) and not(self::xmlns:definitions)]//"\
69
70
  "xmlns:example | ./xmlns:example".freeze
70
71
 
71
- CHILD_SECTIONS = "./clause | ./appendix | ./terms | ./definitions"
72
+ CHILD_SECTIONS = "./clause | ./appendix | ./terms | ./definitions | ./references"
72
73
 
73
74
  def example_anchor_names(sections)
74
75
  sections.each do |s|
@@ -1,15 +1,20 @@
1
1
  module IsoDoc::Function
2
2
  module XrefGen
3
+ def subfigure_increment(j, c, t)
4
+ if t.parent.name == "figure" then j += 1
5
+ else
6
+ j = 0
7
+ c.increment(t)
8
+ end
9
+ j
10
+ end
11
+
3
12
  def sequential_figure_names(clause)
4
13
  c = Counter.new
5
14
  j = 0
6
15
  clause.xpath(ns(".//figure | .//sourcecode[not(ancestor::example)]")).
7
16
  each do |t|
8
- if t.parent.name == "figure" then j += 1
9
- else
10
- j = 0
11
- c.increment(t)
12
- end
17
+ j = subfigure_increment(j, c, t)
13
18
  label = c.print + (j.zero? ? "" : "-#{j}")
14
19
  next if t["id"].nil? || t["id"].empty?
15
20
  @anchors[t["id"]] =
@@ -80,11 +85,7 @@ module IsoDoc::Function
80
85
  j = 0
81
86
  clause.xpath(ns(".//figure | .//sourcecode[not(ancestor::example)]")).
82
87
  each do |t|
83
- if t.parent.name == "figure" then j += 1
84
- else
85
- j = 0
86
- c.increment(t)
87
- end
88
+ j = subfigure_increment(j, c, t)
88
89
  label = "#{num}#{hiersep}#{c.print}" +
89
90
  (j.zero? ? "" : "#{hierfigsep}#{j}")
90
91
  next if t["id"].nil? || t["id"].empty?
@@ -5,10 +5,9 @@ module IsoDoc::Function
5
5
  annex_names(c, (65 + i).chr.to_s)
6
6
  end
7
7
  docxml.xpath(
8
- ns("//bibliography/clause[not(xmlns:title = 'Normative References' or "\
9
- "xmlns:title = 'Normative references')] |"\
10
- "//bibliography/references[not(xmlns:title = 'Normative References'"\
11
- " or xmlns:title = 'Normative references')]")).each do |b|
8
+ ns("//bibliography/clause[.//references[@normative = 'false']] | "\
9
+ "//bibliography/references[@normative = 'false']"
10
+ )).each do |b|
12
11
  preface_names(b)
13
12
  end
14
13
  docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |ref|
@@ -17,23 +16,13 @@ module IsoDoc::Function
17
16
  end
18
17
 
19
18
  def initial_anchor_names(d)
20
- preface_names(d.at(ns("//preface/abstract")))
21
- preface_names(d.at(ns("//foreword")))
22
- preface_names(d.at(ns("//introduction")))
23
- d.xpath(ns("//preface/clause")).each do |c|
24
- preface_names(c)
25
- end
26
- preface_names(d.at(ns("//acknowledgements")))
19
+ d.xpath(ns("//preface/*")).each { |c| c.element? and preface_names(c) }
27
20
  # potentially overridden in middle_section_asset_names()
28
- sequential_asset_names(
29
- d.xpath(ns("//preface/abstract | //foreword | //introduction | "\
30
- "//preface/clause | //acknowledgements")))
21
+ sequential_asset_names(d.xpath(ns("//preface/*")))
31
22
  n = section_names(d.at(ns("//clause[title = 'Scope']")), 0, 1)
32
23
  n = section_names(d.at(ns(
33
- "//bibliography/clause[title = 'Normative References' or "\
34
- "title = 'Normative references'] |"\
35
- "//bibliography/references[title = 'Normative References' or "\
36
- "title = 'Normative references']")), n, 1)
24
+ "//bibliography/clause[.//references[@normative = 'true']] | "\
25
+ "//bibliography/references[@normative = 'true']")), n, 1)
37
26
  n = section_names(d.at(ns("//sections/terms | "\
38
27
  "//sections/clause[descendant::terms]")), n, 1)
39
28
  n = section_names(d.at(ns("//sections/definitions")), n, 1)
@@ -76,10 +65,8 @@ module IsoDoc::Function
76
65
 
77
66
  def middle_section_asset_names(d)
78
67
  middle_sections = "//clause[title = 'Scope'] | "\
79
- "//references[title = 'Normative References' or title = "\
80
- "'Normative references'] | "\
81
- "//sections/terms | //preface/abstract | //foreword | "\
82
- "//introduction | //preface/clause | //acknowledgements "\
68
+ "//references[@normative = 'true'] | "\
69
+ "//sections/terms | //preface/* | "\
83
70
  "//sections/definitions | //clause[parent::sections]"
84
71
  sequential_asset_names(d.xpath(ns(middle_sections)))
85
72
  end
@@ -120,12 +107,25 @@ module IsoDoc::Function
120
107
  l10n("<b>#{@annex_lbl} #{num}</b><br/>#{obl}")
121
108
  end
122
109
 
110
+ def single_annex_special_section(clause)
111
+ a = clause.xpath(ns("./references | ./terms | ./definitions"))
112
+ a.size == 1 or return nil
113
+ clause.xpath(ns("./clause | ./p | ./table | ./ol | ./ul | ./dl | "\
114
+ "./note | ./admonition | ./figure")).size == 0 or
115
+ return nil
116
+ a[0]
117
+ end
118
+
123
119
  def annex_names(clause, num)
124
120
  @anchors[clause["id"]] = { label: annex_name_lbl(clause, num),
125
121
  type: "clause",
126
122
  xref: "#{@annex_lbl} #{num}", level: 1 }
127
- clause.xpath(ns(SUBCLAUSES)).each_with_index do |c, i|
128
- annex_names1(c, "#{num}.#{i + 1}", 2)
123
+ if a = single_annex_special_section(clause)
124
+ annex_names1(a, "#{num}", 1)
125
+ else
126
+ clause.xpath(ns(SUBCLAUSES)).each_with_index do |c, i|
127
+ annex_names1(c, "#{num}.#{i + 1}", 2)
128
+ end
129
129
  end
130
130
  hierarchical_asset_names(clause, num)
131
131
  end