This repository was archived by the owner on Mar 13, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathadd_geo_extension.rb
More file actions
143 lines (133 loc) · 4.7 KB
/
Copy pathadd_geo_extension.rb
File metadata and controls
143 lines (133 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# Usage: ruby add_geo_extension.rb datafile.xlsx inputdir outputdir
# Column headers in datafile:
# druid
# for bounding box coordinates: bb_west, bb_south, bb_east, bb_north
# for point coordinates: point_lat, point_long
# Coordinate data should be provided in decimal degrees
# Inputdir contains MODS files (filename is druid:[druid].xml, one record per file)
# Default assumes dc:format = image/jpeg and dc:type = Image
require 'nokogiri'
require 'roo'
# Set DC constants
dc_format = 'image/jpeg'
dc_type = 'Image'
datafile = ARGV[0]
inputdir = ARGV[1]
outputdir = ARGV[2]
# Check for existence of input and output directories
if !Dir.exist?(inputdir)
puts "#{inputdir} does not exist"
exit
elsif !Dir.exist?(outputdir)
Dir.mkdir(outputdir)
end
# Row count from datafile
count_in = 0
count_out = 0
# Open datafile spreadsheet
datasheet = Roo::Excelx.new("#{datafile}")
# Check for valid headers and set datatypes
data_headers = datasheet.row(1)
if !data_headers.include?('druid')
puts "Datafile does not contain column with header 'druid'"
exit
elsif data_headers.sort == ['bb_east','bb_north','bb_south','bb_west', 'druid']
@datatype = 'bounding box'
elsif data_headers.sort == ['druid', 'point_lat', 'point_long']
@datatype = 'point'
else
puts "Datafile does not contain correct headers"
exit
end
# Parse columns according to expected headers for datatype
if @datatype == 'bounding box'
@rows = datasheet.parse(druid: 'druid', bb_south: 'bb_south', bb_west: 'bb_west', bb_east: 'bb_east', bb_north: 'bb_north')
elsif @datatype == 'point'
@rows = datasheet.parse(druid: 'druid', point_lat: 'point_lat', point_long: 'point_long')
end
# Check for valid data in datafile
error = FALSE
missing_druids = 0
@rows.each do |row|
next if row.values.compact == [] || row[:druid] == 'druid'
if row[:druid] == nil
missing_druids += 1
error = TRUE
elsif row[:druid].to_s.strip.match(/[a-z]{2}[0-9]{3}[a-z]{2}[0-9]{4}/) == nil
puts "Invalid druid: #{row[:druid]}"
error = TRUE
elsif row.values.include?(nil)
puts "Datafile missing coordinate data for #{row[:druid]}"
# error = TRUE
elsif row.values[1..-1].join(' ').match(/[^0-9. ]/)
puts "Datafile contains invalid characters in coordinate data for #{row[:druid]}"
error = TRUE
end
end
if missing_druids > 0
puts "#{missing_druids} row(s) missing druids"
end
if error == TRUE
puts "Exiting due to errors in datafile"
exit
end
# Process datafile and insert geodata into MODS
@rows.each do |row|
next if row.values.compact == [] || row[:druid] == 'druid'
count_in += 1
# Check for existence of MODS file corresponding to druid in datafile row
unless Dir.entries(inputdir).include?("druid:#{row[:druid]}.xml")
puts "File for #{row[:druid]} does not exist in #{inputdir}"
next
end
count_out += 1
# Open MODS XML
doc = Nokogiri::XML(open(File.join(inputdir, "druid:#{row[:druid]}.xml"), "r"))
# Add RDF namespace to root
doc.root.add_namespace('rdf', "http://www.w3.org/1999/02/22-rdf-syntax-ns#") unless doc.root.namespaces.include?('rdf')
# Construct extension element based on DC constants, datatype, and datafile row
if @datatype == 'bounding box'
geodata = <<GEO
<extension displayLabel="geo">
<rdf:RDF xmlns:gml="http://www.opengis.net/gml/3.2/" xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description rdf:about="http://www.stanford.edu/#{row[:druid]}">
<dc:format>#{dc_format}</dc:format>
<dc:type>#{dc_type}</dc:type>
<gml:boundedBy>
<gml:Envelope>
<gml:lowerCorner>#{row[:bb_west]} #{row[:bb_south]}</gml:lowerCorner>
<gml:upperCorner>#{row[:bb_east]} #{row[:bb_north]}</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
</rdf:Description>
</rdf:RDF>
</extension>
GEO
elsif @datatype == 'point'
geodata = <<GEO
<extension displayLabel="geo">
<rdf:RDF xmlns:gml="http://www.opengis.net/gml/3.2/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:gmd="http://www.isotc211.org/2005/gmd">
<rdf:Description rdf:about="http://www.stanford.edu/#{row[:druid]}">
<dc:format>#{dc_format}</dc:format>
<dc:type>#{dc_type}</dc:type>
<gmd:centerPoint>
<gml:Point gml:id="ID">
<gml:pos>#{row[:point_lat]} #{row[:point_long]}</gml:pos>
</gml:Point>
</gmd:centerPoint>
</rdf:Description>
</rdf:RDF>
</extension>
GEO
end
# Insert extension into MODS
geonode = Nokogiri::XML.fragment(geodata)
doc.root << geonode
# Write new MODS file with extension added
outfile = File.new(File.join(outputdir, "druid:#{row[:druid]}.xml"), "w")
outfile.write(doc.to_s)
outfile.close
end
# Report stats
puts "Druids in: #{count_in}"
puts "Druids out: #{count_out}"