metanorma-standoc 1.5.2 → 1.5.3

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/asciidoctor/standoc/base_structured_text_preprocessor.rb +123 -0
  3. data/lib/asciidoctor/standoc/basicdoc.rng +31 -1
  4. data/lib/asciidoctor/standoc/cleanup.rb +1 -0
  5. data/lib/asciidoctor/standoc/cleanup_amend.rb +54 -0
  6. data/lib/asciidoctor/standoc/cleanup_block.rb +0 -2
  7. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +0 -3
  8. data/lib/asciidoctor/standoc/cleanup_inline.rb +6 -1
  9. data/lib/asciidoctor/standoc/cleanup_section.rb +1 -2
  10. data/lib/asciidoctor/standoc/converter.rb +3 -1
  11. data/lib/asciidoctor/standoc/front_contributor.rb +15 -7
  12. data/lib/asciidoctor/standoc/inline.rb +13 -1
  13. data/lib/asciidoctor/standoc/isodoc.rng +108 -8
  14. data/lib/asciidoctor/standoc/json2_text_preprocessor.rb +43 -0
  15. data/lib/asciidoctor/standoc/macros.rb +45 -33
  16. data/lib/asciidoctor/standoc/section.rb +8 -3
  17. data/lib/asciidoctor/standoc/table.rb +3 -2
  18. data/lib/asciidoctor/standoc/views/datamodel/model_representation.adoc.erb +10 -10
  19. data/lib/asciidoctor/standoc/yaml2_text_preprocessor.rb +43 -0
  20. data/lib/liquid/custom_blocks/key_iterator.rb +21 -0
  21. data/lib/liquid/custom_filters/values.rb +7 -0
  22. data/lib/metanorma/standoc/version.rb +1 -1
  23. data/metanorma-standoc.gemspec +1 -3
  24. data/spec/asciidoctor-standoc/blocks_spec.rb +254 -142
  25. data/spec/asciidoctor-standoc/cleanup_spec.rb +31 -31
  26. data/spec/asciidoctor-standoc/macros_json2text_spec.rb +10 -0
  27. data/spec/asciidoctor-standoc/macros_spec.rb +2 -0
  28. data/spec/asciidoctor-standoc/macros_yaml2text_spec.rb +5 -560
  29. data/spec/asciidoctor-standoc/section_spec.rb +0 -1
  30. data/spec/asciidoctor-standoc/table_spec.rb +112 -112
  31. data/spec/asciidoctor-standoc/validate_spec.rb +5 -1
  32. data/spec/examples/codes_table.html +1365 -1365
  33. data/spec/fixtures/macros_datamodel/address_class_profile.xml +46 -46
  34. data/spec/fixtures/macros_datamodel/address_component_profile.xml +21 -21
  35. data/spec/fixtures/macros_datamodel/blank_definition_profile.xml +21 -21
  36. data/spec/spec_helper.rb +110 -109
  37. data/spec/support/shared_examples/structured_data_2_text_preprocessor.rb +583 -0
  38. metadata +24 -3
  39. data/lib/asciidoctor/standoc/macros_yaml2text.rb +0 -165
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 910ada4e6d4f62c6106391e3ec0de46a7ba4a9d5362bb103cd80ee0b2acef9dc
4
- data.tar.gz: de8546c035da0236faa4a6ca5df9b0f54f16806d09386793f359e55b69884212
3
+ metadata.gz: 7503bfc7dd68c2d6a6b2ded8f08611e92067a15aa4088c02f1e5408ff8e027e6
4
+ data.tar.gz: 65cd5d4d3648788113fd30437fe8d649c6e498b9ebdab8d5b41d2fadb7439056
5
5
  SHA512:
