metanorma-standoc 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/metanorma/standoc/base.rb +1 -1
  3. data/lib/metanorma/standoc/basicdoc.rng +5 -3
  4. data/lib/metanorma/standoc/biblio.rng +5 -3
  5. data/lib/metanorma/standoc/cleanup_image.rb +117 -3
  6. data/lib/metanorma/standoc/cleanup_ref.rb +1 -1
  7. data/lib/metanorma/standoc/cleanup_section.rb +1 -1
  8. data/lib/metanorma/standoc/cleanup_xref.rb +12 -5
  9. data/lib/metanorma/standoc/isodoc.rng +10 -0
  10. data/lib/metanorma/standoc/ref.rb +6 -1
  11. data/lib/metanorma/standoc/ref_utility.rb +2 -1
  12. data/lib/metanorma/standoc/term_lookup_cleanup.rb +8 -6
  13. data/lib/metanorma/standoc/terms.rb +10 -7
  14. data/lib/metanorma/standoc/validate.rb +7 -2
  15. data/lib/metanorma/standoc/version.rb +1 -1
  16. data/spec/metanorma/cleanup_blocks_spec.rb +136 -0
  17. data/spec/metanorma/cleanup_spec.rb +3 -3
  18. data/spec/metanorma/isobib_cache_spec.rb +2 -2
  19. data/spec/metanorma/macros_spec.rb +61 -0
  20. data/spec/metanorma/refs_spec.rb +505 -460
  21. data/spec/metanorma/section_spec.rb +1 -1
  22. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +46 -46
  23. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +12 -12
  24. data/spec/vcr_cassettes/hide_refs.yml +98 -98
  25. data/spec/vcr_cassettes/isobib_get_123.yml +12 -12
  26. data/spec/vcr_cassettes/isobib_get_123_1.yml +25 -25
  27. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +35 -35
  28. data/spec/vcr_cassettes/isobib_get_123_2001.yml +12 -12
  29. data/spec/vcr_cassettes/isobib_get_124.yml +11 -11
  30. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +14 -14
  31. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +61 -51
  32. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9031c28646f9cd9a481ad67911f2f0f7e5bd058368f80888a788753e5f63fa3
4
- data.tar.gz: 25b16459f351f266f19b2f00d70b5bf7f6f5c95325a0d61d43fbe5f3fa518802
3
+ metadata.gz: cc4b55c7be36492191bd86bc19646a520c76e94bd2e2af9f96cf0d80d25fb05e
4
+ data.tar.gz: 533fc5380552ab239528a559ee41a47c246203e17cb33df64cb5cdef5df21f34
5
5
  SHA512:
6
- metadata.gz: 885e62405f3198482ffd7e152b25bef8ab09fc227a8107984297e8fa15b64552b2e745f4ce5e1d60dd37df6dc5cf5c505fb9acfeedd1bdc4ef77954e01218893
7
- data.tar.gz: 69cac251a0696b46dd25f37fb23828780e1945e57464e829c91ab5d88ac481311d130c4ff0e670ee89d56fd998eff4ea48e3c5a0c4b24c514021431fb785d852
6
+ metadata.gz: adc2d0b10dd30e5f59060b20574701dc6049b25a9d25eff06557ac51ca66645f62b553517690380009460f01fe135d26e83ab653b81c7746209e8f55221c3703
7
+ data.tar.gz: 8bc78cf1ab42e80d93c8a22f0028e44e7ba735914fa43c2dcdd5eb53cb57b3a3ee52ea1677cae5033dbc738f8b444bc0dc2e5021ff08a443d991535c84c373b2
@@ -71,7 +71,7 @@ module Metanorma
71
71
 
72
72
  def document(node)
73
73
  init(node)
74
- ret = makexml(node).to_xml(encoding: "US-ASCII", indent: 2)
74
+ ret = makexml(node).to_xml(encoding: "UTF-8", indent: 2)
75
75
  outputs(node, ret) unless node.attr("nodoc") || !node.attr("docfile")
76
76
  clean_exit
77
77
  ret
@@ -173,9 +173,11 @@
173
173
  <data type="dateTime"/>
