metanorma 2.0.0 → 2.5.5
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.
- checksums.yaml +4 -4
- data/.envrc +1 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +23 -2
- data/Gemfile +17 -0
- data/Gemfile.devel +10 -0
- data/README.adoc +1 -1
- data/lib/metanorma/collection/artifact_store.rb +142 -0
- data/lib/metanorma/collection/collection.rb +160 -122
- data/lib/metanorma/collection/config/bibdata.rb +3 -3
- data/lib/metanorma/collection/config/compile_options.rb +4 -5
- data/lib/metanorma/collection/config/config.rb +81 -83
- data/lib/metanorma/collection/config/converters.rb +92 -8
- data/lib/metanorma/collection/config/directive.rb +9 -3
- data/lib/metanorma/collection/config/doc_container.rb +28 -0
- data/lib/metanorma/collection/config/manifest.rb +59 -29
- data/lib/metanorma/collection/config/namespaces.rb +12 -0
- data/lib/metanorma/collection/document/document.rb +56 -15
- data/lib/metanorma/collection/filelookup/filelookup.rb +185 -77
- data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +99 -27
- data/lib/metanorma/collection/filelookup/utils.rb +52 -0
- data/lib/metanorma/collection/helpers.rb +82 -0
- data/lib/metanorma/collection/log.rb +24 -0
- data/lib/metanorma/collection/manifest/manifest.rb +45 -14
- data/lib/metanorma/collection/multilingual/multilingual.rb +660 -0
- data/lib/metanorma/collection/renderer/filelocation.rb +166 -0
- data/lib/metanorma/collection/renderer/fileparse.rb +135 -115
- data/lib/metanorma/collection/renderer/fileprocess.rb +185 -37
- data/lib/metanorma/collection/renderer/navigation.rb +21 -7
- data/lib/metanorma/collection/renderer/render_word.rb +15 -10
- data/lib/metanorma/collection/renderer/renderer.rb +236 -32
- data/lib/metanorma/collection/renderer/svg.rb +107 -0
- data/lib/metanorma/collection/renderer/utils.rb +110 -39
- data/lib/metanorma/collection/sectionsplit/collection.rb +110 -0
- data/lib/metanorma/collection/sectionsplit/sectionsplit.rb +198 -115
- data/lib/metanorma/collection/util/disambig_files.rb +4 -5
- data/lib/metanorma/collection/util/util.rb +155 -18
- data/lib/metanorma/collection/xrefprocess/xrefprocess.rb +47 -33
- data/lib/metanorma/compile/assets/icc-boilerplate.adoc +41 -0
- data/lib/metanorma/compile/compile.rb +181 -156
- data/lib/metanorma/compile/compile_options.rb +186 -79
- data/lib/metanorma/compile/extract.rb +75 -58
- data/lib/metanorma/compile/flavor.rb +28 -0
- data/lib/metanorma/compile/output_filename.rb +75 -0
- data/lib/metanorma/compile/output_filename_config.rb +27 -0
- data/lib/metanorma/compile/relaton_drop.rb +56 -0
- data/lib/metanorma/compile/render.rb +226 -0
- data/lib/metanorma/compile/validator.rb +26 -0
- data/lib/metanorma/compile/writeable.rb +12 -0
- data/lib/metanorma/util/fontist_helper.rb +35 -19
- data/lib/metanorma/version.rb +1 -1
- data/lib/metanorma.rb +1 -7
- data/metanorma.gemspec +15 -21
- data/plans/collection-rendering-architecture-review.md +516 -0
- metadata +65 -113
- data/.hound.yml +0 -5
- data/lib/metanorma/asciidoctor_extensions/glob_include_processor.rb +0 -22
- data/lib/metanorma/asciidoctor_extensions.rb +0 -1
- data/lib/metanorma/compile/compile_validate.rb +0 -68
- data/lib/metanorma/config/config.rb +0 -23
- data/lib/metanorma/input/asciidoc.rb +0 -107
- data/lib/metanorma/input/base.rb +0 -9
- data/lib/metanorma/input.rb +0 -7
- data/lib/metanorma/processor/processor.rb +0 -54
- data/lib/metanorma/processor.rb +0 -6
- data/lib/metanorma/registry/registry.rb +0 -63
- data/lib/metanorma/shale_monkeypatch.rb +0 -15
- data/lib/metanorma/util/util.rb +0 -45
|
@@ -1,84 +1,90 @@
|
|
|
1
|
-
require "
|
|
2
|
-
require_relative "../../shale_monkeypatch"
|
|
1
|
+
require "lutaml/model"
|
|
3
2
|
require_relative "../../array_monkeypatch"
|
|
4
3
|
require_relative "compile_options"
|
|
5
4
|
require_relative "converters"
|
|
6
5
|
require_relative "bibdata"
|
|
7
6
|
require_relative "directive"
|
|
8
7
|
require_relative "manifest"
|
|
8
|
+
require_relative "namespaces"
|
|
9
|
+
require_relative "doc_container"
|
|
9
10
|
|
|
10
11
|
module Metanorma
|
|
11
12
|
class Collection
|
|
12
13
|
module Config
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
Lutaml::Model::Config.configure do |config|
|
|
15
|
+
config.xml_adapter_type = :nokogiri
|
|
16
|
+
end
|
|
15
17
|
|
|
16
|
-
class Config < ::
|
|
18
|
+
class Config < ::Lutaml::Model::Serializable
|
|
17
19
|
attr_accessor :path, :collection, :from_xml
|
|
18
20
|
|
|
19
21
|
attribute :bibdata, Bibdata
|
|
20
22
|
attribute :directive, Directive, collection: true
|
|
21
23
|
attribute :manifest, Manifest
|
|
22
|
-
attribute :
|
|
23
|
-
|
|
24
|
-
attribute :
|
|
25
|
-
attribute :
|
|
26
|
-
"cover.html"
|
|
27
|
-
}
|
|
24
|
+
attribute :coverpage, :string, default: -> { "cover.html" }
|
|
25
|
+
attribute :coverpage_pdf_portfolio, :string
|
|
26
|
+
attribute :format, :string, collection: true, default: -> { [:html] }
|
|
27
|
+
attribute :output_folder, :string
|
|
28
28
|
attribute :compile, CompileOptions
|
|
29
|
-
attribute :prefatory_content,
|
|
30
|
-
attribute :final_content,
|
|
31
|
-
attribute :documents,
|
|
32
|
-
attribute :xmlns,
|
|
29
|
+
attribute :prefatory_content, :string, raw: true
|
|
30
|
+
attribute :final_content, :string, raw: true
|
|
31
|
+
attribute :documents, DocContainer, collection: true
|
|
32
|
+
attribute :xmlns, :string, default: -> { "http://metanorma.org" }
|
|
33
33
|
|
|
34
34
|
yaml do
|
|
35
|
-
map "directives",
|
|
36
|
-
|
|
37
|
-
map "bibdata",
|
|
38
|
-
|
|
35
|
+
map "directives", to: :directive, with: { from: :directives_from_yaml,
|
|
36
|
+
to: :directives_to_yaml }
|
|
37
|
+
map "bibdata", to: :bibdata, with: { from: :bibdata_from_yaml,
|
|
38
|
+
to: :bibdata_to_yaml }
|
|
39
39
|
map "manifest", to: :manifest
|
|
40
|
-
map "
|
|
40
|
+
map "entry", to: :manifest, with: { from: :entry_from_yaml,
|
|
41
|
+
to: :nop_to_yaml }
|
|
42
|
+
map "format", to: :format, render_default: true
|
|
41
43
|
map "output_folder", to: :output_folder
|
|
42
|
-
map "coverpage", to: :coverpage
|
|
43
|
-
map "
|
|
44
|
+
map "coverpage", to: :coverpage, render_default: true
|
|
45
|
+
map "coverpage-pdf-portfolio", to: :coverpage_pdf_portfolio,
|
|
46
|
+
render_default: true
|
|
47
|
+
map "compile", to: :compile, render_default: true
|
|
44
48
|
map "prefatory-content", to: :prefatory_content
|
|
45
49
|
map "final-content", to: :final_content
|
|
46
50
|
end
|
|
47
51
|
|
|
48
52
|
xml do
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
map_element "
|
|
55
|
-
|
|
56
|
-
map_element "
|
|
57
|
-
to: :manifest_to_xml }
|
|
58
|
-
map_element "format", to: :format
|
|
53
|
+
element "metanorma-collection"
|
|
54
|
+
namespace MetanormaCollectionNamespace
|
|
55
|
+
map_element "bibdata", to: :bibdata, with: { from: :bibdata_from_xml,
|
|
56
|
+
to: :bibdata_to_xml }
|
|
57
|
+
map_element "directive", to: :directive
|
|
58
|
+
map_element "entry", to: :manifest, with: { from: :manifest_from_xml,
|
|
59
|
+
to: :manifest_to_xml }
|
|
60
|
+
map_element "format", to: :format, render_default: true
|
|
59
61
|
map_element "output_folder", to: :output_folder
|
|
60
|
-
map_element "coverpage", to: :coverpage
|
|
61
|
-
map_element "
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
map_element "
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
map_element "coverpage", to: :coverpage, render_default: true
|
|
63
|
+
map_element "coverpage-pdf-portfolio", to: :coverpage_pdf_portfolio,
|
|
64
|
+
render_default: true
|
|
65
|
+
map_element "compile", to: :compile, render_default: true
|
|
66
|
+
map_element "prefatory-content",
|
|
67
|
+
to: :prefatory_content,
|
|
68
|
+
with: { from: :prefatory_from_xml,
|
|
69
|
+
to: :prefatory_to_xml }
|
|
70
|
+
map_element "doc-container", to: :documents
|
|
71
|
+
map_element "final-content",
|
|
72
|
+
to: :final_content,
|
|
73
|
+
with: { from: :final_from_xml,
|
|
74
|
+
to: :final_to_xml }
|
|
69
75
|
end
|
|
70
76
|
|
|
71
77
|
def manifest_from_xml(model, node)
|
|
72
78
|
model.manifest = Manifest.from_xml(node.to_xml)
|
|
73
79
|
end
|
|
74
80
|
|
|
75
|
-
def manifest_to_xml(model,
|
|
81
|
+
def manifest_to_xml(model, _parent, doc)
|
|
76
82
|
model.collection&.manifest&.clean_manifest(model.manifest)
|
|
77
|
-
doc
|
|
83
|
+
add_raw_xml_element(doc, model.manifest.to_xml)
|
|
78
84
|
end
|
|
79
85
|
|
|
80
86
|
def prefatory_from_xml(model, node)
|
|
81
|
-
model.prefatory_content = node.to_xml
|
|
87
|
+
model.prefatory_content = node.children.map(&:to_xml).join
|
|
82
88
|
end
|
|
83
89
|
|
|
84
90
|
def prefatory_to_xml(model, parent, doc)
|
|
@@ -89,32 +95,21 @@ module Metanorma
|
|
|
89
95
|
content_to_xml(model, parent, doc, "final")
|
|
90
96
|
end
|
|
91
97
|
|
|
92
|
-
def content_to_xml(model,
|
|
98
|
+
def content_to_xml(model, _parent, doc, type)
|
|
93
99
|
x = model.send("#{type}_content") or return
|
|
94
100
|
n = Nokogiri::XML(x)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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)
|
|
102
109
|
end
|
|
103
110
|
|
|
104
111
|
def final_from_xml(model, node)
|
|
105
|
-
model.final_content = node.to_xml
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def directive_from_xml(model, node)
|
|
109
|
-
model.directive ||= []
|
|
110
|
-
model.directive << Directive.from_xml(node.to_xml)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def directive_to_xml(model, parent, doc)
|
|
114
|
-
Array(model.directive).each do |e|
|
|
115
|
-
elem = e.to_xml
|
|
116
|
-
doc.add_element(parent, elem)
|
|
117
|
-
end
|
|
112
|
+
model.final_content = node.children.map(&:to_xml).join
|
|
118
113
|
end
|
|
119
114
|
|
|
120
115
|
def directives_from_yaml(model, value)
|
|
@@ -134,26 +129,29 @@ module Metanorma
|
|
|
134
129
|
end
|
|
135
130
|
end
|
|
136
131
|
|
|
137
|
-
def
|
|
138
|
-
|
|
139
|
-
value.content
|
|
140
|
-
else Nokogiri::XML(value)
|
|
141
|
-
end
|
|
142
|
-
model.documents = x.xpath(".//bibdata")
|
|
143
|
-
.each_with_object([]) do |b, m|
|
|
144
|
-
m << Bibdata.from_xml(b.to_xml)
|
|
145
|
-
end
|
|
132
|
+
def entry_from_yaml(model, value)
|
|
133
|
+
model.manifest ||= value
|
|
146
134
|
end
|
|
147
135
|
|
|
148
|
-
def
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
|
157
155
|
end
|
|
158
156
|
|
|
159
157
|
include Converters
|
|
@@ -1,29 +1,113 @@
|
|
|
1
|
-
require "relaton
|
|
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
|
-
|
|
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
|
|
30
|
+
end
|
|
31
|
+
|
|
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
|
|
46
|
+
end
|
|
47
|
+
|
|
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
|
|
10
59
|
end
|
|
11
60
|
|
|
12
61
|
def bibdata_to_yaml(model, doc)
|
|
13
|
-
|
|
62
|
+
return unless model.bibdata
|
|
63
|
+
|
|
64
|
+
doc["bibdata"] = YAML.safe_load(model.bibdata.to_yaml,
|
|
65
|
+
permitted_classes: [Date, Symbol])
|
|
14
66
|
end
|
|
15
67
|
|
|
16
68
|
def bibdata_from_xml(model, node)
|
|
17
|
-
|
|
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
|
|
73
|
+
|
|
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"
|
|
18
78
|
end
|
|
19
79
|
|
|
20
|
-
def bibdata_to_xml(model,
|
|
80
|
+
def bibdata_to_xml(model, _parent, doc)
|
|
21
81
|
b = model.bibdata or return
|
|
22
|
-
|
|
23
|
-
doc.add_element(parent, elem)
|
|
82
|
+
add_raw_xml_element(doc, b.to_xml(bibdata: true, date_format: :full))
|
|
24
83
|
end
|
|
25
84
|
|
|
26
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)
|
|
107
|
+
end
|
|
108
|
+
el.raw_content = src.children.map(&:to_xml).join
|
|
109
|
+
el
|
|
110
|
+
end
|
|
27
111
|
end
|
|
28
112
|
end
|
|
29
113
|
end
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
module Metanorma
|
|
2
2
|
class Collection
|
|
3
3
|
module Config
|
|
4
|
-
class Directive < ::
|
|
5
|
-
attribute :key,
|
|
6
|
-
attribute :value,
|
|
4
|
+
class Directive < ::Lutaml::Model::Serializable
|
|
5
|
+
attribute :key, :string
|
|
6
|
+
attribute :value, :string
|
|
7
|
+
|
|
8
|
+
xml do
|
|
9
|
+
root "directive"
|
|
10
|
+
map_element "key", to: :key
|
|
11
|
+
map_element "value", to: :value
|
|
12
|
+
end
|
|
7
13
|
end
|
|
8
14
|
end
|
|
9
15
|
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
|
-
require "
|
|
2
|
-
require_relative "../../shale_monkeypatch"
|
|
1
|
+
require "lutaml/model"
|
|
3
2
|
require_relative "../../array_monkeypatch"
|
|
4
3
|
require_relative "converters"
|
|
5
4
|
require_relative "bibdata"
|
|
@@ -7,68 +6,99 @@ require_relative "bibdata"
|
|
|
7
6
|
module Metanorma
|
|
8
7
|
class Collection
|
|
9
8
|
module Config
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Lutaml::Model::Config.configure do |config|
|
|
10
|
+
config.xml_adapter_type = :nokogiri
|
|
11
|
+
end
|
|
12
12
|
|
|
13
|
-
class Manifest < ::
|
|
14
|
-
attribute :identifier,
|
|
13
|
+
class Manifest < ::Lutaml::Model::Serializable
|
|
14
|
+
attribute :identifier, :string,
|
|
15
15
|
default: -> { UUIDTools::UUID.random_create.to_s }
|
|
16
|
-
attribute :id,
|
|
16
|
+
attribute :id, :string
|
|
17
17
|
attribute :bibdata, Bibdata
|
|
18
|
-
attribute :type,
|
|
19
|
-
attribute :title,
|
|
20
|
-
attribute :url,
|
|
21
|
-
attribute :
|
|
22
|
-
attribute :
|
|
23
|
-
attribute :
|
|
18
|
+
attribute :type, :string
|
|
19
|
+
attribute :title, :string
|
|
20
|
+
attribute :url, :string
|
|
21
|
+
attribute :level, :string
|
|
22
|
+
attribute :attachment, :boolean
|
|
23
|
+
attribute :sectionsplit, :boolean
|
|
24
|
+
attribute :index, :boolean, default: -> { true }
|
|
24
25
|
attribute :entry, Manifest, collection: true
|
|
25
|
-
attribute :file,
|
|
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
|
|
26
32
|
|
|
27
33
|
yaml do
|
|
28
34
|
map "identifier", to: :identifier
|
|
35
|
+
map "pdf-file", to: :pdffile
|
|
29
36
|
map "type", to: :type
|
|
30
|
-
map "level",
|
|
37
|
+
map "level", to: :level,
|
|
38
|
+
with: { from: :level_from_yaml, to: :nop_to_yaml }
|
|
31
39
|
map "title", to: :title
|
|
32
40
|
map "url", to: :url
|
|
33
41
|
map "attachment", to: :attachment
|
|
34
42
|
map "sectionsplit", to: :sectionsplit
|
|
35
43
|
map "index", to: :index
|
|
36
44
|
map "file", to: :file
|
|
37
|
-
map "fileref",
|
|
45
|
+
map "fileref", to: :file,
|
|
46
|
+
with: { from: :fileref_from_yaml, to: :nop_to_yaml }
|
|
38
47
|
map "entry", to: :entry
|
|
39
|
-
map "docref",
|
|
40
|
-
|
|
41
|
-
map "
|
|
42
|
-
|
|
48
|
+
map "docref", to: :entry,
|
|
49
|
+
with: { from: :docref_from_yaml, to: :nop_to_yaml }
|
|
50
|
+
map "manifest", to: :entry,
|
|
51
|
+
with: { from: :docref_from_yaml, to: :nop_to_yaml }
|
|
52
|
+
map "bibdata", to: :bibdata, with: { from: :bibdata_from_yaml,
|
|
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
|
|
43
58
|
end
|
|
44
59
|
|
|
45
60
|
xml do
|
|
46
61
|
root "entry"
|
|
47
|
-
map_attribute "
|
|
62
|
+
map_attribute "target", to: :id
|
|
48
63
|
map_attribute "attachment", to: :attachment
|
|
49
64
|
map_attribute "sectionsplit", to: :sectionsplit
|
|
50
65
|
map_attribute "index", to: :index
|
|
51
66
|
map_attribute "url", to: :url
|
|
67
|
+
map_attribute "pdf-file", to: :pdffile
|
|
52
68
|
map_attribute "fileref", to: :file
|
|
53
|
-
map_element "identifier", to: :identifier
|
|
69
|
+
map_element "identifier", to: :identifier, render_default: true
|
|
54
70
|
map_element "type", to: :type
|
|
55
71
|
map_element "title", to: :title
|
|
56
|
-
map_element "
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
map_element "format", to: :format
|
|
73
|
+
map_element "bibdata", to: :bibdata, with: { from: :bibdata_from_xml,
|
|
74
|
+
to: :bibdata_to_xml }
|
|
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 }
|
|
59
82
|
end
|
|
60
83
|
|
|
61
84
|
def entry_from_xml(model, node)
|
|
62
|
-
model.entry = Manifest.from_xml(node.
|
|
85
|
+
model.entry = Manifest.from_xml(node.node.to_xml)
|
|
63
86
|
end
|
|
64
87
|
|
|
65
|
-
def entry_to_xml(model,
|
|
88
|
+
def entry_to_xml(model, _parent, doc)
|
|
66
89
|
Array(model.entry).each do |e|
|
|
67
|
-
|
|
68
|
-
doc.add_element(parent, elem)
|
|
90
|
+
add_raw_xml_element(doc, e.to_xml)
|
|
69
91
|
end
|
|
70
92
|
end
|
|
71
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
|
+
|
|
72
102
|
def level_from_yaml(model, value)
|
|
73
103
|
model.type ||= value
|
|
74
104
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require "relaton-cli"
|
|
2
|
+
|
|
1
3
|
module Metanorma
|
|
2
4
|
class Collection
|
|
3
5
|
class Document
|
|
@@ -46,26 +48,65 @@ module Metanorma
|
|
|
46
48
|
|
|
47
49
|
private
|
|
48
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
|
|
49
58
|
def mn2relaton_parser(tag)
|
|
50
|
-
case tag
|
|
51
|
-
when "bipm"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
when "
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
when "
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
|
61
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
|
|
62
93
|
end
|
|
63
94
|
|
|
64
95
|
# #param xml [Nokogiri::XML::Document, Nokogiri::XML::Element]
|
|
65
96
|
# @return [RelatonBib::BibliographicItem,RelatonIso::IsoBibliographicItem]
|
|
66
97
|
def from_xml(xml)
|
|
67
98
|
b = xml.at("//xmlns:bibitem|//xmlns:bibdata")
|
|
68
|
-
|
|
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)
|
|
69
110
|
r.from_xml(b.to_xml)
|
|
70
111
|
end
|
|
71
112
|
|
|
@@ -111,9 +152,9 @@ module Metanorma
|
|
|
111
152
|
|
|
112
153
|
# @return [String]
|
|
113
154
|
def type
|
|
114
|
-
first = @bibitem.docidentifier
|
|
155
|
+
first = @bibitem.docidentifier&.first
|
|
115
156
|
@type ||= (first&.type&.downcase ||
|
|
116
|
-
first&.
|
|
157
|
+
first&.content&.match(/^[^\s]+/)&.to_s)&.downcase ||
|
|
117
158
|
"standoc"
|
|
118
159
|
end
|
|
119
160
|
|
|
@@ -123,7 +164,7 @@ module Metanorma
|
|
|
123
164
|
if @raw
|
|
124
165
|
builder.parent.add_child(@bibitem.root)
|
|
125
166
|
else
|
|
126
|
-
builder.send(
|
|
167
|
+
builder.send(:metanorma) do |b|
|
|
127
168
|
b << @bibitem.to_xml(bibdata: true)
|
|
128
169
|
end
|
|
129
170
|
end
|