metanorma-standoc 3.5.0 → 3.5.1.pre.alpha.1

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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +23 -0
  3. data/Gemfile.devel +0 -0
  4. data/lib/metanorma/cleanup/bibdata.rb +5 -1
  5. data/lib/metanorma/cleanup/bibitem.rb +10 -4
  6. data/lib/metanorma/cleanup/boilerplate.rb +5 -1
  7. data/lib/metanorma/cleanup/image.rb +21 -1
  8. data/lib/metanorma/cleanup/inline.rb +23 -2
  9. data/lib/metanorma/cleanup/maths.rb +31 -12
  10. data/lib/metanorma/cleanup/section.rb +23 -2
  11. data/lib/metanorma/cleanup/spans_to_bibitem_preprocessing.rb +4 -1
  12. data/lib/metanorma/cleanup/terms.rb +5 -1
  13. data/lib/metanorma/cleanup/text.rb +10 -4
  14. data/lib/metanorma/converter/base.rb +66 -10
  15. data/lib/metanorma/converter/converter.rb +5 -0
  16. data/lib/metanorma/converter/front.rb +27 -1
  17. data/lib/metanorma/converter/macros.rb +1 -0
  18. data/lib/metanorma/converter/macros_nosub.rb +38 -18
  19. data/lib/metanorma/converter/utils.rb +8 -2
  20. data/lib/metanorma/standoc/document/annotation_container.rb +41 -0
  21. data/lib/metanorma/standoc/document/block_attributes.rb +311 -0
  22. data/lib/metanorma/standoc/document/blocks/amend_block.rb +50 -0
  23. data/lib/metanorma/standoc/document/blocks/amend_content_block.rb +46 -0
  24. data/lib/metanorma/standoc/document/blocks/auto_number.rb +20 -0
  25. data/lib/metanorma/standoc/document/blocks/block_source.rb +22 -0
  26. data/lib/metanorma/standoc/document/blocks/change_type.rb +21 -0
  27. data/lib/metanorma/standoc/document/blocks/element_name.rb +22 -0
  28. data/lib/metanorma/standoc/document/blocks/form.rb +38 -0
  29. data/lib/metanorma/standoc/document/blocks/image_map_area_type.rb +24 -0
  30. data/lib/metanorma/standoc/document/blocks/image_map_area_type_type.rb +21 -0
  31. data/lib/metanorma/standoc/document/blocks/image_map_block.rb +32 -0
  32. data/lib/metanorma/standoc/document/blocks/image_map_coords.rb +19 -0
  33. data/lib/metanorma/standoc/document/blocks/image_map_radius.rb +19 -0
  34. data/lib/metanorma/standoc/document/blocks/multilingual_rendering_type.rb +21 -0
  35. data/lib/metanorma/standoc/document/blocks/passthrough.rb +3 -0
  36. data/lib/metanorma/standoc/document/blocks/requirement_model.rb +20 -0
  37. data/lib/metanorma/standoc/document/blocks/source_origin_element.rb +23 -0
  38. data/lib/metanorma/standoc/document/blocks/standard_admonition_block.rb +32 -0
  39. data/lib/metanorma/standoc/document/blocks/standard_block.rb +28 -0
  40. data/lib/metanorma/standoc/document/blocks/standard_block_no_notes.rb +34 -0
  41. data/lib/metanorma/standoc/document/blocks/standard_example_block.rb +30 -0
  42. data/lib/metanorma/standoc/document/blocks/standard_figure_block.rb +32 -0
  43. data/lib/metanorma/standoc/document/blocks/standard_formula_block.rb +30 -0
  44. data/lib/metanorma/standoc/document/blocks/standard_note_block.rb +64 -0
  45. data/lib/metanorma/standoc/document/blocks/standard_paragraph_block.rb +25 -0
  46. data/lib/metanorma/standoc/document/blocks/standard_quote_block.rb +29 -0
  47. data/lib/metanorma/standoc/document/blocks/standard_sourcecode_block.rb +32 -0
  48. data/lib/metanorma/standoc/document/blocks/standard_table_block.rb +39 -0
  49. data/lib/metanorma/standoc/document/blocks/svg_map_block.rb +23 -0
  50. data/lib/metanorma/standoc/document/blocks/svg_target_type.rb +20 -0
  51. data/lib/metanorma/standoc/document/blocks/table_col.rb +16 -0
  52. data/lib/metanorma/standoc/document/blocks/to_c.rb +19 -0
  53. data/lib/metanorma/standoc/document/blocks.rb +60 -0
  54. data/lib/metanorma/standoc/document/boilerplate.rb +40 -0
  55. data/lib/metanorma/standoc/document/elements/add.rb +3 -0
  56. data/lib/metanorma/standoc/document/elements/del.rb +3 -0
  57. data/lib/metanorma/standoc/document/elements/form_input.rb +27 -0
  58. data/lib/metanorma/standoc/document/elements/input.rb +12 -0
  59. data/lib/metanorma/standoc/document/elements/input_type.rb +27 -0
  60. data/lib/metanorma/standoc/document/elements/label.rb +19 -0
  61. data/lib/metanorma/standoc/document/elements/option.rb +27 -0
  62. data/lib/metanorma/standoc/document/elements/orientation_type.rb +27 -0
  63. data/lib/metanorma/standoc/document/elements/select.rb +32 -0
  64. data/lib/metanorma/standoc/document/elements/standard_page_break_element.rb +22 -0
  65. data/lib/metanorma/standoc/document/elements/textarea.rb +25 -0
  66. data/lib/metanorma/standoc/document/elements.rb +20 -0
  67. data/lib/metanorma/standoc/document/lists/standard_definition.rb +24 -0
  68. data/lib/metanorma/standoc/document/lists/standard_definition_list.rb +30 -0
  69. data/lib/metanorma/standoc/document/lists/standard_definition_term.rb +27 -0
  70. data/lib/metanorma/standoc/document/lists/standard_unordered_list.rb +28 -0
  71. data/lib/metanorma/standoc/document/lists/unordered_checkable_list_item.rb +26 -0
  72. data/lib/metanorma/standoc/document/lists.rb +17 -0
  73. data/lib/metanorma/standoc/document/metadata/editorial_group_type.rb +25 -0
  74. data/lib/metanorma/standoc/document/metadata/ics_type.rb +26 -0
  75. data/lib/metanorma/standoc/document/metadata/metanorma_extension.rb +58 -0
  76. data/lib/metanorma/standoc/document/metadata/presentation_metadata.rb +107 -0
  77. data/lib/metanorma/standoc/document/metadata/semantic_metadata.rb +18 -0
  78. data/lib/metanorma/standoc/document/metadata/standard_bib_data.rb +25 -0
  79. data/lib/metanorma/standoc/document/metadata/standard_bib_data_extension_type.rb +37 -0
  80. data/lib/metanorma/standoc/document/metadata/structured_identifier_type.rb +48 -0
  81. data/lib/metanorma/standoc/document/metadata/technical_committee_type.rb +27 -0
  82. data/lib/metanorma/standoc/document/metadata/unitsml/amount_of_substance.rb +19 -0
  83. data/lib/metanorma/standoc/document/metadata/unitsml/base_quantity.rb +34 -0
  84. data/lib/metanorma/standoc/document/metadata/unitsml/dimension.rb +39 -0
  85. data/lib/metanorma/standoc/document/metadata/unitsml/dimension_set.rb +19 -0
  86. data/lib/metanorma/standoc/document/metadata/unitsml/electric_current.rb +19 -0
  87. data/lib/metanorma/standoc/document/metadata/unitsml/enumerated_root_unit.rb +23 -0
  88. data/lib/metanorma/standoc/document/metadata/unitsml/length.rb +19 -0
  89. data/lib/metanorma/standoc/document/metadata/unitsml/luminous_intensity.rb +19 -0
  90. data/lib/metanorma/standoc/document/metadata/unitsml/mass.rb +19 -0
  91. data/lib/metanorma/standoc/document/metadata/unitsml/namespace.rb +17 -0
  92. data/lib/metanorma/standoc/document/metadata/unitsml/plane_angle.rb +19 -0
  93. data/lib/metanorma/standoc/document/metadata/unitsml/prefix.rb +30 -0
  94. data/lib/metanorma/standoc/document/metadata/unitsml/prefix_name.rb +21 -0
  95. data/lib/metanorma/standoc/document/metadata/unitsml/prefix_set.rb +19 -0
  96. data/lib/metanorma/standoc/document/metadata/unitsml/prefix_symbol.rb +21 -0
  97. data/lib/metanorma/standoc/document/metadata/unitsml/quantity.rb +28 -0
  98. data/lib/metanorma/standoc/document/metadata/unitsml/quantity_name.rb +21 -0
  99. data/lib/metanorma/standoc/document/metadata/unitsml/quantity_set.rb +19 -0
  100. data/lib/metanorma/standoc/document/metadata/unitsml/root_units.rb +19 -0
  101. data/lib/metanorma/standoc/document/metadata/unitsml/thermodynamic_temperature.rb +19 -0
  102. data/lib/metanorma/standoc/document/metadata/unitsml/time.rb +19 -0
  103. data/lib/metanorma/standoc/document/metadata/unitsml/unit.rb +32 -0
  104. data/lib/metanorma/standoc/document/metadata/unitsml/unit_name.rb +21 -0
  105. data/lib/metanorma/standoc/document/metadata/unitsml/unit_set.rb +19 -0
  106. data/lib/metanorma/standoc/document/metadata/unitsml/unit_symbol.rb +36 -0
  107. data/lib/metanorma/standoc/document/metadata/unitsml/unit_system.rb +23 -0
  108. data/lib/metanorma/standoc/document/metadata/unitsml/unitsml_root.rb +28 -0
  109. data/lib/metanorma/standoc/document/metadata/unitsml.rb +39 -0
  110. data/lib/metanorma/standoc/document/metadata.rb +23 -0
  111. data/lib/metanorma/standoc/document/namespace.rb +11 -0
  112. data/lib/metanorma/standoc/document/refs/reference_to_term.rb +26 -0
  113. data/lib/metanorma/standoc/document/refs/reference_to_termbase.rb +27 -0
  114. data/lib/metanorma/standoc/document/refs/standoc_locality_stack.rb +24 -0
  115. data/lib/metanorma/standoc/document/refs/standoc_reference_to_citation_element.rb +27 -0
  116. data/lib/metanorma/standoc/document/refs/standoc_reference_to_id_element.rb +36 -0
  117. data/lib/metanorma/standoc/document/refs/xref_case_type.rb +27 -0
  118. data/lib/metanorma/standoc/document/refs/xref_connective_type.rb +27 -0
  119. data/lib/metanorma/standoc/document/refs/xref_target_type.rb +25 -0
  120. data/lib/metanorma/standoc/document/refs.rb +18 -0
  121. data/lib/metanorma/standoc/document/root.rb +28 -0
  122. data/lib/metanorma/standoc/document/root_attributes.rb +78 -0
  123. data/lib/metanorma/standoc/document/sections/abstract.rb +19 -0
  124. data/lib/metanorma/standoc/document/sections/acknowledgements.rb +19 -0
  125. data/lib/metanorma/standoc/document/sections/annex_section.rb +80 -0
  126. data/lib/metanorma/standoc/document/sections/bibliography_section.rb +20 -0
  127. data/lib/metanorma/standoc/document/sections/boilerplate_type.rb +32 -0
  128. data/lib/metanorma/standoc/document/sections/clause_hierarchical_section.rb +32 -0
  129. data/lib/metanorma/standoc/document/sections/clause_section.rb +91 -0
  130. data/lib/metanorma/standoc/document/sections/colophon.rb +16 -0
  131. data/lib/metanorma/standoc/document/sections/definition_section.rb +72 -0
  132. data/lib/metanorma/standoc/document/sections/floating_section_title.rb +23 -0
  133. data/lib/metanorma/standoc/document/sections/floating_title.rb +27 -0
  134. data/lib/metanorma/standoc/document/sections/foreword.rb +19 -0
  135. data/lib/metanorma/standoc/document/sections/introduction.rb +20 -0
  136. data/lib/metanorma/standoc/document/sections/misc_container.rb +31 -0
  137. data/lib/metanorma/standoc/document/sections/normative_type.rb +29 -0
  138. data/lib/metanorma/standoc/document/sections/preface.rb +36 -0
  139. data/lib/metanorma/standoc/document/sections/sections.rb +49 -0
  140. data/lib/metanorma/standoc/document/sections/standard_content_section.rb +41 -0
  141. data/lib/metanorma/standoc/document/sections/standard_hierarchical_section.rb +30 -0
  142. data/lib/metanorma/standoc/document/sections/standard_references_section.rb +95 -0
  143. data/lib/metanorma/standoc/document/sections/standard_section.rb +39 -0
  144. data/lib/metanorma/standoc/document/sections/terms_section.rb +70 -0
  145. data/lib/metanorma/standoc/document/sections.rb +34 -0
  146. data/lib/metanorma/standoc/document/standard_document_type.rb +15 -0
  147. data/lib/metanorma/standoc/document/terms/abbreviation_type.rb +27 -0
  148. data/lib/metanorma/standoc/document/terms/concept.rb +48 -0
  149. data/lib/metanorma/standoc/document/terms/definition_collection.rb +24 -0
  150. data/lib/metanorma/standoc/document/terms/designation.rb +55 -0
  151. data/lib/metanorma/standoc/document/terms/expression_designation.rb +38 -0
  152. data/lib/metanorma/standoc/document/terms/expression_type.rb +27 -0
  153. data/lib/metanorma/standoc/document/terms/fmt_definition.rb +41 -0
  154. data/lib/metanorma/standoc/document/terms/fmt_definition_semx.rb +37 -0
  155. data/lib/metanorma/standoc/document/terms/fmt_deprecates.rb +22 -0
  156. data/lib/metanorma/standoc/document/terms/fmt_related.rb +28 -0
  157. data/lib/metanorma/standoc/document/terms/grammar_gender.rb +27 -0
  158. data/lib/metanorma/standoc/document/terms/grammar_info.rb +44 -0
  159. data/lib/metanorma/standoc/document/terms/grammar_number.rb +27 -0
  160. data/lib/metanorma/standoc/document/terms/graphical_symbol_designation.rb +25 -0
  161. data/lib/metanorma/standoc/document/terms/letter_symbol_designation.rb +27 -0
  162. data/lib/metanorma/standoc/document/terms/non_verbal_representation.rb +33 -0
  163. data/lib/metanorma/standoc/document/terms/related_term.rb +33 -0
  164. data/lib/metanorma/standoc/document/terms/related_term_type.rb +28 -0
  165. data/lib/metanorma/standoc/document/terms/term.rb +88 -0
  166. data/lib/metanorma/standoc/document/terms/term_collection.rb +24 -0
  167. data/lib/metanorma/standoc/document/terms/term_definition.rb +51 -0
  168. data/lib/metanorma/standoc/document/terms/term_example.rb +46 -0
  169. data/lib/metanorma/standoc/document/terms/term_expression.rb +27 -0
  170. data/lib/metanorma/standoc/document/terms/term_name_element.rb +30 -0
  171. data/lib/metanorma/standoc/document/terms/term_note.rb +46 -0
  172. data/lib/metanorma/standoc/document/terms/term_source.rb +43 -0
  173. data/lib/metanorma/standoc/document/terms/term_source_status.rb +29 -0
  174. data/lib/metanorma/standoc/document/terms/term_source_type.rb +21 -0
  175. data/lib/metanorma/standoc/document/terms/verbal_expression.rb +39 -0
  176. data/lib/metanorma/standoc/document/terms.rb +40 -0
  177. data/lib/metanorma/standoc/document.rb +53 -0
  178. data/lib/metanorma/standoc/mirror_seed.rb +75 -0
  179. data/lib/metanorma/standoc/version.rb +1 -1
  180. data/lib/metanorma/standoc.rb +23 -1
  181. data/lib/metanorma/validate/schema.rb +18 -59
  182. data/lib/metanorma/validate/{isodoc-compile.rng → standoc-compile.rng} +1 -1
  183. data/lib/metanorma/validate/{isodoc.rng → standoc.rng} +2 -2
  184. data/metanorma-standoc.gemspec +18 -8
  185. metadata +260 -22
  186. data/lib/isodoc/html/htmlstyle.css +0 -1429
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95fe16d69ea9558d1d2b3cec445ae0d71cfeb90f319ba138e631a05034421b1c
4
- data.tar.gz: eafe128e6beaf35465a309a24b043ceb23ba84c330e4ba40930bd90b6952aebb
3
+ metadata.gz: 8001a19a529d536d37e1f035e1fcc45585ecfdecaece0e2466b00a684807f71c
4
+ data.tar.gz: aa1838be7a5e6dfb6675251a4c0871aafb58e427a4bea598a60849e5263b4e22
5
5
  SHA512:
