isodoc 3.4.5 → 3.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ module IsoDoc
7
7
 
8
8
  def modification_parse(node, out)
9
9
  para = node.at(ns("./p"))
10
- para.children.each { |n| parse(n, out) }
10
+ children_parse(para, out)
11
11
  end
12
12
 
13
13
  def semx_deprecated_term_parse(node, out); end
@@ -16,7 +16,7 @@ module IsoDoc
16
16
  node.children.each do |c|
17
17
  if c.name == "p"
18
18
  out.p class: "DeprecatedTerms", style: "text-align:left;" do |p|
19
- c.children.each { |c1| parse(c1, p) }
19
+ children_parse(c, p)
20
20
  end
21
21
  else parse(c, out)
22
22
  end
@@ -29,7 +29,7 @@ module IsoDoc
29
29
  node.children.each do |c|
30
30
  if c.name == "p"
31
31
  out.p class: "AltTerms", style: "text-align:left;" do |p|
32
- c.children.each { |c1| parse(c1, p) }
32
+ children_parse(c, p)
33
33
  end
34
34
  else parse(c, out)
35
35
  end
@@ -38,7 +38,7 @@ module IsoDoc
38
38
 
39
39
  def related_parse(node, out)
40
40
  out.div class: "RelatedTerms", style: "text-align:left;" do |p|
41
- node.children.each { |c1| parse(c1, p) }
41
+ children_parse(node, p)
42
42
  end
43
43
  end
44
44
 
@@ -49,28 +49,33 @@ module IsoDoc
49
49
  def term_parse(node, out)
50
50
  node.children.each do |c|
51
51
  if c.name == "p"
52
- out.p class: "Terms", style: "text-align:left;" do |p|
53
- c.children.each { |c1| parse(c1, p) }
54
- end
55
- else parse(c, out)
52
+ term_p_parse(c, out)
53
+ else
54
+ parse(c, out)
56
55
  end
57
56
  end
58
57
  end
59
58
 
59
+ def term_p_parse(node, out)
60
+ out.p class: "Terms", style: "text-align:left;" do |p|
61
+ children_parse(node, p)
62
+ end
63
+ end
64
+
60
65
  def termnote_p_class
61
66
  nil
62
67
  end
63
68
 
64
69
  def termnote_parse(node, out)
65
70
  para = block_body_first_elem(node)
66
- out.div **note_attrs(node) do |div|
71
+ out.div(**note_attrs(node)) do |div|
67
72
  termnote_parse1(node, para, div)
68
73
  para&.xpath("./following-sibling::*")&.each { |n| parse(n, div) }
69
74
  end
70
75
  end
71
76
 
72
77
  def termnote_parse1(node, para, div)
73
- div.p **attr_code(class: termnote_p_class) do |p|
78
+ div.p(**attr_code(class: termnote_p_class)) do |p|
74
79
  name = node.at(ns("./fmt-name")) and
75
80
  p.span class: "termnote_label" do |s|
76
81
  children_parse(name, s)
@@ -22,7 +22,7 @@ module IsoDoc
22
22
  end
23
23
 
24
24
  def make_body(xml, docxml)
25
- xml.body **body_attr do |body|
25
+ xml.body(**body_attr) do |body|
26
26
  make_body1(body, docxml)
27
27
  make_body2(body, docxml)
28
28
  make_body3(body, docxml)
@@ -100,8 +100,7 @@ module IsoDoc
100
100
  array.nil? || array.empty? and return ""
101
101
  if array.length == 1 then array[0]
102
102
  else
