Ejemplo n.º 1
0
    def _write_response(self):
        """ Generate response """
        # set HTTP response headers and XML declaration

        xmldecl = ""
        appinfo = ""

        LOGGER.debug("Writing response.")

        if hasattr(self, "soap") and self.soap:
            self._gen_soap_wrapper()

        if isinstance(self.kvp, dict) and "outputformat" in self.kvp and self.kvp["outputformat"] == "application/json":
            self.contenttype = self.kvp["outputformat"]
            from pycsw.core.formats import fmt_json

            response = fmt_json.exml2json(self.response, self.context.namespaces, self.pretty_print)
        else:  # it's XML
            if "outputformat" in self.kvp:
                self.contenttype = self.kvp["outputformat"]
            else:
                self.contenttype = self.mimetype
            response = etree.tostring(self.response, pretty_print=self.pretty_print, encoding="unicode")
            xmldecl = '<?xml version="1.0" encoding="%s" standalone="no"?>' "\n" % self.encoding
            appinfo = "<!-- pycsw %s -->\n" % self.context.version

        s = (u"%s%s%s" % (xmldecl, appinfo, response)).encode(self.encoding)
        LOGGER.debug("Response code: %s", self.context.response_codes[self.status])
        LOGGER.debug("Response:\n%s", s)
        return [self.context.response_codes[self.status], s]
Ejemplo n.º 2
0
    def _write_response(self):
        ''' Generate response '''
        # set HTTP response headers and XML declaration

        xmldecl=''
        appinfo=''

        LOGGER.debug('Writing response.')

        if hasattr(self, 'soap') and self.soap:
            self._gen_soap_wrapper()

        if (isinstance(self.kvp, dict) and 'outputformat' in self.kvp and
            self.kvp['outputformat'] == 'application/json'):
            self.contenttype = self.kvp['outputformat']
            from pycsw.core.formats import fmt_json
            response = fmt_json.exml2json(self.response,
            self.context.namespaces, self.pretty_print)
        else:  # it's XML
            if 'outputformat' in self.kvp:
                self.contenttype = self.kvp['outputformat']
            else:
                self.contenttype = self.mimetype
            response = etree.tostring(self.response,
            pretty_print=self.pretty_print, encoding='unicode')
            xmldecl = '<?xml version="1.0" encoding="%s" standalone="no"?>\n' \
            % self.encoding
            appinfo = '<!-- pycsw %s -->\n' % self.context.version

        s = (u'%s%s%s' % (xmldecl, appinfo, response)).encode(self.encoding)
        LOGGER.debug('Response code: %s', self.context.response_codes[self.status])
        LOGGER.debug('Response:\n%s', s)
        return [self.context.response_codes[self.status], s]
Ejemplo n.º 3
0
Archivo: admin.py Proyecto: bukun/pycsw
def gen_sitemap(context, database, table, url, output_file):
    """generate an XML sitemap from all records in repository"""

    # get configuration and init repo connection
    repos = repository.Repository(database, context, table=table)

    # write out sitemap document
    urlset = etree.Element(util.nspath_eval("sitemap:urlset", context.namespaces), nsmap=context.namespaces)

    schema_loc = util.nspath_eval("xsi:schemaLocation", context.namespaces)

    urlset.attrib[schema_loc] = (
        "%s http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" % context.namespaces["sitemap"]
    )

    # get all records
    count, records = repos.query(constraint={}, maxrecords=99999999)

    LOGGER.info("Found %s records", count)

    for rec in records:
        url = etree.SubElement(urlset, util.nspath_eval("sitemap:url", context.namespaces))
        uri = "%s?service=CSW&version=2.0.2&request=GetRepositoryItem&id=%s" % (
            url,
            getattr(rec, context.md_core_model["mappings"]["pycsw:Identifier"]),
        )
        etree.SubElement(url, util.nspath_eval("sitemap:loc", context.namespaces)).text = uri

    # write to file
    LOGGER.info("Writing to %s", output_file)
    with open(output_file, "w") as ofile:
        ofile.write(etree.tostring(urlset, pretty_print=1, encoding="utf8", xml_declaration=1))
Ejemplo n.º 4
0
def cql2fes1(cql, namespaces):
    """transforms Common Query Language (CQL) query into OGC fes1 syntax"""

    filters = []
    tmp_list = []
    logical_op = None

    LOGGER.debug('CQL: %s', cql)

    if ' or ' in cql:
        logical_op = etree.Element(util.nspath_eval('ogc:Or', namespaces))
        tmp_list = cql.split(' or ')
    elif ' OR ' in cql:
        logical_op = etree.Element(util.nspath_eval('ogc:Or', namespaces))
        tmp_list = cql.split(' OR ')
    elif ' and ' in cql:
        logical_op = etree.Element(util.nspath_eval('ogc:And', namespaces))
        tmp_list = cql.split(' and ')
    elif ' AND ' in cql:
        logical_op = etree.Element(util.nspath_eval('ogc:And', namespaces))
        tmp_list = cql.split(' AND ')

    if tmp_list:
        LOGGER.debug('Logical operator found (AND/OR)')
    else:
        tmp_list.append(cql)

    for t in tmp_list:
        filters.append(_parse_condition(t))

    root = etree.Element(util.nspath_eval('ogc:Filter', namespaces))

    if logical_op is not None:
        root.append(logical_op)

    for flt in filters:
        condition = etree.Element(util.nspath_eval(flt[0], namespaces))

        etree.SubElement(
            condition,
            util.nspath_eval('ogc:PropertyName', namespaces)).text = flt[1]

        etree.SubElement(
            condition,
            util.nspath_eval('ogc:Literal', namespaces)).text = flt[2]

        if logical_op is not None:
            logical_op.append(condition)
        else:
            root.append(condition)

    LOGGER.debug('Resulting OGC Filter: %s',
                 etree.tostring(root, pretty_print=1))

    return root
Ejemplo n.º 5
0
def caps2iso(record, caps, context):
    """Creates ISO metadata from Capabilities XML"""

    from pycsw.plugins.profiles.apiso.apiso import APISO

    apiso_obj = APISO(context.model, context.namespaces, context)
    apiso_obj.ogc_schemas_base = 'http://schemas.opengis.net'
    apiso_obj.url = context.url
    queryables = dict(apiso_obj.repository['queryables']['SupportedISOQueryables'].items() + apiso_obj.repository['queryables']['SupportedISOQueryables'].items())
    iso_xml = apiso_obj.write_record(record, 'full', 'http://www.isotc211.org/2005/gmd', queryables, caps)
    return etree.tostring(iso_xml)
Ejemplo n.º 6
0
    def _write_response(self):
        """ Generate response """
        # set HTTP response headers and XML declaration

        xmldecl = ''
        appinfo = ''

        LOGGER.info('Writing response.')

        if hasattr(self, 'soap') and self.soap:
            self._gen_soap_wrapper()

        if etree.__version__ >= '3.5.0':  # remove superfluous namespaces
            etree.cleanup_namespaces(self.response,
                                     keep_ns_prefixes=self.context.keep_ns_prefixes)

        response = etree.tostring(self.response,
                                  pretty_print=self.pretty_print,
                                  encoding='unicode')


        if (isinstance(self.kvp, dict) and 'outputformat' in self.kvp and
                (self.kvp['outputformat'] == 'application/xml' or self.kvp['outputformat'] == 'application/XML')):
            self.contenttype = self.kvp['outputformat']
            

            xmldecl = ('<?xml version="1.0" encoding="%s" standalone="no"?>'
                       '\n' % self.encoding)
            appinfo = '<!-- pycsw %s -->\n' % self.context.version

        else:  # it's json

            self.contenttype = "application/json"

            from pycsw.core.formats import fmt_json
            response = fmt_json.xml2json(response,
                                         self.context.namespaces,
                                         self.pretty_print)
        
        if isinstance(self.contenttype, bytes):
            self.contenttype = self.contenttype.decode()
        LOGGER.debug(response)
        #response = '{"csw30:SummaryRecord": {"dc:identifier123": "urn:uuid:a06af396-3105-442d-8b40-22b57a90d2f2","dc:title": "Lorem ipsum dolor sit amet","dc:type": "http://purl.org/dc/dcmitype/Image","dc:format": "image/jpeg", "": {"": ""}}}'
        s = (u'%s%s%s' % (xmldecl, appinfo, response)).encode(self.encoding)
        LOGGER.debug('Response code: %s',
                     self.context.response_codes[self.status])
        LOGGER.debug('Response:\n%s', s)
        return [self.context.response_codes[self.status], s]
Ejemplo n.º 7
0
    def _write_response(self):
        """ Generate response """
        # set HTTP response headers and XML declaration

        xmldecl = ''
        appinfo = ''

        LOGGER.info('Writing response.')

        if hasattr(self, 'soap') and self.soap:
            self._gen_soap_wrapper()

        if etree.__version__ >= '3.5.0':  # remove superfluous namespaces
            etree.cleanup_namespaces(self.response,
                                     keep_ns_prefixes=self.context.keep_ns_prefixes)

        response = etree.tostring(self.response,
                                  pretty_print=self.pretty_print,
                                  encoding='unicode')

        if (isinstance(self.kvp, dict) and 'outputformat' in self.kvp and
                self.kvp['outputformat'] == 'application/json'):
            self.contenttype = self.kvp['outputformat']
            from pycsw.core.formats import fmt_json
            response = fmt_json.xml2json(response,
                                         self.context.namespaces,
                                         self.pretty_print)
        else:  # it's XML
            if 'outputformat' in self.kvp:
                self.contenttype = self.kvp['outputformat']
            else:
                self.contenttype = self.mimetype

            xmldecl = ('<?xml version="1.0" encoding="%s" standalone="no"?>'
                       '\n' % self.encoding)
            appinfo = '<!-- pycsw %s -->\n' % self.context.version

        if isinstance(self.contenttype, bytes):
            self.contenttype = self.contenttype.decode()

        s = (u'%s%s%s' % (xmldecl, appinfo, response)).encode(self.encoding)
        LOGGER.debug('Response code: %s',
                     self.context.response_codes[self.status])
        LOGGER.debug('Response:\n%s', s)
        return [self.context.response_codes[self.status], s]