174
174
  </attribute>
175
175
  </optional>
176
- <attribute name="from">
177
- <data type="IDREF"/>
178
- </attribute>
176
+ <optional>
177
+ <attribute name="from">
178
+ <data type="IDREF"/>
179
+ </attribute>
180
+ </optional>
179
181
  <optional>
180
182
  <attribute name="to">
181
183
  <data type="IDREF"/>
@@ -209,9 +209,6 @@
209
209
  <zeroOrMore>
210
210
  <ref name="contact"/>
211
211
  </zeroOrMore>
212
- <zeroOrMore>
213
- <ref name="uri"/>
214
- </zeroOrMore>
215
212
  </element>
216
213
  </define>
217
214
  <define name="fullname">
@@ -828,6 +825,11 @@
828
825
  <optional>
829
826
  <attribute name="scope"/>
830
827
  </optional>
828
+ <optional>
829
+ <attribute name="primary">
830
+ <data type="boolean"/>
831
+ </attribute>
832
+ </optional>
831
833
  <text/>
832
834
  </element>
833
835
  </define>
@@ -2,6 +2,7 @@ module Metanorma
2
2
  module Standoc
3
3
  module Cleanup
4
4
  def svgmap_cleanup(xmldoc)
5
+ svg_uniqueids(xmldoc)
5
6
  svgmap_moveattrs(xmldoc)
6
7
  svgmap_populate(xmldoc)
7
8
  Metanorma::Utils::svgmap_rewrite(xmldoc, @localdir)
@@ -59,12 +60,125 @@ module Metanorma
59
60
  end
60
61
 
61
62
  def img_cleanup(xmldoc)
62
- return xmldoc unless @datauriimage
63
+ if @datauriimage
64
+ xmldoc.xpath("//image").each do |i|
65
+ # do not datauri encode SVG, we need to deduplicate its IDs
66
+ unless read_in_if_svg(i, @localdir)
67
+ i["src"] = Metanorma::Utils::datauri(i["src"], @localdir)
68
+ end
69
+ end
70
+ end
71
+ svg_uniqueids(xmldoc)
72
+ xmldoc
73
+ end
74
+
75
+ def read_in_if_svg(img, localdir)
76
+ return false unless img["src"]
77
+
78
+ path = Metanorma::Utils::svgmap_rewrite0_path(img["src"], localdir)
79
+ File.file?(path) or return false
80
+ types = MIME::Types.type_for(path) or return false
81
+ types.first == "image/svg+xml" or return false
82
+ svg = File.read(path, encoding: "utf-8") or return false
83
+ img.replace(Nokogiri::XML(svg).root.to_xml)
84
+ true
85
+ end
86
+
87
+ IRI_TAG_PROPERTIES_MAP = {
88
+ clipPath: ["clip-path"],
89
+ "color-profile": nil,
90
+ cursor: nil,
91
+ filter: nil,
92
+ linearGradient: ["fill", "stroke"],
93
+ marker: ["marker", "marker-end", "marker-mid", "marker-start"],
94
+ mask: nil,
95
+ pattern: ["fill", "stroke"],
96
+ radialGradient: ["fill", "stroke"],
97
+ }.freeze
98
+
99
+ SVG_NS = "http://www.w3.org/2000/svg".freeze
100
+
101
+ def svg_uniqueids(xmldoc)
102
+ # only keep non-unique identifiers
103
+ ids = xmldoc.xpath("//m:svg//*/@id | //svg/@id", "m" => SVG_NS)
104
+ .map(&:text).group_by(&:itself).transform_values(&:count)
105
+ .delete_if { |_, v| v < 2 }
106
+ xmldoc.xpath("//m:svg", "m" => SVG_NS).each_with_index do |s, i|
107
+ ids = svg_uniqueids1(s, i, ids)
108
+ end
109
+ end
110
+
111
+ def svg_iri_properties(id_elems)
112
+ iri_tag_names = id_elems.each_with_object([]) do |e, m|
113
+ IRI_TAG_PROPERTIES_MAP.key?(e.name.to_sym) and m = m << e.name
114
+ end.uniq
115
+ iri_properties = iri_tag_names.each_with_object([]) do |t, m|
116
+ (IRI_TAG_PROPERTIES_MAP[t.to_sym] || [t]).each { |t1| m = m << t1 }
117
+ end.uniq
118
+ return [] if iri_properties.empty?
119
+
120
+ iri_properties << "style"
121
+ end
63
122
 
