Class: Dor::GeoMetadataDS

Inherits:
ActiveFedora::NokogiriDatastream
  • Object
show all
Includes:
SolrDocHelper
Defined in:
lib/dor/datastreams/geo_metadata_ds.rb

Overview

GeoMetadataDS is a Fedora datastream for geographic metadata. It uses the ISO 19139 metadata standard schema - a metadata standard for Geographic Information The datastream is packaged using RDF to identify the optional ISO 19139 feature catalog

See Also:

Author:

  • Darren Hardy

Constant Summary collapse

NS =

namespaces

{
  :rdf => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
  :gco => 'http://www.isotc211.org/2005/gco',
  :gmd => 'http://www.isotc211.org/2005/gmd',
  :gfc => 'http://www.isotc211.org/2005/gfc'
}
XMLNS =

hash with all namespaces

Hash[NS.map {|k,v| ["xmlns:#{k}", v]}]
NS_XSD =

schema locations

NS.keys.collect {|k| "#{NS[k]} #{NS[k]}/#{k}.xsd"}
XSLT_GEOMODS =
Nokogiri::XSLT::Stylesheet

for ISO 19139 to MODS

Nokogiri::XSLT(File.read(
                                    File.join(
File.dirname(__FILE__), 'geo2mods.xsl')))
XSLT_DC =
Nokogiri::XSLT(File.new(
                               File.expand_path(
File.dirname(__FILE__) + '/../models/mods2dc.xslt')))

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SolrDocHelper

#add_solr_value

Instance Attribute Details

#geometryTypeObject

Returns the value of attribute geometryType


15
16
17
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 15

def geometryType
  @geometryType
end

#purlObject

Returns the value of attribute purl


15
16
17
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 15

def purl
  @purl
end

#zipNameObject

Returns the value of attribute zipName


15
16
17
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 15

def zipName
  @zipName
end

Class Method Details

.xml_templateNokogiri::XML::Document


102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 102

def self.xml_template
  Nokogiri::XML::Builder.new do |xml|
    xml['rdf'].RDF XMLNS, 
      'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
      "xsi:schemaLocation" => NS_XSD.join(' ') do
      xml['rdf'].Description 'rdf:about' => nil do
        xml['gmd'].
      end
      xml['rdf'].Description 'rdf:about' => nil do
        xml['gfc'].FC_FeatureCatalogue
      end
    end
  end.doc
end

Instance Method Details

#feature_catalogueNokogiri::XML::Document


90
91
92
93
94
95
96
97
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 90

def feature_catalogue
  root = ng_xml.xpath('/rdf:RDF/rdf:Description/gfc:FC_FeatureCatalogue', XMLNS)
  if root.nil? or root.empty?
    nil # Feature catalog is optional
  else
    Nokogiri::XML(root.first.to_xml)
  end
end

#metadataNokogiri::XML::Document

Returns with gmd:MD_Metadata as root node

Raises:


79
80
81
82
83
84
85
86
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 79

def 
  root = ng_xml.xpath('/rdf:RDF/rdf:Description/gmd:MD_Metadata', XMLNS)
  if root.nil? or root.empty?
    raise Dor::ParameterError, "Invalid geoMetadata -- missing MD_Metadata: #{root}" 
  else
    Nokogiri::XML(root.first.to_xml)
  end
end

#to_bboxStruct


204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 204

def to_bbox
  params = { 'xmlns:gmd' => NS[:gmd], 'xmlns:gco' => NS[:gco] }
  bb = .xpath(
    '//gmd:EX_Extent/gmd:geographicElement' + 
    '/gmd:EX_GeographicBoundingBox', params).first
  Struct.new(:w, :e, :n, :s).new(
    bb.xpath('gmd:westBoundLongitude/gco:Decimal', params).text.to_f,
    bb.xpath('gmd:eastBoundLongitude/gco:Decimal', params).text.to_f,
    bb.xpath('gmd:northBoundLatitude/gco:Decimal', params).text.to_f,
    bb.xpath('gmd:southBoundLatitude/gco:Decimal', params).text.to_f
  )
end

#to_centroidArray<Numeric>

Returns (x y) coordinates of center point - assumes #to_bbox


219
220
221
222
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 219

def to_centroid
  bb = to_bbox
  [ (bb.w + bb.e)/2, (bb.n + bb.s)/2 ]
end

#to_dc_coverageString


246
247
248
249
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 246

def to_dc_coverage
  bb = to_bbox
  "x.min=#{bb.w} x.max=#{bb.e} y.min=#{bb.s} y.max=#{bb.n}"
end

#to_dublin_coreObject


159
160
161
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 159

def to_dublin_core
  XSLT_DC.transform(to_mods)
end

#to_mods(params = {}) ⇒ Nokogiri::XML::Document

Generates MODS from ISO 19139