6
- metadata.gz: ce581d496eba88c15d71bdc63f55206c14bc4f823f5fcaabb9cbbfb982c6b32a555472c67e1ef9ca08fb1d3ca6cb3d67a33c5f93a4ea14777af4038814a45ef1
7
- data.tar.gz: 817f107bdbf9d2e2ddf2f3ba8c6dd7e1f520b5945e61dc93d97fbad0c1fca1342332cdb4453ee5b52f4ad4fbee3e17209248d4716db20e6205b36f7eb3838b39
6
+ metadata.gz: 48756dd12f0f9ba7f553e0c762b398688d812bf86780a6a860f88c09c32395e7460a3bbc9556e0a0c02b5d9d61a998ff1897c04708b6f545693e6600ceb93be8
7
+ data.tar.gz: c9bfc8a020ab69a476d91d737acdf13d319b41b8e234b64d23ceb2770ab976cf79dbddd984c3393a395bae69adc54cd2d06797e4b725c023ac1c5bfb4ce5ef78
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ source "https://rubygems.org"
5
5
  git_source(:github) { |repo| "https://github.com/#{repo}" }
6
6
 
7
7
  gemspec
8
+ gem "metanorma-mirror", "~> 1.0", github: "metanorma/metanorma-mirror", branch: "main"
8
9
 