103
- @i18n.l10n("#{array[0..-2].join(', ')} " \
104
- "#{@i18n.and} #{array.last}",
103
+ @i18n.l10n("#{array[0..-2].join(', ')} #{@i18n.and} #{array.last}",
105
104
  @lang, @script)
106
105
  end
107
106
  end
@@ -141,7 +140,7 @@ module IsoDoc
141
140
  def liquid(doc)
142
141
  # unescape HTML escapes in doc
143
142
  doc = doc.split(%r<(\{%|%\})>).each_slice(4).map do |a|
144
- a[2] = a[2].gsub(/&lt;/, "<").gsub(/&gt;/, ">") if a.size > 2
143
+ a[2] = a[2].gsub("&lt;", "<").gsub("&gt;", ">") if a.size > 2
145
144
  a.join
146
145
  end.join
147
146
  Liquid::Template.parse(doc)
@@ -223,8 +222,7 @@ module IsoDoc
223
222
  a[0] = c.encode(c.decode(a[0]), :hexadecimal)
224
223
  a
225
224
  end.join
226
- else
227
- c.encode(c.decode(text), :hexadecimal)
225
+ else c.encode(c.decode(text), :hexadecimal)
228
226
  end
229
227
  end
230
228
 
@@ -239,6 +237,23 @@ module IsoDoc
239
237
  def imgfile_suffix(uri, suffix)
240
238
  "#{File.join(File.dirname(uri), File.basename(uri, '.*'))}.#{suffix}"
241
239
  end
240
+
241
+ # Unescape &#x26; to & in href attributes only
242
+ # This ensures URLs work correctly while preserving &#x26; in text content
243
+ # This operates on the final string output after all Nokogiri processing
244
+ def unescape_amp_in_hrefs(html)
245
+ # Match href="..." and href='...' separately
246
+ # Note: populate_template converts &amp; to &#x26;, so we replace that
247
+ html.gsub(/(href\s*=\s*")([^"]*)"|(href\s*=\s*')([^']*)'/) do
248
+ if Regexp.last_match(1)
249
+ "#{Regexp.last_match(1)}#{Regexp.last_match(2).gsub('&#x26;',
250
+ '&')}\""
251
+ else
252
+ "#{Regexp.last_match(3)}#{Regexp.last_match(4).gsub('&#x26;',
253
+ '&')}'"
254
+ end
255
+ end
256
+ end
242
257
  end
243
258
  end
244
259
  end
@@ -2,53 +2,53 @@ module IsoDoc
2
2
  module HtmlFunction
3
3
  module Form
4
4
  def form_parse(node, out)
5
- out.form **attr_code(id: node["id"], name: node["name"],
5
+ out.form(**attr_code(id: node["id"], name: node["name"],
6
6
  class: node["class"],
7
- action: node["action"]) do |div|
7
+ action: node["action"])) do |div|
8
8
  children_parse(node, div)
9
9
  end
10
10
  end
11
11
 
12
12
  def input_parse(node, out)
13
- out.input nil, **attr_code(
13
+ out.input(nil, **attr_code(
14
14
  id: node["id"], name: node["name"], type: node["type"],
15
15
  value: node["value"], disabled: node["disabled"],
16
16
  readonly: node["readonly"], checked: node["checked"],
17
17
  maxlength: node["maxlength"], minlength: node["minlength"]
18
- )
18
+ ))
19
19
  end
20
20
 
21
21
  def select_parse(node, out)
22
22
  selected = node.at(ns("./option[@value = '#{node['value']}']"))
23
23
  selected and selected["selected"] = true
24
- out.select **attr_code(
24
+ out.select(**attr_code(
25
25
  id: node["id"], name: node["name"], size: node["size"],
26
26
  disabled: node["disabled"], multiple: node["multiple"]
27
- ) do |div|
27
+ )) do |div|
28
28
  children_parse(node, div)
29
29
  end
30
30
  end
31
31
 
32
32
  def label_parse(node, out)
33
- out.label **attr_code(for: node["for"]) do |div|
33
+ out.label(**attr_code(for: node["for"])) do |div|
34
34
  children_parse(node, div)
35
35
  end
36
36
  end
37
37
 
38
38
  def option_parse(node, out)
39
- out.option **attr_code(
39
+ out.option(**attr_code(
40
40
  disabled: node["disabled"], selected: node["selected"],
41
41
  value: node["value"]
42
- ) do |o|
42
+ )) do |o|
43
43
  children_parse(node, o)
44
44
  end
