metanorma 2.1.4 → 2.5.4

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +23 -2
  3. data/Gemfile +14 -0
  4. data/README.adoc +1 -1
  5. data/lib/metanorma/collection/artifact_store.rb +142 -0
  6. data/lib/metanorma/collection/collection.rb +140 -131
  7. data/lib/metanorma/collection/config/bibdata.rb +1 -1
  8. data/lib/metanorma/collection/config/config.rb +50 -20
  9. data/lib/metanorma/collection/config/converters.rb +89 -31
  10. data/lib/metanorma/collection/config/doc_container.rb +28 -0
  11. data/lib/metanorma/collection/config/manifest.rb +30 -6
  12. data/lib/metanorma/collection/config/namespaces.rb +12 -0
  13. data/lib/metanorma/collection/document/document.rb +54 -15
  14. data/lib/metanorma/collection/filelookup/filelookup.rb +170 -74
  15. data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +62 -27
  16. data/lib/metanorma/collection/filelookup/utils.rb +52 -0
  17. data/lib/metanorma/collection/helpers.rb +82 -0
  18. data/lib/metanorma/collection/log.rb +24 -0
  19. data/lib/metanorma/collection/manifest/manifest.rb +27 -14
  20. data/lib/metanorma/collection/multilingual/multilingual.rb +1 -1
  21. data/lib/metanorma/collection/renderer/filelocation.rb +166 -0
  22. data/lib/metanorma/collection/renderer/fileparse.rb +60 -55
  23. data/lib/metanorma/collection/renderer/fileprocess.rb +184 -40
  24. data/lib/metanorma/collection/renderer/navigation.rb +20 -6
  25. data/lib/metanorma/collection/renderer/render_word.rb +8 -4
  26. data/lib/metanorma/collection/renderer/renderer.rb +202 -19
  27. data/lib/metanorma/collection/renderer/svg.rb +60 -5
  28. data/lib/metanorma/collection/renderer/utils.rb +76 -42
  29. data/lib/metanorma/collection/sectionsplit/collection.rb +14 -4
  30. data/lib/metanorma/collection/sectionsplit/sectionsplit.rb +141 -61
  31. data/lib/metanorma/collection/util/disambig_files.rb +4 -5
  32. data/lib/metanorma/collection/util/util.rb +147 -23
  33. data/lib/metanorma/collection/xrefprocess/xrefprocess.rb +7 -7
  34. data/lib/metanorma/compile/assets/icc-boilerplate.adoc +41 -0
  35. data/lib/metanorma/compile/compile.rb +180 -165
  36. data/lib/metanorma/compile/compile_options.rb +155 -83
  37. data/lib/metanorma/compile/extract.rb +76 -56
  38. data/lib/metanorma/compile/flavor.rb +19 -0
  39. data/lib/metanorma/compile/output_filename.rb +75 -0
  40. data/lib/metanorma/compile/output_filename_config.rb +27 -0
  41. data/lib/metanorma/compile/relaton_drop.rb +56 -0
  42. data/lib/metanorma/compile/render.rb +196 -0
  43. data/lib/metanorma/compile/validator.rb +26 -0
  44. data/lib/metanorma/compile/writeable.rb +12 -0
  45. data/lib/metanorma/util/fontist_helper.rb +35 -19
  46. data/lib/metanorma/version.rb +1 -1
  47. data/lib/metanorma.rb +1 -7
  48. data/metanorma.gemspec +11 -20
  49. data/plans/collection-rendering-architecture-review.md +516 -0
  50. metadata +42 -122
  51. data/.hound.yml +0 -5
  52. data/lib/metanorma/asciidoctor_extensions/glob_include_processor.rb +0 -22
  53. data/lib/metanorma/asciidoctor_extensions.rb +0 -1
  54. data/lib/metanorma/compile/compile_validate.rb +0 -68
  55. data/lib/metanorma/config/config.rb +0 -23
  56. data/lib/metanorma/input/asciidoc.rb +0 -88
  57. data/lib/metanorma/input/base.rb +0 -9
  58. data/lib/metanorma/input.rb +0 -7
  59. data/lib/metanorma/processor/processor.rb +0 -54
  60. data/lib/metanorma/processor.rb +0 -6
  61. data/lib/metanorma/registry/registry.rb +0 -63
  62. data/lib/metanorma/util/util.rb +0 -45