9
10
  # Stopgap: lutaml 0.11.x removed lib/lutaml/xmi.rb, which metanorma-plugin-lutaml
10
11
  # 0.7.x still `require`s. Hold lutaml at 0.10.x until plugin-lutaml follows the
@@ -12,4 +13,26 @@ gemspec
12
13
  # https://github.com/metanorma/metanorma-plugin-lutaml/issues/292
13
14
  gem "lutaml", "< 0.11"
14
15
 
16
+ # TEMPORARY: cross-PR branch pins so CI can resolve the in-flight pubid-2 /
17
+ # relaton-bib 2.2 / metanorma-document 0.5 chain. Revert each to its
18
+ # released line once the corresponding PR merges.
19
+ # TEMPORARY pin: the svgmap/imagemap models (metanorma-document#62/#63
20
+ # branch) — flip to main when they merge.
21
+ gem "metanorma-document", github: "metanorma/metanorma-document",
22
+ branch: "main"
23
+ # document seed registers — restore main on merge, version on release.
24
+ # isodoc: relaton-cli 3.0.0.pre allowance (#824) merged after the 3.7.2 release — main until the next release
25
+ gem "isodoc", github: "metanorma/isodoc", branch: "main"
26
+ # relaton 3.0.0.pre.alpha.1 from rubygems called the removed pubid
27
+ # base_identifier; the fix (db9840bdf) shipped in the 3.0.0.pre.alpha.4
28
+ # release. Prefer the released gem over a git pin: relaton main has since
29
+ # moved to lutaml-store ~> 0.3, which conflicts with glossarist 2.14's
30
+ # lutaml-store ~> 0.2.0 and makes this bundle unresolvable.
31
+ gem "relaton", "~> 3.0.0.pre.alpha" # the 3.0.0.pre line: alpha.17 carries singular_tolerance + the worker-pool fix
32
+ gem "pubid", "~> 2.0.0.pre.alpha"
33
+
34
+ gem "metanorma-plugin-lutaml", github: "metanorma/metanorma-plugin-lutaml", branch: "main"
35
+
15
36
  eval_gemfile("Gemfile.devel") rescue nil