45
45
  end
46
46
 
47
47
  def textarea_parse(node, out)
48
- out.textarea **attr_code(
48
+ out.textarea(**attr_code(
49
49
  id: node["id"], name: node["name"], rows: node["rows"],
50
50
  cols: node["cols"]
51
- ) do |div|
51
+ )) do |div|
52
52
  node["value"] and div << node["value"]
53
53
  end
54
54
  end
@@ -16,8 +16,7 @@ module IsoDoc
16
16
  end
17
17
 
18
18
  def make_body1(body, _docxml)
19
- return if @bare
20
-
19
+ @bare and return
21
20
  body.div class: "title-section" do |div1|
22
21
  div1.p { |p| p << "&#xa0;" } # placeholder
23
22
  end
@@ -25,8 +24,7 @@ module IsoDoc
25
24
  end
26
25
 
27
26
  def make_body2(body, _docxml)
28
- return if @bare
29
-
27
+ @bare and return
30
28
  body.div class: "prefatory-section" do |div2|
31
29
  div2.p { |p| p << "&#xa0;" } # placeholder
32
30
  end
@@ -60,36 +58,68 @@ module IsoDoc
60
58
  end
61
59
 
62
60
  def html_button
63
- return "" if @bare
64
-
61
+ @bare and return ""
65
62
  '<button onclick="topFunction()" id="myBtn" ' \
66
63
  'title="Go to top">Top</button>'.freeze
67
64
  end
68
65
 
69
66
  def html_main(docxml)
70
- docxml.at("//head").add_child(html_head)
67
+ docxml.at("//head") << Nokogiri::HTML.fragment(html_head)
71
68
  d = docxml.at('//div[@class="main-section"]')
72
69
  d.name = "main"
73
70
  d.children.empty? or d.children.first.previous = html_button
74
71
  end
75
72
 
76
73
  def sourcecode_parse(node, out)
77
- name = node.at(ns("./fmt-name"))
78
- tag = node.at(ns(".//sourcecode | .//table")) ? "div" : "pre"
79
- n = node.at(ns("./fmt-sourcecode"))
80
- s = n || node
74
+ tag, child_tag = sourcecode_tag(node)
75
+ s = node.at(ns("./fmt-sourcecode")) || node
81
76
  attr = sourcecode_attrs(node).merge(class: "sourcecode")
82
77
  out.send tag, **attr do |div|
83
- sourcecode_parse1(s, div)
78
+ sourcecode_pre_wrap(child_tag, s, div)
79
+ annotation_parse(s, div)
80
+ sourcecode_name_parse(node, div, node.at(ns("./fmt-name")))
81
+ end
82
+ end
83
+
84
+ def sourcecode_attrs(node)
85
+ super.merge(spellcheck: "false", translation: "no")
86
+ end
87
+
88
+ def sourcecode_tag(node)
89
+ ancestors = node.ancestors.map(&:name)
90
+ .intersection(%w(sourcecode table))
91
+ tag = ancestors.empty? ? "figure" : "pre"
92
+ child_tag = "pre"
93
+ tag == "pre" || node.at(ns(".//sourcecode | .//table")) and
94
+ child_tag = "figure"
95
+ [tag, child_tag]
96
+ end
97
+
98
+ def sourcecode_pre_wrap(tag, node, div)
99
+ if tag == "pre"
100
+ div.pre do |pre|
101
+ sourcecode_parse1(node, pre)
102
+ end
103
+ else
104
+ sourcecode_parse1(node, div)
84
105
  end
85
- annotation_parse(s, out)
86
- sourcecode_name_parse(node, out, name)
106
+ end
107
+
108
+ def sourcecode_name_parse(_node, div, name)
109
+ name.nil? and return
110
+ div.figcaption class: "SourceTitle" do |p|
111
+ children_parse(name, p)
112
+ end
113
+ end
114
+
115
+ def pseudocode_tag
116
+ "figure"
87
117
  end
88
118
 
89
119
  def underline_parse(node, out)
90
120
  style = node["style"] ? " #{node['style']}" : ""