@@ -5,12 +5,14 @@ require_relative "converters"
5
5
  require_relative "bibdata"
6
6
  require_relative "directive"
7
7
  require_relative "manifest"
8
+ require_relative "namespaces"
9
+ require_relative "doc_container"
8
10
 
9
11
  module Metanorma
10
12
  class Collection
11
13
  module Config
12
14
  Lutaml::Model::Config.configure do |config|
13
- config.xml_adapter = Lutaml::Model::XmlAdapter::NokogiriAdapter
15
+ config.xml_adapter_type = :nokogiri
14
16
  end
15
17
 
16
18
  class Config < ::Lutaml::Model::Serializable
@@ -20,12 +22,13 @@ module Metanorma
20
22
  attribute :directive, Directive, collection: true
21
23
  attribute :manifest, Manifest
22
24
  attribute :coverpage, :string, default: -> { "cover.html" }
25
+ attribute :coverpage_pdf_portfolio, :string
23
26
  attribute :format, :string, collection: true, default: -> { [:html] }
24
27
  attribute :output_folder, :string
25
28
  attribute :compile, CompileOptions
26
29
  attribute :prefatory_content, :string, raw: true
27
30
  attribute :final_content, :string, raw: true
28
- attribute :documents, Bibdata, collection: true
31
+ attribute :documents, DocContainer, collection: true
29
32
  attribute :xmlns, :string, default: -> { "http://metanorma.org" }
30
33
 
31
34
  yaml do
@@ -34,18 +37,21 @@ module Metanorma
34
37
  map "bibdata", to: :bibdata, with: { from: :bibdata_from_yaml,
35
38
  to: :bibdata_to_yaml }
36
39
  map "manifest", to: :manifest
40
+ map "entry", to: :manifest, with: { from: :entry_from_yaml,
41
+ to: :nop_to_yaml }
37
42
  map "format", to: :format, render_default: true
38
43
  map "output_folder", to: :output_folder
39
44
  map "coverpage", to: :coverpage, render_default: true
45
+ map "coverpage-pdf-portfolio", to: :coverpage_pdf_portfolio,
46
+ render_default: true
40
47
  map "compile", to: :compile, render_default: true
41
48
  map "prefatory-content", to: :prefatory_content
42
49
  map "final-content", to: :final_content
43
50
  end
44
51
 
45
52
  xml do
46
- root "metanorma-collection"
47
- # namespace "http://metanorma.org", "m"
48
- # map_attribute "xmlns", to: :xmlns
53
+ element "metanorma-collection"
54
+ namespace MetanormaCollectionNamespace
49
55
  map_element "bibdata", to: :bibdata, with: { from: :bibdata_from_xml,
50
56
  to: :bibdata_to_xml }
51
57
  map_element "directive", to: :directive
@@ -54,15 +60,14 @@ module Metanorma
54
60
  map_element "format", to: :format, render_default: true
55
61
  map_element "output_folder", to: :output_folder
56
62
  map_element "coverpage", to: :coverpage, render_default: true
63
+ map_element "coverpage-pdf-portfolio", to: :coverpage_pdf_portfolio,
64
+ render_default: true
57
65
  map_element "compile", to: :compile, render_default: true
58
66
  map_element "prefatory-content",
59
67
  to: :prefatory_content,
60
68
  with: { from: :prefatory_from_xml,
61
69
  to: :prefatory_to_xml }
62
- map_element "doc-container",
63
- to: :documents,
64
- with: { from: :documents_from_xml,
65
- to: :documents_to_xml }
70
+ map_element "doc-container", to: :documents
66
71
  map_element "final-content",
67
72
  to: :final_content,
