relaton-cli 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b73f1ac92117d1c3426a66fbe8ece05535b4441696a62a84f9aa5ce93379900f
4
- data.tar.gz: fb5ceb3383573256860f22af4eea6a2699b7a04e5d014b4764d1d9b4964674d6
3
+ metadata.gz: 602dc6b5405f7e9ad64b82a2db8d7c01e1f3de2aa95324a48cb1bef1f5d83394
4
+ data.tar.gz: 3d59d3c875327a1444f6d95be1d83f9b44e1edb78a40c3e3d1ae62096611f2b3
5
5
  SHA512:
6
- metadata.gz: f3274a54be270c3e9bd72aac19590a78a783015a0b1963b16cea1de3bc7f03924e11399c10324506119f384bdb5ea78392074b43c1666f832ec4eb58bd273b32
7
- data.tar.gz: 99351248582ea4313b872ddcb59ead76c41f6fc4fd1dabde7666b9dae14516d889f734d81d08bf8ceb562dd87fcedb34570c3f18255ee316b35ee6d326650c1d
6
+ metadata.gz: e0b7c3d7b95e26db2bb8392860e2ccaef744caa588885c285cb2ab472ecadda6d08d1393dd0f093f33d918f705351a1092f8b869940a8ee8aa50267446886849
7
+ data.tar.gz: 7c91b43960fbd34ee9500524fad1b355f3681960c623dd1af95f637736f577d516107330de97c4b97bf7785fc50b747c198c7f67ca4003fce8309760aa6a207a
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ ## 0.1.8 (2019-02-23)
2
+
3
+ Features:
4
+ - Add the `relaton split` interface
5
+ - Add support to convert single xml file
6
+ - Minor cleanup on bibdata and bibcollection
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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
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 = source&.at(ns("./relaton-collection/title"))&.text
44
- author = source&.at(ns("./relaton-collection/contributor[role/@type = 'author']/organization/name"))&.text
45
- items = source&.xpath(ns("./relaton-collection/relation"))&.map do |item|
46
- klass = item.at(ns("./bibdata")) ? Bibdata : Bibcollection
47
- klass.from_xml(item.at(ns("./bibdata")) || item)
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
- opts = { title: title, author: author, items: items }
50
- new(opts)
47
+
48
+ new(title: title, author: author, items: items)
51
49
  end
52
50
 
53
51
  def new_bib_item_class(options)
@@ -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
@@ -1,5 +1,6 @@
1
1
  require "thor"
2
2
  require "relaton"
3
+ require "relaton/xml_document"
3
4
  require_relative "cli/command"
4
5
 
5
6
  module Relaton
@@ -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
- File.open(outfile, "w:utf-8") { |file| file.write(content) }
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)
@@ -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 YAML into Relaton Bibcollection YAML (and separate files)"
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
- ## This interface expect us to provide a source directory, output
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
- outfile = [outdir, build_filename(file, bib)].join("/")
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 ||= outfile
156
- File.open(output_file, "w:utf-8") { |file| file.write(content) }
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 build_filename(file, document)
160
- identifier = Pathname.new(File.basename(file, ".xml")).to_s
161
- filename = identifier.downcase.gsub(/^\s+/, "").gsub(/\s+$/, "").gsub(/\s+/, "-")
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
@@ -1,5 +1,5 @@
1
1
  module Relaton
2
2
  module Cli
3
- VERSION = "0.1.7".freeze
3
+ VERSION = "0.1.8".freeze
4
4
  end
5
5
  end
@@ -30,7 +30,11 @@ module Relaton
30
30
  end
31
31
 
32
32
  def convert_content(content)
33
- Relaton::Bibcollection.from_xml(content)
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
- def initialize(options)
9
- @liquid_dir = options[:liquid_dir]
10
- @stylesheet = File.read(options[:stylesheet], encoding: "utf-8")
35
+ private
11
36
 
12
- @file_system = Liquid::LocalFileSystem.new(@liquid_dir)
13
- @template = File.read(@file_system.full_path("index"), encoding: "utf-8")
14
- Liquid::Template.file_system = @file_system
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 ns(xpath)
18
- xpath.gsub(%r{/([a-zA-z])}, "/xmlns:\\1").
19
- gsub(%r{::([a-zA-z])}, "::xmlns:\\1").
20
- gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1").
21
- gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
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 empty2nil(v)
25
- return nil if !v.nil? && v.is_a?(String) && v.empty?
26
- v
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 { |k, v| [k.to_s, empty2nil(v)] }.to_h
64
+ hash.map { |key, value| [key.to_s, empty2nil(value)] }.to_h
32
65
  end
33
66
 
34
- def render(index_xml)
35
- source = Nokogiri::XML(index_xml)
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 uri_for_extension(uri, extension)
48
- return nil if uri.nil?
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 self.render(file, options)
53
- new(options).render(file)
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.7
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-01-21 00:00:00.000000000 Z
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