91
121
  attr = { style: "text-decoration: underline#{style}" }
92
- out.span **attr do |e|
122
+ out.span(**attr) do |e|
93
123
  node.children.each { |n| parse(n, e) }
94
124
  end
95
125
  end
@@ -104,24 +134,92 @@ module IsoDoc
104
134
  end
105
135
 
106
136
  def svg_supply_viewbox(svg)
107
- svg["viewbox"] and return
108
- svg["height"] && svg["width"] or return
137
+ svg_supply_viewbox?(svg) or return
109
138
  h = svg["height"].to_s[/\d+/].to_s
110
139
  w = svg["width"].to_s[/\d+/].to_s
111
- h.to_i.positive? && w.to_i.positive? or return
140
+ (h.to_i.positive? && w.to_i.positive?) or return
112
141
  svg["viewbox"] = "0 0 #{w} #{h}"
113
142
  end
114
143
 
144
+ def svg_supply_viewbox?(svg)
145
+ svg["viewbox"] and return false
146
+ (svg["height"] && svg["width"]) or return false
147
+ true
148
+ end
149
+
150
+ def image_body_parse_svg(svg, out)
151
+ svg_supply_viewbox(svg)
152
+ out.div class: "svg-container" do |div|
153
+ div.parent.add_child(svg)
154
+ end
155
+ end
156
+
157
+ def select_altsource?(_altsource, tags)
158
+ tags.include?("html")
159
+ end
160
+
115
161
  def image_body_parse(node, attrs, out)
116
- if svg = node.at("./m:svg", "m" => "http://www.w3.org/2000/svg")
117
- svg_supply_viewbox(svg)
118
- out.div class: "svg-container" do |div|
119
- div.parent.add_child(svg)
162
+ svg = node.at(".//m:svg", "m" => "http://www.w3.org/2000/svg")
163
+ alts = select_altsource(node)
164
+ if svg && alts.empty?
165
+ image_body_parse_svg(svg, out)
166
+ else
167
+ image_body_parse_picture(node, attrs, alts, out)
168
+ end
169
+ end
170
+
171
+ def image_body_parse_picture(node, _attrs, alts, out)
172
+ out.picture do |p|
173
+ alts.each do |i|
174
+ if i["tag"] == "default" then next
175
+ else
176
+ p.source **attr_code(altsource_attrs(i)
177
+ .merge({ srcset: svg2datauri(i) }.compact))
178
+ end
179
+ end
180
+ image_picture_img(node, p)
181
+ end
182
+ end
183
+
184
+ def image_picture_img(node, out)
185
+ default = node.at(ns("./altsource[@tag = 'default']")) || node
186
+ out.img **attr_code(image_attrs(default)
187
+ .merge({ src: svg2datauri(default) }.compact))
188
+ end
189
+
190
+ def altsource_attrs(node)
191
+ media = node["media"]
192
+ media.blank? and media = "all"
193
+ { srcset: node["src"], media: @c.decode(media), type: node["type"] }
194
+ end
195
+
196
+ def svg2datauri(node)
197
+ svg = node.at(".//m:svg", "m" => "http://www.w3.org/2000/svg") or
198
+ return nil
199
+ v = Vectory::Svg.from_node(svg.parent)
200
+ Vectory::Datauri.from_vector(v).content
201
+ end
202
+
203
+ def semx_parse(node, out)
204
+ if %w(expression/name letter-symbol/name).include?(node["element"])
205
+ tag = designation_tag(node)
206
+ out.send tag do |d|
207
+ children_parse(node, d)
120
208
  end
121
209
  else super
122
210
  end
123
211
  end
124
212
 
213
+ def designation_tag(node)
214
+ term = node.at("./ancestor::xmlns:term")
215
+ if node["element"] == "expression/name"
216
+ e = term.at(".//*[@id = '#{node['source']}']")
217
+ # <expression type='abbreviation'><name>...
218
+ e&.parent && e.parent["type"] == "abbreviation" and return "abbr"
219
+ end
220
+ "dfn"
221
+ end
222
+
125
223
  def in_comment
