metanorma-standoc 2.1.5 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/metanorma/standoc/base.rb +13 -0
  3. data/lib/metanorma/standoc/blocks.rb +26 -17
  4. data/lib/metanorma/standoc/cleanup.rb +1 -1
  5. data/lib/metanorma/standoc/cleanup_biblio.rb +210 -0
  6. data/lib/metanorma/standoc/cleanup_block.rb +6 -4
  7. data/lib/metanorma/standoc/cleanup_maths.rb +2 -15
  8. data/lib/metanorma/standoc/cleanup_ref.rb +22 -13
  9. data/lib/metanorma/standoc/cleanup_reqt.rb +3 -103
  10. data/lib/metanorma/standoc/cleanup_symbols.rb +1 -1
  11. data/lib/metanorma/standoc/cleanup_text.rb +10 -8
  12. data/lib/metanorma/standoc/cleanup_xref.rb +1 -2
  13. data/lib/metanorma/standoc/converter.rb +2 -0
  14. data/lib/metanorma/standoc/front.rb +1 -1
  15. data/lib/metanorma/standoc/front_contributor.rb +0 -10
  16. data/lib/metanorma/standoc/inline.rb +8 -4
  17. data/lib/metanorma/standoc/isodoc.rng +6 -1
  18. data/lib/metanorma/standoc/macros.rb +1 -180
  19. data/lib/metanorma/standoc/macros_inline.rb +194 -0
  20. data/lib/metanorma/standoc/ref_sect.rb +2 -2
  21. data/lib/metanorma/standoc/ref_utility.rb +1 -1
  22. data/lib/metanorma/standoc/reqt.rb +19 -75
  23. data/lib/metanorma/standoc/reqt.rng +1 -1
  24. data/lib/metanorma/standoc/section.rb +35 -3
  25. data/lib/metanorma/standoc/utils.rb +9 -43
  26. data/lib/metanorma/standoc/validate.rb +1 -69
  27. data/lib/metanorma/standoc/validate_table.rb +91 -0
  28. data/lib/metanorma/standoc/version.rb +1 -1
  29. data/metanorma-standoc.gemspec +4 -5
  30. data/spec/metanorma/{refs_dl_spec.rb → biblio_spec.rb} +90 -7
  31. data/spec/metanorma/blocks_spec.rb +31 -267
  32. data/spec/metanorma/cleanup_blocks_spec.rb +0 -171
  33. data/spec/metanorma/inline_spec.rb +4 -0
  34. data/spec/metanorma/macros_concept_spec.rb +1033 -0
  35. data/spec/metanorma/macros_spec.rb +2 -1030
  36. data/spec/metanorma/refs_spec.rb +0 -2
  37. data/spec/metanorma/reqt_spec.rb +130 -0
  38. data/spec/metanorma/section_spec.rb +5 -0
  39. data/spec/metanorma/validate_spec.rb +46 -6
  40. data/spec/vcr_cassettes/bsi16341.yml +80 -52
  41. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +94 -94
  42. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +12 -12
  43. data/spec/vcr_cassettes/hide_refs.yml +70 -70
  44. data/spec/vcr_cassettes/isobib_get_123.yml +11 -11
  45. data/spec/vcr_cassettes/isobib_get_123_1.yml +23 -23
  46. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +35 -35
  47. data/spec/vcr_cassettes/isobib_get_123_2.yml +22 -22
  48. data/spec/vcr_cassettes/isobib_get_123_2001.yml +13 -13
  49. data/spec/vcr_cassettes/isobib_get_124.yml +11 -11
  50. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +34 -64
  51. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +45 -45
  52. data/spec/vcr_cassettes/std-link.yml +12 -12
  53. metadata +15 -11
  54. data/lib/metanorma/standoc/cleanup_ref_dl.rb +0 -113
@@ -10,19 +10,26 @@ module Metanorma
10
10
  @norm_ref = false
11
11
 
12
12
  def sectiontype1(node)
13
+ return "abstract" if node.attr("style") == "abstract"
14
+
13
15
  node&.attr("heading")&.downcase ||