Ejemplo n.º 8
0
    def _write_response(self):
        """ Generate response """
        # set HTTP response headers and XML declaration

        xmldecl = ''
        appinfo = ''

        LOGGER.info('Writing response.')

        if hasattr(self, 'soap') and self.soap:
            self._gen_soap_wrapper()

        if etree.__version__ >= '3.5.0':  # remove superfluous namespaces
            etree.cleanup_namespaces(self.response,
                                     keep_ns_prefixes=self.context.keep_ns_prefixes)

        response = etree.tostring(self.response,
                                  pretty_print=self.pretty_print,
                                  encoding='unicode')

        if (isinstance(self.kvp, dict) and 'outputformat' in self.kvp and
                self.kvp['outputformat'] == 'application/json'):
            self.contenttype = self.kvp['outputformat']
            from pycsw.core.formats import fmt_json
            response = fmt_json.xml2json(response,
                                         self.context.namespaces,
                                         self.pretty_print)
        else:  # it's XML
            if 'outputformat' in self.kvp:
                self.contenttype = self.kvp['outputformat']
            else:
                self.contenttype = self.mimetype

            xmldecl = ('<?xml version="1.0" encoding="%s" standalone="no"?>'
                       '\n' % self.encoding)
            appinfo = '<!-- pycsw %s -->\n' % self.context.version

        if isinstance(self.contenttype, bytes):
            self.contenttype = self.contenttype.decode()

        s = (u'%s%s%s' % (xmldecl, appinfo, response)).encode(self.encoding)
        LOGGER.debug('Response code: %s',
                     self.context.response_codes[self.status])
        LOGGER.debug('Response:\n%s', s)
        return [self.context.response_codes[self.status], s]
Ejemplo n.º 9
0
def update_xpath(nsmap, xml, recprop):
    """Update XML document XPath values"""

    if isinstance(xml, unicode):  # not lxml serialized yet
        xml = etree.fromstring(xml, PARSER)

    recprop = eval(recprop)
    nsmap = eval(nsmap)
    try:
        nodes = xml.xpath(recprop['rp']['xpath'], namespaces=nsmap)
        if len(nodes) > 0:  # matches
            for node1 in nodes:
                if node1.text != recprop['value']:  # values differ, update
                    node1.text = recprop['value']
    except Exception as err:
        raise RuntimeError('ERROR: %s' % str(err))

    return etree.tostring(xml)
Ejemplo n.º 10
0
def update_xpath(nsmap, xml, recprop):
    """Update XML document XPath values"""

    if isinstance(xml, unicode):  # not lxml serialized yet
        xml = etree.fromstring(xml, PARSER)

    recprop = eval(recprop)
    nsmap = eval(nsmap)
    try:
        nodes = xml.xpath(recprop['rp']['xpath'], namespaces=nsmap)
        if len(nodes) > 0:  # matches
            for node1 in nodes:
                if node1.text != recprop['value']:  # values differ, update
                    node1.text = recprop['value']
    except Exception as err:
        raise RuntimeError('ERROR: %s' % str(err))

    return etree.tostring(xml)
Ejemplo n.º 11
0
def update_xpath(nsmap, xml, recprop):
    """Update XML document XPath values"""

    if isinstance(xml, bytes) or isinstance(xml, str):
        # serialize to lxml
        xml = etree.fromstring(xml, PARSER)

    recprop = eval(recprop)
    nsmap = eval(nsmap)
    try:
        nodes = xml.xpath(recprop['rp']['xpath'], namespaces=nsmap)
        if len(nodes) > 0:  # matches
            for node1 in nodes:
                if node1.text != recprop['value']:  # values differ, update
                    node1.text = recprop['value']
    except Exception as err:
        LOGGER.warning('update_xpath error', exc_info=True)
        raise RuntimeError('ERROR: %s' % str(err)) from err

    return etree.tostring(xml)
Ejemplo n.º 12
0
def gen_sitemap(context, database, table, url, output_file):
    """generate an XML sitemap from all records in repository"""

    # get configuration and init repo connection
    repos = repository.Repository(database, context, table=table)

    # write out sitemap document
    urlset = etree.Element(util.nspath_eval('sitemap:urlset',
                                            context.namespaces),
                           nsmap=context.namespaces)

    schema_loc = util.nspath_eval('xsi:schemaLocation', context.namespaces)

    urlset.attrib[schema_loc] = \
        '%s http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd' % \
        context.namespaces['sitemap']

    # get all records
    count, records = repos.query(constraint={}, maxrecords=99999999)

    LOGGER.info('Found %s records', count)

    for rec in records:
        url_ = etree.SubElement(
            urlset, util.nspath_eval('sitemap:url', context.namespaces))
        uri = '%s?service=CSW&version=2.0.2&request=GetRepositoryItem&id=%s' % \
            (url,
             getattr(rec,
                     context.md_core_model['mappings']['pycsw:Identifier']))
        etree.SubElement(url_,
                         util.nspath_eval('sitemap:loc',
                                          context.namespaces)).text = uri

    # write to file
    LOGGER.info('Writing to %s', output_file)
    with open(output_file, 'wb') as ofile:
        ofile.write(
            etree.tostring(urlset,
                           pretty_print=1,
                           encoding='utf8',
                           xml_declaration=1))
Ejemplo n.º 13
0
    def _write_response(self):
        ''' Generate response '''
        # set HTTP response headers and XML declaration

        xmldecl = ''
        appinfo = ''

        LOGGER.debug('Writing response.')

        if hasattr(self, 'soap') and self.soap:
            self._gen_soap_wrapper()

        if (isinstance(self.kvp, dict) and 'outputformat' in self.kvp
                and self.kvp['outputformat'] == 'application/json'):
            self.contenttype = self.kvp['outputformat']
            from pycsw.core.formats import fmt_json
            response = fmt_json.exml2json(self.response,
                                          self.context.namespaces,
                                          self.pretty_print)
        else:  # it's XML
            if 'outputformat' in self.kvp:
                self.contenttype = self.kvp['outputformat']
            else:
                self.contenttype = self.mimetype
            response = etree.tostring(self.response,
                                      pretty_print=self.pretty_print,
                                      encoding='unicode')
            xmldecl = '<?xml version="1.0" encoding="%s" standalone="no"?>\n' \
            % self.encoding
            appinfo = '<!-- pycsw %s -->\n' % self.context.version

        s = (u'%s%s%s' % (xmldecl, appinfo, response)).encode(self.encoding)
        LOGGER.debug('Response code: %s',
                     self.context.response_codes[self.status])
        LOGGER.debug('Response:\n%s', s)
        return [self.context.response_codes[self.status], s]
Ejemplo n.º 14
0
def kvp2filterxml(kvp, context):
    ''' transform kvp to filter XML string '''

    bbox_element = None
    time_element = None
    anytext_elements = []

    # Count parameters
    par_count = 0
    for p in ['q','bbox','time']:
        if p in kvp and kvp[p] != '':
            par_count += 1

    # Create root element for FilterXML
    root = etree.Element(util.nspath_eval('ogc:Filter', context.namespaces))

    # bbox to FilterXML
    if 'bbox' in kvp and kvp['bbox'] != '':
        LOGGER.debug('Detected bbox parameter')
        bbox_list = [x.strip() for x in kvp['bbox'].split(',')]
        bbox_element = etree.Element(util.nspath_eval('ogc:BBOX',
                    context.namespaces))
        el = etree.Element(util.nspath_eval('ogc:PropertyName',
                    context.namespaces))
        el.text = 'ows:BoundingBox'
        bbox_element.append(el)
        env = etree.Element(util.nspath_eval('gml:Envelope',
                    context.namespaces))
        el = etree.Element(util.nspath_eval('gml:lowerCorner',
                    context.namespaces))

        if len(bbox_list) == 5:  # add srsName
            LOGGER.debug('Found CRS')
            env.attrib['srsName'] = bbox_list[4]
        else:
            LOGGER.debug('Assuming 4326')
            env.attrib['srsName'] = 'urn:ogc:def:crs:OGC:1.3:CRS84'
            if not util.validate_4326(bbox_list):
                msg = '4326 coordinates out of range: %s' % bbox_list
                LOGGER.debug(msg)
                raise RuntimeError(msg)

        try:
            el.text = "%s %s" % (bbox_list[0], bbox_list[1])
        except Exception as err:
            errortext = 'Exception: OpenSearch bbox not valid.\nError: %s.' % str(err)
            LOGGER.debug(errortext)
        env.append(el)
        el = etree.Element(util.nspath_eval('gml:upperCorner',
                    context.namespaces))
        try:
            el.text = "%s %s" % (bbox_list[2], bbox_list[3])
        except Exception as err:
            errortext = 'Exception: OpenSearch bbox not valid.\nError: %s.' % str(err)
            LOGGER.debug(errortext)
        env.append(el)
        bbox_element.append(env)

    # q to FilterXML
    if 'q' in kvp and kvp['q'] != '':
        LOGGER.debug('Detected q parameter')
        qvals = kvp['q'].split()
        LOGGER.debug(qvals)
        if len(qvals) > 1:
            par_count += 1
        for qval in qvals:
            LOGGER.debug('processing q token')
            anytext_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo',
                        context.namespaces))
            el = etree.Element(util.nspath_eval('ogc:PropertyName',
                        context.namespaces))
            el.text = 'csw:AnyText'
            anytext_element.append(el)
            el = etree.Element(util.nspath_eval('ogc:Literal',
                        context.namespaces))
            if six.PY2:
                el.text = qval.decode('utf8')
            else:
                el.text = qval
            anytext_element.append(el)
            anytext_elements.append(anytext_element)

    # time to FilterXML
    if 'time' in kvp and kvp['time'] != '':
        LOGGER.debug('Detected time parameter %s', kvp['time'])
        time_list = kvp['time'].split("/")
        if (len(time_list) == 2):
            LOGGER.debug('TIMELIST: %s', time_list)
            # This is a normal request
            if '' not in time_list:
                LOGGER.debug('Both dates present')
                # Both dates are present
                time_element = etree.Element(util.nspath_eval('ogc:PropertyIsBetween',
                            context.namespaces))
                el = etree.Element(util.nspath_eval('ogc:PropertyName',
                            context.namespaces))
                el.text = 'dc:date'
                time_element.append(el)
                el = etree.Element(util.nspath_eval('ogc:LowerBoundary',
                            context.namespaces))
                el2 = etree.Element(util.nspath_eval('ogc:Literal',
                            context.namespaces))
                el2.text = time_list[0]
                el.append(el2)
                time_element.append(el)
                el = etree.Element(util.nspath_eval('ogc:UpperBoundary',
                            context.namespaces))
                el2 = etree.Element(util.nspath_eval('ogc:Literal',
                            context.namespaces))
                el2.text = time_list[1]
                el.append(el2)
                time_element.append(el)
            else:
                if time_list == ['', '']:
                    par_count -= 1
                # One of two is empty
                elif time_list[1] is '':
                    time_element = etree.Element(util.nspath_eval('ogc:PropertyIsGreaterThanOrEqualTo',
                                context.namespaces))
                    el = etree.Element(util.nspath_eval('ogc:PropertyName',
                                context.namespaces))
                    el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval('ogc:Literal',
                                context.namespaces))
                    el.text = time_list[0]
                    time_element.append(el)
                else:
                    time_element = etree.Element(util.nspath_eval('ogc:PropertyIsLessThanOrEqualTo',
                                context.namespaces))
                    el = etree.Element(util.nspath_eval('ogc:PropertyName',
                                context.namespaces))
                    el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval('ogc:Literal',
                                context.namespaces))
                    el.text = time_list[1]
                    time_element.append(el)
        elif ((len(time_list) == 1) and ('' not in time_list)):
            # This is an equal request
            time_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo',
                        context.namespaces))
            el = etree.Element(util.nspath_eval('ogc:PropertyName',
                        context.namespaces))
            el.text = 'dc:date'
            time_element.append(el)
            el = etree.Element(util.nspath_eval('ogc:Literal',
                        context.namespaces))
            el.text = time_list[0]
            time_element.append(el)
        else:
            # Error
            errortext = 'Exception: OpenSearch time not valid: %s.' % str(kvp['time'])
            LOGGER.debug(errortext)

    if par_count == 0:
        return ''
    elif par_count == 1:
        LOGGER.debug('Single predicate filter')
        # Only one OpenSearch parameter exists
        if 'bbox' in kvp and kvp['bbox'] != '':
            LOGGER.debug('Adding bbox')
            root.append(bbox_element)
        elif time_element is not None:
            LOGGER.debug('Adding time')
            root.append(time_element)
        elif anytext_elements:
            LOGGER.debug('Adding anytext')
            root.extend(anytext_elements)
    elif (par_count > 1):
        LOGGER.debug('ogc:And query (%d predicates)', par_count)
        # Since more than 1 parameter, append the AND logical operator
        logical_and = etree.Element(util.nspath_eval('ogc:And',
                context.namespaces))
        if bbox_element is not None:
            logical_and.append(bbox_element)
        if time_element is not None:
            logical_and.append(time_element)
        if anytext_elements is not None:
            logical_and.extend(anytext_elements)
        root.append(logical_and)

    # Render etree to string XML
    LOGGER.debug(etree.tostring(root, encoding='unicode'))
    return etree.tostring(root, encoding='unicode')