126
224
  @in_comment
127
225
  end
@@ -8,15 +8,19 @@ module IsoDoc
8
8
  module Html
9
9
  def postprocess(result, filename, _dir)
10
10
  result = from_xhtml(cleanup(to_xhtml(textcleanup(result))))
11
- toHTML(result, filename)
11
+ result = toHTML(result, filename)
12
12
  @files_to_delete.each { |f| FileUtils.rm_rf f }
13
+ result
13
14
  end
14
15
 
15
16
  def toHTML(result, filename)
16
17
  result = from_xhtml(html_cleanup(to_xhtml(result)))
17
18
  result = from_xhtml(move_images(resize_images(to_xhtml(result))))
18
19
  result = html5(script_cdata(inject_script(result)))
20
+ # Unescape &#x26; to & in href attributes after all Nokogiri processing
21
+ result = unescape_amp_in_hrefs(result)
19
22
  File.open(filename, "w:UTF-8") { |f| f.write(result) }
23
+ result
20
24
  end
21
25
 
22
26
  def html5(doc)
@@ -31,7 +35,7 @@ module IsoDoc
31
35
  end
32
36
 
33
37
  def heading_anchors(html)
34
- html.xpath("//h1 | //h2 | //h3 | //h4 | //h5 | //h6 | //h7 | //h8 "\
38
+ html.xpath("//h1 | //h2 | //h3 | //h4 | //h5 | //h6 | //h7 | //h8 | " \
35
39
  "//span[@class = 'inline-header']").each do |h|
36
40
  h.at("./ancestor::div[@id='toc']") and next
37
41
  div = h.xpath("./ancestor::div[@id]")
@@ -49,7 +53,7 @@ module IsoDoc
49
53
 
50
54
  def sourcecode_cleanup(html)
51
55
  ann = ".//div[@class = 'annotation']"
52
- html.xpath("//pre[#{ann}] | //div[@class = 'sourcecode'][#{ann}]")
56
+ html.xpath("//pre[#{ann}] | //figure[@class = 'sourcecode'][#{ann}]")
53
57
  .each do |p|
54
58
  ins = p.after("<pre class='sourcecode'/>").next_element
55
59
  p.xpath(ann).each do |d|
@@ -104,7 +104,8 @@ module IsoDoc
104
104
  end
105
105
 
106
106
  def designation_annotate(desgn, name, orig)
107
- designation_boldface(desgn)
107
+ # designation_boldface(desgn)
108
+ designation_expression(desgn, name, orig)
108
109
  designation_field(desgn, name, orig)
109
110
  designation_grammar(desgn, name)
110
111
  designation_localization(desgn, name, orig)
@@ -113,12 +114,32 @@ module IsoDoc
113
114
  desgn.children = name.children
114
115
  end
115
116
 
116
- def designation_boldface(desgn)
117
+ # KILL
118
+ def designation_boldfacex(desgn)
117
119
  desgn["element"] == "preferred" or return
118
120
  name = desgn.at(ns("./expression/name | ./letter-symbol/name")) or return
119
121
  name.children = "<strong>#{name.children}</strong>"
120
122
  end
121
123
 
124
+ def designation_expression(desgn, name, orig)
125
+ if origname = orig.at(ns("./expression/name"))
126
+ element = "expression/name"
127
+ elsif origname = orig.at(ns("./letter-symbol/name"))
128
+ element = "letter-symbol/name"
129
+ elsif origname = orig.at(ns("./graphical-symbol"))
130
+ element = "graphical-symbol"
131
+ end
132
+ name.children = <<~XML.strip
133
+ <semx element='#{element}' source='#{origname['id'] || origname['original-id']}'>#{to_xml(name.children).strip}</semx>
134
+ XML
135
+ designation_expression_boldface(desgn, name)
136
+ end
137
+
138
+ def designation_expression_boldface(desgn, name)
139
+ name.name == "name" && desgn["element"] == "preferred" and
140
+ name.children = "<strong>#{to_xml(name.children)}</strong>"
141
+ end
142
+
122
143
  def designation_field(_desgn, name, orig)
123
144
  f = orig.xpath(ns("./field-of-application | ./usage-info"))
124
145
  &.map { |u| to_xml(semx_fmt_dup(u)) }&.join(", ")
@@ -99,7 +99,9 @@ module IsoDoc
99
99
  "//annotation | //floating-title | //li | //executivesummary | " \
100
100
  "//preface/abstract | //foreword | //introduction | //annex | " \
101
101
  "//acknowledgements | //clause | //references | //terms | " \
102
- "//preferred | //deprecates | //admitted | //related")).each do |s|
102
+ "//preferred | //deprecates | //admitted | //related | " \
103
+ "//expression/name | //letter-symbol/name | //graphical-symbol"))
104
+ .each do |s|
103
105
  add_id(s)
