class DefraRuby::Area::BaseAreaService

Attributes

easting[R]
northing[R]

Public Class Methods

new(easting, northing) click to toggle source
# File lib/defra_ruby/area/services/base_area_service.rb, line 13
def initialize(easting, northing)
  @easting = easting
  @northing = northing
end
run(easting, northing) click to toggle source
# File lib/defra_ruby/area/services/base_area_service.rb, line 9
def self.run(easting, northing)
  new(easting, northing).run
end

Public Instance Methods

run() click to toggle source
# File lib/defra_ruby/area/services/base_area_service.rb, line 18
def run
  Response.new(response_exe)
end

Private Instance Methods

dataset() click to toggle source

Name of the Environment Agency dataset we are querying.

Not actually a part of the WFS interface or spec. This is simply how we route through to the right 'dataset' (how the EA terms it).

# File lib/defra_ruby/area/services/base_area_service.rb, line 63
def dataset
  implemented_in_subclass
end
domain() click to toggle source

Domain where the WFS is hosted

# File lib/defra_ruby/area/services/base_area_service.rb, line 55
def domain
  "https://environment.data.gov.uk"
end
extract_areas(xml_response) click to toggle source
# File lib/defra_ruby/area/services/base_area_service.rb, line 41
def extract_areas(xml_response)
  areas = []
  xml_response.xpath("//wfs:FeatureCollection/gml:featureMember").each do |parent|
    areas << Area.new(parent.first_element_child)
  end

  areas
end
filter() click to toggle source

WFS's use filters in GetFeature requests to return data that only matches a certain criteria.

docs.geoserver.org/latest/en/user/filter/function.html

There are various formats you can use for doing those, though it will be dependent on what the WFS supports. In our case we use XML-based Filter Encoding language because

  • this was how the team that manage the WFS have always provided their examples

  • we know this format is supported by the WFS's we are interacting with

The others are CQL and ECQL. docs.geoserver.org/latest/en/user/tutorials/cql/cql_tutorial.html

Our filter is looking for the result where our coordinates intersect with the feature property SHAPE, with SHAPE being a MultiPolygonPropertyType.

xml.fmi.fi/namespace/meteorology/conceptual-model/meteorological-objects/2009/04/28/docindex647.html

# File lib/defra_ruby/area/services/base_area_service.rb, line 178
      def filter
        # The filter is done in this way purely for readability. It could just
        # as easily been a one line string statement, but we think this is
        # better.
        filter = <<-XML
          (
            <Filter>
              <Intersects>
                <PropertyName>SHAPE</PropertyName>
                <gml:Point>
                  <gml:coordinates>#{easting},#{northing}</gml:coordinates>
                </gml:Point>
              </Intersects>
            </Filter>
          )
        XML
        filter.strip.squeeze(" ").gsub(/\s+/, "")
      end
implemented_in_subclass() click to toggle source
# File lib/defra_ruby/area/services/base_area_service.rb, line 197
def implemented_in_subclass
  raise NotImplementedError, "This #{self.class} cannot respond to:"
end
property_name() click to toggle source

Specify which attribute of the feature we want to return. You can check the attributes of a feature by making DescribeFeatureType request.

environment.data.gov.uk/spatialdata/administrative-boundaries-water-management-areas/wfs?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType

In our case the administrative boundary features contain a number of properties, but we are only interested in

  • area_id

  • area_name

  • code

  • long_name

  • short_name

# File lib/defra_ruby/area/services/base_area_service.rb, line 136
def property_name
  "area_id,area_name,code,long_name,short_name"
end
request() click to toggle source

Used to tell the WFS what kind of request you are making. In the case of `GetFeature` this means

Return a selection of features from a data source including geometry and attribute values

docs.geoserver.org/latest/en/user/services/wfs/reference.html#getfeature

# File lib/defra_ruby/area/services/base_area_service.rb, line 110
def request
  "GetFeature"
end
response_exe() click to toggle source
# File lib/defra_ruby/area/services/base_area_service.rb, line 26
def response_exe
  lambda do
    response = RestClient::Request.execute(
      method: :get,
      url: url,
      timeout: DefraRuby::Area.configuration.timeout
    )
    areas = extract_areas(Nokogiri::XML(response))

    raise NoMatchError unless areas.any?

    { areas: areas }
  end
end
service() click to toggle source

There are generally 3 kinds of GIS services; WFS, WMS, and WCS.

  • WFS - allows features to be queried, updated, created, or deleted by the client

  • WMS - returns map images based on the request made

  • WCS - transfer “coverages”, ie. objects covering a geographical area

We are querying a 'feature' hence we request to use the WFS service.

N.B. A feature is an Object that is an abstraction of a real world phenomenon. This object has a set of properties associated with each having a name, a type, and a value.

# File lib/defra_ruby/area/services/base_area_service.rb, line 90
def service
  "WFS"
end
srs_name() click to toggle source

SRS stands for Spatial Reference System. It can also be known as a Coordinate Reference System (CRS). It is a coordinate-based local, regional or global system used to locate geographical entities. A spatial reference system defines a specific map projection, as well as transformations between different spatial reference systems.

The SRSName paramater tells the WFS which SRS definition to use. The value is an EPSG (European Petroleum Survey Group) code. You can find a list of them at spatialreference.org/ref/epsg/

EPSG:27700 refers to OSGB 1936 - British National Grid (spatialreference.org/ref/epsg/27700/)

For more info on SRS read en.wikipedia.org/wiki/Spatial_reference_system

# File lib/defra_ruby/area/services/base_area_service.rb, line 154
def srs_name
  "EPSG:27700"
end
type_name() click to toggle source

Name of the feature we wish to query.

A WFS may host multiple features, so you need to specify which one you are querying in the url.

# File lib/defra_ruby/area/services/base_area_service.rb, line 118
def type_name
  implemented_in_subclass
end
url() click to toggle source
# File lib/defra_ruby/area/services/base_area_service.rb, line 50
def url
  "#{domain}/spatialdata/#{dataset}/wfs?#{url_params}"
end
url_params() click to toggle source
# File lib/defra_ruby/area/services/base_area_service.rb, line 67
def url_params
  {
    "SERVICE" => service,
    "VERSION" => version,
    "REQUEST" => request,
    "typeName" => type_name,
    "propertyName" => property_name,
    "SRSName" => srs_name,
    "Filter" => filter
  }.map { |k, v| "#{k}=#{v}" }.join("&")
end
version() click to toggle source

Currently there are various versions of the WFS standard, for example 1.0, 1.1 and 2.0.

The WFS's we are working with only support version 1.0. A WFS may suppport multiple versions hence you need to state the version in the request.

# File lib/defra_ruby/area/services/base_area_service.rb, line 100
def version
  "1.0.0"
end