37
+
38
+ gem "metanorma-utils", "~> 2.0.8" # GcBudget (utils#54) + the array-join asciidoctor table cell buffer (utils#55/#56), released in 2.0.8, github: "metanorma/metanorma-utils", branch: "main"
data/Gemfile.devel ADDED
File without changes
@@ -192,7 +192,11 @@ module Metanorma
192
192
  ins = add_misc_container(xmldoc)
193
193
  ins ||= add_misc_container(xmldoc)
194
194
  ins.at("./semantic-metadata/stage-published") and return
195
- p = published_base?(xmldoc.at("bibdata/status/stage")&.text, xmldoc)
195
+ # Absolute path: the sectioned assembly nests bibdata one level
196
+ # deeper than the classic document, so a root-relative lookup
197
+ # misses the stage and stage-published resolves "false"
198
+ # (metanorma-standoc#1290). The absolute form finds both shapes.
199
+ p = published_base?(xmldoc.at("//bibdata/status/stage")&.text, xmldoc)
196
200
  ins << <<~XML
197
201
  <semantic-metadata><stage-published>#{p}</stage-published></semantic-metadata>
198
202
  XML
@@ -28,11 +28,17 @@ module Metanorma
28
28
  merge_bibitem_from_formattedref_span_attrs(bib, new)
29
29
  if bib.at("./title") && bib["amend"]
30
30
  # there already is a fetched record here: merge
31
- bib.children = Metanorma::Standoc::Cleanup::MergeBibitems
32
- .new(bib.to_xml, new.to_xml).merge.to_noko.children
31
+ # to_noko children are Nokogiri natives; handing them to moxml's
32
+ # children= crosses adapters (type-confused natives under leptris,
33
+ # segfault at serialize on windows). Serialize to markup and let
34
+ # moxml re-parse in bib's own context.
35
+ merged = Metanorma::Standoc::Cleanup::MergeBibitems
36
+ .new(bib.to_xml, new.to_xml).merge.to_noko.children.to_xml
37
+ bib.children = merged
33
38
  elsif bib.at("./title") # replace record
34
- bib.children = new.children.to_xml
35
- else bib << new.children.to_xml
39
+ bib.children = new.children.map(&:to_xml).join
40
+ else
41
+ bib << new.children.map(&:to_xml).join
36
42
  end
37
43
  bibitem_reorder_elems(bib)
38
44
  end
@@ -41,7 +41,11 @@ module Metanorma
41
41
 
42
42
  def dup_with_namespace(elem)
43
43
  ret = elem.dup
44
- ret.add_namespace(nil, @conv.xml_namespace)
44
+ # adding a namespace to a deep-copied leptris tree corrupts it
45
+ # (segfault at serialize); flavors without an XML namespace
46
+ # never needed the call
47
+ ns = @conv.xml_namespace
48
+ ret.add_namespace(nil, ns) if ns
45
49
  ret
46
50
  end
47
51
 
@@ -7,7 +7,27 @@ module Metanorma
7
7
  def svgmap_cleanup(xmldoc)
8
8
  svgmap_moveattrs(xmldoc)
9
9
  svgmap_populate(xmldoc)
10
- Vectory::SvgMapping.new(xmldoc, @localdir).call
10
+ processed = Vectory::SvgMapping.new(xmldoc, @localdir).call.to_xml
11
+
12
+ # vectory 0.13 processes on its own tree and returns the result
13
+ # instead of mutating the caller's document; reparse the processed
14
+ # XML with the caller's own XML library and graft the content back
15
+ # so the cleanup pipeline (which threads xmldoc by reference
16
+ # through every step) keeps working. With vectory 0.12 the document
17
+ # is already mutated and the graft is a no-op.
18
+ new_doc = if defined?(Moxml) && xmldoc.is_a?(Moxml::Node)
19
+ Moxml.new.parse(processed)
20
+ elsif defined?(Nokogiri) && xmldoc.is_a?(Nokogiri::XML::Node)
21
+ Nokogiri::XML(processed)
22
+ else
23
+ raise ArgumentError,
24
+ "unsupported xmldoc type: #{xmldoc.class}"
25
+ end
26
+ old_root = xmldoc.root
27
+ new_root = new_doc.root
28
+ old_root.children.each(&:remove)
29
+ new_root.children.each { |n| old_root << n }
30
+ xmldoc
11
31
  end
12
32
 
13
33
  def svgmap_moveattrs(xmldoc)
@@ -161,8 +161,29 @@ module Metanorma
161
161
  # overwrite xmldoc, so must assign result to xmldoc
162
162
  def passthrough_metanorma_cleanup(doc)
163
163
  ret = to_xml(doc)
