spatial-d4science/ckanext/spatial/lib/csw_client.py

192 lines
6.4 KiB
Python
Raw Normal View History

"""
Some very thin wrapper classes around those in OWSLib
for convenience.
"""
2020-04-14 22:11:15 +02:00
import six
import logging
from owslib.etree import etree
from owslib.fes import PropertyIsEqualTo, SortBy, SortProperty
log = logging.getLogger(__name__)
class CswError(Exception):
pass
class OwsService(object):
def __init__(self, endpoint=None):
if endpoint is not None:
self._ows(endpoint)
2020-04-14 22:11:15 +02:00
def __call__(self, args):
return getattr(self, args.operation)(**self._xmd(args))
2020-04-14 22:11:15 +02:00
@classmethod
def _operations(cls):
return [x for x in dir(cls) if not x.startswith("_")]
2020-04-14 22:11:15 +02:00
def _xmd(self, obj):
md = {}
for attr in [x for x in dir(obj) if not x.startswith("_")]:
val = getattr(obj, attr)
if not val:
pass
elif callable(val):
pass
2020-04-14 22:11:15 +02:00
elif isinstance(val, six.string_types):
md[attr] = val
elif isinstance(val, int):
md[attr] = val
elif isinstance(val, list):
md[attr] = val
else:
md[attr] = self._xmd(val)
return md
2020-04-14 22:11:15 +02:00
def _ows(self, endpoint=None, **kw):
if not hasattr(self, "_Implementation"):
raise NotImplementedError("Needs an Implementation")
if not hasattr(self, "__ows_obj__"):
if endpoint is None:
raise ValueError("Must specify a service endpoint")
self.__ows_obj__ = self._Implementation(endpoint)
return self.__ows_obj__
2020-04-14 22:11:15 +02:00
def getcapabilities(self, debug=False, **kw):
ows = self._ows(**kw)
caps = self._xmd(ows)
if not debug:
if "request" in caps: del caps["request"]
if "response" in caps: del caps["response"]
if "owscommon" in caps: del caps["owscommon"]
return caps
2020-04-14 22:11:15 +02:00
class CswService(OwsService):
"""
Perform various operations on a CSW service
"""
from owslib.csw import CatalogueServiceWeb as _Implementation
2016-01-25 16:33:48 +01:00
def __init__(self, endpoint=None):
super(CswService, self).__init__(endpoint)
self.sortby = SortBy([SortProperty('dc:identifier')])
def getrecords(self, qtype=None, keywords=[],
typenames="csw:Record", esn="brief",
skip=0, count=10, outputschema="gmd", **kw):
from owslib.csw import namespaces
constraints = []
csw = self._ows(**kw)
if qtype is not None:
constraints.append(PropertyIsEqualTo("dc:type", qtype))
kwa = {
"constraints": constraints,
"typenames": typenames,
"esn": esn,
"startposition": skip,
"maxrecords": count,
"outputschema": namespaces[outputschema],
"sortby": self.sortby
}
log.info('Making CSW request: getrecords2 %r', kwa)
csw.getrecords2(**kwa)
if csw.exceptionreport:
err = 'Error getting records: %r' % \
csw.exceptionreport.exceptions
#log.error(err)
raise CswError(err)
2019-12-11 13:23:03 +01:00
return [self._xmd(r) for r in list(csw.records.values())]
def getidentifiers(self, qtype=None, typenames="csw:Record", esn="brief",
keywords=[], limit=None, page=10, outputschema="gmd",
startposition=0, cql=None, **kw):
from owslib.csw import namespaces
constraints = []
csw = self._ows(**kw)
if qtype is not None:
constraints.append(PropertyIsEqualTo("dc:type", qtype))
kwa = {
"constraints": constraints,
"typenames": typenames,
"esn": esn,
"startposition": startposition,
"maxrecords": page,
"outputschema": namespaces[outputschema],
"cql": cql,
"sortby": self.sortby
}
i = 0
matches = 0
while True:
log.info('Making CSW request: getrecords2 %r', kwa)
csw.getrecords2(**kwa)
if csw.exceptionreport:
err = 'Error getting identifiers: %r' % \
csw.exceptionreport.exceptions
#log.error(err)
raise CswError(err)
if matches == 0:
matches = csw.results['matches']
2019-12-11 13:23:03 +01:00
identifiers = list(csw.records.keys())
if limit is not None:
identifiers = identifiers[:(limit-startposition)]
for ident in identifiers:
yield ident
if len(identifiers) == 0:
break
i += len(identifiers)
if limit is not None and i > limit:
break
startposition += page
if startposition >= (matches + 1):
break
kwa["startposition"] = startposition
def getrecordbyid(self, ids=[], esn="full", outputschema="gmd", **kw):
from owslib.csw import namespaces
csw = self._ows(**kw)
kwa = {
"esn": esn,
"outputschema": namespaces[outputschema],
}
# Ordinary Python version's don't support the metadata argument
log.info('Making CSW request: getrecordbyid %r %r', ids, kwa)
csw.getrecordbyid(ids, **kwa)
if csw.exceptionreport:
err = 'Error getting record by id: %r' % \
csw.exceptionreport.exceptions
#log.error(err)
raise CswError(err)
if not csw.records:
return
2019-12-11 13:23:03 +01:00
record = self._xmd(list(csw.records.values())[0])
## strip off the enclosing results container, we only want the metadata
#md = csw._exml.find("/gmd:MD_Metadata")#, namespaces=namespaces)
# Ordinary Python version's don't support the metadata argument
md = csw._exml.find("/{http://www.isotc211.org/2005/gmd}MD_Metadata")
mdtree = etree.ElementTree(md)
try:
2019-12-11 13:23:03 +01:00
record["xml"] = etree.tostring(mdtree, pretty_print=True, encoding=str)
except TypeError:
# API incompatibilities between different flavours of elementtree
try:
2019-12-11 13:23:03 +01:00
record["xml"] = etree.tostring(mdtree, pretty_print=True, encoding=str)
except AssertionError:
2019-12-11 13:23:03 +01:00
record["xml"] = etree.tostring(md, pretty_print=True, encoding=str)
record["xml"] = '<?xml version="1.0" encoding="UTF-8"?>\n' + record["xml"]
record["tree"] = mdtree
return record