Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for GetDataAvailabilitiy 2.0 and check for referenced phenomenonTime #7

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions sos4py/sos_2_0_0.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
from owslib.swe.observation.om import MeasurementObservation
from owslib.etree import etree
from owslib import ows
from urllib.parse import urlencode
import pandas as pd
import geopandas as gpd
from shapely.geometry import Point
import pyproj
import inspect
from .util import get_namespaces, nspv, TimePeriod, parseGDAReferencedElement, gda_member, check_list_param
from .util import get_namespaces, nspv, gda_member, gda2_member, check_list_param, check_gda_references

namespaces = get_namespaces()

Expand Down Expand Up @@ -139,15 +140,20 @@ def get_data_availability(self, procedures=None, observedProperties=None, featur
for kw in kwargs:
request[kw] = kwargs[kw]

request_gda = openURL(base_url, request, method, username=self.username, password=self.password, **url_kwargs).read()
data = urlencode(request)
request_gda = openURL(base_url, data, method, username=self.username, password=self.password, **url_kwargs).read()
gda = etree.fromstring(request_gda)

if gda.tag == nspath_eval("ows:ExceptionReport", namespaces):
raise ows.ExceptionReport(gda)

final = None
gdaMembers = gda.findall(nspath_eval("gda:dataAvailabilityMember", namespaces))
final = list(map(gda_member, gdaMembers))
return(final)
if gdaMembers is None or len(gdaMembers) == 0:
gdaMembers = gda.findall(nspath_eval("gda2:dataAvailabilityMember", namespaces))
final = list(map(gda2_member, gdaMembers))
else:
final = list(map(gda_member, gdaMembers))
return(check_gda_references(final))

def get_feature_of_interest(self, featuresOfInterest=None, observedProperties=None, procedures=None, responseFormat=None, method=None, **kwargs):
"""Performs "GetFeatureOfInterest" request
Expand Down Expand Up @@ -203,7 +209,8 @@ def get_feature_of_interest(self, featuresOfInterest=None, observedProperties=No
for kw in kwargs:
request[kw] = kwargs[kw]

response = openURL(base_url, request, method,
data = urlencode(request)
response = openURL(base_url, data, method,
username=self.username, password=self.password, **url_kwargs).read()
try:
tr = etree.fromstring(response)
Expand Down Expand Up @@ -331,7 +338,8 @@ def get_observation(self, responseFormat=None, offerings=None, observedPropertie
for kw in kwargs:
request[kw] = kwargs[kw]

response = openURL(base_url, request, method, username=self.username, password=self.password, **url_kwargs).read()
data = urlencode(request)
response = openURL(base_url, data, method, username=self.username, password=self.password, **url_kwargs).read()

try:
tr = etree.fromstring(response)
Expand Down
80 changes: 58 additions & 22 deletions sos4py/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,23 @@
from owslib.util import nspath_eval, testXMLAttribute, extract_time
from owslib.namespaces import Namespaces
import pandas as pd
from owslib.etree import etree

PHENOMENON_TIME_ID = 'PhenomenonTimeId'
PHENOMENON_TIME = 'PhenomenonTime'
START_TIME = 'StartTime'
END_TIME = 'EndTime'

def get_namespaces():
n = Namespaces()
ns = n.get_namespaces(["fes", "gml32", "ogc", "om20", "sa", "sml", "swe20", "swes", "wml2", "xlink", "xsi"])
ns["gda"] = 'http://www.opengis.net/sosgda/1.0'
ns["ns"] = "http://www.opengis.net/gml/3.2"
ns["ows"] = n.get_namespace("ows110")
ns["sams"] = "http://www.opengis.net/samplingSpatial/2.0"
ns["sf"] = "http://www.opengis.net/sampling/2.0"
ns["sos"] = n.get_namespace("sos20")
ns["gda"] = 'http://www.opengis.net/sosgda/1.0'
ns["gda2"] = 'http://www.opengis.net/sosgda/2.0'
return ns

def nspv(path):
Expand All @@ -35,46 +41,76 @@ def TimePeriod(start, end):
''' gml TimePeriod construction '''
return ("start: " + str(start) + " " + "end: " + str(end))

def parseGDAReferencedElement(gdaMembers, elementName):
def parseGDAReferencedElement(gdaMember, elementName):
"""Function to parse an element of a "GetDataAvailability" member"""
element = testXMLAttribute(gdaMembers.find(nspv(elementName)), nspv("xlink:href"))
element = testXMLAttribute(gdaMember.find(nspv(elementName)), nspv("xlink:href"))
return(element)

def gda_member(gdaMembers):
def gda2_member(gdaMember):
return gda_member(gdaMember, 'gda2')

def gda_member(gdaMember, gdaPrefix='gda'):
"""Function to parse each "GetDataAvailability" member"""
#Prefixes
gdaPrefix = "gda"
gdaProcedureName = gdaPrefix + ":procedure"
gdaObservedPropertyName = gdaPrefix + ":observedProperty"
gdaFeatureOfInterestName = gdaPrefix + ":featureOfInterest"
gdaOfferingName = gdaPrefix + ":offering"
gdaPhenomenonTime = gdaPrefix + ":phenomenonTime"
gdaResultTime = gdaPrefix + ":resultTime"

#Applying a parsing function to the elements
procedure_gda = parseGDAReferencedElement(gdaMembers, gdaProcedureName)
observedProperty_gda = parseGDAReferencedElement(gdaMembers, gdaObservedPropertyName)
featureOfInterest_gda = parseGDAReferencedElement(gdaMembers, gdaFeatureOfInterestName)
procedure_gda = parseGDAReferencedElement(gdaMember, gdaProcedureName)
observedProperty_gda = parseGDAReferencedElement(gdaMember, gdaObservedPropertyName)
featureOfInterest_gda = parseGDAReferencedElement(gdaMember, gdaFeatureOfInterestName)
offering_gda = parseGDAReferencedElement(gdaMember, gdaOfferingName)

''' Determine if phenomenonTime is instant or period. This
depend on the type of observation '''
instant_element = gdaMembers.find(nspv(
"gda:phenomenonTime/gml32:TimeInstant"))

if instant_element is not None:
phenomenonTime_gda = extract_time(instant_element)
pt_gml_id = parseGDAReferencedElement(gdaMember, gdaPhenomenonTime)
if pt_gml_id is not None:
phenomenonTime_gda = None
resultTime_gda = None
start = None
end = None
else:
start = extract_time(gdaMembers.find(nspv(
"gda:phenomenonTime/gml32:TimePeriod/gml32:beginPosition")))
end = extract_time(gdaMembers.find(nspv(
"gda:phenomenonTime/gml32:TimePeriod/gml32:endPosition")))
phenomenonTime_gda = TimePeriod(start, end)
resultTime_gda = extract_time(gdaMembers.find(nspv(
"gda:resultTime/gml32:TimeInstant/gml32:timePosition")))
instant_element = gdaMember.find(nspv(
gdaPhenomenonTime + "/gml32:TimeInstant"))
if instant_element is not None:
pt_gml_id = testXMLAttribute(instant_element, nspv("gml32:id"))
phenomenonTime_gda = extract_time(instant_element)
else:
period_element = gdaMember.find(nspv(gdaPhenomenonTime + "/gml32:TimePeriod"))
pt_gml_id = testXMLAttribute(period_element, nspv("gml32:id"))
start = extract_time(period_element.find(nspv("gml32:beginPosition")))
end = extract_time(period_element.find(nspv("gml32:endPosition")))
phenomenonTime_gda = TimePeriod(start, end)
resultTime_gda = extract_time(gdaMember.find(nspv(gdaResultTime + "/gml32:TimeInstant/gml32:timePosition")))

#Constructing the results
gda_values = [procedure_gda, observedProperty_gda, featureOfInterest_gda, phenomenonTime_gda, start, end, resultTime_gda]
gda_index = ['Procedure', 'ObservedProperty','FeatureOfInterest', 'PhenomenonTime', 'StartTime', 'EndTime', 'ResultTime']
gda_values = [procedure_gda, observedProperty_gda, featureOfInterest_gda, offering_gda, pt_gml_id, phenomenonTime_gda, start, end, resultTime_gda]
gda_index = ['Procedure', 'ObservedProperty','FeatureOfInterest', 'Offering', PHENOMENON_TIME_ID, PHENOMENON_TIME, START_TIME, END_TIME, 'ResultTime']
a = pd.Series(gda_values, index=gda_index, name="gda_member")
return(a)

def _get_gda_for_id(id, gdaMembers):
validId = id.replace('#', '')
for gdaMember in gdaMembers:
if gdaMember.get(PHENOMENON_TIME_ID) == validId:
return gdaMember
return None

def check_gda_references(gdaMembers):
for gdaMember in gdaMembers:
if gdaMember.get(PHENOMENON_TIME_ID).startswith('#'):
data = _get_gda_for_id(gdaMember.get(PHENOMENON_TIME_ID), gdaMembers)
if data is not None:
gdaMember.at[PHENOMENON_TIME_ID] = None
gdaMember.at[PHENOMENON_TIME] = data.get(PHENOMENON_TIME)
gdaMember.at[START_TIME] = data.get(START_TIME)
gdaMember.at[END_TIME] = data.get(END_TIME)
return gdaMembers

def check_list_param(list_param):
''' Check parameters conditions and if the condition is not satisfied the program will stop and give an assertion error '''
correctness = (isinstance(list_param, list) and \
Expand Down