68
73
  with: { from: :final_from_xml,
@@ -73,9 +78,9 @@ module Metanorma
73
78
  model.manifest = Manifest.from_xml(node.to_xml)
74
79
  end
75
80
 
76
- def manifest_to_xml(model, parent, doc)
81
+ def manifest_to_xml(model, _parent, doc)
77
82
  model.collection&.manifest&.clean_manifest(model.manifest)
78
- doc.add_element(parent, model.manifest.to_xml)
83
+ add_raw_xml_element(doc, model.manifest.to_xml)
79
84
  end
80
85
 
81
86
  def prefatory_from_xml(model, node)
@@ -90,17 +95,17 @@ module Metanorma
90
95
  content_to_xml(model, parent, doc, "final")
91
96
  end
92
97
 
93
- def content_to_xml(model, parent, doc, type)
98
+ def content_to_xml(model, _parent, doc, type)
94
99
  x = model.send("#{type}_content") or return
95
100
  n = Nokogiri::XML(x)
96
- elem = if n.elements.size == 1
97
- "<#{type}-content>#{x}</#{type}-content>" # n.root
98
- else
99
- b = Nokogiri::XML::Builder.new
100
- model.collection.content_to_xml(type, b)
101
- b.parent.elements.first
102
- end
103
- doc.add_element(parent, elem)
101
+ raw = if n.elements.size == 1
102
+ "<#{type}-content>#{x}</#{type}-content>"
103
+ else
104
+ b = Nokogiri::XML::Builder.new
105
+ model.collection.content_to_xml(type, b)
106
+ b.parent.elements.first.to_xml
107
+ end
108
+ add_raw_xml_element(doc, raw)
104
109
  end
105
110
 
106
111
  def final_from_xml(model, node)
@@ -124,6 +129,31 @@ module Metanorma
124
129
  end
125
130
  end
126
131
 
132
+ def entry_from_yaml(model, value)
133
+ model.manifest ||= value
134
+ end
135
+
136
+ def self.flavor_from_yaml(yaml)
137
+ yaml["directives"]&.detect do |x|
138
+ x.is_a?(Hash) && x.has_key?("flavor")
139
+ end&.dig("flavor")&.upcase
140
+ end
141
+
142
+ def self.flavor_to_bibdata(file)
143
+ # propagate flavor from directives to bibdata
144
+ yaml = YAML.safe_load(file)
145
+ flavor = flavor_from_yaml(yaml) or return file
146
+ yaml["bibdata"] or return file
147
+ yaml["bibdata"]["ext"] ||= {}
148
+ yaml["bibdata"]["ext"]["flavor"] ||= flavor
149
+ yaml.to_yaml
150
+ end
151
+
152
+ def self.from_yaml(file)
153
+ file = flavor_to_bibdata(file)
154
+ super
155
+ end
156
+
127
157
  include Converters
128
158
  end
129
159
  end
@@ -1,54 +1,112 @@
1
- require "relaton-cli"
1
+ require "relaton/bib"
2
+ require "relaton/bib/hash_parser_v1"
3
+ require_relative "namespaces"
2
4
 
3
5
  module Metanorma
4
6
  class Collection
5
7
  module Config
6
8
  module Converters
9
+ # Keys present only in 1.x YAML format — unambiguously absent in 2.x
10
+ V1_BIBDATA_KEYS = %w[docid link biblionote].freeze
11
+
7
12
  def bibdata_from_yaml(model, value)
8
- value and !value.empty? or return
9
- model.bibdata = Relaton::Cli::YAMLConvertor.convert_single_file(value)
13
+ (value and !value.empty?) or return
14
+ if value.is_a?(String)
15
+ value = YAML.safe_load_file(value,
16
+ permitted_classes: [Date,
17
+ Symbol])
18
+ end
19
+ force_primary_docidentifier_yaml(value)
20
+ model.bibdata = if bibdata_yaml_v1_format?(value)
21
+ # 1.x YAML format (docid:/link:/biblionote: present) —
22
+ # bridge via HashParserV1 for backward compatibility
23
+ h = Relaton::Bib::HashParserV1.hash_to_bib(value)
24
+ Relaton::Bib::ItemData.new(**h)
25
+ else
26
+ # 2.x YAML format (docidentifier:/uri:/note: keys) —
27
+ # parse directly with lutaml-model
28
+ Relaton::Bib::Item.from_yaml(value.to_yaml)
29
+ end
10
30
  end
11
31
 
12
- def bibdata_to_yaml(model, doc)
13
- doc["bibdata"] = model.bibdata&.to_hash
32
+ # Recursively detect 1.x-format YAML by presence of renamed keys.
33
+ # Checks the entire nested structure so relation:/contributor: entries
34
+ # are also detected.
35
+ def bibdata_yaml_v1_format?(obj)
36
+ case obj
37
+ when Hash
38
+ return true if (obj.keys.map(&:to_s) & V1_BIBDATA_KEYS).any?
39
+
40
+ obj.values.any? { |v| bibdata_yaml_v1_format?(v) }
41
+ when Array
42
+ obj.any? { |v| bibdata_yaml_v1_format?(v) }
43
+ else
44
+ false
45
+ end
14
46
  end
15
47
 
16
- def bibdata_from_xml(model, node)
17
- node and
18
- model.bibdata = Relaton::Cli.parse_xml(node.adapter_node)
48
+ def force_primary_docidentifier_yaml(value)
49
+ case value["docid"]
50
+ when Array
51
+ value["docid"].empty? ||
52
+ value["docid"].none? do |x|
53
+ x["primary"] == "true"
54
+ end or
55
+ value["docid"].first["primary"] = "true"
56
+ when Hash
57
+ value["docid"]["primary"] ||= "true"
58
+ end
19
59
  end
20
60
 
21
- def bibdata_to_xml(model, parent, doc)
22
- b = model.bibdata or return
23
- elem = b.to_xml(bibdata: true, date_format: :full)
24
- doc.add_element(parent, elem)
61
+ def bibdata_to_yaml(model, doc)
62
+ return unless model.bibdata
63
+
64
+ doc["bibdata"] = YAML.safe_load(model.bibdata.to_yaml,
65
+ permitted_classes: [Date, Symbol])
25
66
  end
26
67
 
27
- def nop_to_yaml(model, doc); end
68
+ def bibdata_from_xml(model, node)
69
+ node or return
70
+ force_primary_docidentifier_xml(node.adapter_node.native)
71
+ model.bibdata = Relaton::Cli.parse_xml(node.adapter_node.native)
72
+ end
28
73
 
29
- def documents_from_xml(model, value)
30
- model.documents = value
31
- .each_with_object([]) do |b, m|
32
- m << b
33
- end
74
+ def force_primary_docidentifier_xml(node)
75
+ node.at("//docidentifier[@primary = 'true']") and return node
76
+ d = node.at("//docidentifier") or return node
77
+ d["primary"] = "true"
34
78
  end
35
79
 
36
- def documents_to_xml(model, parent, doc)
37
- documents_to_xml?(doc) or return
38
- b = Nokogiri::XML::Builder.new do |xml|
39
- xml.document do |m|
40
- model.collection.doccontainer(m) or return
41
- end
42
- end
43
- b.parent.elements.first.elements
44
- .each { |x| doc.add_element(parent, x) }
80
+ def bibdata_to_xml(model, _parent, doc)
81
+ b = model.bibdata or return
82
+ add_raw_xml_element(doc, b.to_xml(bibdata: true, date_format: :full))
45
83
  end
46
84
 
47
- def documents_to_xml?(doc)
48
- ret = doc.parent.elements.detect do |x|
49
- x.name == "doc-container"
85
+ def nop_to_yaml(model, doc); end
86
+ def nop_to_xml(model, parent, doc); end
87
+
88
+ # Add a single-element XML string as a child of the wrapper's current
89
+ # context, preserving inline namespace declarations.
90
+ #
91
+ # The custom-method `doc.add_element(parent, str)` path under
92
+ # lutaml-model 0.8 routes through Moxml fragment parsing, whose graft
93
+ # (`CustomMethodWrapper#add_fragment_children_to_parent`) discards
94
+ # xmlns declarations on grafted DataModel children. The
95
+ # `create_and_add_element` + `raw_content` path goes through the XML
96
+ # adapter's raw-content handler, which uses Nokogiri's native fragment
97
+ # parser and keeps xmlns intact. Tag the new element with
98
+ # MetanormaCollectionNamespace so it inherits cleanly from the
99
+ # metanorma-collection root rather than emitting `xmlns=""`.
100
+ def add_raw_xml_element(doc, raw)
101
+ parsed = Nokogiri::XML.fragment(raw)
102
+ src = parsed.elements.first or return
103
+ el = doc.create_and_add_element(src.name)
104
+ el.namespace_class = MetanormaCollectionNamespace
105
+ src.attribute_nodes.each do |a|
106
+ doc.add_attribute(el, a.name, a.value)
50
107
  end
51
- !ret
108
+ el.raw_content = src.children.map(&:to_xml).join
109
+ el
52
110
  end
53
111
  end
54
112
  end
@@ -0,0 +1,28 @@
1
+ require "lutaml/model"
2
+ require_relative "namespaces"
3
+
4
+ module Metanorma
5
+ class Collection
6
+ module Config
7
+ # Serializable wrapper for a single <doc-container> element.
8
+ #
9
+ # The body of a doc-container is the inline presentation XML of an
10
+ # individual document, in a flavour-specific namespace (e.g. bipm,
11
+ # iso, ietf). We round-trip it as an opaque string via `map_all`
12
+ # so the underlying XML adapter (Nokogiri) preserves the inner xmlns
13
+ # declaration; if we let lutaml-model parse the body into typed
14
+ # children it would lose the inner namespace.
15
+ class DocContainer < ::Lutaml::Model::Serializable
16
+ attribute :id, :string
17
+ attribute :content, :string
18
+
19
+ xml do
20
+ element "doc-container"
21
+ namespace MetanormaCollectionNamespace
22
+ map_attribute "id", to: :id
23
+ map_all to: :content
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,5 +1,4 @@
1
1
  require "lutaml/model"
2
- require "lutaml/model/xml_adapter/nokogiri_adapter"
3
2
  require_relative "../../array_monkeypatch"
4
3
  require_relative "converters"
5
4
  require_relative "bibdata"
@@ -8,12 +7,12 @@ module Metanorma
8
7
  class Collection
9
8
  module Config
10
9
  Lutaml::Model::Config.configure do |config|
11
- config.xml_adapter = Lutaml::Model::XmlAdapter::NokogiriAdapter
10
+ config.xml_adapter_type = :nokogiri
12
11
  end
13
12
 
14
13
  class Manifest < ::Lutaml::Model::Serializable
15
14
  attribute :identifier, :string,
16
- default: -> { UUIDTools::UUID.random_create.to_s }
15
+ default: -> { UUIDTools::UUID.random_create.to_s }
17
16
  attribute :id, :string
18
17
  attribute :bibdata, Bibdata
19
18
  attribute :type, :string
@@ -25,9 +24,15 @@ module Metanorma
25
24
  attribute :index, :boolean, default: -> { true }
26
25
  attribute :entry, Manifest, collection: true
27
26
  attribute :file, :string
27
+ attribute :pdffile, :string
28
+ attribute :format, :string, collection: true
29
+ attribute :output_filename, :string
30
+ attribute :sectionsplit_filename, :string
31
+ attribute :sectionsplit_output, :boolean
28
32
 
29
33
  yaml do
30
34
  map "identifier", to: :identifier
35
+ map "pdf-file", to: :pdffile
31
36
  map "type", to: :type
32
37
  map "level", to: :level,
33
38
  with: { from: :level_from_yaml, to: :nop_to_yaml }
@@ -46,6 +51,10 @@ module Metanorma
46
51
  with: { from: :docref_from_yaml, to: :nop_to_yaml }
47
52
  map "bibdata", to: :bibdata, with: { from: :bibdata_from_yaml,
48
53
  to: :bibdata_to_yaml }
54
+ map "format", to: :format, render_default: true
55
+ map "output-filename", to: :output_filename
56
+ map "sectionsplit-filename", to: :sectionsplit_filename
57
+ map "sectionsplit-output", to: :sectionsplit_output
49
58
  end
50
59
 
51
60
  xml do
@@ -55,26 +64,41 @@ module Metanorma
55
64
  map_attribute "sectionsplit", to: :sectionsplit
56
65
  map_attribute "index", to: :index
57
66
  map_attribute "url", to: :url
67
+ map_attribute "pdf-file", to: :pdffile
58
68
  map_attribute "fileref", to: :file
59
69
  map_element "identifier", to: :identifier, render_default: true
60
70
  map_element "type", to: :type
61
71
  map_element "title", to: :title
72
+ map_element "format", to: :format
62
73
  map_element "bibdata", to: :bibdata, with: { from: :bibdata_from_xml,
63
74
  to: :bibdata_to_xml }
64
75
  map_element "entry", to: :entry
76
+ map_element "output-filename", to: :output_filename,
77
+ with: { from: :output_filename_from_xml,
78
+ to: :nop_to_xml }
79
+ map_element "sectionsplit-filename", to: :sectionsplit_filename,
80
+ with: { from: :sectionsplit_filename_from_xml,
81
+ to: :nop_to_xml }
65
82
  end
66
83
 
67
84
  def entry_from_xml(model, node)
68
85
  model.entry = Manifest.from_xml(node.node.to_xml)
69
86
  end
70
87
 
71
- def entry_to_xml(model, parent, doc)
88
+ def entry_to_xml(model, _parent, doc)
72
89
  Array(model.entry).each do |e|
73
- elem = e.to_xml
74
- doc.add_element(parent, elem)
90
+ add_raw_xml_element(doc, e.to_xml)
75
91
  end
76
92
  end
77
93
 
94
+ def output_filename_from_xml(model, node)
95
+ model.output_filename ||= node.content
96
+ end
97
+
98
+ def sectionsplit_filename_from_xml(model, node)
99
+ model.sectionsplit_filename ||= node.content
100
+ end
101
+
78
102
  def level_from_yaml(model, value)
79
103
  model.type ||= value
80
104
  end
@@ -0,0 +1,12 @@
1
+ require "lutaml/xml"
2
+
3
+ module Metanorma
4
+ class Collection
5
+ module Config
6
+ class MetanormaCollectionNamespace < ::Lutaml::Xml::Namespace
7
+ uri "http://metanorma.org"
8
+ element_form_default :qualified
9
+ end
10
+ end
11
+ end
12
+ end
@@ -48,26 +48,65 @@ module Metanorma
48
48
 
49
49
  private
50
50
 
51
+ # Select the appropriate Relaton parser class for the given flavor tag.
52
+ # Uses the flavor's Item class (not Bibdata) because in Relaton 2.x,
53
+ # Bibdata.from_xml produces a generic Relaton::Bib::ItemData instance
54
+ # (due to BibdataShared resolving `model ItemData` in the definer's scope),
55
+ # while Item.from_xml correctly produces a flavor-specific ItemData instance.
56
+ # @param tag [String, nil] flavor tag (e.g. "iso", "ietf")
57
+ # @return [Class] Relaton Item parser class
51
58
  def mn2relaton_parser(tag)
52
- case tag.sub(/-standard/, "")
53
- when "bipm" then ::RelatonBipm::XMLParser
54
- when "bsi" then ::RelatonBsi::XMLParser
55
- when "ietf" then ::RelatonIetf::XMLParser
56
- when "iho" then ::RelatonIho::XMLParser
57
- when "itu" then ::RelatonItu::XMLParser
58
- when "iec" then ::RelatonIec::XMLParser
59
- when "iso" then ::RelatonIsoBib::XMLParser
60
- when "nist" then ::RelatonNist::XMLParser
61
- when "ogc" then ::RelatonOgc::XMLParser
62
- else ::RelatonBib::XMLParser
59
+ case tag
60
+ when "bipm"
61
+ require "relaton/bipm" unless defined?(::Relaton::Bipm::Item)
62
+ ::Relaton::Bipm::Item
63
+ when "bsi"
64
+ require "relaton/bsi" unless defined?(::Relaton::Bsi::Item)
65
+ ::Relaton::Bsi::Item
66
+ when "ietf"
67
+ require "relaton/ietf" unless defined?(::Relaton::Ietf::Item)
68
+ ::Relaton::Ietf::Item
69
+ when "iho"
70
+ require "relaton/iho" unless defined?(::Relaton::Iho::Item)
71
+ ::Relaton::Iho::Item
72
+ when "itu"
73
+ require "relaton/itu" unless defined?(::Relaton::Itu::Item)
74
+ ::Relaton::Itu::Item
75
+ when "iec"
76
+ require "relaton/iec" unless defined?(::Relaton::Iec::Item)
77
+ ::Relaton::Iec::Item
78
+ when "iso"
79
+ require "relaton/iso" unless defined?(::Relaton::Iso::Item)
80
+ ::Relaton::Iso::Item
81
+ when "nist"
82
+ require "relaton/nist" unless defined?(::Relaton::Nist::Item)
83
+ ::Relaton::Nist::Item
84
+ when "ogc"
85
+ require "relaton/ogc" unless defined?(::Relaton::Ogc::Item)
86
+ ::Relaton::Ogc::Item
87
+ else
88
+ ::Relaton::Bib::Item
63
89
  end
90
+ rescue LoadError => e
91
+ warn "Warning: Failed to load relaton gem for '#{tag}': #{e.message}. Falling back to Relaton::Bib::Item"
92
+ ::Relaton::Bib::Item
64
93
  end
65
94
 
66
95
  # #param xml [Nokogiri::XML::Document, Nokogiri::XML::Element]
67
96
  # @return [RelatonBib::BibliographicItem,RelatonIso::IsoBibliographicItem]
68
97
  def from_xml(xml)
69
98
  b = xml.at("//xmlns:bibitem|//xmlns:bibdata")
70
- r = mn2relaton_parser(xml.root.name)
99
+ # <bibitem> elements are always flavor-independent: use the base
100
+ # Relaton::Bib::Bibitem regardless of collection flavor.
101
+ # <bibdata> elements carry flavor-specific metadata (<ext> etc.) and
102
+ # must be parsed with the appropriate flavor Bibdata class.
103
+ r = if b.name == "bibitem"
104
+ ::Relaton::Bib::Bibitem
105
+ else
106
+ mn2relaton_parser(xml.root["flavor"])
107
+ end
108
+ # Relaton doesn't understand Pres XML tags
109
+ b.xpath("//xmlns:fmt-identifier").each(&:remove)
71
110
  r.from_xml(b.to_xml)
72
111
  end
73
112
 
@@ -113,9 +152,9 @@ module Metanorma
113
152
 
114
153
  # @return [String]
115
154
  def type
116
- first = @bibitem.docidentifier.first
155
+ first = @bibitem.docidentifier&.first
117
156
  @type ||= (first&.type&.downcase ||
118
- first&.id&.match(/^[^\s]+/)&.to_s)&.downcase ||
157
+ first&.content&.match(/^[^\s]+/)&.to_s)&.downcase ||
119
158
  "standoc"
120
159
  end
121
160
 
@@ -125,7 +164,7 @@ module Metanorma
125
164
  if @raw
126
165
  builder.parent.add_child(@bibitem.root)
127
166
  else
128
- builder.send("#{type}-standard") do |b|
167
+ builder.send(:metanorma) do |b|
129
168
  b << @bibitem.to_xml(bibdata: true)
130
169
  end
131
170
  end