From fbaaebb18a80bbc323b0dac0556e75240a3ee27e Mon Sep 17 00:00:00 2001 From: Benjamin Adams Date: Thu, 29 Nov 2018 10:45:42 -0500 Subject: [PATCH] Handle MI_Metadata from CSW record XML Handles MI_Metadata elements returned from CSW XML records, rather than returning None and causing an error later. Raises an exception when neither MD_Metadata nor MI_Metadata are found. Also sets encoding argument to 'unicode' rather than unicode (type), so that Python 3 does not break. --- ckanext/spatial/lib/csw_client.py | 38 ++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/ckanext/spatial/lib/csw_client.py b/ckanext/spatial/lib/csw_client.py index 207a0d40..576f1e17 100644 --- a/ckanext/spatial/lib/csw_client.py +++ b/ckanext/spatial/lib/csw_client.py @@ -17,14 +17,14 @@ class OwsService(object): def __init__(self, endpoint=None): if endpoint is not None: self._ows(endpoint) - + def __call__(self, args): return getattr(self, args.operation)(**self._xmd(args)) - + @classmethod def _operations(cls): return [x for x in dir(cls) if not x.startswith("_")] - + def _xmd(self, obj): md = {} for attr in [x for x in dir(obj) if not x.startswith("_")]: @@ -42,7 +42,7 @@ def _xmd(self, obj): else: md[attr] = self._xmd(val) return md - + def _ows(self, endpoint=None, **kw): if not hasattr(self, "_Implementation"): raise NotImplementedError("Needs an Implementation") @@ -51,7 +51,7 @@ def _ows(self, endpoint=None, **kw): raise ValueError("Must specify a service endpoint") self.__ows_obj__ = self._Implementation(endpoint) return self.__ows_obj__ - + def getcapabilities(self, debug=False, **kw): ows = self._ows(**kw) caps = self._xmd(ows) @@ -60,7 +60,7 @@ def getcapabilities(self, debug=False, **kw): if "response" in caps: del caps["response"] if "owscommon" in caps: del caps["owscommon"] return caps - + class CswService(OwsService): """ Perform various operations on a CSW service @@ -173,19 +173,31 @@ def getrecordbyid(self, ids=[], esn="full", outputschema="gmd", **kw): record = self._xmd(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") + # Ordinary Python versions don't support the metadata argument + # get the first element matching gmd:MD_Metadata or gmi:MI_Metadata + # or return None if not found + md = next(iter(csw._exml.xpath("./gmd:MD_Metadata|./gmi:MI_Metadata", + namespaces=namespaces)), None) + # If MD_Metadata or MI_Metadata is not the root element, raise + # an error + if md is None: + raise ValueError("Could not find MD_Metadata or MI_Metadata " + "in XML document") + mdtree = etree.ElementTree(md) try: - record["xml"] = etree.tostring(mdtree, pretty_print=True, encoding=unicode) + record["xml"] = etree.tostring(mdtree, pretty_print=True, + encoding='unicode') except TypeError: # API incompatibilities between different flavours of elementtree try: - record["xml"] = etree.tostring(mdtree, pretty_print=True, encoding=unicode) + record["xml"] = etree.tostring(mdtree, pretty_print=True, + encoding='unicode') except AssertionError: - record["xml"] = etree.tostring(md, pretty_print=True, encoding=unicode) + record["xml"] = etree.tostring(md, pretty_print=True, + encoding='unicode') - record["xml"] = '\n' + record["xml"] + record["xml"] = ('\n' + '{}'.format(record["xml"])) record["tree"] = mdtree return record