14
- node.title.gsub(%r{<index>.*?</index>}m, "").gsub(/<[^>]+>/, "")
16
+ node.title
17
+ .gsub(%r{<index>.*?</index>}m, "")
18
+ .gsub(%r{<fn[^>]*>.*?</fn>}m, "")
19
+ .gsub(/<[^>]+>/, "")
15
20
  .strip.downcase
21
+ .sub(/\.$/, "")
16
22
  end
17
23
 
18
24
  def sectiontype(node, level = true)
19
25
  ret = sectiontype1(node)
20
- ret1 = sectiontype_streamline(ret)
26
+ ret1 = preface_main_filter(sectiontype_streamline(ret), node)
21
27
  return ret1 if ret1 == "symbols and abbreviated terms"
22
28
  return nil unless !level || node.level == 1
23
29
  return nil if @seen_headers.include? ret
24
30
 
25
- @seen_headers << ret
31
+ @seen_headers << ret unless ret1.nil?
32
+ @seen_headers_canonical << ret1 unless ret1.nil?
26
33
  ret1
27
34
  end
28
35
 
@@ -45,6 +52,31 @@ module Metanorma
45
52
  end
46
53
  end
47
54
 
55
+ PREFACE_CLAUSE_NAMES = %w(abstract foreword introduction
56
+ acknowledgements).freeze
57
+
58
+ MAIN_CLAUSE_NAMES =
59
+ ["normative references", "terms and definitions", "scope",
60
+ "symbols and abbreviated terms", "clause", "bibliography"].freeze
61
+
62
+ def start_main_section(ret, node)
63
+ @preface = false if MAIN_CLAUSE_NAMES.include?(ret) &&
64
+ node.role != "preface" && node.attr("style") != "preface"
65
+ @preface = false if (PREFACE_CLAUSE_NAMES)
66
+ .intersection(@seen_headers_canonical + [ret]).empty?
67
+ end
68
+
69
+ def preface_main_filter(ret, node)
70
+ start_main_section(ret, node)
71
+ if @preface
72
+ self.class::MAIN_CLAUSE_NAMES.include?(ret) and return nil
73
+ else
74
+ self.class::PREFACE_CLAUSE_NAMES.include?(ret) and return nil
75
+ end
76
+
77
+ ret
78
+ end
79
+
48
80
  def section_attributes(node)