Ejemplo n.º 15
0
def kvp2filterxml(kvp, context, profiles):
    ''' transform kvp to filter XML string '''

    bbox_element = None
    time_element = None
    anytext_elements = []
    query_temporal_by_iso = False

    if profiles is not None and 'plugins' in profiles and 'APISO' in profiles[
            'plugins']:
        query_temporal_by_iso = True

    # Count parameters
    par_count = 0
    for p in ['q', 'bbox', 'time']:
        if p in kvp and kvp[p] != '':
            par_count += 1

    # Create root element for FilterXML
    root = etree.Element(util.nspath_eval('ogc:Filter', context.namespaces))

    # bbox to FilterXML
    if 'bbox' in kvp and kvp['bbox'] != '':
        LOGGER.debug('Detected bbox parameter')
        bbox_list = [x.strip() for x in kvp['bbox'].split(',')]
        bbox_element = etree.Element(
            util.nspath_eval('ogc:BBOX', context.namespaces))
        el = etree.Element(
            util.nspath_eval('ogc:PropertyName', context.namespaces))
        el.text = 'ows:BoundingBox'
        bbox_element.append(el)
        env = etree.Element(
            util.nspath_eval('gml:Envelope', context.namespaces))
        el = etree.Element(
            util.nspath_eval('gml:lowerCorner', context.namespaces))

        if len(bbox_list) == 5:  # add srsName
            LOGGER.debug('Found CRS')
            env.attrib['srsName'] = bbox_list[4]
        else:
            LOGGER.debug('Assuming 4326')
            env.attrib['srsName'] = 'urn:ogc:def:crs:OGC:1.3:CRS84'
            if not validate_4326(bbox_list):
                msg = '4326 coordinates out of range: %s' % bbox_list
                LOGGER.error(msg)
                raise RuntimeError(msg)

        try:
            el.text = "%s %s" % (bbox_list[0], bbox_list[1])
        except Exception as err:
            errortext = 'Exception: OpenSearch bbox not valid.\nError: %s.' % str(
                err)
            LOGGER.exception(errortext)
        env.append(el)
        el = etree.Element(
            util.nspath_eval('gml:upperCorner', context.namespaces))
        try:
            el.text = "%s %s" % (bbox_list[2], bbox_list[3])
        except Exception as err:
            errortext = 'Exception: OpenSearch bbox not valid.\nError: %s.' % str(
                err)
            LOGGER.exception(errortext)
        env.append(el)
        bbox_element.append(env)

    # q to FilterXML
    if 'q' in kvp and kvp['q'] != '':
        LOGGER.debug('Detected q parameter')
        qvals = kvp['q'].split()
        LOGGER.debug(qvals)
        if len(qvals) > 1:
            par_count += 1
        for qval in qvals:
            LOGGER.debug('processing q token')
            anytext_element = etree.Element(
                util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
            el = etree.Element(
                util.nspath_eval('ogc:PropertyName', context.namespaces))
            el.text = 'csw:AnyText'
            anytext_element.append(el)
            el = etree.Element(
                util.nspath_eval('ogc:Literal', context.namespaces))
            el.text = qval
            anytext_element.append(el)
            anytext_elements.append(anytext_element)

    if ('start' in kvp or 'stop' in kvp) and 'time' not in kvp:
        LOGGER.debug('Detected start/stop in KVP')
        kvp['time'] = ''
        if 'start' in kvp and kvp['start'] != '':
            kvp['time'] = kvp['start'] + '/'
        if 'stop' in kvp and kvp['stop'] != '':
            if len(kvp['time']) > 0:
                kvp['time'] += kvp['stop']
            else:
                kvp['time'] = '/' + kvp['stop']
            LOGGER.debug('new KVP time: {}'.format(kvp['time']))

    # time to FilterXML
    if 'time' in kvp and kvp['time'] != '':
        LOGGER.debug('Detected time parameter %s', kvp['time'])
        time_list = kvp['time'].split("/")

        LOGGER.debug('TIMELIST: %s', time_list)

        if len(time_list) == 2:
            if '' not in time_list:  # both dates present
                LOGGER.debug('Both dates present')
                if query_temporal_by_iso:
                    LOGGER.debug('Querying by ISO data extent')
                    time_element = etree.Element(
                        util.nspath_eval('ogc:And', context.namespaces))

                    begin_element = etree.Element(
                        util.nspath_eval('ogc:PropertyIsGreaterThanOrEqualTo',
                                         context.namespaces))
                    etree.SubElement(
                        begin_element,
                        util.nspath_eval('ogc:PropertyName', context.namespaces
                                         )).text = 'apiso:TempExtent_begin'
                    etree.SubElement(
                        begin_element,
                        util.nspath_eval(
                            'ogc:Literal',
                            context.namespaces)).text = time_list[0]

                    end_element = etree.Element(
                        util.nspath_eval('ogc:PropertyIsLessThanOrEqualTo',
                                         context.namespaces))
                    etree.SubElement(
                        end_element,
                        util.nspath_eval(
                            'ogc:PropertyName',
                            context.namespaces)).text = 'apiso:TempExtent_end'
                    etree.SubElement(
                        end_element,
                        util.nspath_eval(
                            'ogc:Literal',
                            context.namespaces)).text = time_list[1]

                    time_element.append(begin_element)
                    time_element.append(end_element)

                else:
                    LOGGER.debug('Querying by DC date')
                    time_element = etree.Element(
                        util.nspath_eval('ogc:PropertyIsBetween',
                                         context.namespaces))
                    el = etree.Element(
                        util.nspath_eval('ogc:PropertyName',
                                         context.namespaces))
                    el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(
                        util.nspath_eval('ogc:LowerBoundary',
                                         context.namespaces))
                    el2 = etree.Element(
                        util.nspath_eval('ogc:Literal', context.namespaces))
                    el2.text = time_list[0]
                    el.append(el2)
                    time_element.append(el)
                    el = etree.Element(
                        util.nspath_eval('ogc:UpperBoundary',
                                         context.namespaces))
                    el2 = etree.Element(
                        util.nspath_eval('ogc:Literal', context.namespaces))
                    el2.text = time_list[1]
                    el.append(el2)
                    time_element.append(el)

            else:  # one is empty
                LOGGER.debug('Querying by open-ended date')
                if time_list == ['', '']:
                    par_count -= 1
                # One of two is empty
                elif time_list[1] == '':  # start datetime but no end datetime
                    time_element = etree.Element(
                        util.nspath_eval('ogc:PropertyIsGreaterThanOrEqualTo',
                                         context.namespaces))
                    el = etree.Element(
                        util.nspath_eval('ogc:PropertyName',
                                         context.namespaces))
                    if query_temporal_by_iso:
                        el.text = 'apiso:TempExtent_begin'
                    else:
                        el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(
                        util.nspath_eval('ogc:Literal', context.namespaces))
                    el.text = time_list[0]
                    time_element.append(el)
                else:  # end datetime but no start datetime
                    time_element = etree.Element(
                        util.nspath_eval('ogc:PropertyIsLessThanOrEqualTo',
                                         context.namespaces))
                    el = etree.Element(
                        util.nspath_eval('ogc:PropertyName',
                                         context.namespaces))
                    if query_temporal_by_iso:
                        el.text = 'apiso:TempExtent_end'
                    else:
                        el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(
                        util.nspath_eval('ogc:Literal', context.namespaces))
                    el.text = time_list[1]
                    time_element.append(el)
        elif ((len(time_list) == 1) and ('' not in time_list)):
            LOGGER.debug('Querying time instant via dc:date')
            # This is an equal request
            time_element = etree.Element(
                util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
            el = etree.Element(
                util.nspath_eval('ogc:PropertyName', context.namespaces))
            el.text = 'dc:date'
            time_element.append(el)
            el = etree.Element(
                util.nspath_eval('ogc:Literal', context.namespaces))
            el.text = time_list[0]
            time_element.append(el)
        else:
            # Error
            errortext = 'Exception: OpenSearch time not valid: %s.' % str(
                kvp['time'])
            LOGGER.error(errortext)

    if par_count == 0:
        return ''
    elif par_count == 1:
        LOGGER.debug('Single predicate filter')
        # Only one OpenSearch parameter exists
        if 'bbox' in kvp and kvp['bbox'] != '':
            LOGGER.debug('Adding bbox')
            root.append(bbox_element)
        elif time_element is not None:
            LOGGER.debug('Adding time')
            root.append(time_element)
        elif anytext_elements:
            LOGGER.debug('Adding anytext')
            root.extend(anytext_elements)
    elif (par_count > 1):
        LOGGER.debug('ogc:And query (%d predicates)', par_count)
        # Since more than 1 parameter, append the AND logical operator
        logical_and = etree.Element(
            util.nspath_eval('ogc:And', context.namespaces))
        if bbox_element is not None:
            logical_and.append(bbox_element)
        if time_element is not None:
            logical_and.append(time_element)
        if anytext_elements is not None:
            logical_and.extend(anytext_elements)
        root.append(logical_and)

    # Render etree to string XML
    LOGGER.debug(etree.tostring(root, encoding='unicode'))
    return etree.tostring(root, encoding='unicode')
Ejemplo n.º 16
0
def kvp2filterxml(kvp, context):
    """ transform kvp to filter XML string """

    bbox_element = None
    time_element = None
    anytext_elements = []

    # Count parameters
    par_count = 0
    for p in ["q", "bbox", "time"]:
        if p in kvp and kvp[p] != "":
            par_count += 1

    # Create root element for FilterXML
    root = etree.Element(util.nspath_eval("ogc:Filter", context.namespaces))

    # bbox to FilterXML
    if "bbox" in kvp and kvp["bbox"] != "":
        LOGGER.debug("Detected bbox parameter")
        bbox_list = [x.strip() for x in kvp["bbox"].split(",")]
        bbox_element = etree.Element(util.nspath_eval("ogc:BBOX", context.namespaces))
        el = etree.Element(util.nspath_eval("ogc:PropertyName", context.namespaces))
        el.text = "ows:BoundingBox"
        bbox_element.append(el)
        env = etree.Element(util.nspath_eval("gml:Envelope", context.namespaces))
        el = etree.Element(util.nspath_eval("gml:lowerCorner", context.namespaces))

        if len(bbox_list) == 5:  # add srsName
            LOGGER.debug("Found CRS")
            env.attrib["srsName"] = bbox_list[4]
        else:
            LOGGER.debug("Assuming 4326")
            env.attrib["srsName"] = "urn:ogc:def:crs:OGC:1.3:CRS84"
            if not util.validate_4326(bbox_list):
                msg = "4326 coordinates out of range: %s" % bbox_list
                LOGGER.debug(msg)
                raise RuntimeError(msg)

        try:
            el.text = "%s %s" % (bbox_list[0], bbox_list[1])
        except Exception as err:
            errortext = "Exception: OpenSearch bbox not valid.\nError: %s." % str(err)
            LOGGER.debug(errortext)
        env.append(el)
        el = etree.Element(util.nspath_eval("gml:upperCorner", context.namespaces))
        try:
            el.text = "%s %s" % (bbox_list[2], bbox_list[3])
        except Exception as err:
            errortext = "Exception: OpenSearch bbox not valid.\nError: %s." % str(err)
            LOGGER.debug(errortext)
        env.append(el)
        bbox_element.append(env)

    # q to FilterXML
    if "q" in kvp and kvp["q"] != "":
        LOGGER.debug("Detected q parameter")
        qvals = kvp["q"].split()
        LOGGER.debug(qvals)
        if len(qvals) > 1:
            par_count += 1
        for qval in qvals:
            LOGGER.debug("processing q token")
            anytext_element = etree.Element(util.nspath_eval("ogc:PropertyIsEqualTo", context.namespaces))
            el = etree.Element(util.nspath_eval("ogc:PropertyName", context.namespaces))
            el.text = "csw:AnyText"
            anytext_element.append(el)
            el = etree.Element(util.nspath_eval("ogc:Literal", context.namespaces))
            if six.PY2:
                el.text = qval.decode("utf8")
            else:
                el.text = qval
            anytext_element.append(el)
            anytext_elements.append(anytext_element)

    # time to FilterXML
    if "time" in kvp and kvp["time"] != "":
        LOGGER.debug("Detected time parameter %s", kvp["time"])
        time_list = kvp["time"].split("/")
        if len(time_list) == 2:
            LOGGER.debug("TIMELIST: %s", time_list)
            # This is a normal request
            if "" not in time_list:
                LOGGER.debug("Both dates present")
                # Both dates are present
                time_element = etree.Element(util.nspath_eval("ogc:PropertyIsBetween", context.namespaces))
                el = etree.Element(util.nspath_eval("ogc:PropertyName", context.namespaces))
                el.text = "dc:date"
                time_element.append(el)
                el = etree.Element(util.nspath_eval("ogc:LowerBoundary", context.namespaces))
                el2 = etree.Element(util.nspath_eval("ogc:Literal", context.namespaces))
                el2.text = time_list[0]
                el.append(el2)
                time_element.append(el)
                el = etree.Element(util.nspath_eval("ogc:UpperBoundary", context.namespaces))
                el2 = etree.Element(util.nspath_eval("ogc:Literal", context.namespaces))
                el2.text = time_list[1]
                el.append(el2)
                time_element.append(el)
            else:
                if time_list == ["", ""]:
                    par_count -= 1
                # One of two is empty
                elif time_list[1] is "":
                    time_element = etree.Element(
                        util.nspath_eval("ogc:PropertyIsGreaterThanOrEqualTo", context.namespaces)
                    )
                    el = etree.Element(util.nspath_eval("ogc:PropertyName", context.namespaces))
                    el.text = "dc:date"
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval("ogc:Literal", context.namespaces))
                    el.text = time_list[0]
                    time_element.append(el)
                else:
                    time_element = etree.Element(
                        util.nspath_eval("ogc:PropertyIsLessThanOrEqualTo", context.namespaces)
                    )
                    el = etree.Element(util.nspath_eval("ogc:PropertyName", context.namespaces))
                    el.text = "dc:date"
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval("ogc:Literal", context.namespaces))
                    el.text = time_list[1]
                    time_element.append(el)
        elif (len(time_list) == 1) and ("" not in time_list):
            # This is an equal request
            time_element = etree.Element(util.nspath_eval("ogc:PropertyIsEqualTo", context.namespaces))
            el = etree.Element(util.nspath_eval("ogc:PropertyName", context.namespaces))
            el.text = "dc:date"
            time_element.append(el)
            el = etree.Element(util.nspath_eval("ogc:Literal", context.namespaces))
            el.text = time_list[0]
            time_element.append(el)
        else:
            # Error
            errortext = "Exception: OpenSearch time not valid: %s." % str(kvp["time"])
            LOGGER.debug(errortext)

    if par_count == 0:
        return ""
    elif par_count == 1:
        LOGGER.debug("Single predicate filter")
        # Only one OpenSearch parameter exists
        if "bbox" in kvp and kvp["bbox"] != "":
            LOGGER.debug("Adding bbox")
            root.append(bbox_element)
        elif time_element:
            LOGGER.debug("Adding time")
            root.append(time_element)
        elif anytext_elements:
            LOGGER.debug("Adding anytext")
            root.extend(anytext_elements)
    elif par_count > 1:
        LOGGER.debug("ogc:And query (%d predicates)", par_count)
        # Since more than 1 parameter, append the AND logical operator
        logical_and = etree.Element(util.nspath_eval("ogc:And", context.namespaces))
        if bbox_element is not None:
            logical_and.append(bbox_element)
        if time_element is not None:
            logical_and.append(time_element)
        if anytext_elements is not None:
            logical_and.extend(anytext_elements)
        root.append(logical_and)

    # Render etree to string XML
    LOGGER.debug(etree.tostring(root, encoding="unicode"))
    return etree.tostring(root, encoding="unicode")