164
- .gsub(%r{<passthrough formats="metanorma">([^<]*)</passthrough>}) { @c.decode($1) }
165
- doc.root = Nokogiri::XML(ret, &:huge).root
164
+ .gsub(%r{<passthrough formats="metanorma">([^<]*)</passthrough>}) do
165
+ encoded = $1
166
+ content = @c.decode(encoded)
167
+ passthrough_injectable?(content) ? content : encoded
168
+ end
169
+ doc.root = if doc.is_a?(Moxml::Document)
170
+ @conv.moxml_context.parse(ret).root
171
+ else
172
+ Nokogiri::XML(ret, &:huge).root
173
+ end
174
+ end
175
+
176
+ # Passthrough content is markup to splice into the document. Text
177
+ # that is malformed XML (an escaped literal such as
178
+ # "&lt;Date Approved&gt;", or a bare "&") must stay escaped:
179
+ # decoding it would corrupt the reparse. Tag-name mismatch alone
180
+ # is not disqualifying: markup legitimately split across
181
+ # consecutive passthroughs reports it until the pieces meet.
182
+ TAG_MISMATCH = 76 # XML_ERR_TAG_NAME_MISMATCH
183
+
184
+ def passthrough_injectable?(content)
185
+ Nokogiri::XML::DocumentFragment.parse(content).errors
186
+ .all? { |e| e.code == TAG_MISMATCH }
166
187
  end
167
188
 
168
189
  def link_cleanup(xmldoc)
@@ -72,11 +72,19 @@ module Metanorma
72
72
  end
73
73
 
74
74
  def xml_unescape_mathml(xml)
75
- xml.children.any?(&:element?) and return
76
- math = xml.text.gsub("&lt;", "<").gsub("&gt;", ">")
77
- .gsub("&quot;", '"').gsub("&apos;", "'").gsub("&amp;", "&")
78
- .gsub(/<[^: \r\n\t\/]+:/, "<").gsub(/<\/[^ \r\n\t:]+:/, "</")
79
- xml.children = math
75
+ if xml.children.any?(&:element?)
76
+ # The stem macro hands the builder raw markup, so a MathML
77
+ # fragment whose flavor prefix is unbound at the root parses
78
+ # into bare "mml:"-named elements; namespace-aware cleanup
79
+ # cannot see them. Re-normalize over the serialized tree.
80
+ xml.children = xml.children.to_xml
81
+ .gsub(/<[^: \r\n\t\/]+:/, "<").gsub(/<\/[^ \r\n\t:]+:/, "</")
82
+ .gsub(/\s+xmlns:[^=]+="[^"]*"/, "")
83
+ else
84
+ xml.children = xml.text.gsub("&lt;", "<").gsub("&gt;", ">")
85
+ .gsub("&quot;", '"').gsub("&apos;", "'").gsub("&amp;", "&")
86
+ .gsub(/<[^: \r\n\t\/]+:/, "<").gsub(/<\/[^ \r\n\t:]+:/, "</")
87
+ end
80
88
  end
81
89
 
82
90
  def mathml_preserve_space(math)
@@ -88,19 +96,30 @@ module Metanorma
88
96
 
89
97
  def mathml_namespace(stem)
90
98
  stem.xpath("./*[local-name() = 'math']").each do |x|
91
- x.default_namespace = MATHML_NS
99
+ if (prefix = x.name[/\A([^:]+):/, 1])
100
+ # a stem may arrive with a prefixed MathML root (mml:math);
101
+ # a default namespace does not bind that prefix, so the
102
+ # serialized document is not well-formed. Bind the prefix.
103
+ x.add_namespace_definition(prefix, MATHML_NS)
104
+ else
105
+ x.default_namespace = MATHML_NS
106
+ end
92
107
  end
93
108
  end
94
109
 
95
110
  UNITSML_NS = "https://schema.unitsml.org/unitsml/1.0".freeze
96
111
 
97
112
  def add_misc_container(xmldoc)
98
- unless ins = xmldoc.at("//metanorma-extension")
99
- a = xmldoc.xpath("//termdocsource")&.last || xmldoc.at("//bibdata") ||
100
- xmldoc.root.children.first
101
- a.next = "<metanorma-extension/>"
102
- ins = xmldoc.at("//metanorma-extension")
103
- end
113
+ ins = xmldoc.at("//metanorma-extension")
114
+ return ins if ins
115
+
116
+ a = xmldoc.xpath("//termdocsource")&.last || xmldoc.at("//bibdata") ||
117
+ xmldoc.root.children.first
118
+ # Create in the document's pool and return the node: a
119
+ # fragment-parsed node belongs to another Moxml document, and
120
+ # re-querying it back can miss on the native Leptris lane.
121
+ ins = xmldoc.create_element("metanorma-extension")
122
+ a.next = ins
104
123
  ins
105
124
  end
106
125
 
@@ -39,7 +39,14 @@ module Metanorma
39
39
  preface = sect.at("//preface") ||
40
40
  sect.add_previous_sibling("<preface/>").first
41
41
  abstract = xml.at("//abstract[not(ancestor::bibitem)]").remove
42
- preface.prepend_child abstract.remove
42
+ # prepend_child is a Nokogiri-only API; the first-child
43
+ # previous-sibling insertion works on every adapter
44
+ first = preface.children.first
45
+ if first
46
+ first.add_previous_sibling(abstract.remove)
47
+ else
48
+ preface.add_child(abstract.remove)
49
+ end
43
50
  bibabstract = bibabstract_location(xml)
44
51
  bibabstract.next = clean_abstract(abstract.dup)
45
52
  end
@@ -47,6 +54,8 @@ module Metanorma
47
54
 
48
55
  def clean_abstract(dupabstract)
49
56
  dupabstract.traverse do |n|
57
+ next unless n.element? # only elements carry attributes
58
+
50
59
  n.remove_attribute("id")
51
60
  n.remove_attribute("anchor")
52
61
  end
@@ -70,7 +79,19 @@ module Metanorma
70
79
 
71
80
  def make_bibliography(xml, sect)
72
81
  if xml.at("//sections/references | //xref[@hidden]")
73
- biblio = sect.add_next_sibling("<bibliography/>").first
82
+ # On the FFI-only Moxml lane (no compiled Leptris read layer,
83
+ # e.g. Ruby 4.0), a fragment-parsed wrapper belongs to another
84
+ # document and cross-pool appends drop silently. Create it in
85
+ # the document's own pool there; the native lane handles the
86
+ # fragment path and rejects document-created inserts when
87
+ # combined with later pool operations.
88
+ biblio = if xml.is_a?(Moxml::Document) && !defined?(::Leptris::XML::NativeNode)
89
+ xml.create_element("bibliography").tap do |b|
90
+ sect.add_next_sibling(b)
91
+ end
92
+ else
93
+ sect.add_next_sibling("<bibliography/>").first
94
+ end
74
95
  xml.xpath("//sections/references").each do |r|