49
81
  ret = { id: Metanorma::Utils::anchor_or_uuid(node),
50
82
  language: node.attributes["language"],
@@ -17,43 +17,20 @@ module Metanorma
17
17
  nil
18
18
  end
19
19
 
20
- NOKOHEAD = <<~HERE.freeze
21
- <!DOCTYPE html SYSTEM
22
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
23
- <html xmlns="http://www.w3.org/1999/xhtml">
24
- <head> <title></title> <meta charset="UTF-8" /> </head>
25
- <body> </body> </html>
26
- HERE
27
-
28
- # block for processing XML document fragments as XHTML,
29
- # to allow for HTMLentities
30
- # Unescape special chars used in Asciidoctor substitution processing
31
20
  def noko(&block)
32
- doc = ::Nokogiri::XML.parse(NOKOHEAD)
33
- fragment = doc.fragment("")
34
- ::Nokogiri::XML::Builder.with fragment, &block
35
- fragment.to_xml(encoding: "US-ASCII", indent: 0,
36
- save_with: Nokogiri::XML::Node::SaveOptions::AS_XML)
37
- .lines.map do |l|
38
- l.gsub(/>\n$/, ">").gsub(/\s*\n$/m, " ").gsub("&#150;", "\u0096")
39
- .gsub("&#151;", "\u0097").gsub("&#x96;", "\u0096")
40
- .gsub("&#x97;", "\u0097")
41
- end
21
+ Metanorma::Utils::noko(&block)
42
22
  end
43
23
 
44
24
  def attr_code(attributes)
45
- attributes.compact.transform_values do |v|
46
- v.is_a?(String) ? HTMLEntities.new.decode(v) : v
47
- end
25
+ Metanorma::Utils::attr_code(attributes)
26
+ end
27
+
28
+ def csv_split(text, delim = ";")
29
+ Metanorma::Utils::csv_split(text, delim)
48
30
  end
49
31
 
50
- # if the contents of node are blocks, output them to out;
51
- # else, wrap them in <p>
52
32
  def wrap_in_para(node, out)
53
- if node.blocks? then out << node.content
54
- else
55
- out.p { |p| p << node.content }
56
- end
33
+ Metanorma::Utils::wrap_in_para(node, out)
57
34
  end
58
35
 
59
36
  SUBCLAUSE_XPATH = "//clause[not(parent::sections)]"\
@@ -67,22 +44,11 @@ module Metanorma
67
44
  end
68
45
 
69
46
  def dl_to_attrs(elem, dlist, name)
70
- e = dlist.at("./dt[text()='#{name}']") or return
71
- val = e.at("./following::dd/p") || e.at("./following::dd") or return
72
- elem[name] = val.text
47
+ Metanorma::Utils::dl_to_attrs(elem, dlist, name)
73
48
  end
74
49
 
75
50
  def dl_to_elems(ins, elem, dlist, name)
76
- a = elem.at("./#{name}[last()]")
77
- ins = a if a
78
- dlist.xpath("./dt[text()='#{name}']").each do |e|
79
- v = e.at("./following::dd")
80
- e = v.elements and e.size == 1 && e.first.name == "p" and v = e.first
81
- v.name = name
82
- ins.next = v
83
- ins = ins.next
84
- end
85
- ins
51
+ Metanorma::Utils::dl_to_elems(ins, elem, dlist, name)
86
52
  end
87
53
 
88
54
  def term_expr(elem)
@@ -1,5 +1,6 @@
1
1
  require "metanorma/standoc/utils"
2
2
  require_relative "./validate_section"
3
+ require_relative "./validate_table"
3
4
  require "nokogiri"
4
5
  require "jing"
5
6
  require "iev"
@@ -53,75 +54,6 @@ module Metanorma
53
54
  @fatalerror.empty? or clean_abort(@fatalerror.join("\n"), doc.to_xml)
54
55
  end
55
56
 
56
- def table_validate(doc)
57
- doc.xpath("//table[colgroup]").each do |t|
58
- maxrowcols_validate(t, t.xpath("./colgroup/col").size)
59
- end
60
- doc.xpath("//table[.//*[@colspan] | .//*[@rowspan]]").each do |t|
61
- maxrowcols_validate(t, max_td_count(t))
62
- end
63
- end
64
-
65
- def max_td_count(table)
66
- max = 0
67
- table.xpath("./tr").each do |tr|
68
- n = tr.xpath("./td | ./th").size
69
- max < n and max = n
70
- end
71
- max
72
- end
73
-
74
- def maxrowcols_validate(table, maxcols)
75
- cells2d = table.xpath("./*/tr").each_with_object([]) { |_r, m| m << {} }
76
- table.xpath("./*/tr").each_with_index do |tr, r|
77
- curr = 0
78
- tr.xpath("./td | ./th").each do |td|
79
- curr = maxcols_validate1(td, r, curr, cells2d, maxcols)
80
- end
81
- end
82
- maxrows_validate(table, cells2d)
83
- end
84
-
85
- # code doesn't actually do anything, since Asciidoctor refuses to generate
86
- # table with inconsistent column count
87
- def maxcols_validate1(tcell, row, curr, cells2d, maxcols)
88
- rs = tcell&.attr("rowspan")&.to_i || 1
89
- cs = tcell&.attr("colspan")&.to_i || 1
90
- curr = table_tracker_update(cells2d, row, curr, rs, cs)
91
- maxcols_check(curr + cs - 1, maxcols, tcell)
92
- curr + cs
93
- end
94
-
95
- def table_tracker_update(cells2d, row, curr, rowspan, colspan)
96
- cells2d[row] ||= {}
97
- while cells2d[row][curr]
98
- curr += 1
99
- end
100
- (row..(row + rowspan - 1)).each do |y2|
101
- cells2d[y2] ||= {}
102
- (curr..(curr + colspan - 1)).each { |x2| cells2d[y2][x2] = 1 }
103
- end
104
- curr
105
- end
106
-
107
- def maxrows_validate(table, cells2d)
108
- if cells2d.any? { |x| x.size != cells2d.first.size }
109
- @log.add("Table", table,
110
- "Table rows in table are inconsistent: check rowspan")
111
- @fatalerror << "Table rows in table are inconsistent: check rowspan"
112
- end
113
- end
114
-
115
- # if maxcols or maxrows negative, do not check them
116
- def maxcols_check(col, maxcols, tcell)
117
- if maxcols.positive? && col > maxcols
118
- @log.add("Table", tcell, "Table exceeds maximum number of columns "\
119
- "defined (#{maxcols})")
120
- @fatalerror << "Table exceeds maximum number of columns defined "\
121
- "(#{maxcols})"
122
- end
123
- end
124
-
125
57
  def norm_ref_validate(doc)
126
58
  found = false
127
59
  doc.xpath("//references[@normative = 'true']/bibitem").each do |b|
@@ -0,0 +1,91 @@
1
+ module Metanorma
2
+ module Standoc
3
+ module Validate
4
+ def table_validate(doc)
5
+ doc.xpath("//table[colgroup]").each do |t|
6
+ maxrowcols_validate(t, t.xpath("./colgroup/col").size)
7
+ end
8
+ doc.xpath("//table[.//*[@colspan] | .//*[@rowspan]]").each do |t|
9
+ maxrowcols_validate(t, max_td_count(t), mode: "row_cols")
10
+ end
11
+ doc.xpath("//table[.//*[@rowspan]]").each do |t|
12
+ maxrowcols_validate(t, max_td_count(t), mode: "thead_row")
13
+ end
14
+ end
15
+
16
+ def max_td_count(table)
17
+ max = 0
18
+ table.xpath("./tr").each do |tr|
19
+ n = tr.xpath("./td | ./th").size
20
+ max < n and max = n
21
+ end
22
+ max
23
+ end
24
+
25
+ def maxrowcols_validate(table, maxcols, mode: "row_cols")
26
+ case mode
27
+ when "row_cols"
28
+ maxrowcols_validate0(table, maxcols, "*", mode)
29
+ when "thead_row"
30
+ %w{thead tbody tfoot}.each do |w|
31
+ maxrowcols_validate0(table, maxcols, w, mode)
32
+ end
33
+ end
34
+ end
35
+
36
+ def maxrowcols_validate0(table, maxcols, tablechild, mode)
37
+ cells2d = table.xpath("./#{tablechild}/tr")
38
+ .each_with_object([]) { |_r, m| m << {} }
39
+ table.xpath("./#{tablechild}/tr").each_with_index do |tr, r|
40
+ curr = 0
41
+ tr.xpath("./td | ./th").each do |td|
42
+ curr = maxcols_validate1(td, r, curr, cells2d, maxcols, mode)
43
+ end
44
+ end
45
+ maxrows_validate(table, cells2d, tablechild, mode)
46
+ end
47
+
48
+ # code doesn't actually do anything, since Asciidoctor refuses to generate
49
+ # table with inconsistent column count
50
+ def maxcols_validate1(tcell, row, curr, cells2d, maxcols, mode)
51
+ rs = tcell&.attr("rowspan")&.to_i || 1
52
+ cs = tcell&.attr("colspan")&.to_i || 1
53
+ curr = table_tracker_update(cells2d, row, curr, rs, cs)
54
+ maxcols_check(curr + cs - 1, maxcols, tcell) if mode == "row_cols"
55
+ curr + cs
56
+ end
57
+
58
+ def table_tracker_update(cells2d, row, curr, rowspan, colspan)
59
+ cells2d[row] ||= {}
60
+ while cells2d[row][curr]
61
+ curr += 1
62
+ end
63
+ (row..(row + rowspan - 1)).each do |y2|
64
+ cells2d[y2] ||= {}
65
+ (curr..(curr + colspan - 1)).each { |x2| cells2d[y2][x2] = 1 }
66
+ end
67
+ curr
68
+ end
69
+
70
+ def maxrows_validate(table, cells2d, tablechild, mode)
71
+ err = "are inconsistent"
72
+ mode == "thead_row" and err = "cannot go outside #{tablechild}"
73
+ err = "Table rows in table #{err}: check rowspan"
74
+ if cells2d.any? { |x| x.size != cells2d.first.size }
75
+ @log.add("Table", table, err)
76
+ @fatalerror << err
77
+ end
78
+ end
79
+
80
+ # if maxcols or maxrows negative, do not check them
81
+ def maxcols_check(col, maxcols, tcell)
82
+ if maxcols.positive? && col > maxcols
83
+ @log.add("Table", tcell, "Table exceeds maximum number of columns "\
84
+ "defined (#{maxcols})")
85
+ @fatalerror << "Table exceeds maximum number of columns defined "\
86
+ "(#{maxcols})"
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -19,6 +19,6 @@ module Metanorma
19
19
  end
20
20
 
21
21
  module Standoc
22
- VERSION = "2.1.5".freeze
22
+ VERSION = "2.2.1".freeze
23
23
  end
24
24
  end
@@ -23,12 +23,11 @@ Gem::Specification.new do |spec|
23
23
  spec.bindir = "bin"
24
24
  spec.require_paths = ["lib"]
25
25
  spec.files = `git ls-files`.split("\n")
26
- spec.test_files = `git ls-files -- {spec}/*`.split("\n")
27
26
  spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
28
27
 
29
28
  spec.add_dependency "asciidoctor", "~> 2.0.0"
30
29
  spec.add_dependency "iev", "~> 0.3.0"
31
- spec.add_dependency "isodoc", "~> 2.1.0"
30
+ spec.add_dependency "isodoc", "~> 2.2.0"
32
31
  spec.add_dependency "metanorma-plugin-datastruct", "~> 0.2.0"
33
32
  spec.add_dependency "metanorma-plugin-lutaml"
34
33
  spec.add_dependency "ruby-jing"
@@ -37,8 +36,8 @@ Gem::Specification.new do |spec|
37
36
  spec.add_dependency "concurrent-ruby"
38
37
  spec.add_dependency "latexmath"
39
38
  spec.add_dependency "mathml2asciimath"
40
- spec.add_dependency "metanorma-utils", "~> 1.2.8"
41
- spec.add_dependency "relaton-cli", "~> 1.12.0"
39
+ spec.add_dependency "mn-requirements", "~> 0.0.1"
40
+ spec.add_dependency "relaton-cli", "~> 1.13.0"
42
41
  spec.add_dependency "relaton-iev", "~> 1.1.0"
43
42
  spec.add_dependency "unicode2latex", "~> 0.0.1"
44
43
 
@@ -55,5 +54,5 @@ Gem::Specification.new do |spec|
55
54
  spec.add_development_dependency "timecop", "~> 0.9"
56
55
  spec.add_development_dependency "vcr", "~> 6.1.0"
57
56
  spec.add_development_dependency "webmock"
58
- #spec.metadata["rubygems_mfa_required"] = "true"
57
+ # spec.metadata["rubygems_mfa_required"] = "true"
59
58
  end
@@ -235,7 +235,7 @@ RSpec.describe Metanorma::Standoc do
235
235
  person::
236
236
  name:::
237
237
  language:::: en
238
- initial:::: A.
238
+ formatted_initials:::: A.
239
239
  surname:::: Bierman
240
240
  affiliation:::
241
241
  +
@@ -377,8 +377,8 @@ RSpec.describe Metanorma::Standoc do
377
377
  <role type="author"/>
378
378
  <person>
379
379
  <name>
380
- <initial language="en">A.</initial>
381
- <surname language="en">Bierman</surname>
380
+ <formatted-initials>A.</formatted-initials>
381
+ <surname>Bierman</surname>
382
382
  </name>
383
383
  <affiliation>
384
384
  <description language="en" script="Latn">Affiliation description</description>
@@ -590,7 +590,7 @@ RSpec.describe Metanorma::Standoc do
590
590
  contributor.role:: publisher
591
591
  contributor::
592
592
  contributor.person.name.language:: en
593
- contributor.person.name.initial:: A.
593
+ contributor.person.name.formatted_initials:: A.
594
594
  contributor.person.name.surname:: Bierman
595
595
  contributor.person.affiliation.organization.name:: IETF
596
596
  contributor.person.affiliation.organization.abbreviation:: IETF
@@ -706,8 +706,8 @@ RSpec.describe Metanorma::Standoc do
706
706
  <role type="author"/>
707
707
  <person>
708
708
  <name>
709
- <initial language="en">A.</initial>
710
- <surname language="en">Bierman</surname>
709
+ <formatted-initials>A.</formatted-initials>
710
+ <surname>Bierman</surname>
711
711
  </name>
712
712
  <affiliation>
713
713
  <description language="en" script="Latn">Affiliation description</description>
@@ -840,7 +840,7 @@ RSpec.describe Metanorma::Standoc do
840
840
 
841
841
  INPUT
842
842
  output = <<~OUTPUT
843
- #{BLANK_HDR}
843
+ #{BLANK_HDR}
844
844
  <sections>
845
845
  <clause id='_' inline-header='false' obligation='normative'>
846
846
  <title>Section</title>
@@ -888,4 +888,87 @@ RSpec.describe Metanorma::Standoc do
888
888
  expect(xmlpp(strip_guid(Asciidoctor.convert(input, *OPTIONS))))
889
889
  .to be_equivalent_to xmlpp(output)
890
890
  end
891
+
892
+ it "processes microformatting of formatted references" do
893
+ input = <<~INPUT
894
+ #{ASCIIDOC_BLANK_HDR}
895
+
896
+ [bibliography]
897
+ === Normative References
898
+
899
+ * [[[A, B]]], span:surname[Wozniak], span:initials[S.] & span:givenname[Steve] span:surname[Jobs]. span:pubyear[1996]. span:title[_Work_]. In span:surname.editor[Gates], span:initials.editor[W. H], Collected Essays. span:docid.ISO[ISO 1234]. span:pubplace[Geneva]: span:publisher[International Standardization Organization]. span:uri.citation[http://www.example.com]. span:type[inbook]
900
+ INPUT
901
+ output = <<~OUTPUT
902
+ #{BLANK_HDR}
903
+ <sections> </sections>
904
+ <bibliography>
905
+ <references id='_' normative='true' obligation='informative'>
906
+ <title>Normative references</title>
907
+ <p id='_'>
908
+ The following documents are referred to in the text in such a way that
909
+ some or all of their content constitutes requirements of this document.
910
+ For dated references, only the edition cited applies. For undated
911
+ references, the latest edition of the referenced document (including any
912
+ amendments) applies.
913
+ </p>
914
+ <bibitem id='A' type="inbook">
915
+ <formattedref format='application/x-isodoc+xml'>
916
+ Wozniak, S. &amp; Steve Jobs. 1996.
917
+ <em>Work</em>
918
+ . In Gates, W. H, Collected Essays. ISO 1234. Geneva: International
919
+ Standardization Organization.
920
+ <link target='http://www.example.com'/>
921
+ .
922
+ </formattedref>
923
+ <title>
924
+ <em>Work</em>
925
+ </title>
926
+ <uri type='citation'>
927
+ <link target='http://www.example.com'/>
928
+ </uri>
929
+ <docidentifier>B</docidentifier>
930
+ <docidentifier type='ISO'>ISO 1234</docidentifier>
931
+ <date type='published'>1996</date>
932
+ <contributor>
933
+ <role type='author'/>
934
+ <person>
935
+ <name>
936
+ <formatted-initials>S.</formatted-initials>
937
+ <surname>Wozniak</surname>
938
+ </name>
939
+ </person>
940
+ </contributor>
941
+ <contributor>
942
+ <role type='author'/>
943
+ <person>
944
+ <name>
945
+ <forename>Steve</forename>
946
+ <surname>Jobs</surname>
947
+ </name>
948
+ </person>
949
+ </contributor>
950
+ <contributor>
951
+ <role type='editor'/>
952
+ <person>
953
+ <name>
954
+ <formatted-initials>W. H</formatted-initials>
955
+ <surname>Gates</surname>
956
+ </name>
957
+ </person>
958
+ </contributor>
959
+ <contributor>
960
+ <role type='publisher'/>
961
+ <organization>
962
+ <name>International Standardization Organization</name>
963
+ </organization>
964
+ </contributor>
965
+ <place/>
966
+ </bibitem>
967
+ </references>
968
+ </bibliography>
969
+ </standard-document>
970
+ OUTPUT
971
+ expect(xmlpp(strip_guid(Asciidoctor.convert(input, *OPTIONS))))
972
+ .to be_equivalent_to xmlpp(output)
973
+ end
891
974
  end