Ejemplo n.º 17
0
    def _write_response(self):
        """ Generate response """
        # set HTTP response headers and XML declaration

        xmldecl = ''
        appinfo = ''

        LOGGER.info('Writing response.')

        #import webbrowser

        # neuer code für unsere API html anzeigen zu können TAN
        #if self.response == 'a':
            #print('ja')
            
            #new = 2 # open in a new tab, if possible

            #url = "'/usr/lib/python3.5/site-packages/pycsw/test.html'"
            #webbrowser.open(url,new=new)
            #open('/usr/lib/python3.5/site-packages/pycsw/test.html')
            #print('nein')

        if hasattr(self, 'soap') and self.soap:
            self._gen_soap_wrapper()

        if etree.__version__ >= '3.5.0':  # remove superfluous namespaces
            etree.cleanup_namespaces(self.response,
                                     keep_ns_prefixes=self.context.keep_ns_prefixes)

        response = etree.tostring(self.response,
                                  pretty_print=self.pretty_print,
                                  encoding='unicode')

        # Funktion wird aufgerufen um xml in json umzuwandeln, wenn es in der url angegeben ist 
        if (isinstance(self.kvp, dict) and 'outputformat' in self.kvp and
                self.kvp['outputformat'] == 'application/json'):
            self.contenttype = self.kvp['outputformat']
            from pycsw.core.formats import fmt_json
            response = fmt_json.xml2json(response,
                                         self.context.namespaces,
                                         self.pretty_print)
        
        # new requests for the similarities should be always in json format (@author: Anika Graupner)
        elif (isinstance(self.kvp, dict) and 'request' in self.kvp and
                self.kvp['request'] == 'GetSimilarRecords'):
            
                if (isinstance(self.kvp, dict) and 'outputformat' in self.kvp and
                    self.kvp['outputformat'] == 'application/xml'):
                        if 'outputformat' in self.kvp:
                            self.contenttype = self.kvp['outputformat']
                        else:
                            self.contenttype = self.mimetype

                        xmldecl = ('<?xml version="1.0" encoding="%s" standalone="no"?>'
                                '\n' % self.encoding)
                        appinfo = '<!-- pycsw %s -->\n' % self.context.version 

                else:
                    self.contenttype = self.kvp['request']
                    from pycsw.core.formats import fmt_json
                    response = fmt_json.xml2json(response,
                                                self.context.namespaces,
                                                self.pretty_print)
                                                
        
        elif (isinstance(self.kvp, dict) and 'request' in self.kvp and
                self.kvp['request'] == 'GetSimilarityBBox'):
            
                if (isinstance(self.kvp, dict) and 'outputformat' in self.kvp and
                    self.kvp['outputformat'] == 'application/xml'):
                        if 'outputformat' in self.kvp:
                            self.contenttype = self.kvp['outputformat']
                        else:
                            self.contenttype = self.mimetype

                        xmldecl = ('<?xml version="1.0" encoding="%s" standalone="no"?>'
                                '\n' % self.encoding)
                        appinfo = '<!-- pycsw %s -->\n' % self.context.version 

                else:
                    self.contenttype = self.kvp['request']
                    from pycsw.core.formats import fmt_json
                    response = fmt_json.xml2json(response,
                                                self.context.namespaces,
                                                self.pretty_print)                                        

        else:  # it's XML
            if 'outputformat' in self.kvp:
                self.contenttype = self.kvp['outputformat']
            else:
                self.contenttype = self.mimetype

            xmldecl = ('<?xml version="1.0" encoding="%s" standalone="no"?>'
                       '\n' % self.encoding)
            appinfo = '<!-- pycsw %s -->\n' % self.context.version

        if isinstance(self.contenttype, bytes):
            self.contenttype = self.contenttype.decode()

        s = (u'%s%s%s' % (xmldecl, appinfo, response)).encode(self.encoding)
        LOGGER.debug('Response code: %s',
                     self.context.response_codes[self.status])
        LOGGER.debug('Response:\n%s', s)
        return [self.context.response_codes[self.status], s]