64
- xmldoc.xpath("//image").each do |i|
65
- i["src"] = Metanorma::Utils::datauri(i["src"], @localdir)
123
+ def svg_uniqueids1(svg, idx, ids)
124
+ id_elems = svg.xpath(".//*[@id] | ./@id/..")
125
+ iri_properties = svg_iri_properties(id_elems)
126
+ svg_uniqueids2(svg, iri_properties, idx, ids)
127
+ new_ids = id_elems.map { |x| x["id"] }
128
+ .map { |x| x + (ids[x] ? "_inject_#{idx}" : "") }
129
+ ids.merge(new_ids.each.map { |value| [value, true] }.to_h)
130
+ end
131
+
132
+ def svg_uniqueids2(svg, iri_properties, idx, ids)
133
+ svg.traverse do |e|
134
+ next unless e.element?
135
+
136
+ if e.name == "style"
137
+ svg_styleupdate(e, idx, ids)
138
+ elsif !e.attributes.empty?
139
+ svg_attrupdate(e, iri_properties, idx, ids)
140
+ end
141
+ svg_linkupdate(e, idx, ids)
142
+ svg_idupdate(e, idx, ids)
66
143
  end
67
144
  end
145
+
146
+ def svg_update_url(text, idx, ids)
147
+ text.gsub(/url\("?#([a-zA-Z][\w:.-]*)"?\)/) do |x|
148
+ if ids[$1] then "url(##{$1}_inject_#{idx})"
149
+ else x
150
+ end
151
+ end
152
+ end
153
+
154
+ def svg_styleupdate(elem, idx, ids)
155
+ elem.children = svg_update_url(elem.text, idx, ids)
156
+ end
157
+
158
+ def svg_attrupdate(elem, iri_properties, idx, ids)
159
+ iri_properties.each do |p|
160
+ next unless elem[p]
161
+
162
+ elem[p] = svg_update_url(elem[p], idx, ids)
163
+ end
164
+ end
165
+
166
+ def svg_linkupdate(elem, idx, ids)
167
+ %w(xlink:href href).each do |ref|
168
+ iri = elem[ref]&.strip
169
+ next unless /^#/.match?(iri)
170
+ next unless ids[iri.sub(/^#/, "")]
171
+
172
+ elem[ref] += "_inject_#{idx}"
173
+ end
174
+ end
175
+
176
+ def svg_idupdate(elem, idx, ids)
177
+ return unless elem["id"]
178
+ return unless ids[elem["id"]]
179
+
180
+ elem["id"] += "_inject_#{idx}"
181
+ end
68
182
  end
69
183
  end
70
184
  end
@@ -117,7 +117,7 @@ module Metanorma
117
117
  # isopub = ref.at(ISO_PUBLISHER_XPATH)
118
118
  docid = ref.at("./docidentifier[@type = 'metanorma']") ||
119
119
  ref.at("./docidentifier[not(@type = 'DOI')]") or next
120
- reference = format_ref(docid.text, docid["type"])
120
+ reference = format_ref(docid.children.to_xml, docid["type"])
121
121
  @anchors[ref["id"]] = { xref: reference }
122
122
  end
123
123
  end
@@ -193,7 +193,7 @@ module Metanorma
193
193
  next unless t.next_element.nil?
194
194
  next if %w(sections annex preface).include? t.parent.name
195
195
 
196
- t.parent.parent << t
196
+ t.parent.next = t
197
197
  found = true
198
198
  end
199
199
  break unless found
@@ -47,16 +47,23 @@ module Metanorma
47
47
 
48
48
  def xref_to_eref(elem)
49
49
  elem["bibitemid"] = elem["target"]
50
- unless elem["citeas"] = @anchors&.dig(elem["target"], :xref)
51
- @internal_eref_namespaces.include?(elem["type"]) or
52
- @log.add("Crossreferences", elem,
53
- "#{elem['target']} does not have a corresponding "\
54
- "anchor ID in the bibliography!")
50
+ if ref = @anchors&.dig(elem["target"], :xref)
51
+ elem["citeas"] = HTMLEntities.new.encode(ref, :hexadecimal)
52
+ else
53
+ elem["citeas"] = ""
54
+ xref_to_eref1(elem)
55
55
  end
56
56
  elem.delete("target")
57
57
  extract_localities(elem) unless elem.children.empty?
58
58
  end
59
59
 
60
+ def xref_to_eref1(elem)
61
+ @internal_eref_namespaces.include?(elem["type"]) or
62
+ @log.add("Crossreferences", elem,
63
+ "#{elem['target']} does not have a corresponding "\
64
+ "anchor ID in the bibliography!")
65
+ end
66
+
60
67
  def xref_cleanup(xmldoc)
61
68
  xmldoc.xpath("//xref").each do |x|
62
69
  /:/.match(x["target"]) and xref_to_internal_eref(x)
@@ -1098,6 +1098,16 @@
1098
1098
  </define>
1099
1099
  </include>
1100
1100
  <!-- end overrides -->
1101
+ <define name="image" combine="choice">
1102
+ <element name="svg">
1103
+ <oneOrMore>
1104
+ <choice>
1105
+ <text/>
1106
+ <ref name="AnyElement"/>
1107
+ </choice>
1108
+ </oneOrMore>
1109
+ </element>
1110
+ </define>
1101
1111
  <define name="MultilingualRenderingType">
1102
1112
  <choice>
1103
1113
  <value>common</value>
@@ -131,6 +131,7 @@ module Metanorma
131
131
  # TODO: alternative where only title is available
132
132
  def refitemcode(item, node)
133
133
  m = NON_ISO_REF.match(item) and return refitem1code(item, m).compact
134
+ m = NON_ISO_REF1.match(item) and return refitem1code(item, m).compact
134
135
  @log.add("AsciiDoc Input", node, "#{MALFORMED_REF}: #{item}")
135
136
  {}
136
137
  end
@@ -180,7 +181,11 @@ module Metanorma
180
181
  (<fn[^>]*>\s*<p>(?<fn>[^\]]+)</p>\s*</fn>,?\s?)?(?<text>.*)$}xm.freeze