Uses GML SimpleFeatures for the geometry type (e.g., Polygon, LineString, etc.)

Raises:

  • (CrosswalkError)

    Raises if the generated MODS is empty or has no children

See Also:


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 125

def to_mods(params = {})      
  params = params.merge({ 
    'geometryType' => "'#{@geometryType.nil?? 'Polygon' : @geometryType}'",
    'zipName' => "'#{@zipName.nil?? 'data.zip' : @zipName}'",
    'purl' => "'#{@purl}'"
  })
  doc = XSLT_GEOMODS.transform(.document, params.to_a.flatten)
  unless doc.root and doc.root.children.size > 0
    raise CrosswalkError, 'to_mods produced incorrect xml'
  end
  # ap doc
  doc.xpath('/mods:mods' + 
    '/mods:subject' + 
    '/mods:cartographics' + 
    '/mods:projection', 
    'xmlns:mods' => Dor::DescMetadataDS::MODS_NS).each do |e|
    # Retrieve this mapping from config file
    case e.content.downcase
    when 'epsg:4326', 'epsg::4326', 'urn:ogc:def:crs:epsg::4326'
      e.content = 'World Geodetic System (WGS84)'
    when 'epsg:4269', 'epsg::4269', 'urn:ogc:def:crs:epsg::4269'
      e.content = 'North American Datum (NAD83)'
    end
  end
  doc.xpath('/mods:mods' +
    '/mods:subject' +
    '/mods:cartographics' +
    '/mods:coordinates', 
    'xmlns:mods' => Dor::DescMetadataDS::MODS_NS).each do |e|
    e.content = '(' + self.class.to_coordinates_ddmmss(e.content.to_s) + ')'
  end
  doc
end

#to_solr_bbox(format = :solr4) ⇒ String

A lat-lon rectangle can be indexed with 4 numbers in minX minY maxX maxY order:

<field name="geo">-74.093 41.042 -69.347 44.558</field> 
<field name="geo">POLYGON((...))</field>

232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 232

def to_solr_bbox format = :solr4
  bb = to_bbox
  
  case format
  when :solr3
    [bb.w, bb.s, bb.e, bb.n].join(' ')
  when :solr4
    Dor::GeoMetadataDS.to_wkt [bb.w, bb.s], [bb.e, bb.n]
  else
    raise ArgumentError, "Unsupported format #{format}"
  end
end

#to_solr_centroid(format = :solr4) ⇒ String

Returns (y,x) coordinates of center point matching the LatLonType Solr type


262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 262

def to_solr_centroid format = :solr4
  x, y = to_centroid
  
  case format
  when :solr3
    [y,x].join(',') # for solr.LatLonType
  when :solr4
    Dor::GeoMetadataDS.to_wkt [x, y]
  else
    raise ArgumentError, "Unsupported format #{format}"
  end
end

#to_solr_spatial(solr_doc = Hash.new, *args) ⇒ Object

Deprecated.

stub for GeoBlacklight (not Argo – use to_solr as usual)


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/dor/datastreams/geo_metadata_ds.rb', line 164

def to_solr_spatial(solr_doc=Hash.new, *args)
  # There are a whole bunch of namespace-related things that can go
  # wrong with this terminology. Until it's fixed in OM, ignore them all.
  begin
    doc = solr_doc#super solr_doc, *args
    bb = to_bbox
    ap({:doc => doc, :bb => bb, :self => self}) if $DEBUG
    {
      :id => self.id.first,
      :druid => URI(self.id.first).path.gsub(%r{^/}, ''),
      :file_id_s => self.file_id.first,
      :geo_bbox => to_solr_bbox,
      :geo_data_type_s => 'vector',
      :geo_format_s => self.format.first,
      :geo_geometry_type_s => 'Polygon',
      :geo_layername_s => File.basename(self.layername.first, '.shp'),
      :geo_ne_pt => Dor::GeoMetadataDS.to_wkt([bb.e, bb.n]),
      :geo_pt => to_solr_centroid,
      :geo_sw_pt => Dor::GeoMetadataDS.to_wkt([bb.w, bb.s]),
      :geo_proj => self.projection.first,
      :dc_coverage_t => to_dc_coverage,
      :dc_creator_t => self.originator.first,
      :dc_date_i => self.publish_dt.map {|i| i.to_s[0..3]},
      :dc_description_t => [self.abstract.first, self.purpose.first].join(";\n"),
      :dc_format_s => 'application/x-esri-shapefile',
      :dc_language_s => self..first,
      :dc_title_t => self.title.first,
      :text => [self.title.first, self.abstract.first, self.purpose.first].join(";\n")
    }.each do |id, v|
      ::Solrizer::Extractor.insert_solr_field_value(doc, id.to_s, v)
    end

    return doc
  rescue 
    solr_doc
  end
end