Ejemplo n.º 18
0
def _parse_sos(context, repos, record, identifier, version):

    from owslib.sos import SensorObservationService

    bboxs = []
    recobjs = []
    serviceobj = repos.dataset()

    if version == '1.0.0':
        schema = 'http://www.opengis.net/sos/1.0'
    else:
        schema = 'http://www.opengis.net/sos/2.0'

    md = SensorObservationService(record, version=version)

    # generate record of service instance
    _set(context, serviceobj, 'pycsw:Identifier', identifier)
    _set(context, serviceobj, 'pycsw:Typename', 'csw:Record')
    _set(context, serviceobj, 'pycsw:Schema', schema)
    _set(context, serviceobj, 'pycsw:MdSource', record)
    _set(context, serviceobj, 'pycsw:InsertDate', util.get_today_and_now())
    _set(context, serviceobj, 'pycsw:AnyText', util.get_anytext(etree.tostring(md._capabilities)))
    _set(context, serviceobj, 'pycsw:Type', 'service')
    _set(context, serviceobj, 'pycsw:Title', md.identification.title)
    _set(context, serviceobj, 'pycsw:Abstract', md.identification.abstract)
    _set(context, serviceobj, 'pycsw:Keywords', ','.join(md.identification.keywords))
    _set(context, serviceobj, 'pycsw:Creator', md.provider.contact.name)
    _set(context, serviceobj, 'pycsw:Publisher', md.provider.name)
    _set(context, serviceobj, 'pycsw:Contributor', md.provider.contact.name)
    _set(context, serviceobj, 'pycsw:OrganizationName', md.provider.contact.name)
    _set(context, serviceobj, 'pycsw:AccessConstraints', md.identification.accessconstraints)
    _set(context, serviceobj, 'pycsw:OtherConstraints', md.identification.fees)
    _set(context, serviceobj, 'pycsw:Source', record)
    _set(context, serviceobj, 'pycsw:Format', md.identification.type)
    _set(context, serviceobj, 'pycsw:CRS', 'urn:ogc:def:crs:EPSG:6.11:4326')
    _set(context, serviceobj, 'pycsw:DistanceUOM', 'degrees')
    _set(context, serviceobj, 'pycsw:ServiceType', 'OGC:SOS')
    _set(context, serviceobj, 'pycsw:ServiceTypeVersion', md.identification.version)
    _set(context, serviceobj, 'pycsw:Operation', ','.join([d.name for d in md.operations]))
    _set(context, serviceobj, 'pycsw:OperatesOn', ','.join(list(md.contents)))
    _set(context, serviceobj, 'pycsw:CouplingType', 'tight')

    links = [
        '%s,OGC-SOS Sensor Observation Service,OGC:SOS,%s' % (identifier, md.url),
    ]

    _set(context, serviceobj, 'pycsw:Links', '^'.join(links))

    # generate record foreach offering

    LOGGER.debug('Harvesting %d SOS ObservationOffering\'s ', len(md.contents))

    for offering in md.contents:
        recobj = repos.dataset()
        identifier2 = '%s-%s' % (identifier, md.contents[offering].id)
        _set(context, recobj, 'pycsw:Identifier', identifier2)
        _set(context, recobj, 'pycsw:Typename', 'csw:Record')
        _set(context, recobj, 'pycsw:Schema', schema)
        _set(context, recobj, 'pycsw:MdSource', record)
        _set(context, recobj, 'pycsw:InsertDate', util.get_today_and_now())
        _set(context, recobj, 'pycsw:Type', 'dataset')
        _set(context, recobj, 'pycsw:ParentIdentifier', identifier)
        _set(context, recobj, 'pycsw:Title', md.contents[offering].description)
        _set(context, recobj, 'pycsw:Abstract', md.contents[offering].description)
        _set(context, recobj, 'pycsw:TempExtent_begin', util.datetime2iso8601(md.contents[offering].begin_position))
        _set(context, recobj, 'pycsw:TempExtent_end', util.datetime2iso8601(md.contents[offering].end_position))

        #For observed_properties that have mmi url or urn, we simply want the observation name.
        observed_properties = []
        for obs in md.contents[offering].observed_properties:
          #Observation is stored as urn representation: urn:ogc:def:phenomenon:mmisw.org:cf:sea_water_salinity
          if obs.lower().startswith(('urn:', 'x-urn')):
            observed_properties.append(obs.rsplit(':', 1)[-1])
          #Observation is stored as uri representation: http://mmisw.org/ont/cf/parameter/sea_floor_depth_below_sea_surface
          elif obs.lower().startswith(('http://', 'https://')):
            observed_properties.append(obs.rsplit('/', 1)[-1])
          else:
            observed_properties.append(obs)
        #Build anytext from description and the observed_properties.
        anytext = []
        anytext.append(md.contents[offering].description)
        anytext.extend(observed_properties)
        _set(context, recobj, 'pycsw:AnyText', util.get_anytext(anytext))
        _set(context, recobj, 'pycsw:Keywords', ','.join(observed_properties))

        bbox = md.contents[offering].bbox
        if bbox is not None:
            tmp = '%s,%s,%s,%s' % (bbox[0], bbox[1], bbox[2], bbox[3])
            wkt_polygon = util.bbox2wktpolygon(tmp)
            _set(context, recobj, 'pycsw:BoundingBox', wkt_polygon)
            _set(context, recobj, 'pycsw:CRS', md.contents[offering].bbox_srs.id)
            _set(context, recobj, 'pycsw:DistanceUOM', 'degrees')
            bboxs.append(wkt_polygon)

        _set(context, recobj, 'pycsw:XML', caps2iso(recobj, md, context))
        recobjs.append(recobj)

    # Derive a bbox based on aggregated featuretype bbox values

    bbox_agg = util.bbox_from_polygons(bboxs)

    if bbox_agg is not None:
        _set(context, serviceobj, 'pycsw:BoundingBox', bbox_agg)

    _set(context, serviceobj, 'pycsw:XML', caps2iso(serviceobj, md, context))
    recobjs.insert(0, serviceobj)

    return recobjs
Ejemplo n.º 19
0
def _parse_wcs(context, repos, record, identifier):

    from owslib.wcs import WebCoverageService

    bboxs = []
    recobjs = []
    serviceobj = repos.dataset()

    md = WebCoverageService(record, '1.0.0')

    # generate record of service instance
    _set(context, serviceobj, 'pycsw:Identifier', identifier)
    _set(context, serviceobj, 'pycsw:Typename', 'csw:Record')
    _set(context, serviceobj, 'pycsw:Schema', 'http://www.opengis.net/wcs')
    _set(context, serviceobj, 'pycsw:MdSource', record)
    _set(context, serviceobj, 'pycsw:InsertDate', util.get_today_and_now())
    _set(context, serviceobj, 'pycsw:AnyText', util.get_anytext(etree.tostring(md._capabilities)))
    _set(context, serviceobj, 'pycsw:Type', 'service')
    _set(context, serviceobj, 'pycsw:Title', md.identification.title)
    _set(context, serviceobj, 'pycsw:Abstract', md.identification.abstract)
    _set(context, serviceobj, 'pycsw:Keywords', ','.join(md.identification.keywords))
    _set(context, serviceobj, 'pycsw:Creator', md.provider.contact.name)
    _set(context, serviceobj, 'pycsw:Publisher', md.provider.name)
    _set(context, serviceobj, 'pycsw:Contributor', md.provider.contact.name)
    _set(context, serviceobj, 'pycsw:OrganizationName', md.provider.contact.name)
    _set(context, serviceobj, 'pycsw:AccessConstraints', md.identification.accessConstraints)
    _set(context, serviceobj, 'pycsw:OtherConstraints', md.identification.fees)
    _set(context, serviceobj, 'pycsw:Source', record)
    _set(context, serviceobj, 'pycsw:Format', md.identification.type)
    _set(context, serviceobj, 'pycsw:CRS', 'urn:ogc:def:crs:EPSG:6.11:4326')
    _set(context, serviceobj, 'pycsw:DistanceUOM', 'degrees')
    _set(context, serviceobj, 'pycsw:ServiceType', 'OGC:WCS')
    _set(context, serviceobj, 'pycsw:ServiceTypeVersion', md.identification.version)
    _set(context, serviceobj, 'pycsw:Operation', ','.join([d.name for d in md.operations]))
    _set(context, serviceobj, 'pycsw:OperatesOn', ','.join(list(md.contents)))
    _set(context, serviceobj, 'pycsw:CouplingType', 'tight')

    links = [
        '%s,OGC-WCS Web Coverage Service,OGC:WCS,%s' % (identifier, md.url)
    ]

    _set(context, serviceobj, 'pycsw:Links', '^'.join(links))

    # generate record foreach coverage

    LOGGER.debug('Harvesting %d WCS coverages ' % len(md.contents))

    for coverage in md.contents:
        recobj = repos.dataset()
        identifier2 = '%s-%s' % (identifier, md.contents[coverage].id)
        _set(context, recobj, 'pycsw:Identifier', identifier2)
        _set(context, recobj, 'pycsw:Typename', 'csw:Record')
        _set(context, recobj, 'pycsw:Schema', 'http://www.opengis.net/wcs')
        _set(context, recobj, 'pycsw:MdSource', record)
        _set(context, recobj, 'pycsw:InsertDate', util.get_today_and_now())
        _set(context, recobj, 'pycsw:Type', 'dataset')
        _set(context, recobj, 'pycsw:ParentIdentifier', identifier)
        _set(context, recobj, 'pycsw:Title', md.contents[coverage].title)
        _set(context, recobj, 'pycsw:Abstract', md.contents[coverage].abstract)
        _set(context, recobj, 'pycsw:Keywords', ','.join(md.contents[coverage].keywords))

        _set(context, recobj, 'pycsw:AnyText',
             util.get_anytext([md.contents[coverage].title,
                              md.contents[coverage].abstract,
                              ','.join(md.contents[coverage].keywords)]))

        bbox = md.contents[coverage].boundingBoxWGS84
        if bbox is not None:
            tmp = '%s,%s,%s,%s' % (bbox[0], bbox[1], bbox[2], bbox[3])
            wkt_polygon = util.bbox2wktpolygon(tmp)
            _set(context, recobj, 'pycsw:BoundingBox', wkt_polygon)
            _set(context, recobj, 'pycsw:CRS', 'urn:ogc:def:crs:EPSG:6.11:4326')
            _set(context, recobj, 'pycsw:DistanceUOM', 'degrees')
            bboxs.append(wkt_polygon)

        links = [
            '%s,OGC-Web Coverage Service,OGC:WCS,%s' % (md.contents[coverage].id, md.url)
        ]

        _set(context, recobj, 'pycsw:Links', '^'.join(links))
        _set(context, recobj, 'pycsw:XML', caps2iso(recobj, md, context))

        recobjs.append(recobj)

    # Derive a bbox based on aggregated coverage bbox values

    bbox_agg = util.bbox_from_polygons(bboxs)

    if bbox_agg is not None:
        _set(context, serviceobj, 'pycsw:BoundingBox', bbox_agg)

    _set(context, serviceobj, 'pycsw:XML', caps2iso(serviceobj, md, context))
    recobjs.insert(0, serviceobj)

    return recobjs