181
182
 
182
183
  NON_ISO_REF = %r{^<ref\sid="(?<anchor>[^"]+)">
183
- \[(?<usrlbl>\([^)]+\))?(?<code>[^\]]+?)\]</ref>,?\s*(?<text>.*)$}xm
184
+ \[(?<usrlbl>\([^)]+\))?(?<code>.+?)\]</ref>,?\s*(?<text>.*)$}xm
185
+ .freeze
186
+
187
+ NON_ISO_REF1 = %r{^<ref\sid="(?<anchor>[^"]+)">
188
+ (?<usrlbl>\([^)]+\))?(?<code>.+?)</ref>,?\s*(?<text>.*)$}xm
184
189
  .freeze
185
190
 
186
191
  def reference1_matches(item)
@@ -75,7 +75,8 @@ module Metanorma
75
75
 
76
76
  def analyse_ref_repo_path(ret)
77
77
  return ret unless m =
78
- /^(?<type>repo|path):\((?<key>[^,]+),?(?<id>.*)\)$/.match(ret[:id])
78
+ /^(?<type>repo|path):\((?<key>[^,]+),?(?<id>.*)\)$/
79
+ .match(ret[:id])
79
80
 
80
81
  id = m[:id].empty? ? m[:key].sub(%r{^[^/]+/}, "") : m[:id]
81
82
  ret.merge(id: id, type: m[:type], key: m[:key], nofetch: true)
@@ -58,7 +58,7 @@ module Metanorma
58
58
 
59
59
  def set_termxref_tags_target
60
60
  xmldoc.xpath("//termxref").each do |node|