75
96
  biblio.add_child r.remove
76
97
  end
@@ -19,7 +19,10 @@ module Metanorma
19
19
  acc << { key: keys[0], type: keys[1],
20
20
  val: span.children.to_xml }
21
21
  (span["class"] == "type" and span.remove) or
22
- span.replace(span.children)
22
+ # moxml's replace accepts a fragment string and preserves text
23
+ # nodes; its add_previous_sibling drops text children, and node
24
+ # moves over a live collection lose the leading ones
25
+ span.replace(span.children.to_xml)
23
26
  end
24
27
 
25
28
  def extract_docid(bib)
@@ -33,7 +33,11 @@ module Metanorma
33
33
  def generate_termdefinitions(xmldoc)
34
34
  xmldoc.xpath("//term[not(definition)]").each do |d|
35
35
  first_child = d.at(TERMDEF_BLOCKS) || next
36
- t = Nokogiri::XML::Element.new("definition", xmldoc)
36
+ t = if xmldoc.respond_to?(:create_element)
37
+ xmldoc.create_element("definition")
38
+ else
39
+ Nokogiri::XML::Element.new("definition", xmldoc)
40
+ end
37
41
  add_id(t)
38
42
  first_child.replace(t)
39
43
  t << first_child.remove
@@ -80,7 +80,9 @@ module Metanorma
80
80
 
81
81
  # "abc<tag/>", def => "abc",<tag/> def
82
82
  def uninterrupt_quotes_around_xml(xmldoc)
83
+ i = 0
83
84
  xmldoc.traverse do |n|
85
+ Metanorma::Utils::GcBudget.gc_when_bloated! if ((i += 1) % 1000).zero?
84
86
  next unless n.text? && n&.previous&.element?
85
87
  next if uninterrupt_quotes_around_xml_skip(n)
86
88
 
@@ -145,7 +147,9 @@ module Metanorma
145
147
 
146
148
  def dumb2smart_quotes(xmldoc)
147
149
  prev = ""
150
+ n = 0
148
151
  xmldoc.traverse do |x|
152
+ Metanorma::Utils::GcBudget.gc_when_bloated! if ((n += 1) % 1000).zero?
149
153
  block?(x) and prev = ""
150
154
  empty_tag_with_text_content?(x) and prev = "dummy"
151
155
  x.text? or next
@@ -164,11 +168,13 @@ module Metanorma
164
168
  end
165
169
 
166
170
  def dumbquote_cleanup(xmldoc)
167
- xmldoc.traverse do |n|
168
- next unless n.text? && n.text.include?("\u2019")
171
+ i = 0
172
+ xmldoc.traverse do |node|
173
+ Metanorma::Utils::GcBudget.gc_when_bloated! if ((i += 1) % 1000).zero?
174
+ next unless node.text? && node.text.include?("\u2019")
169
175
 
170
- n.replace(@c.encode(
171
- @c.decode(n.text)
176
+ node.replace(@c.encode(
177
+ @c.decode(node.text)
172
178
  .gsub(/(?<=\p{Alnum})\u2019(?=\p{Alpha})/, "'"),
173
179
  :basic, :hexadecimal
174
180
  ))
@@ -1,5 +1,6 @@
1
1
  require "date"
2
2
  require "nokogiri"
3
+ require "moxml"
3
4
  require "htmlentities"
4
5
  require "pathname"
5
6
  require "isodoc"
@@ -49,17 +50,27 @@ module Metanorma
49
50
  ret
50
51
  end
51
52
 
52
- def insert_xml_cr(doc)
53
- doc.gsub(%r{(</(clause|table|figure|p|bibitem|ul|ol|dl|dt|dd|li|example|
53
+ # In-place bang passes: the three sequential whole-document
54
+ # substitutions each allocate a full copy of the document string
55
+ # when written with non-bang gsub; on large compiles this phase
56
+ # was a top transient-allocation site. Sequential semantics are
57
+ # preserved exactly (the sourcecode/name collapse relies on the
58
+ # newlines the first two passes insert).
59
+ CLOSE_TAG = %r{(</(clause|table|figure|p|bibitem|ul|ol|dl|dt|dd|li|example|
54
60
  sourcecode|formula|quote|references|annex|appendix|title|name|note|
55
61
  thead|tbody|tfoot|th|td|form|requirement|recommendation|permission|
56
62
  imagemap|svgmap|preferred|admitted|related|domain|deprecates|
57
63
  letter-symbol|graphical-symbol|expression|subject|abbreviation-type|
58
64
  pronunciation|grammar|term|terms|termnote|termexample|source|
59
- origin|termref|modification)>)}x, "\\1\n")
60
- .gsub(%r{(<(title|name))}, "\n\\1")
61
- .gsub(%r{(<sourcecode[^<>]*+>)\s++(<name[^<>]*+>(?>.*?</name>))\s++}m,
62
- "\\1\\2")
65
+ origin|termref|modification)>)}x.freeze
66
+ OPEN_TITLE_NAME = %r{(<(title|name))}.freeze
67
+ SOURCECODE_NAME = %r{(<sourcecode[^<>]*+>)\s++(<name[^<>]*+>(?>.*?</name>))\s++}m.freeze
68
+
69
+ def insert_xml_cr(doc)
70
+ doc.gsub!(CLOSE_TAG, "\\1\n")
71
+ doc.gsub!(OPEN_TITLE_NAME, "\n\\1")
72
+ doc.gsub!(SOURCECODE_NAME, "\\1\\2")
73
+ doc
63
74
  end
64
75
 
65
76
  def version
@@ -69,7 +80,7 @@ module Metanorma
69
80
 
70
81
  def schema_version
71
82
  f = File.read(File.join(File.dirname(__FILE__), "..", "validate",
72
- "isodoc.rng"))
83
+ "standoc.rng"))
73
84
  m = / VERSION (v\S+)/.match(f)
74
85
  m[1]
75
86
  end
