metanorma-standoc 1.5.2 → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
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>