Ejemplo n.º 20
0
def kvp2filterxml(kvp, context, profiles, fes_version='1.0'):
    ''' transform kvp to filter XML string '''

    bbox_element = None
    time_element = None
    anytext_elements = []
    query_temporal_by_iso = False

    eo_parentidentifier_element = None
    eo_bands_element = None
    eo_cloudcover_element = None
    eo_instrument_element = None
    eo_orbitdirection_element = None
    eo_orbitnumber_element = None
    eo_platform_element = None
    eo_processinglevel_element = None
    eo_producttype_element = None
    eo_sensortype_element = None
    eo_snowcover_element = None

    if profiles is not None and 'plugins' in profiles and 'APISO' in profiles['plugins']:
        query_temporal_by_iso = True

    # Count parameters
    par_count = 0
    for p in ['q','bbox','time']:
        if p in kvp and kvp[p] != '':
            par_count += 1

    # Create root element for FilterXML
    root = etree.Element(util.nspath_eval('ogc:Filter', context.namespaces))

    # bbox to FilterXML
    if 'bbox' in kvp and kvp['bbox'] != '':
        LOGGER.debug('Detected bbox parameter')
        bbox_list = [x.strip() for x in kvp['bbox'].split(',')]
        bbox_element = etree.Element(util.nspath_eval('ogc:BBOX',
                    context.namespaces))
        el = etree.Element(util.nspath_eval('ogc:PropertyName',
                    context.namespaces))
        el.text = 'ows:BoundingBox'
        bbox_element.append(el)
        env = etree.Element(util.nspath_eval('gml:Envelope',
                    context.namespaces))
        el = etree.Element(util.nspath_eval('gml:lowerCorner',
                    context.namespaces))

        if len(bbox_list) == 5:  # add srsName
            LOGGER.debug('Found CRS')
            env.attrib['srsName'] = bbox_list[4]
        else:
            LOGGER.debug('Assuming 4326')
            env.attrib['srsName'] = 'urn:ogc:def:crs:OGC:1.3:CRS84'
            if not validate_4326(bbox_list):
                msg = '4326 coordinates out of range: %s' % bbox_list
                LOGGER.error(msg)
                raise RuntimeError(msg)

        try:
            el.text = "%s %s" % (bbox_list[0], bbox_list[1])
        except Exception as err:
            errortext = 'Exception: OpenSearch bbox not valid.\nError: %s.' % str(err)
            LOGGER.exception(errortext)
        env.append(el)
        el = etree.Element(util.nspath_eval('gml:upperCorner',
                    context.namespaces))
        try:
            el.text = "%s %s" % (bbox_list[2], bbox_list[3])
        except Exception as err:
            errortext = 'Exception: OpenSearch bbox not valid.\nError: %s.' % str(err)
            LOGGER.exception(errortext)
        env.append(el)
        bbox_element.append(env)

    # q to FilterXML
    if 'q' in kvp and kvp['q'] != '':
        LOGGER.debug('Detected q parameter')
        qvals = kvp['q'].split()
        LOGGER.debug(qvals)
        if len(qvals) > 1:
            par_count += 1
        for qval in qvals:
            LOGGER.debug('processing q token')
            anytext_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo',
                        context.namespaces))
            el = etree.Element(util.nspath_eval('ogc:PropertyName',
                        context.namespaces))
            el.text = 'csw:AnyText'
            anytext_element.append(el)
            el = etree.Element(util.nspath_eval('ogc:Literal',
                        context.namespaces))
            el.text = qval
            anytext_element.append(el)
            anytext_elements.append(anytext_element)

    if ('start' in kvp or 'stop' in kvp) and 'time' not in kvp:
        LOGGER.debug('Detected start/stop in KVP')
        kvp['time'] = ''
        if 'start' in kvp and kvp['start'] != '':
            kvp['time'] = kvp['start'] + '/'
        if 'stop' in kvp and kvp['stop'] != '':
            if len(kvp['time']) > 0:
                kvp['time'] += kvp['stop']
            else:
                kvp['time'] = '/' + kvp['stop']
            LOGGER.debug('new KVP time: {}'.format(kvp['time']))

    # time to FilterXML
    if 'time' in kvp and kvp['time'] != '':
        LOGGER.debug('Detected time parameter %s', kvp['time'])
        time_list = kvp['time'].split("/")

        LOGGER.debug('TIMELIST: %s', time_list) 

        if len(time_list) == 2:
            if '' not in time_list:  # both dates present
                LOGGER.debug('Both dates present')
                if query_temporal_by_iso:
                    LOGGER.debug('Querying by ISO data extent')
                    time_element = etree.Element(util.nspath_eval('ogc:And',
                                   context.namespaces))
    
                    begin_element = etree.Element(util.nspath_eval('ogc:PropertyIsGreaterThanOrEqualTo',
                                    context.namespaces))
                    etree.SubElement(begin_element, util.nspath_eval('ogc:PropertyName',
                                    context.namespaces)).text = 'apiso:TempExtent_begin'
                    etree.SubElement(begin_element, util.nspath_eval('ogc:Literal',
                                     context.namespaces)).text = time_list[0]
    
                    end_element = etree.Element(util.nspath_eval('ogc:PropertyIsLessThanOrEqualTo',
                                  context.namespaces))
                    etree.SubElement(end_element, util.nspath_eval('ogc:PropertyName',
                                     context.namespaces)).text = 'apiso:TempExtent_end'
                    etree.SubElement(end_element, util.nspath_eval('ogc:Literal',
                                     context.namespaces)).text = time_list[1]
    
                    time_element.append(begin_element)
                    time_element.append(end_element)

                else:
                    LOGGER.debug('Querying by DC date')
                    time_element = etree.Element(util.nspath_eval('ogc:PropertyIsBetween',
                                   context.namespaces))
                    el = etree.Element(util.nspath_eval('ogc:PropertyName',
                                       context.namespaces))
                    el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval('ogc:LowerBoundary',
                                       context.namespaces))
                    el2 = etree.Element(util.nspath_eval('ogc:Literal',
                                        context.namespaces))
                    el2.text = time_list[0]
                    el.append(el2)
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval('ogc:UpperBoundary',
                                context.namespaces))
                    el2 = etree.Element(util.nspath_eval('ogc:Literal',
                                context.namespaces))
                    el2.text = time_list[1]
                    el.append(el2)
                    time_element.append(el)
    
            else:   # one is empty
                LOGGER.debug('Querying by open-ended date')
                if time_list == ['', '']:
                    par_count -= 1
                # One of two is empty
                elif time_list[1] == '':  # start datetime but no end datetime
                    time_element = etree.Element(util.nspath_eval('ogc:PropertyIsGreaterThanOrEqualTo',
                                context.namespaces))
                    el = etree.Element(util.nspath_eval('ogc:PropertyName',
                                context.namespaces))
                    if query_temporal_by_iso:
                        el.text = 'apiso:TempExtent_begin'
                    else:
                        el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval('ogc:Literal',
                                context.namespaces))
                    el.text = time_list[0]
                    time_element.append(el)
                else:  # end datetime but no start datetime
                    time_element = etree.Element(util.nspath_eval('ogc:PropertyIsLessThanOrEqualTo',
                                context.namespaces))
                    el = etree.Element(util.nspath_eval('ogc:PropertyName',
                                context.namespaces))
                    if query_temporal_by_iso:
                        el.text = 'apiso:TempExtent_end'
                    else:
                        el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval('ogc:Literal',
                                context.namespaces))
                    el.text = time_list[1]
                    time_element.append(el)
        elif ((len(time_list) == 1) and ('' not in time_list)):
            LOGGER.debug('Querying time instant via dc:date')
            # This is an equal request
            time_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo',
                        context.namespaces))
            el = etree.Element(util.nspath_eval('ogc:PropertyName',
                        context.namespaces))
            el.text = 'dc:date'
            time_element.append(el)
            el = etree.Element(util.nspath_eval('ogc:Literal',
                        context.namespaces))
            el.text = time_list[0]
            time_element.append(el)
        else:
            # Error
            errortext = 'Exception: OpenSearch time not valid: %s.' % str(kvp['time'])
            LOGGER.error(errortext)

    LOGGER.debug('Processing EO queryables')
    if not util.is_none_or_empty(kvp.get('eo:parentidentifier')):
        par_count += 1
        eo_parentidentifier_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
        etree.SubElement(eo_parentidentifier_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:ParentIdentifier'
        etree.SubElement(eo_parentidentifier_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = kvp['eo:parentidentifier']

    if not util.is_none_or_empty(kvp.get('eo:producttype')):
        par_count += 1
        eo_producttype_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
        etree.SubElement(eo_producttype_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
        etree.SubElement(eo_producttype_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = '*eo:productType:%s*' % kvp['eo:producttype']

    if not util.is_none_or_empty(kvp.get('eo:platform')):
        par_count += 1
        eo_platform_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
        etree.SubElement(eo_platform_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Platform'
        etree.SubElement(eo_platform_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = kvp['eo:platform']

    if not util.is_none_or_empty(kvp.get('eo:processinglevel')):
        par_count += 1
        eo_processinglevel_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
        etree.SubElement(eo_processinglevel_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
        etree.SubElement(eo_processinglevel_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = '*eo:processingLevel:%s*' % kvp['eo:processinglevel']

    if not util.is_none_or_empty(kvp.get('eo:instrument')):
        par_count += 1
        eo_instrument_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
        etree.SubElement(eo_instrument_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Instrument'
        etree.SubElement(eo_instrument_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = kvp['eo:instrument']

    if not util.is_none_or_empty(kvp.get('eo:sensortype')):
        par_count += 1
        eo_sensortype_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
        etree.SubElement(eo_sensortype_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:SensorType'
        etree.SubElement(eo_sensortype_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = kvp['eo:sensortype']

    if not util.is_none_or_empty(kvp.get('eo:cloudcover')):
        par_count += 1
        eo_cloudcover_element = evaluate_literal(context, 'apiso:CloudCover', kvp['eo:cloudcover'])

    if not util.is_none_or_empty(kvp.get('eo:snowcover')):
        par_count += 1
        eo_snowcover_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
        etree.SubElement(eo_snowcover_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
        etree.SubElement(eo_snowcover_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = '*eo:snowCover:%s*' % kvp['eo:snowcover']

    if not util.is_none_or_empty(kvp.get('eo:spectralrange')):
        par_count += 1
        eo_bands_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
        etree.SubElement(eo_bands_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Bands'
        etree.SubElement(eo_bands_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = '*%s*' % kvp['eo:spectralrange']

    if not util.is_none_or_empty(kvp.get('eo:orbitnumber')):
        par_count += 1
        eo_orbitnumber_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
        etree.SubElement(eo_orbitnumber_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
        etree.SubElement(eo_orbitnumber_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = '*eo:orbitNumber:%s*' % kvp['eo:orbitnumber']

    if not util.is_none_or_empty(kvp.get('eo:orbitdirection')):
        par_count += 1
        eo_orbitdirection_element = etree.Element(util.nspath_eval('ogc:PropertyIsLike', context.namespaces),
            matchCase='false', wildCard='*', singleChar='?', escapeChar='\\')
        etree.SubElement(eo_orbitdirection_element,
           util.nspath_eval('ogc:PropertyName', context.namespaces)).text = 'apiso:Subject'
        etree.SubElement(eo_orbitdirection_element, util.nspath_eval(
            'ogc:Literal', context.namespaces)).text = '*eo:orbitDirection:%s*' % kvp['eo:orbitdirection']

    LOGGER.info('Query parameter count: %s', par_count)
    if par_count == 0:
        return ''
    elif par_count == 1:
        LOGGER.debug('Single predicate filter')
        # Only one OpenSearch parameter exists
        if 'bbox' in kvp and kvp['bbox'] != '':
            LOGGER.debug('Adding bbox')
            root.append(bbox_element)
        elif time_element is not None:
            LOGGER.debug('Adding time')
            root.append(time_element)
        elif anytext_elements:
            LOGGER.debug('Adding anytext')
            root.extend(anytext_elements)
    elif par_count > 1:
        LOGGER.debug('ogc:And query (%d predicates)', par_count)
        # Since more than 1 parameter, append the AND logical operator
        logical_and = etree.Element(util.nspath_eval('ogc:And',
                context.namespaces))
        if bbox_element is not None:
            logical_and.append(bbox_element)
        if time_element is not None:
            logical_and.append(time_element)
        if anytext_elements is not None:
            logical_and.extend(anytext_elements)
        root.append(logical_and)

    if par_count == 1:
        node_to_append = root
    elif par_count > 1:
        node_to_append = logical_and

    LOGGER.debug('Adding EO queryables')
    for eo_element in [eo_producttype_element, eo_platform_element, eo_instrument_element,
                       eo_sensortype_element, eo_cloudcover_element, eo_snowcover_element,
                       eo_bands_element, eo_orbitnumber_element, eo_orbitdirection_element,
                       eo_processinglevel_element, eo_parentidentifier_element]:
        if eo_element is not None:
            node_to_append.append(eo_element)

    # Render etree to string XML
    LOGGER.debug(etree.tostring(root, encoding='unicode'))
    filterstring = etree.tostring(root, encoding='unicode')
    if fes_version == '2.0':
        filterstring = filterstring.replace('PropertyName', 'ValueReference')\
                                   .replace('xmlns:ogc="http://www.opengis.net/ogc"', 'xmlns:fes20="http://www.opengis.net/fes/2.0"')\
                                   .replace('ogc:', 'fes20:')
    return filterstring
Ejemplo n.º 21
0
    def response(self, response, kvp, repository, server_url):
        """process OAI-PMH request"""

        mode = kvp.pop('mode', None)
        if 'config' in kvp:
            config_val = kvp.pop('config')
        url = '%smode=oaipmh' % util.bind_url(server_url)

        node = etree.Element(util.nspath_eval('oai:OAI-PMH', self.namespaces),
                             nsmap=self.namespaces)
        node.set(
            util.nspath_eval('xsi:schemaLocation', self.namespaces),
            '%s http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd' %
            self.namespaces['oai'])
        LOGGER.info(etree.tostring(node))

        etree.SubElement(node,
                         util.nspath_eval(
                             'oai:responseDate',
                             self.namespaces)).text = util.get_today_and_now()
        etree.SubElement(node,
                         util.nspath_eval('oai:request', self.namespaces),
                         attrib=kvp).text = url

        if 'verb' not in kvp:
            etree.SubElement(
                node,
                util.nspath_eval('oai:error', self.namespaces),
                code='badArgument').text = 'Missing \'verb\' parameter'
            return node

        if kvp['verb'] not in self.request_model.keys():
            etree.SubElement(
                node,
                util.nspath_eval('oai:error', self.namespaces),
                code='badArgument').text = 'Unknown verb \'%s\'' % kvp['verb']
            return node

        if util.xmltag_split(response.tag) == 'ExceptionReport':
            etree.SubElement(node,
                             util.nspath_eval('oai:error', self.namespaces),
                             code='badArgument').text = response.xpath(
                                 '//ows:ExceptionText|//ows20:ExceptionText',
                                 namespaces=self.context.namespaces)[0].text
            return node

        verb = kvp.pop('verb')

        if verb in ['GetRecord', 'ListIdentifiers', 'ListRecords']:
            if 'metadataprefix' not in kvp:
                etree.SubElement(node,
                                 util.nspath_eval('oai:error',
                                                  self.namespaces),
                                 code='badArgument'
                                 ).text = 'Missing metadataPrefix parameter'
                return node
            elif kvp['metadataprefix'] not in self.metadata_formats.keys():
                etree.SubElement(node,
                                 util.nspath_eval('oai:error',
                                                  self.namespaces),
                                 code='badArgument'
                                 ).text = 'Invalid metadataPrefix parameter'
                return node

        for key, value in kvp.iteritems():
            if key != 'mode' and key not in self.request_model[verb]:
                etree.SubElement(
                    node,
                    util.nspath_eval('oai:error', self.namespaces),
                    code='badArgument').text = 'Illegal parameter \'%s\'' % key
                return node

        verbnode = etree.SubElement(
            node, util.nspath_eval('oai:%s' % verb, self.namespaces))

        if verb == 'Identify':
            etree.SubElement(
                verbnode,
                util.nspath_eval('oai:repositoryName',
                                 self.namespaces)).text = self.config.get(
                                     'metadata:main', 'identification_title')
            etree.SubElement(verbnode,
                             util.nspath_eval('oai:baseURL',
                                              self.namespaces)).text = url
            etree.SubElement(
                verbnode,
                util.nspath_eval('oai:protocolVersion',
                                 self.namespaces)).text = '2.0'
            etree.SubElement(
                verbnode,
                util.nspath_eval('oai:adminEmail',
                                 self.namespaces)).text = self.config.get(
                                     'metadata:main', 'contact_email')
            etree.SubElement(
                verbnode,
                util.nspath_eval(
                    'oai:earliestDatestamp',
                    self.namespaces)).text = repository.query_insert('min')
            etree.SubElement(
                verbnode, util.nspath_eval('oai:deletedRecord',
                                           self.namespaces)).text = 'no'
            etree.SubElement(
                verbnode, util.nspath_eval(
                    'oai:granularity',
                    self.namespaces)).text = 'YYYY-MM-DDThh:mm:ssZ'

        elif verb == 'ListSets':
            for key, value in self.metadata_sets.iteritems():
                setnode = etree.SubElement(
                    verbnode, util.nspath_eval('oai:set', self.namespaces))
                etree.SubElement(
                    setnode, util.nspath_eval('oai:setSpec',
                                              self.namespaces)).text = key
                etree.SubElement(
                    setnode, util.nspath_eval('oai:setName',
                                              self.namespaces)).text = value[0]

        elif verb == 'ListMetadataFormats':
            for key, value in self.metadata_formats.iteritems():
                mdfnode = etree.SubElement(
                    verbnode,
                    util.nspath_eval('oai:metadataFormat', self.namespaces))
                etree.SubElement(
                    mdfnode,
                    util.nspath_eval('oai:metadataPrefix',
                                     self.namespaces)).text = key
                etree.SubElement(
                    mdfnode,
                    util.nspath_eval('oai:schema',
                                     self.namespaces)).text = value['schema']
                etree.SubElement(
                    mdfnode,
                    util.nspath_eval(
                        'oai:metadataNamespace',
                        self.namespaces)).text = value['namespace']

        elif verb in ['GetRecord', 'ListIdentifiers', 'ListRecords']:
            if verb == 'GetRecord':  # GetRecordById
                records = response.getchildren()
            else:  # GetRecords
                records = response.getchildren()[1].getchildren()
            for child in records:
                recnode = etree.SubElement(
                    verbnode, util.nspath_eval('oai:record', self.namespaces))
                header = etree.SubElement(
                    recnode, util.nspath_eval('oai:header', self.namespaces))
                self._transform_element(header, response, 'oai:identifier')
                self._transform_element(header, response, 'oai:dateStamp')
                self._transform_element(header, response, 'oai:setSpec')
                if verb in ['GetRecord', 'ListRecords']:
                    metadata = etree.SubElement(
                        recnode,
                        util.nspath_eval('oai:metadata', self.namespaces))
                    if 'metadataprefix' in kvp and kvp[
                            'metadataprefix'] == 'oai_dc':
                        child.tag = util.nspath_eval('oai_dc:dc',
                                                     self.namespaces)
                    metadata.append(child)
            if verb != 'GetRecord':
                complete_list_size = response.xpath(
                    '//@numberOfRecordsMatched')[0]
                next_record = response.xpath('//@nextRecord')[0]
                cursor = str(int(complete_list_size) - int(next_record) - 1)

                resumption_token = etree.SubElement(
                    verbnode,
                    util.nspath_eval('oai:resumptionToken', self.namespaces),
                    completeListSize=complete_list_size,
                    cursor=cursor).text = next_record
        return node
Ejemplo n.º 22
0
def kvp2filterxml(kvp, context):
    ''' transform kvp to filter XML string '''

    bbox_element = None
    time_element = None
    anytext_elements = []

    # Count parameters
    par_count = 0
    for p in ['q','bbox','time']:
        if p in kvp and kvp[p] != '':
            par_count += 1

    # Create root element for FilterXML
    root = etree.Element(util.nspath_eval('ogc:Filter', context.namespaces))

    # bbox to FilterXML
    if 'bbox' in kvp and kvp['bbox'] != '':
        LOGGER.debug('Detected bbox parameter')
        bbox_list = [x.strip() for x in kvp['bbox'].split(',')]
        bbox_element = etree.Element(util.nspath_eval('ogc:BBOX',
                    context.namespaces))
        el = etree.Element(util.nspath_eval('ogc:PropertyName',
                    context.namespaces))
        el.text = 'ows:BoundingBox'
        bbox_element.append(el)
        env = etree.Element(util.nspath_eval('gml:Envelope',
                    context.namespaces))
        el = etree.Element(util.nspath_eval('gml:lowerCorner',
                    context.namespaces))

        if len(bbox_list) == 5:  # add srsName
            LOGGER.debug('Found CRS')
            env.attrib['srsName'] = bbox_list[4]
        else:
            LOGGER.debug('Assuming 4326')
            env.attrib['srsName'] = 'urn:ogc:def:crs:OGC:1.3:CRS84'
            if not util.validate_4326(bbox_list):
                msg = '4326 coordinates out of range: %s' % bbox_list
                LOGGER.debug(msg)
                raise RuntimeError(msg)

        try:
            el.text = "%s %s" % (bbox_list[0], bbox_list[1])
        except Exception as err:
            errortext = 'Exception: OpenSearch bbox not valid.\nError: %s.' % str(err)
            LOGGER.debug(errortext)
        env.append(el)
        el = etree.Element(util.nspath_eval('gml:upperCorner',
                    context.namespaces))
        try:
            el.text = "%s %s" % (bbox_list[2], bbox_list[3])
        except Exception as err:
            errortext = 'Exception: OpenSearch bbox not valid.\nError: %s.' % str(err)
            LOGGER.debug(errortext)
        env.append(el)
        bbox_element.append(env)

    # q to FilterXML
    if 'q' in kvp and kvp['q'] != '':
        LOGGER.debug('Detected q parameter')
        qvals = kvp['q'].split()
        LOGGER.debug(qvals)
        if len(qvals) > 1:
            par_count += 1
        for qval in qvals:
            LOGGER.debug('processing q token')
            anytext_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo',
                        context.namespaces))
            el = etree.Element(util.nspath_eval('ogc:PropertyName',
                        context.namespaces))
            el.text = 'csw:AnyText'
            anytext_element.append(el)
            el = etree.Element(util.nspath_eval('ogc:Literal',
                        context.namespaces))
            if six.PY2:
                el.text = qval.decode('utf8')
            else:
                el.text = qval
            anytext_element.append(el)
            anytext_elements.append(anytext_element)

    # time to FilterXML
    if 'time' in kvp and kvp['time'] != '':
        LOGGER.debug('Detected time parameter %s', kvp['time'])
        time_list = kvp['time'].split("/")
        if (len(time_list) == 2):
            LOGGER.debug('TIMELIST: %s', time_list)
            # This is a normal request
            if '' not in time_list:
                LOGGER.debug('Both dates present')
                # Both dates are present
                time_element = etree.Element(util.nspath_eval('ogc:PropertyIsBetween',
                            context.namespaces))
                el = etree.Element(util.nspath_eval('ogc:PropertyName',
                            context.namespaces))
                el.text = 'dc:date'
                time_element.append(el)
                el = etree.Element(util.nspath_eval('ogc:LowerBoundary',
                            context.namespaces))
                el2 = etree.Element(util.nspath_eval('ogc:Literal',
                            context.namespaces))
                el2.text = time_list[0]
                el.append(el2)
                time_element.append(el)
                el = etree.Element(util.nspath_eval('ogc:UpperBoundary',
                            context.namespaces))
                el2 = etree.Element(util.nspath_eval('ogc:Literal',
                            context.namespaces))
                el2.text = time_list[1]
                el.append(el2)
                time_element.append(el)
            else:
                if time_list == ['', '']:
                    par_count -= 1
                # One of two is empty
                elif time_list[1] is '':
                    time_element = etree.Element(util.nspath_eval('ogc:PropertyIsGreaterThanOrEqualTo',
                                context.namespaces))
                    el = etree.Element(util.nspath_eval('ogc:PropertyName',
                                context.namespaces))
                    el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval('ogc:Literal',
                                context.namespaces))
                    el.text = time_list[0]
                    time_element.append(el)
                else:
                    time_element = etree.Element(util.nspath_eval('ogc:PropertyIsLessThanOrEqualTo',
                                context.namespaces))
                    el = etree.Element(util.nspath_eval('ogc:PropertyName',
                                context.namespaces))
                    el.text = 'dc:date'
                    time_element.append(el)
                    el = etree.Element(util.nspath_eval('ogc:Literal',
                                context.namespaces))
                    el.text = time_list[1]
                    time_element.append(el)
        elif ((len(time_list) == 1) and ('' not in time_list)):
            # This is an equal request
            time_element = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo',
                        context.namespaces))
            el = etree.Element(util.nspath_eval('ogc:PropertyName',
                        context.namespaces))
            el.text = 'dc:date'
            time_element.append(el)
            el = etree.Element(util.nspath_eval('ogc:Literal',
                        context.namespaces))
            el.text = time_list[0]
            time_element.append(el)
        else:
            # Error
            errortext = 'Exception: OpenSearch time not valid: %s.' % str(kvp['time'])
            LOGGER.debug(errortext)

    if par_count == 0:
        return ''
    elif par_count == 1:
        LOGGER.debug('Single predicate filter')
        # Only one OpenSearch parameter exists
        if 'bbox' in kvp and kvp['bbox'] != '':
            LOGGER.debug('Adding bbox')
            root.append(bbox_element)
        elif time_element is not None:
            LOGGER.debug('Adding time')
            root.append(time_element)
        elif anytext_elements:
            LOGGER.debug('Adding anytext')
            root.extend(anytext_elements)
    elif (par_count > 1):
        LOGGER.debug('ogc:And query (%d predicates)', par_count)
        # Since more than 1 parameter, append the AND logical operator
        logical_and = etree.Element(util.nspath_eval('ogc:And',
                context.namespaces))
        if bbox_element is not None:
            logical_and.append(bbox_element)
        if time_element is not None:
            logical_and.append(time_element)
        if anytext_elements is not None:
            logical_and.extend(anytext_elements)
        root.append(logical_and)

    # Render etree to string XML
    LOGGER.debug(etree.tostring(root, encoding='unicode'))
    return etree.tostring(root, encoding='unicode')
Ejemplo n.º 23
0
    def response(self, response, kvp, repository, server_url):
        """process OAI-PMH request"""

        mode = kvp.pop('mode', None)
        if 'config' in kvp:
            config_val = kvp.pop('config')
        url = '%smode=oaipmh' % util.bind_url(server_url)

        node = etree.Element(util.nspath_eval('oai:OAI-PMH', self.namespaces), nsmap=self.namespaces)
        node.set(util.nspath_eval('xsi:schemaLocation', self.namespaces), '%s http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd' % self.namespaces['oai'])
        LOGGER.info(etree.tostring(node))

        etree.SubElement(node, util.nspath_eval('oai:responseDate', self.namespaces)).text = util.get_today_and_now()
        etree.SubElement(node, util.nspath_eval('oai:request', self.namespaces), attrib=kvp).text = url

        if 'verb' not in kvp:
            etree.SubElement(node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = 'Missing \'verb\' parameter'
            return node

        if kvp['verb'] not in self.request_model.keys():
            etree.SubElement(node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = 'Unknown verb \'%s\'' % kvp['verb']
            return node

        if util.xmltag_split(response.tag) == 'ExceptionReport':
            etree.SubElement(node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = response.xpath('//ows:ExceptionText|//ows20:ExceptionText', namespaces=self.context.namespaces)[0].text
            return node

        verb = kvp.pop('verb')

        if verb in ['GetRecord', 'ListIdentifiers', 'ListRecords']:
            if 'metadataprefix' not in kvp:
                etree.SubElement(node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = 'Missing metadataPrefix parameter'
                return node
            elif kvp['metadataprefix'] not in self.metadata_formats.keys():
                etree.SubElement(node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = 'Invalid metadataPrefix parameter'
                return node

        for key, value in kvp.items():
            if key != 'mode' and key not in self.request_model[verb]:
                etree.SubElement(node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = 'Illegal parameter \'%s\'' % key
                return node

        verbnode = etree.SubElement(node, util.nspath_eval('oai:%s' % verb, self.namespaces))

        if verb == 'Identify':
                etree.SubElement(verbnode, util.nspath_eval('oai:repositoryName', self.namespaces)).text = self.config.get('metadata:main', 'identification_title')
                etree.SubElement(verbnode, util.nspath_eval('oai:baseURL', self.namespaces)).text = url
                etree.SubElement(verbnode, util.nspath_eval('oai:protocolVersion', self.namespaces)).text = '2.0'
                etree.SubElement(verbnode, util.nspath_eval('oai:adminEmail', self.namespaces)).text = self.config.get('metadata:main', 'contact_email')
                etree.SubElement(verbnode, util.nspath_eval('oai:earliestDatestamp', self.namespaces)).text = repository.query_insert('min')
                etree.SubElement(verbnode, util.nspath_eval('oai:deletedRecord', self.namespaces)).text = 'no'
                etree.SubElement(verbnode, util.nspath_eval('oai:granularity', self.namespaces)).text = 'YYYY-MM-DDThh:mm:ssZ'

        elif verb == 'ListSets':
            for key, value in self.metadata_sets.items():
                setnode = etree.SubElement(verbnode, util.nspath_eval('oai:set', self.namespaces))
                etree.SubElement(setnode, util.nspath_eval('oai:setSpec', self.namespaces)).text = key
                etree.SubElement(setnode, util.nspath_eval('oai:setName', self.namespaces)).text = value[0]

        elif verb == 'ListMetadataFormats':
            for key, value in self.metadata_formats.items():
                mdfnode = etree.SubElement(verbnode, util.nspath_eval('oai:metadataFormat', self.namespaces))
                etree.SubElement(mdfnode, util.nspath_eval('oai:metadataPrefix', self.namespaces)).text = key
                etree.SubElement(mdfnode, util.nspath_eval('oai:schema', self.namespaces)).text = value['schema']
                etree.SubElement(mdfnode, util.nspath_eval('oai:metadataNamespace', self.namespaces)).text = value['namespace']

        elif verb in ['GetRecord', 'ListIdentifiers', 'ListRecords']:
                if verb == 'GetRecord':  # GetRecordById
                    records = response.getchildren()
                else:  # GetRecords
                    records = response.getchildren()[1].getchildren()
                for child in records:
                    recnode = etree.SubElement(verbnode, util.nspath_eval('oai:record', self.namespaces))
                    header = etree.SubElement(recnode, util.nspath_eval('oai:header', self.namespaces))
                    self._transform_element(header, response, 'oai:identifier')
                    self._transform_element(header, response, 'oai:dateStamp')
                    self._transform_element(header, response, 'oai:setSpec')
                    if verb in ['GetRecord', 'ListRecords']:
                        metadata = etree.SubElement(recnode, util.nspath_eval('oai:metadata', self.namespaces))
                        if 'metadataprefix' in kvp and kvp['metadataprefix'] == 'oai_dc':
                            child.tag = util.nspath_eval('oai_dc:dc', self.namespaces)
                        metadata.append(child)
                if verb != 'GetRecord':
                    complete_list_size = response.xpath('//@numberOfRecordsMatched')[0]
                    next_record = response.xpath('//@nextRecord')[0]
                    cursor = str(int(complete_list_size) - int(next_record) - 1)
                
                    resumption_token = etree.SubElement(verbnode, util.nspath_eval('oai:resumptionToken', self.namespaces),
                                                        completeListSize=complete_list_size, cursor=cursor).text = next_record
        return node