@@ -95,17 +106,34 @@ module Metanorma
95
106
  <#{xml_root_tag} type='semantic' version='#{version}' schema-version='#{schema_version}' flavor='#{processor.new.asciidoctor_backend}'>
96
107
  XML
97
108
  noko { |ixml| front node, ixml },
98
- noko { |ixml| middle node, ixml },
109
+ semantic_body(node),
99
110
  "</#{xml_root_tag}>"]
100
- insert_xml_cr(textcleanup(result))
111
+ Metanorma::Utils::GcBudget.gc_when_bloated!
112
+ insert_xml_cr(textcleanup(result)).tap do
113
+ # The assembly passes build three whole-document string
114
+ # copies; collect before the cleanup parse so the budget
115
+ # reflects post-assembly, not mid-string, pressure.
116
+ Metanorma::Utils::GcBudget.gc_when_bloated!
117
+ end
118
+ end
119
+
120
+ def semantic_body(node)
121
+ if sectioned_semantic?(node)
122
+ @sectioned_semantic = true
123
+ middle_sectioned(node)
124
+ else
125
+ noko { |ixml| middle node, ixml }
126
+ end
101
127
  end
102
128
 
103
129
  def makexml(node)
104
130
  result = makexml1(node)
105
131
  ret1 = cleanup(result)
132
+ Metanorma::Utils::GcBudget.gc_when_bloated!
106
133
  unless @novalid || in_isolated_conversion?
107
134
  validate_processor = validate_class.new(self)
108
135
  validate_processor.validate(ret1)
136
+ Metanorma::Utils::GcBudget.gc_when_bloated!
109
137
  @files_to_delete = validate_processor.files_to_delete
110
138
  end
111
139
  ret1
@@ -117,8 +145,16 @@ module Metanorma
117
145
  )
118
146
  end
119
147
 
148
+ def moxml_context
149
+ @moxml_context ||= Moxml.new(:leptris)
150
+ end
151
+
120
152
  def cleanup(result)
121
- ret1 = Nokogiri::XML(result)
153
+ ret1 = if @sectioned_semantic
154
+ moxml_context.parse(result)
155
+ else
156
+ Nokogiri::XML(result)
157
+ end
122
158
  @nocleanup and return ret1
123
159
  cleanup_processor = cleanup_class.new(self)
124
160
  ret1 = cleanup_processor.cleanup(ret1)
@@ -161,6 +197,26 @@ module Metanorma
161
197
  end
162
198
  end
163
199
 
200
+ # `:sectioned-semantic:` assembles <sections> through the leptris
201
+ # engine (moxml) instead of the classic whole-document Nokogiri
202
+ # fragment; falls back when middle() is overridden by a flavor
203
+ def sectioned_semantic?(node)
204
+ !node.attr("sectioned-semantic").nil? &&
205
+ method(:middle).owner == Metanorma::Standoc::Base
206
+ end
207
+
208
+ # node.content is already fully serialized per section; a single
209
+ # parse into a lean leptris DOM replaces the classic
210
+ # parse+serialize round trip. The doc wrapper is held while
211
+ # serializing: it owns the native tree via a GC finalizer.
212
+ def middle_sectioned(node)
213
+ return "<sections/>" unless node.blocks?
214
+
215
+ context = Moxml.new(:leptris)
216
+ doc = context.parse("<sections>#{node.content}</sections>")
217
+ doc.root.to_xml(indent: 0)
218
+ end
219
+
164
220
  def metadata_attrs(node)
165
221
  out = node.attributes.each_with_object([]) do |(k, v), ret|
166
222
  %w(presentation semantic).each do |t|
@@ -23,9 +23,14 @@ module Metanorma
23
23
  class Converter
24
24
  Asciidoctor::Extensions.register do
25
25
  preprocessor Metanorma::Standoc::ResolveIncludePreprocessor
26
+ treeprocessor Metanorma::Plugin::Asciichem::Extension::ChemTreeprocessor
27
+ inline_macro Metanorma::Plugin::Asciichem::Extension::ChemInlineMacro, :chem
28
+ preprocessor Metanorma::Plugin::Lutaml::LutamlDataPreprocessor
29
+ preprocessor Metanorma::Plugin::Lutaml::LutamlXsdPreprocessor
26
30
  preprocessor Metanorma::Plugin::Lutaml::LutamlPreprocessor
27
31
  preprocessor Metanorma::Plugin::Lutaml::LutamlUmlDatamodelDescriptionPreprocessor
28
32
  preprocessor Metanorma::Plugin::Lutaml::LutamlEaXmiPreprocessor
33
+ preprocessor Metanorma::Plugin::Lutaml::XmiPartialLoadPreprocessor
29
34
  inline_macro Metanorma::Plugin::Lutaml::LutamlFigureInlineMacro
30
35
  inline_macro Metanorma::Plugin::Lutaml::LutamlTableInlineMacro
31
36
  block_macro Metanorma::Plugin::Lutaml::LutamlDiagramBlockMacro
@@ -164,13 +164,39 @@ module Metanorma
164
164
  id = doc.split(/,\s*/)
165
165
  xml.relation type: relation_normalise(type) do |r|
166
166
  desc.nil? or r.description desc.tr("-", " ")
167
- fetch_ref(r, doc, nil, **{}) or r.bibitem do |b|
167
+ relation_fetch_ref(r, doc) or r.bibitem do |b|
168
168
  add_noko_elem(b, "title", id[1] || "--")
169
169
  add_noko_elem(b, "docidentifier", id[0])
170
170
  end
171
171
  end
172
172
  end
173
173
 
174
+ # A relation described in document attributes is free text, not a
175
+ # normative citation: an unrecognized identifier logs and falls back to
176
+ # the plain bibitem instead of aborting metadata processing.
177
+ #
178
+ # The errors an unresolvable relation reference raises depend on the
179
+ # relaton/pubid generation in the bundle: newer relaton raises
180
+ # Relaton::UnknownReferenceError on strict routing (relaton#243),
181
+ # older ones surface the same condition as Pubid::Errors::ParseError
182
+ # when the free text is not a parseable identifier. Resolving the
183
+ # error set dynamically also keeps the rescue clause itself from
184
+ # raising NameError on bundles where a class is absent — which
185
+ # masked the real error and aborted the conversion.
186
+ def relation_fetch_ref(relation, doc)
187
+ fetch_ref(relation, doc, nil, **{})
188
+ rescue *unresolved_reference_errors
189
+ @log.add("STANDOC_40", nil, params: [doc])
190
+ nil
191
+ end
192
+
193
+ def unresolved_reference_errors
194
+ [
195
+ (Relaton::UnknownReferenceError if defined?(Relaton::UnknownReferenceError)),
196
+ (Pubid::Errors::ParseError if defined?(Pubid::Errors::ParseError)),
197
+ ].compact
198
+ end
199
+
174
200
  def metadata_keywords(node, xml)