104
106
  end
105
107
  end
@@ -185,8 +185,9 @@ module IsoDoc
185
185
  end
186
186
 
187
187
  # used downstream to load svg images inline
188
+ # directory can be string, or array
188
189
  def svg_load(directory, filename)
189
- dir = File.join(@libdir, "html", directory)
190
+ dir = File.join(@libdir, "html", *directory)
190
191
  filename = File.join(dir, filename)
191
192
  File.exist?(filename) or return
192
193
  file = File.read(filename) or return
@@ -1,3 +1,3 @@
1
1
  module IsoDoc
2
- VERSION = "3.4.5".freeze
2
+ VERSION = "3.4.7".freeze
3
3
  end
@@ -69,7 +69,7 @@ module IsoDoc
69
69
  end
70
70
 
71
71
  def para_parse(node, out)
72
- out.p **attr_code(para_attrs(node)) do |p|
72
+ out.p(**attr_code(para_attrs(node))) do |p|
73
73
  unless @termdomain.empty?
74
74
  p << "&#x3c;#{@termdomain}&#x3e; "
75
75
  @termdomain = ""
@@ -87,6 +87,10 @@ module IsoDoc
87
87
  "Note"
88
88
  end
89
89
 
90
+ def admonition_subclass(_node)
91
+ ""
92
+ end
93
+
90
94
  def para_attrs(node)
91
95
  attrs = { class: para_class(node), id: node["id"], style: "" }
92
96
  unless node["align"].nil?
@@ -109,7 +113,7 @@ module IsoDoc
109
113
  end
110
114
 
111
115
  def formula_parse1(node, out)
112
- out.div **attr_code(class: "formula") do |div|
116
+ out.div(**attr_code(class: "formula")) do |div|
113
117
  div.p do |_p|
114
118
  parse(node.at(ns("./fmt-stem")), div)
115
119
  insert_tab(div, 1)
@@ -151,7 +155,7 @@ module IsoDoc
151
155
 
152
156
  def table_of_contents(clause, out)
153
157
  page_break(out)
154
- out.div **attr_code(preface_attrs(clause)) do |div|
158
+ out.div(**attr_code(preface_attrs(clause))) do |div|
155
159
  div.p class: "zzContents" do |p|
156
160
  clause.at(ns("./fmt-title"))&.children&.each { |c| parse(c, p) }
157
161
  end
@@ -162,7 +166,7 @@ module IsoDoc
162
166
  end
163
167
 
164
168
  def figure_parse1(node, out)
165
- out.div **figure_attrs(node) do |div|
169
+ out.div(**figure_attrs(node)) do |div|
166
170
  node.children.each do |n|
167
171
  parse(n, div) unless n.name == "fmt-name"
168
172
  end
@@ -2,7 +2,7 @@ module IsoDoc
2
2
  module WordFunction
3
3
  module Body
4
4
  def insert_tab(out, count)
5
- out.span **attr_code(style: "mso-tab-count:#{count}") do |span|
5
+ out.span(**attr_code(style: "mso-tab-count:#{count}")) do |span|
6
6
  [1..count].each { span << "&#xA0; " }