6
- metadata.gz: 422e64b66f95fa4c49727687c446bd3f79bc09aa0609b352bd68cc659ff06bf57243ed410e4baa8f0cb501f101212d305a756b41548fcee7e877135aea22e1f3
7
- data.tar.gz: 97d6e164975997ecc396376abdaf2edad43c1f4fbfa601dbbc5f2f4d465747164350f500aaadc05f9fd6ed1e499925df7d74626fcde21a0578feeb50d607b84e
6
+ metadata.gz: 73510f7d926c6acf395377794a753cef6bb0f0658fb66c606df07e23548c17f010c7120b77765b388fb363a4309051fcf03a601d6ea95cf20aca6e4645b1c674
7
+ data.tar.gz: bae732755cc47dcae17e0d8ef01bcd35173c8941807b2d5844cf45f008f57c199977756d4fd15b0e3c8c558e73432dd9ba88be2b01f61b32cff180308adcd83d
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "liquid/custom_blocks/key_iterator"
4
+ require "liquid/custom_filters/values"
5
+
6
+ Liquid::Template.register_tag("keyiterator", Liquid::CustomBlocks::KeyIterator)
7
+ Liquid::Template.register_filter(Liquid::CustomFilters)
8
+
9
+ module Asciidoctor
10
+ module Standoc
11
+ # Base class for processing structured data blocks(yaml, json)
12
+ class BaseStructuredTextPreprocessor < Asciidoctor::Extensions::Preprocessor
13
+ BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/
14
+ BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/
15
+
16
+ def process(document, reader)
17
+ input_lines = reader.readlines.to_enum
18
+ Reader.new(processed_lines(document, input_lines))
19
+ end
20
+
21
+ protected
22
+
23
+ def content_from_file(_document, _file_path)
24
+ raise ArgumentError, "Implement `content_from_file` in your class"
25
+ end
26
+
27
+ private
28
+
29
+ def processed_lines(document, input_lines)
30
+ result = []
31
+ loop do
32
+ result.push(*process_text_blocks(document, input_lines))
33
+ end
34
+ result
35
+ end
36
+
37
+ def relative_file_path(document, file_path)
38
+ docfile_directory = File.dirname(document.attributes["docfile"] || ".")
39
+ document
40
+ .path_resolver
41
+ .system_path(file_path, docfile_directory)
42
+ end
43
+
44
+ def process_text_blocks(document, input_lines)
45
+ line = input_lines.next
46
+ block_match = line.match(/^\[#{config[:block_name]},(.+?),(.+?)\]/)
47
+ return [line] if block_match.nil?
48
+
49
+ mark = input_lines.next
50
+ current_block = []
51
+ while (block_line = input_lines.next) != mark
52
+ current_block.push(block_line)
53
+ end
54
+ read_content_and_parse_template(document,
55
+ current_block,
56
+ block_match)
57
+ end
58
+
59
+ def read_content_and_parse_template(document, current_block, block_match)
60
+ transformed_liquid_lines = current_block
61
+ .map(&method(:transform_line_liquid))
62
+ context_items = content_from_file(document, block_match[1])
63
+ parse_context_block(document: document,
64
+ context_lines: transformed_liquid_lines,
65
+ context_items: context_items,
66
+ context_name: block_match[2])
67
+ rescue StandardError => exception
68
+ document.logger
69
+ .warn("Failed to parse #{config[:block_name]} \
70
+ block: #{exception.message}")
71
+ []
72
+ end
73
+
74
+ def transform_line_liquid(line)
75
+ if line.match?(BLOCK_START_REGEXP)
76
+ line.gsub!(BLOCK_START_REGEXP,
77
+ '{% keyiterator \1, \2 %}')
78
+ end
79
+
80
+ if line.strip.match?(BLOCK_END_REGEXP)
81
+ line.gsub!(BLOCK_END_REGEXP, "{% endkeyiterator %}")
82
+ end
83
+ line
84
+ .gsub(/(?<!{){(?!%)([^{}]+)(?<!%)}(?!})/, '{{\1}}')
85
+ .gsub(/[a-z\.]+\#/, "index")
86
+ .gsub(/{{(.+)\s+\+\s+(\d+)\s*?}}/, '{{ \1 | plus: \2 }}')
87
+ .gsub(/{{(.+)\s+\-\s+(\d+)\s*?}}/, '{{ \1 | minus: \2 }}')
88
+ .gsub(/{{(.+).values(.*?)}}/,
89
+ '{% assign custom_value = \1 | values %}{{custom_value\2}}')
90
+ end
91
+
92
+ def parse_context_block(context_lines:,
93
+ context_items:,
94
+ context_name:,
95
+ document:)
96
+ render_result, errors = render_liquid_string(
97
+ template_string: context_lines.join("\n"),
98
+ context_items: context_items,
99
+ context_name: context_name
100
+ )
101
+ notify_render_errors(document, errors)
102
+ render_result.split("\n")
103
+ end
104
+
105
+ def render_liquid_string(template_string:, context_items:, context_name:)
106
+ liquid_template = Liquid::Template.parse(template_string)
107
+ rendered_string = liquid_template
108
+ .render(context_name => context_items,
109
+ strict_variables: true,
110
+ error_mode: :warn)
111
+ [rendered_string, liquid_template.errors]
112
+ end
113
+
114
+ def notify_render_errors(document, errors)
115
+ errors.each do |error_obj|
116
+ document
117
+ .logger
118
+ .warn("Liquid render error: #{error_obj.message}")
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -158,7 +158,17 @@
158
158
  <data type="ID"/>
159
159
  </attribute>
160
160
  <oneOrMore>
161
- <ref name="paragraph"/>
161
+ <choice>
162
+ <ref name="formula"/>
163
+ <ref name="ul"/>
164
+ <ref name="ol"/>
165
+ <ref name="dl"/>
166
+ <ref name="quote"/>
167
+ <ref name="sourcecode"/>
168
+ <ref name="paragraph"/>
169
+ <ref name="table"/>
170
+ <ref name="figure"/>
171
+ </choice>
162
172
  </oneOrMore>
163
173
  </element>
164
174
  </define>
@@ -402,6 +412,16 @@
402
412
  </choice>
403
413
  </attribute>
404
414
  </optional>
415
+ <optional>
416
+ <attribute name="valign">
417
+ <choice>
418
+ <value>top</value>
419
+ <value>middle</value>
420
+ <value>bottom</value>
421
+ <value>baseline</value>
422
+ </choice>
423
+ </attribute>
424
+ </optional>
405
425
  <choice>
406
426
  <zeroOrMore>
407
427
  <ref name="TextElement"/>
@@ -429,6 +449,16 @@
429
449
  </choice>
430
450
  </attribute>
431
451
  </optional>
452
+ <optional>
453
+ <attribute name="valign">
454
+ <choice>
455
+ <value>top</value>
456
+ <value>middle</value>
457
+ <value>bottom</value>
458
+ <value>baseline</value>
459
+ </choice>
460
+ </attribute>
461
+ </optional>
432
462
  <choice>
433
463
  <zeroOrMore>
434
464
  <ref name="TextElement"/>
@@ -9,6 +9,7 @@ require_relative "./cleanup_boilerplate.rb"
9
9
  require_relative "./cleanup_section.rb"
10
10
  require_relative "./cleanup_terms.rb"
11
11
  require_relative "./cleanup_inline.rb"
12
+ require_relative "./cleanup_amend.rb"
12
13
  require "relaton_iev"
13
14
 
14
15
  module Asciidoctor
@@ -0,0 +1,54 @@
1
+ module Asciidoctor
2
+ module Standoc
3
+ module Cleanup
4
+ def change_clauses(x)
5
+ x.xpath("//clause[@change]").each do |c|
6
+ a = create_amend(c)
7
+ end
8
+ end
9
+
10
+ def create_amend(c)
11
+ a = c.add_child("<amend id='_#{UUIDTools::UUID.random_create}'/>").first
12
+ c.elements.each do |e|
13
+ e.parent = a unless %w(amend title).include? e.name
14
+ end
15
+ create_amend1(c, a)
16
+ end
17
+
18
+ def create_amend1(c, a)
19
+ create_amend2(c, a)
20
+ d = a.at("./description")
21
+ d.xpath(".//autonumber").each { |e| d.previous = e }
22
+ d.xpath(".//p[normalize-space(.)='']").each { |e| e.remove }
23
+ move_attrs_to_amend(c, a)
24
+ a
25
+ end
26
+
27
+ def create_amend2(c, a)
28
+ q = a.at("./quote") and q.name = "newcontent"
29
+ if q.nil?
30
+ a.children = "<description>#{a.children.to_xml}</description>"
31
+ else
32
+ pre = q&.xpath("./preceding-sibling::*")&.remove
33
+ post = q&.xpath("./following-sibling::*")&.remove
34
+ pre.empty? or a << "<description>#{pre.to_xml}</description>"
35
+ a << q.remove
36
+ post.empty? or a << "<description>#{post.to_xml}</description>"
37
+ end
38
+ end
39
+
40
+ def move_attrs_to_amend(c, a)
41
+ %w(change path path_end title).each do |e|
42
+ next unless c[e]
43
+ a[e] = c[e]
44
+ c.delete(e)
45
+ end
46
+ return unless a["locality"]
47
+ loc = a.children.add_previous_sibling("<location/>")
48
+ extract_localities1(loc, a["locality"])
49
+ loc1 = loc.at("./localityStack") and loc.replace(loc1.elements)
50
+ a.delete("locality")
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,8 +1,6 @@
1
1
  require "date"
2
- require "nokogiri"
3
2
  require "htmlentities"
4
3
  require "json"
5
- require "pathname"
6
4
  require "open-uri"
7
5
 
8
6
  module Asciidoctor
@@ -1,10 +1,7 @@
1
1
  require "date"
2
- require "nokogiri"
3
2
  require "htmlentities"
4
3
  require "json"
5
- require "pathname"
6
4
  require "open-uri"
7
- require "pp"
8
5
 
9
6
  module Asciidoctor
10
7
  module Standoc
@@ -50,6 +50,10 @@ module Asciidoctor
50
50
 
51
51
  def extract_localities(x)
52
52
  text = x&.children&.first&.remove&.text
53
+ extract_localities1(x, text)
54
+ end
55
+
56
+ def extract_localities1(x, text)
53
57
  b = x.add_child("<localityStack/>").first if LOCALITY_RE.match text
54
58
  while (m = LOCALITY_RE.match text)
55
59
  ref = m[:ref] ? "<referenceFrom>#{tq m[:ref]}</referenceFrom>" : ""
@@ -142,7 +146,8 @@ module Asciidoctor
142
146
  start = s[0]
143
147
  ret1 = %r([#{NAMECHAR}#]).match(start) ? "_" :
144
148
  (%r([#{NAMESTARTCHAR}#]).match(start) ? "_#{start}" : start)
145
- ret = ret1 + s[1..-1].gsub(%r([#{NAMECHAR}#]), "_")
149
+ ret2 = s[1..-1] || ""
150
+ ret = (ret1 || "") + ret2.gsub(%r([#{NAMECHAR}#]), "_")
146
151
  ret
147
152
  end
148
153
 
@@ -1,8 +1,6 @@
1
1
  require "date"
2
- require "nokogiri"
3
2
  require "htmlentities"
4
3
  require "json"
5
- require "pathname"
6
4
  require "open-uri"
7
5
  require "mathml2asciimath"
8
6
 
@@ -107,6 +105,7 @@ module Asciidoctor
107
105
  sections_order_cleanup(x)
108
106
  sections_level_cleanup(x)
109
107
  sections_names_cleanup(x)
108
+ change_clauses(x)
110
109
  end
111
110
 
112
111
  def obligations_cleanup(x)
@@ -24,12 +24,14 @@ module Asciidoctor
24
24
  preprocessor Asciidoctor::Standoc::Datamodel::AttributesTablePreprocessor
25
25
  preprocessor Asciidoctor::Standoc::Datamodel::DiagramPreprocessor
26
26
  preprocessor Asciidoctor::Standoc::Yaml2TextPreprocessor
27
+ preprocessor Asciidoctor::Standoc::Json2TextPreprocessor
27
28
  inline_macro Asciidoctor::Standoc::AltTermInlineMacro
28
29
  inline_macro Asciidoctor::Standoc::DeprecatedTermInlineMacro
29
30
  inline_macro Asciidoctor::Standoc::DomainTermInlineMacro
30
31
  inline_macro Asciidoctor::Standoc::InheritInlineMacro
31
32
  inline_macro Asciidoctor::Standoc::HTML5RubyMacro
32
33
  inline_macro Asciidoctor::Standoc::ConceptInlineMacro
34
+ inline_macro Asciidoctor::Standoc::AutonumberInlineMacro
33
35
  block Asciidoctor::Standoc::ToDoAdmonitionBlock
34
36
  treeprocessor Asciidoctor::Standoc::ToDoInlineAdmonitionBlock
35
37
  block Asciidoctor::Standoc::PlantUMLBlockMacro
@@ -65,7 +67,7 @@ module Asciidoctor
65
67
  attr_accessor :_file
66
68
  end
67
69
 
68
- def self.inherited( k )
70
+ def self.inherited(k)
69
71
  k._file = caller_locations.first.absolute_path
70
72
  end
71
73
 
@@ -52,18 +52,26 @@ module Asciidoctor
52
52
  end
53
53
  end
54
54
 
55
+ def personal_role(node, c, suffix)
56
+ c.role **{ type: node.attr("role#{suffix}")&.downcase || "author" }
57
+ end
58
+
59
+ def personal_contact(node, suffix, p)
60
+ node.attr("phone#{suffix}") and p.phone node.attr("phone#{suffix}")
61
+ node.attr("fax#{suffix}") and
62
+ p.phone node.attr("fax#{suffix}"), **{type: "fax"}
63
+ node.attr("email#{suffix}") and p.email node.attr("email#{suffix}")
64
+ node.attr("contributor-uri#{suffix}") and
65
+ p.uri node.attr("contributor-uri#{suffix}")
66
+ end
67
+
55
68
  def personal_author1(node, xml, suffix)
56
69
  xml.contributor do |c|
57
- c.role **{ type: node.attr("role#{suffix}")&.downcase || "author" }
70
+ personal_role(node, c, suffix)
58
71
  c.person do |p|
59
72
  person_name(node, xml, suffix, p)
60
73
  person_affiliation(node, xml, suffix, p)
61
- node.attr("phone#{suffix}") and p.phone node.attr("phone#{suffix}")
62
- node.attr("fax#{suffix}") and
63
- p.phone node.attr("fax#{suffix}"), **{type: "fax"}
64
- node.attr("email#{suffix}") and p.email node.attr("email#{suffix}")
65
- node.attr("contributor-uri#{suffix}") and
66
- p.uri node.attr("contributor-uri#{suffix}")
74
+ personal_contact(node, suffix, p)
67
75
  end
68
76
  end
69
77
  end
@@ -3,7 +3,8 @@ require "htmlentities"
3
3
  require "unicode2latex"
4
4
  require "mime/types"
5
5
  require "base64"
6
- require 'English'
6
+ require "English"
7
+ require "latexmath"
7
8
 
8
9
  module Asciidoctor
9
10
  module Standoc
@@ -108,6 +109,7 @@ module Asciidoctor
108
109
  gsub(/&quot;/, '"').gsub(/&#xa;/, "\n")
109
110
  end
110
111
 
112
+ =begin
111
113
  def latex_run1(lxm_input, cmd)
112
114
  IO.popen(cmd, "r+", external_encoding: "UTF-8") do |io|
113
115
  io.write(lxm_input)
@@ -137,6 +139,16 @@ module Asciidoctor
137
139
  "latexmlmath failed to process equation:\n#{lxm_input}")
138
140
  results&.sub(%r{<math ([^>]+ )?display="block"}, "<math \\1")
139
141
  end
142
+ =end
143
+
144
+ def latex_parse(text)
145
+ lxm_input = Unicode2LaTeX.unicode2latex(HTMLEntities.new.decode(text))
146
+ results = Latexmath.parse(lxm_input).to_mathml
147
+ results.nil? and
148
+ @log.add('Math', nil,
149
+ "latexmlmath failed to process equation:\n#{lxm_input}")
150
+ results&.sub(%r{<math ([^>]+ )?display="block"}, "<math \\1")
151
+ end
140
152
 
141
153
  def stem_parse(text, xml, style)
142
154
  if /&lt;([^:>&]+:)?math(\s+[^>&]+)?&gt; |
@@ -581,6 +581,8 @@
581
581
  <ref name="ol"/>
582
582
  <ref name="dl"/>
583
583
  <ref name="formula"/>
584
+ <ref name="quote"/>
585
+ <ref name="sourcecode"/>
584
586
  </choice>
585
587
  </oneOrMore>
586
588
  </element>
@@ -664,6 +666,16 @@
664
666
  </choice>
665
667
  </attribute>
666
668
  </optional>
669
+ <optional>
670
+ <attribute name="valign">
671
+ <choice>
672
+ <value>top</value>
673
+ <value>middle</value>
674
+ <value>bottom</value>
675
+ <value>baseline</value>
676
+ </choice>
677
+ </attribute>
678
+ </optional>
667
679
  <choice>
668
680
  <zeroOrMore>
669
681
  <choice>
@@ -700,6 +712,16 @@
700
712
  </choice>
701
713
  </attribute>
702
714
  </optional>
715
+ <optional>
716
+ <attribute name="valign">
717
+ <choice>
718
+ <value>top</value>
719
+ <value>middle</value>
720
+ <value>bottom</value>
721
+ <value>baseline</value>
722
+ </choice>
723
+ </attribute>
724
+ </optional>
703
725
  <choice>
704
726
  <zeroOrMore>
705
727
  <choice>
@@ -1052,14 +1074,17 @@
1052
1074
  <ref name="section-title"/>
1053
1075
  </optional>
1054
1076
  <group>
1055
- <group>
1056
- <zeroOrMore>
1057
- <ref name="BasicBlock"/>
1058
- </zeroOrMore>
1059
- <zeroOrMore>
1060
- <ref name="note"/>
1061
- </zeroOrMore>
1062
- </group>
1077
+ <choice>
1078
+ <group>
1079
+ <zeroOrMore>
1080
+ <ref name="BasicBlock"/>
1081
+ </zeroOrMore>
1082
+ <zeroOrMore>
1083
+ <ref name="note"/>
1084
+ </zeroOrMore>
1085
+ </group>
1086
+ <ref name="amend"/>
1087
+ </choice>
1063
1088
  <zeroOrMore>
1064
1089
  <choice>
1065
1090
  <ref name="clause-subsection"/>
@@ -1510,4 +1535,79 @@
1510
1535
  <ref name="CitationType"/>
1511
1536
  </element>
1512
1537
  </define>
1538
+ <define name="amend">
1539
+ <element name="amend">
1540
+ <optional>
1541
+ <attribute name="id">
1542
+ <data type="ID"/>
1543
+ </attribute>
1544
+ </optional>
1545
+ <attribute name="change">
1546
+ <choice>
1547
+ <value>add</value>
1548
+ <value>modify</value>
1549
+ <value>delete</value>
1550
+ </choice>
1551
+ </attribute>
1552
+ <optional>
1553
+ <attribute name="path"/>
1554
+ </optional>
1555
+ <optional>
1556
+ <attribute name="path_end"/>
1557
+ </optional>
1558
+ <optional>
1559
+ <attribute name="title"/>
1560
+ </optional>
1561
+ <optional>
1562
+ <element name="location">
1563
+ <zeroOrMore>
1564
+ <ref name="locality"/>
1565
+ </zeroOrMore>
1566
+ </element>
1567
+ </optional>
1568
+ <zeroOrMore>
1569
+ <ref name="autonumber"/>
1570
+ </zeroOrMore>
1571
+ <optional>
1572
+ <element name="description">
1573
+ <zeroOrMore>
1574
+ <ref name="BasicBlock"/>
1575
+ </zeroOrMore>
1576
+ </element>
1577
+ </optional>
1578
+ <optional>
1579
+ <element name="newcontent">
1580
+ <zeroOrMore>
1581
+ <ref name="BasicBlock"/>
1582
+ </zeroOrMore>
1583
+ </element>
1584
+ </optional>
1585
+ <optional>
1586
+ <element name="description">
1587
+ <zeroOrMore>
1588
+ <ref name="BasicBlock"/>
1589
+ </zeroOrMore>
1590
+ </element>
1591
+ </optional>
1592
+ </element>
1593
+ </define>
1594
+ <define name="autonumber">
1595
+ <element name="autonumber">
1596
+ <attribute name="type">
1597
+ <choice>
1598
+ <value>requirement</value>
1599
+ <value>recommendation</value>
1600
+ <value>permission</value>
1601
+ <value>table</value>
1602
+ <value>figure</value>
1603
+ <value>admonition</value>
1604
+ <value>formula</value>
1605
+ <value>sourcecode</value>
1606
+ <value>example</value>
1607
+ <value>note</value>
1608
+ </choice>
1609
+ </attribute>
1610
+ <text/>
1611
+ </element>
1612
+ </define>
1513
1613
  </grammar>