175
201
  node.attr("keywords") or return
176
202
  node.attr("keywords").split(/,\s*/).each do |kw|
@@ -9,6 +9,7 @@ require_relative "macros_embed"
9
9
  require_relative "macros_link"
10
10
  require_relative "macros_nosub"
11
11
  require_relative "macros_number"
12
+ require "metanorma-plugin-asciichem"
12
13
  require "metanorma-plugin-glossarist"
13
14
  require "metanorma-plugin-lutaml"
14
15
  require "metanorma-plugin-plantuml"
@@ -17,18 +17,28 @@ module Metanorma
17
17
  PASS_INLINE_MACROS = %w(pass pass-format identifier std-link stem)
18
18
  .join("|").freeze
19
19
 
20
+ # NOTE: the pattern deliberately carries no /x-mode comments —
21
+ # TruffleRuby's TRegex parser rejects this pattern whenever any /x
22
+ # comment is present ("missing ), unterminated subpattern",
23
+ # https://github.com/truffleruby/truffleruby/issues/4435). /x strips
24
+ # comments and layout whitespace before parsing, so this spelling
25
+ # compiles to the identical regex on every engine. Anatomy, for the
26
+ # reader:
27
+ # \b(?<![-\\]) word separator, no hyphen/backslash
28
+ # (?:(?:MACROS):[^\s\[]* | span: [^\s\[]*)
29
+ # macro name + second key, OR any span: macro (e.g. span:uri,
30
+ # span:note.display): protect its bracketed content from
31
+ # URL/link rewriting so an injected link:[] cannot close the
32
+ # span early
33
+ # \[.*?(?<!\\)\] [...] not preceded by backslash
20
34
  PASS_INLINE_MACRO_STR = <<~REGEX.freeze
21
35
  (
22
- \\b(?<![-\\\\]) # word-separator, no hyphen or backslash
23
- (?: # don't capture these!
24
- (?:#{PASS_INLINE_MACROS}):[^\\s\\[]* | # macro name, :, second key. OR:
25
- span: [^\\s\\[]* # any span: macro (e.g. span:uri,
26
- # span:note.display): protect its
27
- # bracketed content from URL/link
28
- # rewriting so an injected link:[]
29
- # can't close the span early
36
+ \\b(?<![-\\\\])
37
+ (?:
38
+ (?:#{PASS_INLINE_MACROS}):[^\\s\\[]* |
39
+ span: [^\\s\\[]*
30
40
  )
31
- \\[.*?(?<!\\\\)\\] # [ ... ] not preceded by \\
41
+ \\[.*?(?<!\\\\)\\]
32
42
  )
33
43
  REGEX
34
44
  PASS_INLINE_MACRO_RX = /#{PASS_INLINE_MACRO_STR}/xo
@@ -128,18 +138,28 @@ module Metanorma
128
138
  PASS_INLINE_MACROS = %w(pass pass-format identifier std-link stem)
129
139
  .join("|").freeze
130
140
 
141
+ # NOTE: the pattern deliberately carries no /x-mode comments —
142
+ # TruffleRuby's TRegex parser rejects this pattern whenever any /x
143
+ # comment is present ("missing ), unterminated subpattern",
144
+ # https://github.com/truffleruby/truffleruby/issues/4435). /x strips
145
+ # comments and layout whitespace before parsing, so this spelling
146
+ # compiles to the identical regex on every engine. Anatomy, for the
147
+ # reader:
148
+ # \b(?<![-\\]) word separator, no hyphen/backslash
149
+ # (?:(?:MACROS):[^\s\[]* | span: [^\s\[]*)
150
+ # macro name + second key, OR any span: macro (e.g. span:uri,
151
+ # span:note.display): protect its bracketed content from
152
+ # URL/link rewriting so an injected link:[] cannot close the
153
+ # span early
154
+ # \[.*?(?<!\\)\] [...] not preceded by backslash
131
155
  PASS_INLINE_MACRO_STR = <<~REGEX.freeze
132
156
  (
133
- \\b(?<![-\\\\]) # word-separator, no hyphen or backslash
134
- (?: # don't capture these!
135
- (?:#{PASS_INLINE_MACROS}):[^\\s\\[]* | # macro name, :, second key. OR:
136
- span: [^\\s\\[]* # any span: macro (e.g. span:uri,
137
- # span:note.display): protect its
138
- # bracketed content from URL/link
139
- # rewriting so an injected link:[]
140
- # can't close the span early
157
+ \\b(?<![-\\\\])
158
+ (?:
159
+ (?:#{PASS_INLINE_MACROS}):[^\\s\\[]* |
160
+ span: [^\\s\\[]*
141
161
  )
142
- \\[.*?(?<!\\\\)\\] # [ ... ] not preceded by \\
162
+ \\[.*?(?<!\\\\)\\]
143
163
  )
144
164
  REGEX
145
165
  PASS_INLINE_MACRO_RX = /#{PASS_INLINE_MACRO_STR}/xo
@@ -84,8 +84,14 @@ module Metanorma
84
84
  end
85
85
 
86
86
  def to_xml(node)
87
- node.to_xml(encoding: "UTF-8", indent: 2,
88
- save_with: Nokogiri::XML::Node::SaveOptions::AS_XML)
87
+ if defined?(Moxml::Document) && node.is_a?(Moxml::Document)
88
+ # expand_empty: false — self-close empty elements, matching
89
+ # the Nokogiri AS_XML output the classic pipeline emits
90
+ node.to_xml(encoding: "UTF-8", indent: 2, expand_empty: false)
91
+ else
92
+ node.to_xml(encoding: "UTF-8", indent: 2,
93
+ save_with: Nokogiri::XML::Node::SaveOptions::AS_XML)
94
+ end
89
95
  end
90
96
 
91
97
  SUBCLAUSE_XPATH = "//clause[not(parent::sections)]" \