7
7
  end
8
8
  end
@@ -46,7 +46,7 @@ module IsoDoc
46
46
  attrs = { src: imgsrc(node),
47
47
  height: node["height"], alt: node["alt"],
48
48
  title: node["title"], width: node["width"] }
49
- out.img **attr_code(attrs)
49
+ image_body_parse(node, attrs, out)
50
50
  end
51
51
 
52
52
  def emf_attributes(node)
@@ -89,7 +89,7 @@ module IsoDoc
89
89
  end
90
90
 
91
91
  def rt_parse(node, out)
92
- out.rt **{ style: "font-size: 6pt;" } do |e|
92
+ out.rt(**{ style: "font-size: 6pt;" }) do |e|
93
93
  children_parse(node, e)
94
94
  end
95
95
  end
@@ -8,7 +8,7 @@ module IsoDoc
8
8
  style: "margin-left:0pt;text-align:left;" }.freeze
9
9
 
10
10
  def dt_parse(dterm, term)
11
- term.p **attr_code(WORD_DT_ATTRS) do |p|
11
+ term.p(**attr_code(WORD_DT_ATTRS)) do |p|
12
12
  if dterm.elements.empty?
13
13
  p << dterm.text
14
14
  else
@@ -24,7 +24,7 @@ module IsoDoc
24
24
  end
25
25
 
26
26
  def dl_parse_nontable(node, out)
27
- out.div **attr_code(class: "figdl") do |div|
27
+ out.div(**attr_code(class: "figdl")) do |div|
28
28
  node["id"] and bookmark_parse(node, div)
29
29
  list_title_parse(node, div)
30
30
  node.elements.select { |n| dt_dd?(n) }
@@ -39,7 +39,7 @@ module IsoDoc
39
39
  "text-indent: -2.0cm; margin-left: 2.0cm; tab-stops: 2.0cm;".freeze
40
40
 
41
41
  def dl_parse_nontable1(out, dterm, ddef)
42
- out.p **attr_code(style: WORD_EMBED_DL_ATTRS, id: dterm["id"]) do |p|
42
+ out.p(**attr_code(style: WORD_EMBED_DL_ATTRS, id: dterm["id"])) do |p|
43
43
  dterm.children.each { |n| parse(n, p) }
44
44
  insert_tab(p, 1)
45
45
  ddef["id"] and bookmark_parse(ddef, out)
@@ -70,9 +70,9 @@ module IsoDoc
70
70
  end
71
71
 
72
72
  def dl_parse_table(node, out)
73
- out.div **attr_code(align: "left") do |div|
73
+ out.div(**attr_code(align: "left")) do |div|
74
74
  list_title_parse(node, div)
75
- div.table **attr_code(dl_table_attrs(node)) do |v|
75
+ div.table(**attr_code(dl_table_attrs(node))) do |v|
76
76
  node.elements.select { |n| dt_dd?(n) }
77
77
  .each_slice(2) do |dt, dd|
78
78
  dl_parse_table1(v, dt, dd)
@@ -17,8 +17,10 @@ module IsoDoc
17
17
 
18
18
  def postprocess_cleanup(result)
19
19
  result = cleanup(to_xhtml(textcleanup(result)))
20
- from_xhtml(word_cleanup(result))
20
+ result = from_xhtml(word_cleanup(result))
21
21
  .gsub("-DOUBLE_HYPHEN_ESCAPE-", "--")
22
+ # Unescape &#x26; to & in href attributes after all Nokogiri processing
23
+ unescape_amp_in_hrefs(result)
22
24
  end
23
25
 
24
26
  def toWord(result, filename, dir, header)
@@ -115,7 +115,7 @@ module IsoDoc
115
115
  @in_table = true
116
116
  table_title_parse(node, out)
117
117
  out.div align: "center", class: "table_container" do |div|
118
- div.table **table_attrs(node) do |t|
118
+ div.table(**table_attrs(node)) do |t|
119
119
  table_parse_core(node, t)
120
120
  table_parse_tail(node, t)
121
121
  end