61
- target = normalize_ref_id(node.text)
61
+ target = normalize_ref_id(node)
62
62
  if termlookup[:term][target].nil? && termlookup[:symbol][target].nil?
63
63
  remove_missing_ref(node, target)
64
64
  next
@@ -78,7 +78,7 @@ module Metanorma
78
78
 
79
79
  def remove_missing_ref_term(node, target)
80
80
  log.add("AsciiDoc Input", node,
81
- %(Error: Term reference in `term[#{target}]` missing: \
81
+ %(Error: Term reference to `#{target}` missing: \
82
82
  "#{target}" is not defined in document))
83
83
  node.name = "strong"
84
84
  node&.at("../xrefrender")&.remove
@@ -141,7 +141,7 @@ module Metanorma
141
141
  end
142
142
 
143
143
  def normalize_id_and_memorize_init(node, res_table, text_selector, prefix)
144
- term_text = normalize_ref_id(node.at(text_selector).text)
144
+ term_text = normalize_ref_id(node.at(text_selector))
145
145
  unless AUTOMATIC_GENERATED_ID_REGEXP.match(node["id"]).nil? &&
146
146
  !node["id"].nil?
147
147
  id = unique_text_id(term_text, prefix)
@@ -155,12 +155,14 @@ module Metanorma
155
155
  node.xpath(text_selector).each_with_index do |p, i|
156
156
  next unless i.positive?
157
157
 
158
- res_table[normalize_ref_id(p.text)] = node["id"]
158
+ res_table[normalize_ref_id(p)] = node["id"]
159
159
  end
160
160
  end
161
161
 
162
- def normalize_ref_id(text)
163
- Metanorma::Utils::to_ncname(text.downcase.gsub(/[[:space:]]/, "-"))
162
+ def normalize_ref_id(term)
163
+ t = term.dup
164
+ t.xpath(".//index").map(&:remove)
165
+ Metanorma::Utils::to_ncname(t.text.downcase.gsub(/[[:space:]]/, "-"))
164
166
  end
165
167
 
166
168
  def unique_text_id(text, prefix)
@@ -92,7 +92,7 @@ module Metanorma
92
92
  end
93
93
  end
94
94
 
95
- def term_source_attrs(_node, seen_xref)
95
+ def termsource_origin_attrs(_node, seen_xref)
96
96
  { case: seen_xref.children[0]["case"],
97
97
  droploc: seen_xref.children[0]["droploc"],
98
98
  bibitemid: seen_xref.children[0]["target"],
@@ -103,7 +103,7 @@ module Metanorma
103
103
  if seen_xref.children[0].name == "concept"
104
104
  xml_t.origin { |o| o << seen_xref.children[0].to_xml }
105
105
  else
106
- attrs = term_source_attrs(node, seen_xref)
106
+ attrs = termsource_origin_attrs(node, seen_xref)
107
107
  attrs.delete(:text)
108
108
  xml_t.origin **attr_code(attrs) do |o|
109
109
  o << seen_xref.children[0].children.to_xml
@@ -135,13 +135,16 @@ module Metanorma
135
135
  matched
136
136
  end
137
137
 
138
+ def termsource_attrs(node, matched)
139
+ status = node.attr("status") ||
140
+ (matched[:text] ? "modified" : "identical")
141
+ { status: status, type: node.attr("type") || "authoritative" }
142
+ end
143
+
138
144
  def termsource(node)
139
- matched = extract_termsource_refs(node.content, node) || return
145
+ matched = extract_termsource_refs(node.content, node) or return
140
146
  noko do |xml|
141
- status = node.attr("status") ||
142
- (matched[:text] ? "modified" : "identical")
143
- attrs = { status: status, type: node.attr("type") || "authoritative" }
144
- xml.termsource **attrs do |xml_t|
147
+ xml.termsource **termsource_attrs(node, matched) do |xml_t|
145
148
  seen_xref = Nokogiri::XML.fragment(matched[:xref])
146
149
  add_term_source(node, xml_t, seen_xref, matched)
147
150
  end
@@ -120,20 +120,25 @@ module Metanorma
120
120
  end
121
121
  end
122
122
 
123
+ SVG_NS = "http://www.w3.org/2000/svg".freeze
124
+
123
125
  # RelaxNG cannot cope well with wildcard attributes. So we strip
124
126
  # any attributes from FormattedString instances (which can contain
125
127
  # xs:any markup, and are signalled with @format) before validation.
126
128
  def formattedstr_strip(doc)
127
129
  doc.xpath("//*[@format] | //stem | //bibdata//description | "\
128
130
  "//formattedref | //bibdata//note | //bibdata/abstract | "\
129
- "//bibitem/abstract | //bibitem/note | //misc-container")
130
- .each do |n|
131
+ "//bibitem/abstract | //bibitem/note | //misc-container",
132
+ "m" => SVG_NS).each do |n|
131
133
  n.elements.each do |e|
132
134
  e.traverse do |e1|
133
135
  e1.element? and e1.each { |k, _v| e1.delete(k) }
134
136
  end
135
137
  end
136
138
  end
139
+ doc.xpath("//m:svg", "m" => SVG_NS).each do |n|
140
+ n.replace("<svg/>")
141
+ end
137
142
  doc
138
143
  end
139
144
 
@@ -19,6 +19,6 @@ module Metanorma
19
19
  end
20
20
 
21
21
  module Standoc
22
- VERSION = "2.0.2".freeze
22
+ VERSION = "2.0.3".freeze
23
23
  end
24
24
  end
@@ -1039,4 +1039,140 @@ RSpec.describe Metanorma::Standoc do
1039
1039
  annotation_id = output.at("//xmlns:annotation/@id").text
1040
1040
  expect(callout_id).to eq(annotation_id)
1041
1041
  end
1042
+ it "deduplicates identifiers in inline SVGs" do
1043
+ input = <<~INPUT
1044
+ #{BLANK_HDR}
1045
+ <sections>
1046
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 256 256">
1047
+ <defs>
1048
+ <linearGradient id="gradient1">
1049
+ <stop class="stop1" offset="0%" xlink:href="#gradient1"/>
1050
+ <stop class="stop2" offset="100%"/>
1051
+ <style>url(#gradient1)</style>
1052
+ </linearGradient>
1053
+ </defs>
1054
+ <circle fill="url(#gradient1)" cx="128" cy="128" r="100" />
1055
+ </svg>
1056
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 256 256">
1057
+ <defs>
1058
+ <linearGradient id="gradient2">
1059
+ <stop class="stop1" offset="0%" xlink:href="#gradient2"/>
1060
+ <stop class="stop2" offset="100%"/>
1061
+ <style>url(#gradient2)</style>
1062
+ </linearGradient>
1063
+ </defs>
1064
+ <circle fill="url(#gradient2)" cx="128" cy="128" r="100" />
1065
+ </svg>
1066
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 256 256">
1067
+ <defs>
1068
+ <linearGradient id="gradient1">
1069
+ <stop class="stop1" offset="0%" xlink:href="#gradient1"/>
1070
+ <stop class="stop2" offset="100%"/>
1071
+ <style>url(#gradient1)</style>
1072
+ </linearGradient>
1073
+ </defs>
1074
+ <circle fill="url(#gradient1)" cx="128" cy="128" r="100" />
1075
+ </svg>
1076
+ </sections>
1077
+ </standard-document>
1078
+ INPUT
1079
+ output = <<~OUTPUT
1080
+ #{BLANK_HDR}
1081
+ <sections>
1082
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 256 256">
1083
+ <defs>
1084
+ <linearGradient id="gradient1_inject_0">
1085
+ <stop class="stop1" offset="0%" xlink:href="#gradient1_inject_0"/>
1086
+ <stop class="stop2" offset="100%"/>
1087
+ <style>url(#gradient1_inject_0)</style>
1088
+ </linearGradient>
1089
+ </defs>
1090
+ <circle fill="url(#gradient1_inject_0)" cx="128" cy="128" r="100"/>
1091
+ </svg>
1092
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 256 256">
1093
+ <defs>
1094
+ <linearGradient id="gradient2">
1095
+ <stop class="stop1" offset="0%" xlink:href="#gradient2"/>
1096
+ <stop class="stop2" offset="100%"/>
1097
+ <style>url(#gradient2)</style>
1098
+ </linearGradient>
1099
+ </defs>
1100
+ <circle fill="url(#gradient2)" cx="128" cy="128" r="100"/>
1101
+ </svg>
1102
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 256 256">
1103
+ <defs>
1104
+ <linearGradient id="gradient1_inject_2">
1105
+ <stop class="stop1" offset="0%" xlink:href="#gradient1_inject_2"/>
1106
+ <stop class="stop2" offset="100%"/>
1107
+ <style>url(#gradient1_inject_2)</style>
1108
+ </linearGradient>
1109
+ </defs>
1110
+ <circle fill="url(#gradient1_inject_2)" cx="128" cy="128" r="100"/>
1111
+ </svg>
1112
+ </sections>
1113
+ </standard-document>
1114
+ OUTPUT
1115
+ expect(Metanorma::Standoc::Converter.new(nil, *OPTIONS)
1116
+ .cleanup(Nokogiri::XML(input)).to_xml)
1117
+ .to be_equivalent_to xmlpp(output)
1118
+ end
1119
+
1120
+ it "deduplicates identifiers in embedded SVGs" do
1121
+ input = <<~INPUT
1122
+ #{ASCIIDOC_BLANK_HDR.sub(/:data-uri-image: false/, ':data-uri-image: true')}
1123
+
1124
+ image::spec/fixtures/action_schemaexpg1.svg[]
1125
+
1126
+ image::spec/examples/rice_images/rice_image1.png[]
1127
+
1128
+ image::spec/fixtures/action_schemaexpg1.svg[]
1129
+ INPUT
1130
+
1131
+ output = <<~OUTPUT
1132
+ #{BLANK_HDR}
1133
+ <sections>
1134
+ <figure id='_'>
1135
+ <svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' id='Layer_1' x='0px' y='0px' viewBox='0 0 595.28 841.89' style='enable-background:new 0 0 595.28 841.89;' xml:space='preserve'>
1136
+ <style/>
1137
+ <image/>
1138
+ <a xlink:href='mn://action_schema'>
1139
+ <rect x='123.28' y='273.93' class='st0' width='88.05' height='41.84'/>
1140
+ </a>
1141
+ <a xlink:href='mn://basic_attribute_schema'>
1142
+ <rect x='324.69' y='450.52' class='st0' width='132.62' height='40.75'/>
1143
+ </a>
1144
+ <a xlink:href='mn://support_resource_schema'>
1145
+ <rect x='324.69' y='528.36' class='st0' width='148.16' height='40.75'/>
1146
+ </a>
1147
+ </svg>
1148
+ </figure>
1149
+ <figure id='_'>
1150
+ <image/>
1151
+ </figure>
1152
+ <figure id='_'>
1153
+ <svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' id='Layer_1_inject_1' x='0px' y='0px' viewBox='0 0 595.28 841.89' style='enable-background:new 0 0 595.28 841.89;' xml:space='preserve'>
1154
+ <style/>
1155
+ <image/>
1156
+ <a xlink:href='mn://action_schema'>
1157
+ <rect x='123.28' y='273.93' class='st0' width='88.05' height='41.84'/>
1158
+ </a>
1159
+ <a xlink:href='mn://basic_attribute_schema'>
1160
+ <rect x='324.69' y='450.52' class='st0' width='132.62' height='40.75'/>
1161
+ </a>
1162
+ <a xlink:href='mn://support_resource_schema'>
1163
+ <rect x='324.69' y='528.36' class='st0' width='148.16' height='40.75'/>
1164
+ </a>
1165
+ </svg>
1166
+ </figure>
1167
+ </sections>
1168
+ </standard-document>
1169
+ OUTPUT
1170
+ xml = Nokogiri::XML(Asciidoctor.convert(input, *OPTIONS))
1171
+ xml.xpath("//*[local-name() = 'image']").each do |x|
1172
+ x.replace("<image/>")
1173
+ end
1174
+ expect(xmlpp(strip_guid(xml.to_xml)
1175
+ .gsub(%r{<style.*?</style>}m, "<style/>")))
1176
+ .to be_equivalent_to xmlpp(output)
1177
+ end
1042
1178
  end
@@ -585,7 +585,7 @@ RSpec.describe Metanorma::Standoc do
585
585
  <title type='main' format='text/plain' language='en' script='Latn'>International Electrotechnical Vocabulary (IEV) — Part 102: Mathematics — General concepts and linear algebra</title>
586
586
  <uri type="src">https://webstore.iec.ch/publication/160</uri>
587
587
  <uri type="obp">/preview/info_iec60050-102%7Bed1.0%7Db.pdf</uri>
588
- <docidentifier type="IEC">IEC 60050-102:2007</docidentifier>
588
+ <docidentifier type="IEC" primary="true">IEC 60050-102:2007</docidentifier>
589
589
  <docidentifier type='URN'>urn:iec:std:iec:60050-102:2007:::en</docidentifier>
590
590
  <date type="published">
591
591
  <on>2007-08-27</on>
@@ -624,7 +624,7 @@ RSpec.describe Metanorma::Standoc do
624
624
  <title type="main" format="text/plain" language="en" script="Latn">International Electrotechnical Vocabulary (IEV) — Part 103: Mathematics — Functions</title>
625
625
  <uri type="src">https://webstore.iec.ch/publication/161</uri>
626
626
  <uri type="obp">/preview/info_iec60050-103%7Bed1.0%7Db.pdf</uri>
627
- <docidentifier type="IEC">IEC 60050-103:2009</docidentifier>
627
+ <docidentifier type="IEC" primary="true">IEC 60050-103:2009</docidentifier>
628
628
  <docidentifier type='URN'>urn:iec:std:iec:60050-103:2009:::en</docidentifier>
629
629
  <date type="published">
630
630
  <on>2009-12-14</on>
@@ -1288,7 +1288,7 @@ RSpec.describe Metanorma::Standoc do
1288
1288
  <sourcecode id='L__xf6_we'>
1289
1289
  <name>
1290
1290
  See
1291
- <eref type='inline' bibitemid='L__xf6_wner2016' citeas='L&#246;wner et al. 2016'/>
1291
+ <eref type='inline' bibitemid='L__xf6_wner2016' citeas='L&amp;#xf6;wner et al. 2016'/>
1292
1292
  </name>
1293
1293
  ABC
1294
1294
  </sourcecode>
@@ -49,7 +49,7 @@ ISO_124_DATED = <<~XML.freeze
49
49
  <uri type="src">https://www.iso.org/standard/61884.html</uri>
50
50
  <uri type="obp">https://www.iso.org/obp/ui/#!iso:std:61884:en</uri>
51
51
  <uri type="rss">https://www.iso.org/contents/data/standard/06/18/61884.detail.rss</uri>
52
- <docidentifier type="ISO">ISO 124:2014</docidentifier>
52
+ <docidentifier type="ISO" primary="true">ISO 124:2014</docidentifier>
53
53
  <docidentifier type='URN'>urn:iso:std:iso:124:stage-90.93:ed-7:en</docidentifier>
54
54
  <docnumber>124</docnumber>
55
55
  <date type="published">
@@ -208,7 +208,7 @@ ISO_123_DATED = <<~XML.freeze
208
208
  <uri type="src">https://www.iso.org/standard/23281.html</uri>
209
209
  <uri type="obp">https://www.iso.org/obp/ui/#!iso:std:23281:en</uri>
210
210
  <uri type="rss">https://www.iso.org/contents/data/standard/02/32/23281.detail.rss</uri>
211
- <docidentifier type="ISO">ISO 123:2001</docidentifier>
211
+ <docidentifier type="ISO" primary="true">ISO 123:2001</docidentifier>
212
212
  <docidentifier type='URN'>urn:iso:std:iso:123:stage-90.93:ed-3:en</docidentifier>
213
213
  <docnumber>123</docnumber>
214
214
  <date type="published">