relaton-cli 0.1.7 → 0.1.8
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/CHANGELOG.md +6 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/docs/README.adoc +10 -0
- data/lib/relaton/bibcollection.rb +12 -14
- data/lib/relaton/bibdata.rb +1 -57
- data/lib/relaton/cli.rb +1 -0
- data/lib/relaton/cli/base_convertor.rb +6 -2
- data/lib/relaton/cli/command.rb +12 -1
- data/lib/relaton/cli/relaton_file.rb +62 -10
- data/lib/relaton/cli/version.rb +1 -1
- data/lib/relaton/cli/xml_convertor.rb +5 -1
- data/lib/relaton/cli/xml_to_html_renderer.rb +54 -31
- data/lib/relaton/element_finder.rb +25 -0
- data/lib/relaton/xml_document.rb +87 -0
- data/relaton-cli.gemspec +0 -1
- metadata +7 -17
- data/Gemfile.lock +0 -100
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 602dc6b5405f7e9ad64b82a2db8d7c01e1f3de2aa95324a48cb1bef1f5d83394
|
4
|
+
data.tar.gz: 3d59d3c875327a1444f6d95be1d83f9b44e1edb78a40c3e3d1ae62096611f2b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0b7c3d7b95e26db2bb8392860e2ccaef744caa588885c285cb2ab472ecadda6d08d1393dd0f093f33d918f705351a1092f8b869940a8ee8aa50267446886849
|
7
|
+
data.tar.gz: 7c91b43960fbd34ee9500524fad1b355f3681960c623dd1af95f637736f577d516107330de97c4b97bf7785fc50b747c198c7f67ca4003fce8309760aa6a207a
|
data/CHANGELOG.md
ADDED
data/bin/console
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "relaton/cli"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require "pry"
|
11
|
+
Pry.start
|
data/bin/setup
ADDED
data/docs/README.adoc
CHANGED
@@ -30,6 +30,16 @@ file), a link to that file is inserted.
|
|
30
30
|
If the `TITLE` or `ORGANIZATION` options are given, they are added to the `Collection-File` output as the
|
31
31
|
title and author of the `relaton-collection` document.
|
32
32
|
|
33
|
+
=== relaton split
|
34
|
+
|
35
|
+
[source,console]
|
36
|
+
----
|
37
|
+
$ relaton split Collection-File Relaton-File-Directory -x rxl
|
38
|
+
----
|
39
|
+
|
40
|
+
Splits a `Relaton-Collection-File` into multiple files in the `Relaton-File-Directory`, and it also
|
41
|
+
suports an addional `extension` options to use different extension.
|
42
|
+
|
33
43
|
=== relaton fetch
|
34
44
|
|
35
45
|
[source,console]
|
@@ -1,6 +1,9 @@
|
|
1
|
+
require "relaton/element_finder"
|
1
2
|
|
2
3
|
module Relaton
|
3
4
|
class Bibcollection
|
5
|
+
extend Relaton::ElementFinder
|
6
|
+
|
4
7
|
ATTRIBS = %i[
|
5
8
|
title
|
6
9
|
items
|
@@ -10,13 +13,6 @@ module Relaton
|
|
10
13
|
|
11
14
|
attr_accessor *ATTRIBS
|
12
15
|
|
13
|
-
def self.ns(xpath)
|
14
|
-
xpath.gsub(%r{/([a-zA-z])}, "/xmlns:\\1").
|
15
|
-
gsub(%r{::([a-zA-z])}, "::xmlns:\\1").
|
16
|
-
gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1").
|
17
|
-
gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
|
18
|
-
end
|
19
|
-
|
20
16
|
def initialize(options)
|
21
17
|
self.items = []
|
22
18
|
ATTRIBS.each do |k|
|
@@ -40,14 +36,16 @@ module Relaton
|
|
40
36
|
end
|
41
37
|
|
42
38
|
def self.from_xml(source)
|
43
|
-
title =
|
44
|
-
author =
|
45
|
-
|
46
|
-
|
47
|
-
|
39
|
+
title = find_text("./relaton-collection/title", source)
|
40
|
+
author = find_text("./relaton-collection/contributor[role/@type = 'author']/organization/name", source)
|
41
|
+
|
42
|
+
items = find_xpath("./relaton-collection/relation", source)&.map do |item|
|
43
|
+
bibdata = find("./bibdata", item)
|
44
|
+
klass = bibdata ? Bibdata : Bibcollection
|
45
|
+
klass.from_xml(bibdata || item)
|
48
46
|
end
|
49
|
-
|
50
|
-
new(
|
47
|
+
|
48
|
+
new(title: title, author: author, items: items)
|
51
49
|
end
|
52
50
|
|
53
51
|
def new_bib_item_class(options)
|
data/lib/relaton/bibdata.rb
CHANGED
@@ -31,13 +31,6 @@ module Relaton
|
|
31
31
|
|
32
32
|
attr_accessor *ATTRIBS
|
33
33
|
|
34
|
-
def self.ns(xpath)
|
35
|
-
xpath.gsub(%r{/([a-zA-z])}, "/xmlns:\\1").
|
36
|
-
gsub(%r{::([a-zA-z])}, "::xmlns:\\1").
|
37
|
-
gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1").
|
38
|
-
gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
|
39
|
-
end
|
40
|
-
|
41
34
|
def initialize(options)
|
42
35
|
options.each_pair do |k,v|
|
43
36
|
send("#{k.to_s}=", v)
|
@@ -61,55 +54,7 @@ module Relaton
|
|
61
54
|
end
|
62
55
|
|
63
56
|
def self.from_xml(source)
|
64
|
-
|
65
|
-
datetype = "circulated"
|
66
|
-
|
67
|
-
# bib.relaton_xml_path = URI.escape("#{relaton_root}/#{id_code}.xml")
|
68
|
-
revdate = source.at(ns("./date[@type = 'published']")) ||
|
69
|
-
source.at(ns("./date[@type = 'circulated']")) ||
|
70
|
-
source.at(ns("./date"))
|
71
|
-
revdate_value = revdate&.at(ns("./on")) || revdate&.at(ns("./from"))
|
72
|
-
|
73
|
-
if revdate && revdate_value
|
74
|
-
datetype = revdate["type"]
|
75
|
-
revdate = begin
|
76
|
-
Date.parse(revdate_value.text.strip).to_s
|
77
|
-
rescue
|
78
|
-
warn "[relaton] parsing published date '#{revdate.text}' failed."
|
79
|
-
revdate_value.text.strip
|
80
|
-
end || nil
|
81
|
-
else
|
82
|
-
revdate = nil
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
options = {
|
87
|
-
uri: source.at(ns("./uri[not(@type)]"))&.text,
|
88
|
-
xml: source.at(ns("./uri[@type='xml']"))&.text,
|
89
|
-
pdf: source.at(ns("./uri[@type='pdf']"))&.text,
|
90
|
-
html: source.at(ns("./uri[@type='html']"))&.text,
|
91
|
-
rxl: source.at(ns("./uri[@type='rxl']"))&.text,
|
92
|
-
doc: source.at(ns("./uri[@type='doc']"))&.text,
|
93
|
-
docidentifier: source.at(ns("./docidentifier"))&.text,
|
94
|
-
title: source.at(ns("./title"))&.text,
|
95
|
-
doctype: source.at(ns("./@type"))&.text,
|
96
|
-
stage: source.at(ns("./status"))&.text,
|
97
|
-
technical_committee: source.at(ns("./editorialgroup/technical-committee"))&.text,
|
98
|
-
abstract: source.at(ns("./abstract"))&.text,
|
99
|
-
revdate: revdate,
|
100
|
-
language: source.at(ns("./language"))&.text,
|
101
|
-
script: source.at(ns("./script"))&.text,
|
102
|
-
edition: source.at(ns("./edition"))&.text,
|
103
|
-
copyright_from: source.at(ns("./copyright/from"))&.text,
|
104
|
-
copyright_owner: source.at(ns("./copyright/owner/organization/name"))&.text,
|
105
|
-
contributor_author_role: source.at(ns("./contributor/role[@type='author']"))&.text,
|
106
|
-
contributor_author_organization: source.at(ns("./contributor/role[@type='author']"))&.parent&.at(ns("./organization/name"))&.text,
|
107
|
-
contributor_publisher_role: source.at(ns("./contributor/role[@type='publisher']"))&.text,
|
108
|
-
contributor_publisher_organization: source.at(ns("./contributor/role[@type='publisher']"))&.parent&.at(ns("./organization/name"))&.text,
|
109
|
-
datetype: datetype
|
110
|
-
}
|
111
|
-
|
112
|
-
new(options)
|
57
|
+
new(Relaton::XmlDocument.parse(source))
|
113
58
|
end
|
114
59
|
|
115
60
|
def to_xml
|
@@ -173,6 +118,5 @@ module Relaton
|
|
173
118
|
def to_yaml
|
174
119
|
to_h.to_yaml
|
175
120
|
end
|
176
|
-
|
177
121
|
end
|
178
122
|
end
|
data/lib/relaton/cli.rb
CHANGED
@@ -11,6 +11,7 @@ module Relaton
|
|
11
11
|
@options = options
|
12
12
|
@outdir = options.fetch(:outdir, nil)
|
13
13
|
@writable = options.fetch(:write, true)
|
14
|
+
@overwrite = options.fetch(:overwrite, true)
|
14
15
|
|
15
16
|
install_dependencies(options[:require] || [])
|
16
17
|
end
|
@@ -41,7 +42,7 @@ module Relaton
|
|
41
42
|
|
42
43
|
private
|
43
44
|
|
44
|
-
attr_reader :file, :outdir, :options, :writable
|
45
|
+
attr_reader :file, :outdir, :options, :writable, :overwrite
|
45
46
|
|
46
47
|
def default_ext
|
47
48
|
raise "Override this method"
|
@@ -71,7 +72,10 @@ module Relaton
|
|
71
72
|
|
72
73
|
def write_to_a_file(content, outfile = nil)
|
73
74
|
outfile ||= Pathname.new(file).sub_ext(extension).to_s
|
74
|
-
|
75
|
+
|
76
|
+
if !File.exists?(outfile) || overwrite
|
77
|
+
File.open(outfile, "w:utf-8") { |file| file.write(content) }
|
78
|
+
end
|
75
79
|
end
|
76
80
|
|
77
81
|
def write_to_file_collection(content, format)
|
data/lib/relaton/cli/command.rb
CHANGED
@@ -31,21 +31,30 @@ module Relaton
|
|
31
31
|
Relaton::Cli::RelatonFile.concatenate(source_dir, outfile, options)
|
32
32
|
end
|
33
33
|
|
34
|
+
desc "split Relaton-Collection-File Relaton-XML-Directory", "Split a Relaton Collection into multiple files"
|
35
|
+
option :extension, aliases: :x, desc: "File extension of Relaton XML files, defaults to 'rxl'"
|
36
|
+
|
37
|
+
def split(source, outdir)
|
38
|
+
Relaton::Cli::RelatonFile.split(source, outdir, options)
|
39
|
+
end
|
40
|
+
|
34
41
|
desc "yaml2xml YAML", "Convert Relaton YAML into Relaton Collection XML or separate files"
|
35
42
|
option :extension, aliases: :x, desc: "File extension of Relaton XML files, defaults to 'rxl'"
|
36
43
|
option :prefix, aliases: :p, desc: "Filename prefix of individual Relaton XML files, defaults to empty"
|
37
44
|
option :outdir, aliases: :o, desc: "Output to the specified directory with individual Relaton Bibdata XML files"
|
38
45
|
option :require, aliases: :r, type: :array, desc: "Require LIBRARY prior to execution"
|
46
|
+
option :overwrite, aliases: :f, type: :boolean, default: false, desc: "Overwrite the existing file"
|
39
47
|
|
40
48
|
def yaml2xml(filename)
|
41
49
|
Relaton::Cli::YAMLConvertor.to_xml(filename, options)
|
42
50
|
end
|
43
51
|
|
44
|
-
desc "xml2yaml XML", "Convert Relaton
|
52
|
+
desc "xml2yaml XML", "Convert Relaton XML into Relaton Bibdata / Bibcollection YAML (and separate files)"
|
45
53
|
option :extension, aliases: :x, desc: "File extension of Relaton YAML files, defaults to 'yaml'"
|
46
54
|
option :prefix, aliases: :p, desc: "Filename prefix of Relaton XML files, defaults to empty"
|
47
55
|
option :outdir, aliases: :o, desc: "Output to the specified directory with individual Relaton Bibdata YAML files"
|
48
56
|
option :require, aliases: :r, type: :array, desc: "Require LIBRARY prior to execution"
|
57
|
+
option :overwrite, aliases: :f, type: :boolean, default: false, desc: "Overwrite the existing file"
|
49
58
|
|
50
59
|
def xml2yaml(filename)
|
51
60
|
Relaton::Cli::XMLConvertor.to_yaml(filename, options)
|
@@ -54,6 +63,7 @@ module Relaton
|
|
54
63
|
desc "xml2html RELATON-INDEX-XML", "Convert Relaton Collection XML into HTML"
|
55
64
|
option :stylesheet, aliases: :s, desc: "Stylesheet file path for rendering HTML index"
|
56
65
|
option :templatedir, aliases: :t, desc: "Liquid template directory for rendering Relaton items and collection"
|
66
|
+
option :overwrite, aliases: :f, type: :boolean, default: false, desc: "Overwrite the existing file"
|
57
67
|
|
58
68
|
def xml2html(file, style = nil, template = nil)
|
59
69
|
Relaton::Cli::XMLConvertor.to_html(file, style, template)
|
@@ -62,6 +72,7 @@ module Relaton
|
|
62
72
|
desc "yaml2html RELATON-INDEX-YAML", "Concatenate Relaton Collection YAML into HTML"
|
63
73
|
option :stylesheet, aliases: :s, desc: "Stylesheet file path for rendering HTML index"
|
64
74
|
option :templatedir, aliases: :t, desc: "Liquid template directory for rendering Relaton items and collection"
|
75
|
+
option :overwrite, aliases: :f, type: :boolean, default: false, desc: "Overwrite the existing file"
|
65
76
|
|
66
77
|
def yaml2html(file, style = nil, template = nil)
|
67
78
|
Relaton::Cli::YAMLConvertor.to_html(file, style, template)
|
@@ -19,6 +19,10 @@ module Relaton
|
|
19
19
|
write_to_file(bibcollection.to_xml)
|
20
20
|
end
|
21
21
|
|
22
|
+
def split
|
23
|
+
split_and_write_to_files
|
24
|
+
end
|
25
|
+
|
22
26
|
# Extract files
|
23
27
|
#
|
24
28
|
# This interface expect us to provide a source file / directory,
|
@@ -37,7 +41,7 @@ module Relaton
|
|
37
41
|
|
38
42
|
# Concatenate files
|
39
43
|
#
|
40
|
-
|
44
|
+
# This interface expect us to provide a source directory, output
|
41
45
|
# file and custom configuration options. Normally, this expect the
|
42
46
|
# source directory to contain RXL fles, but it also converts any
|
43
47
|
# YAML files to RXL and then finally combines those together.
|
@@ -54,6 +58,24 @@ module Relaton
|
|
54
58
|
new(source, options.merge(outfile: outfile)).concatenate
|
55
59
|
end
|
56
60
|
|
61
|
+
# Split collection
|
62
|
+
#
|
63
|
+
# This interface expects us to provide a Relaton Collection
|
64
|
+
# file and also an output directory, then it will split that
|
65
|
+
# collection into multiple files.
|
66
|
+
#
|
67
|
+
# By default it usages `rxl` extension for these new files,
|
68
|
+
# but we can also customize that by providing the correct
|
69
|
+
# one as `extension` option parameter.
|
70
|
+
#
|
71
|
+
# @param source [File] The source collection file
|
72
|
+
# @param output [Dir] The output directory for files
|
73
|
+
# @param options [Hash] Options as hash key value pair
|
74
|
+
#
|
75
|
+
def self.split(source, outdir = nil, options = {})
|
76
|
+
new(source, options.merge(outdir: outdir)).split
|
77
|
+
end
|
78
|
+
|
57
79
|
private
|
58
80
|
|
59
81
|
attr_reader :source, :options, :outdir, :outfile
|
@@ -80,6 +102,11 @@ module Relaton
|
|
80
102
|
end
|
81
103
|
end
|
82
104
|
|
105
|
+
def relaton_collection
|
106
|
+
@relaton_collection ||=
|
107
|
+
Relaton::Bibcollection.from_xml(nokogiri_document(nil, source))
|
108
|
+
end
|
109
|
+
|
83
110
|
def extract_and_write_to_files
|
84
111
|
select_source_files.each do |file|
|
85
112
|
xml = nokogiri_document(nil, file)
|
@@ -94,8 +121,7 @@ module Relaton
|
|
94
121
|
bibdata = Relaton::Bibdata.from_xml(bib.root)
|
95
122
|
build_bibdata_relaton(bibdata, file)
|
96
123
|
|
97
|
-
|
98
|
-
write_to_file(bibdata.to_xml, outfile)
|
124
|
+
write_to_file(bibdata.to_xml, outdir, build_filename(file))
|
99
125
|
end
|
100
126
|
end
|
101
127
|
|
@@ -108,6 +134,16 @@ module Relaton
|
|
108
134
|
end.compact
|
109
135
|
end
|
110
136
|
|
137
|
+
def split_and_write_to_files
|
138
|
+
output_dir = outdir || build_dirname(source)
|
139
|
+
write_to_collection_file(relaton_collection.to_yaml, output_dir)
|
140
|
+
|
141
|
+
relaton_collection.items.each do |content|
|
142
|
+
name = build_filename(nil, content.docidentifier)
|
143
|
+
write_to_file(content.to_xml, output_dir, name)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
111
147
|
def bibdata_instance(document, file)
|
112
148
|
document = clean_nokogiri_document(document)
|
113
149
|
bibdata = Relaton::Bibdata.from_xml(document.root)
|
@@ -151,15 +187,31 @@ module Relaton
|
|
151
187
|
Dir[files].reject { |file| File.directory?(file) }
|
152
188
|
end
|
153
189
|
|
154
|
-
def write_to_file(content, output_file = nil)
|
155
|
-
output_file
|
156
|
-
File.open(
|
190
|
+
def write_to_file(content, directory = nil, output_file = nil)
|
191
|
+
file_with_dir = [directory, output_file || outfile].compact.join("/")
|
192
|
+
File.open(file_with_dir, "w:utf-8") { |file| file.write(content) }
|
193
|
+
end
|
194
|
+
|
195
|
+
def write_to_collection_file(content, directory)
|
196
|
+
write_to_file(content, directory, build_filename(source, nil, "yaml"))
|
197
|
+
end
|
198
|
+
|
199
|
+
def build_dirname(filename)
|
200
|
+
basename = File.basename(filename)&.gsub(/.(xml|rxl)/, "")
|
201
|
+
directory_name = sanitize_string(basename)
|
202
|
+
Dir.mkdir(directory_name) unless File.exists?(directory_name)
|
203
|
+
|
204
|
+
directory_name
|
205
|
+
end
|
206
|
+
|
207
|
+
def build_filename(file, identifier = nil, ext = "rxl")
|
208
|
+
identifier ||= Pathname.new(File.basename(file, ".xml")).to_s
|
209
|
+
[sanitize_string(identifier), options[:extension] || ext].join(".")
|
157
210
|
end
|
158
211
|
|
159
|
-
def
|
160
|
-
|
161
|
-
|
162
|
-
[filename, options[:extension] || "rxl"].join(".")
|
212
|
+
def sanitize_string(string)
|
213
|
+
string.downcase.gsub("/", " ").gsub(/^\s+/, "").gsub(/\s+$/, "").
|
214
|
+
gsub(/\s+/, "-")
|
163
215
|
end
|
164
216
|
end
|
165
217
|
end
|
data/lib/relaton/cli/version.rb
CHANGED
@@ -30,7 +30,11 @@ module Relaton
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def convert_content(content)
|
33
|
-
|
33
|
+
if content.root.name == "bibdata"
|
34
|
+
Bibdata.from_xml(content.to_s)
|
35
|
+
else
|
36
|
+
Bibcollection.from_xml(content)
|
37
|
+
end
|
34
38
|
end
|
35
39
|
|
36
40
|
def file_content
|
@@ -4,53 +4,76 @@ require 'pp'
|
|
4
4
|
|
5
5
|
module Relaton::Cli
|
6
6
|
class XmlToHtmlRenderer
|
7
|
+
def initialize(liquid_dir: nil, stylesheet: nil)
|
8
|
+
@liquid_dir = liquid_dir
|
9
|
+
@stylesheet = read_file(stylesheet)
|
10
|
+
init_liquid_template_and_filesystem
|
11
|
+
end
|
12
|
+
|
13
|
+
def render(index_xml)
|
14
|
+
Liquid::Template.
|
15
|
+
parse(template).
|
16
|
+
render(build_liquid_document(index_xml))
|
17
|
+
end
|
18
|
+
|
19
|
+
def uri_for_extension(uri, extension)
|
20
|
+
unless uri.nil?
|
21
|
+
uri.sub(/\.[^.]+$/, ".#{extension.to_s}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Render HTML
|
26
|
+
#
|
27
|
+
# This interface allow us to convert a Relaton XML to HTML
|
28
|
+
# using the specified liquid template and stylesheets. It
|
29
|
+
# also do some minor clean during this conversion.
|
30
|
+
#
|
31
|
+
def self.render(file, options)
|
32
|
+
new(options).render(file)
|
33
|
+
end
|
7
34
|
|
8
|
-
|
9
|
-
@liquid_dir = options[:liquid_dir]
|
10
|
-
@stylesheet = File.read(options[:stylesheet], encoding: "utf-8")
|
35
|
+
private
|
11
36
|
|
12
|
-
|
13
|
-
|
14
|
-
|
37
|
+
attr_reader :stylesheet, :liquid_dir, :template
|
38
|
+
|
39
|
+
def read_file(file)
|
40
|
+
File.read(file, encoding: "utf-8")
|
15
41
|
end
|
16
42
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
43
|
+
def build_liquid_document(source)
|
44
|
+
bibcollection = build_bibcollection(source)
|
45
|
+
|
46
|
+
hash_to_liquid({
|
47
|
+
depth: 2,
|
48
|
+
css: stylesheet,
|
49
|
+
title: bibcollection.title,
|
50
|
+
author: bibcollection.author,
|
51
|
+
documents: document_items(bibcollection)
|
52
|
+
})
|
22
53
|
end
|
23
54
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
55
|
+
def init_liquid_template_and_filesystem
|
56
|
+
file_system = Liquid::LocalFileSystem.new(liquid_dir)
|
57
|
+
@template = read_file(file_system.full_path("index"))
|
58
|
+
|
59
|
+
Liquid::Template.file_system = file_system
|
27
60
|
end
|
28
61
|
|
29
62
|
# TODO: This should be recursive, but it's not
|
30
63
|
def hash_to_liquid(hash)
|
31
|
-
hash.map { |
|
64
|
+
hash.map { |key, value| [key.to_s, empty2nil(value)] }.to_h
|
32
65
|
end
|
33
66
|
|
34
|
-
def
|
35
|
-
|
36
|
-
bibcollection = ::Relaton::Bibcollection.from_xml(source)
|
37
|
-
locals = {
|
38
|
-
css: @stylesheet,
|
39
|
-
title: bibcollection.title,
|
40
|
-
author: bibcollection.author,
|
41
|
-
documents: bibcollection.to_h["root"]["items"].map { |i| hash_to_liquid(i) },
|
42
|
-
depth: 2
|
43
|
-
}
|
44
|
-
Liquid::Template.parse(@template).render(hash_to_liquid(locals))
|
67
|
+
def empty2nil(value)
|
68
|
+
value unless value.is_a?(String) && value.empty? && !value.nil?
|
45
69
|
end
|
46
70
|
|
47
|
-
def
|
48
|
-
|
49
|
-
uri.sub(/\.[^.]+$/, ".#{extension.to_s}")
|
71
|
+
def build_bibcollection(source)
|
72
|
+
Relaton::Bibcollection.from_xml(Nokogiri::XML(source))
|
50
73
|
end
|
51
74
|
|
52
|
-
def
|
53
|
-
|
75
|
+
def document_items(bibcollection)
|
76
|
+
bibcollection.to_h["root"]["items"].map { |item| hash_to_liquid(item) }
|
54
77
|
end
|
55
78
|
end
|
56
79
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Relaton
|
2
|
+
module ElementFinder
|
3
|
+
attr_reader :document
|
4
|
+
|
5
|
+
def find_text(xpath, element = nil)
|
6
|
+
find(xpath, element)&.text
|
7
|
+
end
|
8
|
+
|
9
|
+
def find(xpath, element = nil)
|
10
|
+
(element || document).at(apply_namespace(xpath))
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_xpath(xpath, element = nil)
|
14
|
+
element&.xpath(apply_namespace(xpath))
|
15
|
+
end
|
16
|
+
|
17
|
+
def apply_namespace(xpath)
|
18
|
+
xpath.
|
19
|
+
gsub(%r{/([a-zA-Z])}, "/xmlns:\\1").
|
20
|
+
gsub(%r{::([a-zA-Z])}, "::xmlns:\\1").
|
21
|
+
gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1").
|
22
|
+
gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require "relaton/element_finder"
|
2
|
+
|
3
|
+
module Relaton
|
4
|
+
class XmlDocument
|
5
|
+
include Relaton::ElementFinder
|
6
|
+
|
7
|
+
def initialize(document)
|
8
|
+
@document = nokogiri_document(document) || document
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse
|
12
|
+
base_attributes.merge(complex_attributes)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.parse(document)
|
16
|
+
new(document).parse
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :document
|
22
|
+
|
23
|
+
def nokogiri_document(document)
|
24
|
+
if document.class == String
|
25
|
+
Nokogiri::XML(document)&.root
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def base_attributes
|
30
|
+
Hash.new.tap do |attributes|
|
31
|
+
elements.each {|key, xpath| attributes[key] = find_text(xpath) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def complex_attributes
|
36
|
+
(date_attributes || {}).merge(
|
37
|
+
contributor_author_organization: find_organization_for('author'),
|
38
|
+
contributor_publisher_organization: find_organization_for('publisher'),
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_organization_for(type)
|
43
|
+
find("./contributor/role[@type='#{type}']")&.parent&.
|
44
|
+
at(apply_namespace("./organization/name"))&.text
|
45
|
+
end
|
46
|
+
|
47
|
+
def elements
|
48
|
+
{
|
49
|
+
title: "./title",
|
50
|
+
stage: "./status",
|
51
|
+
script: "./script",
|
52
|
+
doctype: "./@type",
|
53
|
+
edition: "./edition",
|
54
|
+
abstract: "./abstract",
|
55
|
+
language: "./language",
|
56
|
+
uri: "./uri[not(@type)]",
|
57
|
+
rxl: "./uri[@type='rxl']",
|
58
|
+
xml: "./uri[@type='xml']",
|
59
|
+
pdf: "./uri[@type='pdf']",
|
60
|
+
doc: "./uri[@type='doc']",
|
61
|
+
html: "./uri[@type='html']",
|
62
|
+
docidentifier: "./docidentifier",
|
63
|
+
copyright_from: "./copyright/from",
|
64
|
+
copyright_owner: "./copyright/owner/organization/name",
|
65
|
+
technical_committee: "./editorialgroup/technical-committee",
|
66
|
+
contributor_author_role: "./contributor/role[@type='author']",
|
67
|
+
contributor_publisher_role: "./contributor/role[@type='publisher']",
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def date_attributes
|
72
|
+
revdate =
|
73
|
+
find("./date[@type = 'published']") ||
|
74
|
+
find("./date[@type = 'circulated']") ||
|
75
|
+
find("./date")
|
76
|
+
|
77
|
+
value = find_text("./on", revdate) || find_text("./form", revdate)
|
78
|
+
|
79
|
+
if revdate && value
|
80
|
+
{ datetype: revdate["type"], revdate: Date.parse(value.strip).to_s }
|
81
|
+
end
|
82
|
+
rescue
|
83
|
+
warn "[relaton] parsing published date '#{revdate.text}' failed."
|
84
|
+
{ datetype: "circulated", revdate: value.strip }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/relaton-cli.gemspec
CHANGED
@@ -24,7 +24,6 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.required_ruby_version = ">= 2.3.0"
|
26
26
|
|
27
|
-
spec.add_development_dependency "bundler", "~> 2.0.1"
|
28
27
|
spec.add_development_dependency "rake", "~> 12.0"
|
29
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
30
29
|
spec.add_development_dependency "byebug", "~> 10.0"
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: relaton-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 2.0.1
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 2.0.1
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: rake
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,11 +164,13 @@ files:
|
|
178
164
|
- ".hound.yml"
|
179
165
|
- ".rubocop.yml"
|
180
166
|
- ".travis.yml"
|
167
|
+
- CHANGELOG.md
|
181
168
|
- Gemfile
|
182
|
-
- Gemfile.lock
|
183
169
|
- LICENSE
|
184
170
|
- Rakefile
|
171
|
+
- bin/console
|
185
172
|
- bin/rspec
|
173
|
+
- bin/setup
|
186
174
|
- docs/README.adoc
|
187
175
|
- exe/relaton
|
188
176
|
- i18n.yaml
|
@@ -198,6 +186,8 @@ files:
|
|
198
186
|
- lib/relaton/cli/xml_convertor.rb
|
199
187
|
- lib/relaton/cli/xml_to_html_renderer.rb
|
200
188
|
- lib/relaton/cli/yaml_convertor.rb
|
189
|
+
- lib/relaton/element_finder.rb
|
190
|
+
- lib/relaton/xml_document.rb
|
201
191
|
- relaton-cli.gemspec
|
202
192
|
- templates/_document.liquid
|
203
193
|
- templates/_index.liquid
|
data/Gemfile.lock
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
relaton-cli (0.1.7)
|
5
|
-
liquid
|
6
|
-
relaton (~> 0.3)
|
7
|
-
thor
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: https://rubygems.org/
|
11
|
-
specs:
|
12
|
-
addressable (2.6.0)
|
13
|
-
public_suffix (>= 2.0.2, < 4.0)
|
14
|
-
algoliasearch (1.25.2)
|
15
|
-
httpclient (~> 2.8, >= 2.8.3)
|
16
|
-
json (>= 1.5.1)
|
17
|
-
byebug (10.0.2)
|
18
|
-
cnccs (0.1.3)
|
19
|
-
coderay (1.1.2)
|
20
|
-
diff-lcs (1.3)
|
21
|
-
equivalent-xml (0.6.0)
|
22
|
-
nokogiri (>= 1.4.3)
|
23
|
-
gb-agencies (0.0.5)
|
24
|
-
gbbib (0.4.3)
|
25
|
-
cnccs (~> 0.1.1)
|
26
|
-
gb-agencies (~> 0.0.1)
|
27
|
-
iso-bib-item (~> 0.4.2)
|
28
|
-
httpclient (2.8.3)
|
29
|
-
iecbib (0.2.2)
|
30
|
-
addressable
|
31
|
-
iso-bib-item (~> 0.4.2)
|
32
|
-
ietfbib (0.4.5)
|
33
|
-
iso-bib-item (~> 0.4.2)
|
34
|
-
iso-bib-item (0.4.4)
|
35
|
-
isoics (~> 0.1.6)
|
36
|
-
nokogiri (~> 1.8.4)
|
37
|
-
ruby_deep_clone (~> 0.8.0)
|
38
|
-
isobib (0.4.3)
|
39
|
-
algoliasearch
|
40
|
-
iecbib (~> 0.2.1)
|
41
|
-
iso-bib-item (~> 0.4.2)
|
42
|
-
isoics (0.1.7)
|
43
|
-
json (2.1.0)
|
44
|
-
liquid (4.0.1)
|
45
|
-
method_source (0.9.2)
|
46
|
-
mini_portile2 (2.3.0)
|
47
|
-
mixlib-shellout (2.4.4)
|
48
|
-
nokogiri (1.8.5)
|
49
|
-
mini_portile2 (~> 2.3.0)
|
50
|
-
pry (0.12.2)
|
51
|
-
coderay (~> 1.1.0)
|
52
|
-
method_source (~> 0.9.0)
|
53
|
-
public_suffix (3.0.3)
|
54
|
-
rake (12.3.2)
|
55
|
-
relaton (0.3.1)
|
56
|
-
algoliasearch
|
57
|
-
gbbib (~> 0.4.0)
|
58
|
-
iecbib (~> 0.2.0)
|
59
|
-
ietfbib (~> 0.4.2)
|
60
|
-
iso-bib-item (~> 0.4.2)
|
61
|
-
isobib (~> 0.4.0)
|
62
|
-
rspec (3.8.0)
|
63
|
-
rspec-core (~> 3.8.0)
|
64
|
-
rspec-expectations (~> 3.8.0)
|
65
|
-
rspec-mocks (~> 3.8.0)
|
66
|
-
rspec-command (1.0.3)
|
67
|
-
mixlib-shellout (~> 2.0)
|
68
|
-
rspec (~> 3.2)
|
69
|
-
rspec-its (~> 1.2)
|
70
|
-
rspec-core (3.8.0)
|
71
|
-
rspec-support (~> 3.8.0)
|
72
|
-
rspec-expectations (3.8.2)
|
73
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
74
|
-
rspec-support (~> 3.8.0)
|
75
|
-
rspec-its (1.2.0)
|
76
|
-
rspec-core (>= 3.0.0)
|
77
|
-
rspec-expectations (>= 3.0.0)
|
78
|
-
rspec-mocks (3.8.0)
|
79
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
80
|
-
rspec-support (~> 3.8.0)
|
81
|
-
rspec-support (3.8.0)
|
82
|
-
ruby_deep_clone (0.8.0)
|
83
|
-
thor (0.20.3)
|
84
|
-
|
85
|
-
PLATFORMS
|
86
|
-
ruby
|
87
|
-
|
88
|
-
DEPENDENCIES
|
89
|
-
bundler (~> 2.0.1)
|
90
|
-
byebug (~> 10.0)
|
91
|
-
equivalent-xml (~> 0.6)
|
92
|
-
pry
|
93
|
-
rake (~> 12.0)
|
94
|
-
relaton-cli!
|
95
|
-
rspec (~> 3.0)
|
96
|
-
rspec-command (~> 1.0.3)
|
97
|
-
rspec-core (~> 3.4)
|
98
|
-
|
99
|
-
BUNDLED WITH
|
100
|
-
2.0.1
|