Example #1
0
    def _get_envelope(self):
        """Parse gml:Envelope"""

        tmp = self._exml.find(
            util.nspath_eval('gml:Envelope/gml:lowerCorner', self.nsmap))
        if tmp is None:
            raise RuntimeError('Invalid gml:Envelope geometry.\
                               Missing gml:lowerCorner')
        else:
            lower_left = tmp.text

        tmp = self._exml.find(
            util.nspath_eval('gml:Envelope/gml:upperCorner', self.nsmap))
        if tmp is None:
            raise RuntimeError('Invalid gml:Envelope geometry.\
                               Missing gml:upperCorner')
        else:
            upper_right = tmp.text

        llmin = lower_left.split()
        urmax = upper_right.split()

        if len(llmin) < 2 or len(urmax) < 2:
            raise RuntimeError('Invalid gml:Envelope geometry. \
            gml:lowerCorner and gml:upperCorner must hold at least x and y')

        if self.crs.axisorder == 'yx':
            self.wkt = util.bbox2wktpolygon(
                '%s,%s,%s,%s' % (llmin[1], llmin[0], urmax[1], urmax[0]))
        else:
            self.wkt = util.bbox2wktpolygon(
                '%s,%s,%s,%s' % (llmin[0], llmin[1], urmax[0], urmax[1]))
Example #2
0
def write_keywords(keywords, nsmap):
    """generate gmd:MD_Keywords construct"""
    md_keywords = etree.Element(util.nspath_eval('gmd:MD_Keywords', nsmap))
    for kw in keywords.split(','):
        keyword = etree.SubElement(md_keywords, util.nspath_eval('gmd:keyword', nsmap))
        etree.SubElement(keyword, util.nspath_eval('gco:CharacterString', nsmap)).text = kw
    return md_keywords
Example #3
0
def write_extent(bbox, nsmap):
    ''' Generate BBOX extent '''

    if bbox is not None:
        try:
            bbox2 = util.wkt2geom(bbox)
        except:
            return None
        bounding_box = etree.Element(
            util.nspath_eval('gm03:GM03_2_1Core.Core.EX_GeographicBoundingBox',
                             NAMESPACES))
        etree.SubElement(bounding_box,
                         util.nspath_eval('gm03:northBoundLatitude',
                                          nsmap)).text = str(bbox2[3])
        etree.SubElement(bounding_box,
                         util.nspath_eval('gm03:southBoundLatitude',
                                          nsmap)).text = str(bbox2[1])
        etree.SubElement(bounding_box,
                         util.nspath_eval('gm03:eastBoundLongitude',
                                          nsmap)).text = str(bbox2[0])
        etree.SubElement(bounding_box,
                         util.nspath_eval('gm03:westBoundLongitude',
                                          nsmap)).text = str(bbox2[2])
        return bounding_box
    return None
Example #4
0
File: admin.py Project: 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))
Example #5
0
    def _get_envelope(self):
        """Parse gml:Envelope"""

        tmp = self._exml.find(util.nspath_eval('gml:Envelope/gml:lowerCorner',
                                               self.nsmap))
        if tmp is None:
            raise RuntimeError('Invalid gml:Envelope geometry.\
                               Missing gml:lowerCorner')
        else:
            lower_left = tmp.text

        tmp = self._exml.find(util.nspath_eval('gml:Envelope/gml:upperCorner',
                                               self.nsmap))
        if tmp is None:
            raise RuntimeError('Invalid gml:Envelope geometry.\
                               Missing gml:upperCorner')
        else:
            upper_right = tmp.text

        llmin = lower_left.split()
        urmax = upper_right.split()

        if len(llmin) < 2 or len(urmax) < 2:
            raise RuntimeError('Invalid gml:Envelope geometry. \
            gml:lowerCorner and gml:upperCorner must hold at least x and y')

        if self.crs.axisorder == 'yx':
            self.wkt = util.bbox2wktpolygon('%s,%s,%s,%s' % (llmin[1],
                                            llmin[0], urmax[1], urmax[0]))
        else:
            self.wkt = util.bbox2wktpolygon('%s,%s,%s,%s' % (llmin[0],
                                            llmin[1], urmax[0], urmax[1]))
Example #6
0
def _build_xpath(node, path, namespaces, text):
    components = path.split("/")
    if util.nspath_eval(components[0], namespaces) == node.tag:
        components.pop(0)
    while components:
        # take in account positional  indexes in the form /path/para[3] or /path/para[location()=3]
        if "[" in components[0]:
            component, trail = components[0].split("[", 1)
            target_index = int(trail.split("=")[-1].strip("]"))
        else:
            component = components[0]
            target_index = 0

        components.pop(0)
        found_index = -1
        for child in node.getchildren():
            if child.tag == util.nspath_eval(component, namespaces):
                found_index += 1
                if found_index == target_index:
                    node = child
                    break

        if found_index < target_index:
            new_node = None

            for i in range(target_index - found_index):
                new_node = etree.Element(
                    util.nspath_eval(component, namespaces))
                node.append(new_node)

            node = new_node

    node.text = text
    return node
Example #7
0
    def get_schemacomponents(self):
        ''' Return schema components as lxml.etree.Element list '''

        node1 = etree.Element(
        util.nspath_eval('csw:SchemaComponent', self.context.namespaces),
        schemaLanguage='XMLSCHEMA', targetNamespace=self.namespace,
        parentSchema='gmd.xsd')

        schema_file = os.path.join(self.context.pycsw_home, 'plugins',
                                   'profiles', 'apiso', 'schemas', 'ogc',
                                   'iso', '19139', '20060504', 'gmd',
                                   'identification.xsd')

        schema = etree.parse(schema_file, self.context.parser).getroot()

        node1.append(schema)

        node2 = etree.Element(
        util.nspath_eval('csw:SchemaComponent', self.context.namespaces),
        schemaLanguage='XMLSCHEMA', targetNamespace=self.namespace,
        parentSchema='gmd.xsd')

        schema_file = os.path.join(self.context.pycsw_home, 'plugins',
                                   'profiles', 'apiso', 'schemas', 'ogc',
                                   'iso', '19139', '20060504', 'srv',
                                   'serviceMetadata.xsd')

        schema = etree.parse(schema_file, self.context.parser).getroot()

        node2.append(schema)

        return [node1, node2]
Example #8
0
def write_extent(bbox, nsmap):
    ''' Generate BBOX extent '''

    from shapely.wkt import loads

    if bbox is not None:
        try:
            bbox2 = util.wkt2geom(bbox)
        except:
            return None
        extent = etree.Element(util.nspath_eval('dif:Spatial_Coverage', nsmap))
        etree.SubElement(extent,
                         util.nspath_eval('dif:Southernmost_Latitude',
                                          nsmap)).text = str(bbox2[1])
        etree.SubElement(extent,
                         util.nspath_eval('dif:Northernmost_Latitude',
                                          nsmap)).text = str(bbox2[3])
        etree.SubElement(extent,
                         util.nspath_eval('dif:Westernmost_Longitude',
                                          nsmap)).text = str(bbox2[0])
        etree.SubElement(extent,
                         util.nspath_eval('dif:Easternmost_Longitude',
                                          nsmap)).text = str(bbox2[2])
        return extent
    return None
Example #9
0
def test_nspath_eval_invalid_element():
    with pytest.raises(RuntimeError):
        util.nspath_eval(xpath="ns1:tag1/ns2:ns3:tag2",
                         nsmap={
                             "ns1": "something",
                             "ns2": "other",
                             "ns3": "another",
                         })
Example #10
0
def _get_pt_freeurl(val, language):
    freeurl = etree.Element(util.nspath_eval('gm03:GM03_2_1Core.Core.PT_FreeURL', NAMESPACES))
    urlgroup = etree.SubElement(freeurl, util.nspath_eval('gm03:URLGroup', NAMESPACES))
    ptgroup = etree.SubElement(urlgroup, util.nspath_eval('gm03:GM03_2_1Core.Core.PT_URLGroup', NAMESPACES))
    if language:
        etree.SubElement(ptgroup, util.nspath_eval('gm03:language', NAMESPACES)).text = language
    etree.SubElement(ptgroup, util.nspath_eval('gm03:plainURL', NAMESPACES)).text = val

    return freeurl
Example #11
0
def _get_pt_freetext(val, language):
    freetext = etree.Element(util.nspath_eval('gm03:GM03_2_1Core.Core.PT_FreeText', NAMESPACES))
    textgroup = etree.SubElement(freetext, util.nspath_eval('gm03:textGroup', NAMESPACES))
    ptgroup = etree.SubElement(textgroup, util.nspath_eval('gm03:GM03_2_1Core.Core.PT_Group', NAMESPACES))
    if language:
        etree.SubElement(ptgroup, util.nspath_eval('gm03:language', NAMESPACES)).text = language
    etree.SubElement(ptgroup, util.nspath_eval('gm03:plainText', NAMESPACES)).text = val

    return freetext
Example #12
0
def test_nspath_eval_invalid_element():
    with pytest.raises(RuntimeError):
        util.nspath_eval(
            xpath="ns1:tag1/ns2:ns3:tag2",
            nsmap={
                "ns1": "something",
                "ns2": "other",
                "ns3": "another",
            }
        )
Example #13
0
    def _gen_soap_wrapper(self):
        ''' Generate SOAP wrapper '''
        LOGGER.debug('Writing SOAP wrapper.')
        node = etree.Element(util.nspath_eval('soapenv:Envelope',
        self.context.namespaces), nsmap=self.context.namespaces)

        node.attrib[util.nspath_eval('xsi:schemaLocation',
        self.context.namespaces)] = '%s %s' % \
        (self.context.namespaces['soapenv'], self.context.namespaces['soapenv'])

        node2 = etree.SubElement(node, util.nspath_eval('soapenv:Body',
        self.context.namespaces))

        if self.exception:
            node3 = etree.SubElement(node2, util.nspath_eval('soapenv:Fault',
                    self.context.namespaces))
            node4 = etree.SubElement(node3, util.nspath_eval('soapenv:Code',
                    self.context.namespaces))

            etree.SubElement(node4, util.nspath_eval('soapenv:Value',
            self.context.namespaces)).text = 'soap:Server'

            node4 = etree.SubElement(node3, util.nspath_eval('soapenv:Reason',
                    self.context.namespaces))

            etree.SubElement(node4, util.nspath_eval('soapenv:Text',
            self.context.namespaces)).text = 'A server exception was encountered.'

            node4 = etree.SubElement(node3, util.nspath_eval('soapenv:Detail',
                    self.context.namespaces))
            node4.append(self.response)
        else:
            node2.append(self.response)

        self.response = node
Example #14
0
    def _gen_soap_wrapper(self):
        """ Generate SOAP wrapper """
        LOGGER.debug("Writing SOAP wrapper.")
        node = etree.Element(
            util.nspath_eval("soapenv:Envelope", self.context.namespaces), nsmap=self.context.namespaces
        )

        schema_location_ns = util.nspath_eval("xsi:schemaLocation", self.context.namespaces)
        node.attrib[schema_location_ns] = "%s %s" % (
            self.context.namespaces["soapenv"],
            self.context.namespaces["soapenv"],
        )

        node2 = etree.SubElement(node, util.nspath_eval("soapenv:Body", self.context.namespaces))

        if self.exception:
            node3 = etree.SubElement(node2, util.nspath_eval("soapenv:Fault", self.context.namespaces))
            node4 = etree.SubElement(node3, util.nspath_eval("soapenv:Code", self.context.namespaces))

            etree.SubElement(node4, util.nspath_eval("soapenv:Value", self.context.namespaces)).text = "soap:Server"

            node4 = etree.SubElement(node3, util.nspath_eval("soapenv:Reason", self.context.namespaces))

            etree.SubElement(
                node4, util.nspath_eval("soapenv:Text", self.context.namespaces)
            ).text = "A server exception was encountered."

            node4 = etree.SubElement(node3, util.nspath_eval("soapenv:Detail", self.context.namespaces))
            node4.append(self.response)
        else:
            node2.append(self.response)

        self.response = node
Example #15
0
def _write_date(dateval, datetypeval, nsmap):
    date1 = etree.Element(util.nspath_eval('gmd:date', nsmap))
    date2 = etree.SubElement(date1, util.nspath_eval('gmd:CI_Date', nsmap))
    date3 = etree.SubElement(date2, util.nspath_eval('gmd:date', nsmap))
    if dateval.find('T') != -1:
        dateel = 'gco:DateTime'
    else:
        dateel = 'gco:Date'
    etree.SubElement(date3, util.nspath_eval(dateel, nsmap)).text = dateval
    datetype = etree.SubElement(date2, util.nspath_eval('gmd:dateType', nsmap))
    datetype.append(_write_codelist_element('gmd:CI_DateTypeCode', datetypeval, nsmap))
    return date1
Example #16
0
File: atom.py Project: GSA/pycsw
def write_extent(bbox, nsmap):
    ''' Generate BBOX extent '''

    if bbox is not None:
        try:
            bbox2 = util.wkt2geom(bbox)
        except:
            return None
        where = etree.Element(util.nspath_eval('georss:where', NAMESPACES))
        envelope = etree.SubElement(where, util.nspath_eval('gml:Envelope', nsmap), srsName='http://www.opengis.net/def/crs/EPSG/0/4326')
        etree.SubElement(envelope, util.nspath_eval('gml:lowerCorner', nsmap)).text = '%s %s' % (bbox2[1], bbox2[0])
        etree.SubElement(envelope, util.nspath_eval('gml:upperCorner', nsmap)).text = '%s %s' % (bbox2[3], bbox2[2])

        return where
    return None
Example #17
0
def write_extent(bbox, nsmap):
    ''' Generate BBOX extent '''

    if bbox is not None:
        try:
            bbox2 = util.wkt2geom(bbox)
        except:
            return None
        where = etree.Element(util.nspath_eval('georss:where', NAMESPACES))
        envelope = etree.SubElement(where, util.nspath_eval('gml:Envelope', nsmap), srsName='http://www.opengis.net/def/crs/EPSG/0/4326')
        etree.SubElement(envelope, util.nspath_eval('gml:lowerCorner', nsmap)).text = '%s %s' % (bbox2[1], bbox2[0])
        etree.SubElement(envelope, util.nspath_eval('gml:upperCorner', nsmap)).text = '%s %s' % (bbox2[3], bbox2[2])

        return where
    return None
Example #18
0
def write_extent(bbox, nsmap):
    ''' Generate BBOX extent '''
    
    if bbox is not None:
        try:
            bbox2 = util.wkt2geom(bbox)
        except:
            return None
        bounding_box = etree.Element(util.nspath_eval('gm03:GM03_2_1Core.Core.EX_GeographicBoundingBox', NAMESPACES))
        etree.SubElement(bounding_box, util.nspath_eval('gm03:northBoundLatitude', nsmap)).text = str(bbox2[3])
        etree.SubElement(bounding_box, util.nspath_eval('gm03:southBoundLatitude', nsmap)).text = str(bbox2[1])
        etree.SubElement(bounding_box, util.nspath_eval('gm03:eastBoundLongitude', nsmap)).text = str(bbox2[0])
        etree.SubElement(bounding_box, util.nspath_eval('gm03:westBoundLongitude', nsmap)).text = str(bbox2[2])
        return bounding_box
    return None
Example #19
0
def _get_pt_freetext(val, language):
    freetext = etree.Element(
        util.nspath_eval('gm03:GM03_2_1Core.Core.PT_FreeText', NAMESPACES))
    textgroup = etree.SubElement(
        freetext, util.nspath_eval('gm03:textGroup', NAMESPACES))
    ptgroup = etree.SubElement(
        textgroup,
        util.nspath_eval('gm03:GM03_2_1Core.Core.PT_Group', NAMESPACES))
    if language:
        etree.SubElement(ptgroup, util.nspath_eval('gm03:language',
                                                   NAMESPACES)).text = language
    etree.SubElement(ptgroup, util.nspath_eval('gm03:plainText',
                                               NAMESPACES)).text = val

    return freetext
Example #20
0
def _get_pt_freeurl(val, language):
    freeurl = etree.Element(
        util.nspath_eval('gm03:GM03_2_1Core.Core.PT_FreeURL', NAMESPACES))
    urlgroup = etree.SubElement(freeurl,
                                util.nspath_eval('gm03:URLGroup', NAMESPACES))
    ptgroup = etree.SubElement(
        urlgroup,
        util.nspath_eval('gm03:GM03_2_1Core.Core.PT_URLGroup', NAMESPACES))
    if language:
        etree.SubElement(ptgroup, util.nspath_eval('gm03:language',
                                                   NAMESPACES)).text = language
    etree.SubElement(ptgroup, util.nspath_eval('gm03:plainURL',
                                               NAMESPACES)).text = val

    return freeurl
Example #21
0
    def _gen_soap_wrapper(self):
        """ Generate SOAP wrapper """
        LOGGER.debug('Writing SOAP wrapper.')
        node = etree.Element(
            util.nspath_eval('soapenv:Envelope', self.context.namespaces),
            nsmap=self.context.namespaces
        )

        schema_location_ns = util.nspath_eval('xsi:schemaLocation',
                                              self.context.namespaces)
        node.attrib[schema_location_ns] = '%s %s' % (
            self.context.namespaces['soapenv'],
            self.context.namespaces['soapenv']
        )

        node2 = etree.SubElement(
            node, util.nspath_eval('soapenv:Body', self.context.namespaces))

        if self.exception:
            node3 = etree.SubElement(
                node2,
                util.nspath_eval('soapenv:Fault', self.context.namespaces)
            )
            node4 = etree.SubElement(
                node3,
                util.nspath_eval('soapenv:Code', self.context.namespaces)
            )

            etree.SubElement(
                node4,
                util.nspath_eval('soapenv:Value', self.context.namespaces)
            ).text = 'soap:Server'

            node4 = etree.SubElement(
                node3,
                util.nspath_eval('soapenv:Reason', self.context.namespaces)
            )

            etree.SubElement(
                node4,
                util.nspath_eval('soapenv:Text', self.context.namespaces)
            ).text = 'A server exception was encountered.'

            node4 = etree.SubElement(
                node3,
                util.nspath_eval('soapenv:Detail', self.context.namespaces)
            )
            node4.append(self.response)
        else:
            node2.append(self.response)

        self.response = node
Example #22
0
File: dif.py Project: GSA/pycsw
def write_extent(bbox, nsmap):
    ''' Generate BBOX extent '''

    from shapely.wkt import loads

    if bbox is not None:
        try:
            bbox2 = util.wkt2geom(bbox)
        except:
            return None
        extent = etree.Element(util.nspath_eval('dif:Spatial_Coverage', nsmap))
        etree.SubElement(extent, util.nspath_eval('dif:Southernmost_Latitude', nsmap)).text = str(bbox2[1])
        etree.SubElement(extent, util.nspath_eval('dif:Northernmost_Latitude', nsmap)).text = str(bbox2[3])
        etree.SubElement(extent, util.nspath_eval('dif:Westernmost_Longitude', nsmap)).text = str(bbox2[0])
        etree.SubElement(extent, util.nspath_eval('dif:Easternmost_Longitude', nsmap)).text = str(bbox2[2])
        return extent
    return None
Example #23
0
def test_nspath_eval(xpath_expression, expected):
    nsmap = {
        "ns1": "something",
        "ns2": "other",
        "ns3": "another",
    }
    result = util.nspath_eval(xpath_expression, nsmap)
    assert result == expected
Example #24
0
def test_nspath_eval(xpath_expression, expected):
    nsmap = {
        "ns1": "something",
        "ns2": "other",
        "ns3": "another",
    }
    result = util.nspath_eval(xpath_expression, nsmap)
    assert result == expected
Example #25
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
Example #26
0
    def exceptionreport2diagnostic(self, element):
        """transform a CSW exception into an SRU diagnostic"""
        node = etree.Element(util.nspath_eval('zs:searchRetrieveResponse',
                                              self.namespaces),
                             nsmap=self.namespaces)

        etree.SubElement(node, util.nspath_eval(
            'zs:version', self.namespaces)).text = self.sru_version

        diagnostics = etree.SubElement(
            node, util.nspath_eval('zs:diagnostics', self.namespaces))

        diagnostic = etree.SubElement(
            diagnostics, util.nspath_eval('zs:diagnostic', self.namespaces))

        etree.SubElement(diagnostic, util.nspath_eval('zd:diagnostic', self.namespaces)).text = \
            'info:srw/diagnostic/1/7'

        etree.SubElement(diagnostic, util.nspath_eval('zd:message', self.namespaces)).text = \
            element.xpath('//ows:Exception/ows:ExceptionText|//ows20:Exception/ows20:ExceptionText', namespaces=self.context.namespaces)[0].text

        etree.SubElement(diagnostic, util.nspath_eval('zd:details', self.namespaces)).text = \
            element.xpath('//ows:Exception|//ows20:Exception', namespaces=self.context.namespaces)[0].attrib.get('exceptionCode')

        return node
Example #27
0
    def _csw2_2_os(self):
        """CSW 2.0.2 Capabilities to OpenSearch Description"""

        if util.xmltag_split(self.exml.tag) == 'GetRecordsResponse':

            startindex = int(self.exml.xpath('//@nextRecord')[0]) - int(
                        self.exml.xpath('//@numberOfRecordsReturned')[0])
            if startindex < 1:
                startindex = 1

            node = etree.Element(util.nspath_eval('atom:feed',
                       self.context.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('atom:id',
                       self.context.namespaces)).text = self.cfg.get('server', 'url')
            etree.SubElement(node, util.nspath_eval('atom:title',
                       self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'identification_title')
            #etree.SubElement(node, util.nspath_eval('atom:updated',
            #  self.context.namespaces)).text = self.exml.xpath('//@timestamp')[0]

            etree.SubElement(node, util.nspath_eval('os:totalResults',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsMatched')[0]
            etree.SubElement(node, util.nspath_eval('os:startIndex',
                        self.context.namespaces)).text = str(startindex)
            etree.SubElement(node, util.nspath_eval('os:itemsPerPage',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsReturned')[0]

            for rec in self.exml.xpath('//atom:entry',
                        namespaces=self.context.namespaces):
                node.append(rec)
        elif util.xmltag_split(self.exml.tag) == 'Capabilities':
            node = etree.Element('OpenSearchDescription', nsmap=self.namespaces)
            etree.SubElement(node, 'ShortName').text = self.exml.xpath('//ows:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, 'LongName').text = self.exml.xpath('//ows:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, 'Description').text = self.exml.xpath('//ows:Abstract', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, 'Tags').text = ' '.join(x.text for x in self.exml.xpath('//ows:Keyword', namespaces=self.context.namespaces))

            node1 = etree.SubElement(node, 'Url')
            node1.set('type', 'application/atom+xml')
            node1.set('method', 'get')
            node1.set('template', '%smode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}' % self.bind_url)

            node1 = etree.SubElement(node, 'Image')
            node1.set('type', 'image/vnd.microsoft.icon')
            node1.set('width', '16')
            node1.set('height', '16')
            node1.text = 'http://pycsw.org/img/favicon.ico'

            etree.SubElement(node, 'Developer').text = self.exml.xpath('//ows:IndividualName', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, 'Contact').text = self.exml.xpath('//ows:ElectronicMailAddress', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, 'Attribution').text = self.exml.xpath('//ows:ProviderName', namespaces=self.context.namespaces)[0].text
        elif util.xmltag_split(self.exml.tag) == 'ExceptionReport':
            node = self.exml
        else:  # return Description document
            node = etree.Element(util.nspath_eval('os:Description', self.context.namespaces))

        return node
Example #28
0
def _write_codelist_element(codelist_element, codelist_value, nsmap):
    namespace, codelist = codelist_element.split(':')    

    element = etree.Element(util.nspath_eval(codelist_element, nsmap),
    codeSpace=CODESPACE, codeList='%s#%s' % (CODELIST, codelist),
    codeListValue=codelist_value)

    element.text = codelist_value

    return element
Example #29
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))
Example #30
0
    def _get_polygon(self):
        """Parse gml:Polygon"""

        tmp = self._exml.find('.//%s' %
                              util.nspath_eval('gml:posList', self.nsmap))

        if tmp is None:
            raise RuntimeError('Invalid gml:LineString geometry.\
                               Missing gml:posList')
        else:
            self.wkt = 'POLYGON((%s))' % _poslist2wkt(
                tmp.text, self.crs.axisorder, 'polygon')
Example #31
0
    def _get_linestring(self):
        """Parse gml:LineString"""

        tmp = self._exml.find(
            util.nspath_eval('gml:LineString/gml:posList', self.nsmap))

        if tmp is None:
            raise RuntimeError('Invalid gml:LineString geometry.\
                               Missing gml:posList')
        else:
            self.wkt = 'LINESTRING(%s)' % _poslist2wkt(
                tmp.text, self.crs.axisorder, 'line')
Example #32
0
    def _get_linestring(self):
        """Parse gml:LineString"""

        tmp = self._exml.find(util.nspath_eval('gml:LineString/gml:posList',
                                               self.nsmap))

        if tmp is None:
            raise RuntimeError('Invalid gml:LineString geometry.\
                               Missing gml:posList')
        else:
            self.wkt = 'LINESTRING(%s)' % _poslist2wkt(tmp.text,
                                                       self.crs.axisorder)
Example #33
0
    def _get_polygon(self):
        """Parse gml:Polygon"""

        tmp = self._exml.find('.//%s' % util.nspath_eval('gml:posList',
                                                         self.nsmap))

        if tmp is None:
            raise RuntimeError('Invalid gml:LineString geometry.\
                               Missing gml:posList')
        else:
            self.wkt = 'POLYGON((%s))' % _poslist2wkt(tmp.text,
                                                      self.crs.axisorder)
Example #34
0
    def _get_point(self):
        """Parse gml:Point"""

        tmp = self._exml.find(util.nspath_eval('gml:Point/gml:pos',
                                               self.nsmap))

        if tmp is None:
            raise RuntimeError('Invalid gml:Point geometry.  Missing gml:pos')
        else:
            xypoint = tmp.text.split()
            if self.crs.axisorder == 'yx':
                self.wkt = 'POINT(%s %s)' % (xypoint[1], xypoint[0])
            else:
                self.wkt = 'POINT(%s %s)' % (xypoint[0], xypoint[1])
Example #35
0
    def _get_point(self):
        """Parse gml:Point"""

        tmp = self._exml.find(util.nspath_eval('gml:Point/gml:pos',
                                               self.nsmap))

        if tmp is None:
            raise RuntimeError('Invalid gml:Point geometry.  Missing gml:pos')
        else:
            xypoint = tmp.text.split()
            if self.crs.axisorder == 'yx':
                self.wkt = 'POINT(%s %s)' % (xypoint[1], xypoint[0])
            else:
                self.wkt = 'POINT(%s %s)' % (xypoint[0], xypoint[1])
Example #36
0
    def get_schemacomponents(self):
        ''' Return schema components as lxml.etree.Element list '''

        node = etree.Element(
        util.nspath_eval('csw:SchemaComponent', self.context.namespaces),
        schemaLanguage='XMLSCHEMA', targetNamespace=self.namespace)

        schema = etree.parse(os.path.join(self.context.pycsw_home,
                 'plugins', 'profiles', 'ebrim',
                 'schemas', 'ogc', 'csw', '2.0.2',
                 'profiles', 'ebrim', '1.0', 'csw-ebrim.xsd')).getroot()

        node.append(schema)

        return [node]
Example #37
0
    def get_schemacomponents(self):
        ''' Return schema components as lxml.etree.Element list '''

        node = etree.Element(util.nspath_eval('csw:SchemaComponent',
                                              self.context.namespaces),
                             schemaLanguage='XMLSCHEMA',
                             targetNamespace=self.namespace)

        schema = etree.parse(
            os.path.join(self.context.pycsw_home, 'plugins', 'profiles',
                         'ebrim', 'schemas', 'ogc', 'csw', '2.0.2', 'profiles',
                         'ebrim', '1.0', 'csw-ebrim.xsd')).getroot()

        node.append(schema)

        return [node]
Example #38
0
    def _transform_element(self, parent, element, elname):
        """tests for existence of a given xpath, writes out text if exists"""

        xpath = self.metadata_formats[self.metadata_prefix][elname.split(':')[1]]
        if xpath.startswith('//'):
            value = element.xpath(xpath, namespaces=self.context.namespaces)
            if value:
                value = value[0].text
        else:  # bare string literal
            value = xpath
        el = etree.SubElement(parent, util.nspath_eval(elname, self.context.namespaces))
        if value:
            if elname == 'oai:setSpec': 
                value = None
                for k, v in self.metadata_sets.items():
                    if v[1] == elname:
                        value = k
                        break
            el.text = value
Example #39
0
    def get_schemacomponents(self):
        ''' Return schema components as lxml.etree.Element list '''

        schema_nodes = []

        for schema_path in self.schemas_paths:

            node = etree.Element(util.nspath_eval('csw:SchemaComponent',
                                                  self.context.namespaces),
                                 schemaLanguage='XMLSCHEMA',
                                 targetNamespace=self.namespace)

            schema_file = os.path.join(self.context.pycsw_home, *schema_path)

            schema = etree.parse(schema_file, self.context.parser).getroot()

            node.append(schema)

            schema_nodes.append(node)

        return schema_nodes
Example #40
0
    def exceptionreport2diagnostic(self, element):
        """transform a CSW exception into an SRU diagnostic"""
        node = etree.Element(
            util.nspath_eval('zs:searchRetrieveResponse', self.namespaces), nsmap=self.namespaces)

        etree.SubElement(node, util.nspath_eval('zs:version', self.namespaces)).text = self.sru_version

        diagnostics = etree.SubElement(node, util.nspath_eval('zs:diagnostics', self.namespaces))

        diagnostic = etree.SubElement(
            diagnostics, util.nspath_eval('zs:diagnostic', self.namespaces))

        etree.SubElement(diagnostic, util.nspath_eval('zd:diagnostic', self.namespaces)).text = \
            'info:srw/diagnostic/1/7'

        etree.SubElement(diagnostic, util.nspath_eval('zd:message', self.namespaces)).text = \
            element.xpath('//ows:Exception/ows:ExceptionText|//ows20:Exception/ows20:ExceptionText', namespaces=self.context.namespaces)[0].text

        etree.SubElement(diagnostic, util.nspath_eval('zd:details', self.namespaces)).text = \
            element.xpath('//ows:Exception|//ows20:Exception', namespaces=self.context.namespaces)[0].attrib.get('exceptionCode')

        return node
Example #41
0
    def _csw3_2_os(self):
        """CSW 3.0.0 Capabilities to OpenSearch Description"""

        response_name = etree.QName(self.exml).localname
        if response_name == 'GetRecordsResponse':

            startindex = int(self.exml.xpath('//@nextRecord')[0]) - int(
                        self.exml.xpath('//@numberOfRecordsReturned')[0])
            if startindex < 1:
                startindex = 1

            node = etree.Element(util.nspath_eval('atom:feed',
                       self.context.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('atom:id',
                       self.context.namespaces)).text = self.cfg.get('server', 'url')
            etree.SubElement(node, util.nspath_eval('atom:title',
                       self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'identification_title')
            author = etree.SubElement(node, util.nspath_eval('atom:author', self.context.namespaces))
            etree.SubElement(author, util.nspath_eval('atom:name', self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'provider_name')
            etree.SubElement(node, util.nspath_eval('atom:link',
                       self.context.namespaces), rel='search',
                           type='application/opensearchdescription+xml',
                           href='%smode=opensearch&service=CSW&version=3.0.0&request=GetCapabilities' % self.bind_url)

            etree.SubElement(node, util.nspath_eval('atom:updated',
                self.context.namespaces)).text = self.exml.xpath('//@timestamp')[0]

            etree.SubElement(node, util.nspath_eval('os:Query', self.context.namespaces), role='request')

            matched = sum(int(x) for x in self.exml.xpath('//@numberOfRecordsMatched'))

            etree.SubElement(node, util.nspath_eval('os:totalResults', self.context.namespaces)).text = str(matched)

            etree.SubElement(node, util.nspath_eval('os:startIndex',
                        self.context.namespaces)).text = str(startindex)

            returned = sum(int(x) for x in self.exml.xpath('//@numberOfRecordsReturned'))

            etree.SubElement(node, util.nspath_eval('os:itemsPerPage', self.context.namespaces)).text = str(returned)

            for rec in self.exml.xpath('//atom:entry', namespaces=self.context.namespaces):
                LOGGER.debug('ADDING ATOM ENTRY')
                node.append(rec)

            for rec in self.exml.xpath('//csw30:Record|//csw30:BriefRecord|//csw30:SummaryRecord', namespaces=self.context.namespaces):
                node.append(self.cswrecord2atom(rec))

        elif response_name == 'Capabilities':
            node = etree.Element(util.nspath_eval('os:OpenSearchDescription', self.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('os:ShortName', self.namespaces)).text = self.exml.xpath('//ows20:Title', namespaces=self.context.namespaces)[0].text[:16]
            etree.SubElement(node, util.nspath_eval('os:LongName', self.namespaces)).text = self.exml.xpath('//ows20:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Description', self.namespaces)).text = self.exml.xpath('//ows20:Abstract', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Tags', self.namespaces)).text = ' '.join(x.text for x in self.exml.xpath('//ows20:Keyword', namespaces=self.context.namespaces))

            # Requirement-022
            node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
            node1.set('type', 'application/xml')

            kvps = {
                'service': 'CSW',
                'version': '3.0.0',
                'request': 'GetRecords',
                'elementsetname': 'full',
                'typenames': 'csw:Record',
                'outputformat': 'application/xml',
                'outputschema': 'http://www.opengis.net/cat/csw/3.0',
                'recordids': '{geo:uid?}',
                'q': '{searchTerms?}',
                'bbox': '{geo:box?}',
                'time': '{time:start?}/{time:end?}',
                'start': '{time:start?}',
                'stop': '{time:end?}',
                'startposition': '{startIndex?}',
                'maxrecords': '{count?}',
                'eo:cloudCover': '{eo:cloudCover?}',
                'eo:instrument': '{eo:instrument?}',
                'eo:orbitDirection': '{eo:orbitDirection?}',
                'eo:orbitNumber': '{eo:orbitNumber?}',
                'eo:parentIdentifier': '{eo:parentIdentifier?}',
                'eo:platform': '{eo:platform?}',
                'eo:processingLevel': '{eo:processingLevel?}',
                'eo:productType': '{eo:productType?}',
                'eo:sensorType': '{eo:sensorType?}',
                'eo:snowCover': '{eo:snowCover?}',
                'eo:spectralRange': '{eo:spectralRange?}'
            }

            node1.set('template', '%s%s' % (self.bind_url,
                '&'.join('{}={}'.format(*i) for i in kvps.items())))

            # Requirement-023
            node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
            node1.set('type', 'application/atom+xml')

            kvps['outputformat'] = r'application%2Fatom%2Bxml'
            kvps['mode'] = 'opensearch'

            node1.set('template', '%s%s' % (self.bind_url,
                '&'.join('{}={}'.format(*i) for i in kvps.items())))

            node1 = etree.SubElement(node, util.nspath_eval('os:Image', self.namespaces))
            node1.set('type', 'image/vnd.microsoft.icon')
            node1.set('width', '16')
            node1.set('height', '16')
            node1.text = 'https://pycsw.org/img/favicon.ico'

            os_query = etree.SubElement(node, util.nspath_eval('os:Query', self.namespaces), role='example', searchTerms='cat')

            etree.SubElement(node, util.nspath_eval('os:Developer', self.namespaces)).text = self.exml.xpath('//ows20:IndividualName', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Contact', self.namespaces)).text = self.exml.xpath('//ows20:ElectronicMailAddress', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Attribution', self.namespaces)).text = self.exml.xpath('//ows20:ProviderName', namespaces=self.context.namespaces)[0].text
        elif response_name == 'ExceptionReport':
            node = self.exml
        else:  # GetRecordById output
            node = etree.Element(util.nspath_eval('atom:feed',
                       self.context.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('atom:id',
                       self.context.namespaces)).text = self.cfg.get('server', 'url')
            etree.SubElement(node, util.nspath_eval('atom:title',
                       self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'identification_title')
            #etree.SubElement(node, util.nspath_eval('atom:updated',
            #  self.context.namespaces)).text = self.exml.xpath('//@timestamp')[0]

            etree.SubElement(node, util.nspath_eval('os:totalResults',
                        self.context.namespaces)).text = '1'
            etree.SubElement(node, util.nspath_eval('os:startIndex',
                        self.context.namespaces)).text = '1'
            etree.SubElement(node, util.nspath_eval('os:itemsPerPage',
                        self.context.namespaces)).text = '1'

            for rec in self.exml.xpath('//atom:entry', namespaces=self.context.namespaces):
                #node.append(rec)
                node = rec
        return node
Example #42
0
    def _csw2_2_os(self):
        """CSW 2.0.2 Capabilities to OpenSearch Description"""

        operation_name = etree.QName(self.exml).localname
        if operation_name == 'GetRecordsResponse':

            startindex = int(self.exml.xpath('//@nextRecord')[0]) - int(
                        self.exml.xpath('//@numberOfRecordsReturned')[0])
            if startindex < 1:
                startindex = 1

            node = etree.Element(util.nspath_eval('atom:feed',
                       self.context.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('atom:id',
                       self.context.namespaces)).text = self.cfg.get('server', 'url')
            etree.SubElement(node, util.nspath_eval('atom:title',
                       self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'identification_title')
            #etree.SubElement(node, util.nspath_eval('atom:updated',
            #  self.context.namespaces)).text = self.exml.xpath('//@timestamp')[0]

            etree.SubElement(node, util.nspath_eval('os:totalResults',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsMatched')[0]
            etree.SubElement(node, util.nspath_eval('os:startIndex',
                        self.context.namespaces)).text = str(startindex)
            etree.SubElement(node, util.nspath_eval('os:itemsPerPage',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsReturned')[0]

            for rec in self.exml.xpath('//atom:entry',
                        namespaces=self.context.namespaces):
                node.append(rec)
            for rec in self.exml.xpath('//csw:Record|//csw:BriefRecord|//csw:SummaryRecord',
                        namespaces=self.context.namespaces):
                node.append(self.cswrecord2atom(rec))
        elif operation_name == 'Capabilities':
            node = etree.Element(util.nspath_eval('os:OpenSearchDescription', self.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('os:ShortName', self.namespaces)).text = self.exml.xpath('//ows:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:LongName', self.namespaces)).text = self.exml.xpath('//ows:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Description', self.namespaces)).text = self.exml.xpath('//ows:Abstract', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Tags', self.namespaces)).text = ' '.join(x.text for x in self.exml.xpath('//ows:Keyword', namespaces=self.context.namespaces))

            node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
            node1.set('type', 'application/atom+xml')
            node1.set('method', 'get')

            kvps = {
                'mode': 'opensearch',
                'service': 'CSW',
                'version': '2.0.2',
                'request': 'GetRecords',
                'elementsetname': 'full',
                'typenames': 'csw:Record',
                'resulttype': 'results',
                'q': '{searchTerms?}',
                'bbox': '{geo:box?}',
                'time': '{time:start?}/{time:end?}',
                'start': '{time:start?}',
                'stop': '{time:end?}',
                'startposition': '{startIndex?}',
                'maxrecords': '{count?}',
                'eo:cloudCover': '{eo:cloudCover?}',
                'eo:instrument': '{eo:instrument?}',
                'eo:orbitDirection': '{eo:orbitDirection?}',
                'eo:orbitNumber': '{eo:orbitNumber?}',
                'eo:parentIdentifier': '{eo:parentIdentifier?}',
                'eo:platform': '{eo:platform?}',
                'eo:processingLevel': '{eo:processingLevel?}',
                'eo:productType': '{eo:productType?}',
                'eo:sensorType': '{eo:sensorType?}',
                'eo:snowCover': '{eo:snowCover?}',
                'eo:spectralRange': '{eo:spectralRange?}'
            }

            node1.set('template', '%s%s' % (self.bind_url,
                '&'.join('{}={}'.format(*i) for i in kvps.items())))


            #node1.set('template', '%smode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&start={time:start?}&stop={time:end?}&startposition={startIndex?}&maxrecords={count?}' % self.bind_url)

            node1 = etree.SubElement(node, util.nspath_eval('os:Image', self.namespaces))
            node1.set('type', 'image/vnd.microsoft.icon')
            node1.set('width', '16')
            node1.set('height', '16')
            node1.text = 'https://pycsw.org/img/favicon.ico'

            etree.SubElement(node, util.nspath_eval('os:Developer', self.namespaces)).text = self.exml.xpath('//ows:IndividualName', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Context', self.namespaces)).text = self.exml.xpath('//ows:ElectronicMailAddress', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Attribution', self.namespaces)).text = self.exml.xpath('//ows:ProviderName', namespaces=self.context.namespaces)[0].text
        elif operation_name == 'ExceptionReport':
            node = self.exml
        else:  # return Description document
            node = etree.Element(util.nspath_eval('os:Description', self.context.namespaces))

        return node
Example #43
0
def write_record(result, esn, context, url=None):
    ''' Return csw:SearchResults child as lxml.etree.Element '''

    typename = util.getqattr(
        result, context.md_core_model['mappings']['pycsw:Typename'])

    if esn == 'full' and typename == 'atom:entry':
        # dump record as is and exit
        return etree.fromstring(
            util.getqattr(result,
                          context.md_core_model['mappings']['pycsw:XML']),
            context.parser)

    node = etree.Element(util.nspath_eval('atom:entry', NAMESPACES),
                         nsmap=NAMESPACES)
    node.attrib[util.nspath_eval('xsi:schemaLocation', context.namespaces)] = \
            '%s http://www.kbcafe.com/rss/atom.xsd.xml' % NAMESPACES['atom']

    # author
    val = util.getqattr(result,
                        context.md_core_model['mappings']['pycsw:Creator'])
    if val:
        author = etree.SubElement(node,
                                  util.nspath_eval('atom:author', NAMESPACES))
        etree.SubElement(author, util.nspath_eval('atom:name',
                                                  NAMESPACES)).text = val

    # category
    val = util.getqattr(result,
                        context.md_core_model['mappings']['pycsw:Keywords'])

    if val:
        for kw in val.split(','):
            etree.SubElement(node,
                             util.nspath_eval('atom:category', NAMESPACES),
                             term=kw)

    for qval in ['pycsw:Contributor', 'pycsw:Identifier']:
        val = util.getqattr(result, context.md_core_model['mappings'][qval])
        if val:
            etree.SubElement(
                node, util.nspath_eval(XPATH_MAPPINGS[qval],
                                       NAMESPACES)).text = val
            if qval == 'pycsw:Identifier':
                etree.SubElement(
                    node, util.nspath_eval('dc:identifier',
                                           context.namespaces)).text = val

    rlinks = util.getqattr(result,
                           context.md_core_model['mappings']['pycsw:Links'])
    if rlinks:
        for link in util.jsonify_links(rlinks):
            url2 = etree.SubElement(node,
                                    util.nspath_eval('atom:link', NAMESPACES),
                                    href=link['url'])

            if link['description']:
                url2.attrib['title'] = link['description']

            if link['protocol']:
                if link['protocol'] == 'enclosure':
                    url2.attrib['rel'] = link['protocol']
                    url2.attrib['type'] = 'application/octet-stream'
                else:
                    url2.attrib['type'] = link['protocol']

    etree.SubElement(
        node,
        util.nspath_eval('atom:link', NAMESPACES),
        href='%s?service=CSW&version=2.0.2&request=GetRepositoryItem&id=%s' %
        (url,
         util.getqattr(result,
                       context.md_core_model['mappings']['pycsw:Identifier'])))

    # atom:title
    el = etree.SubElement(
        node, util.nspath_eval(XPATH_MAPPINGS['pycsw:Title'], NAMESPACES))
    val = util.getqattr(result,
                        context.md_core_model['mappings']['pycsw:Title'])
    if val:
        el.text = val

    # atom:updated
    el = etree.SubElement(
        node, util.nspath_eval(XPATH_MAPPINGS['pycsw:Modified'], NAMESPACES))
    val = util.getqattr(result,
                        context.md_core_model['mappings']['pycsw:Modified'])
    if val:
        el.text = val
    else:
        val = util.getqattr(
            result, context.md_core_model['mappings']['pycsw:InsertDate'])
        el.text = val

    for qval in [
            'pycsw:PublicationDate', 'pycsw:AccessConstraints', 'pycsw:Source',
            'pycsw:Abstract'
    ]:
        val = util.getqattr(result, context.md_core_model['mappings'][qval])
        if val:
            etree.SubElement(
                node, util.nspath_eval(XPATH_MAPPINGS[qval],
                                       NAMESPACES)).text = val

    # bbox extent
    val = util.getqattr(result,
                        context.md_core_model['mappings']['pycsw:BoundingBox'])
    bboxel = write_extent(val, context.namespaces)
    if bboxel is not None:
        node.append(bboxel)

    return node
Example #44
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')
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')
Example #46
0
def evaluate_literal(context, pname, pvalue):
    """
    Transforms OpenSearch EO mathematical notation
    to OGC FES syntax

    :param pname: parameter name
    :param pvalue: parameter value

    :returns: lxml Element of predicate
    """

    LOGGER.debug('property name: {}'.format(pname))
    LOGGER.debug('property value: {}'.format(pvalue))

    if pvalue.startswith('{') and pvalue.endswith('}'):
        # {n1,n2,…} equals to field=n1 OR field=n2 OR …
        values = pvalue.lstrip('{').rstrip('}').split(',')
        el = etree.Element(util.nspath_eval('ogc:Or', context.namespaces))

        for value in values:
            el2 = etree.SubElement(el, util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
            etree.SubElement(el2, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
            etree.SubElement(el2, util.nspath_eval('ogc:Literal', context.namespaces)).text = value

    elif pvalue.startswith('[') and pvalue.endswith(']'):
        # [n1,n2] equal to n1 <= field <= n2
        values = pvalue.lstrip('[').rstrip(']').split(',')
        el = etree.Element(util.nspath_eval('ogc:And', context.namespaces))

        el2 = etree.SubElement(el, util.nspath_eval('ogc:PropertyIsLessThanOrEqualTo', context.namespaces))
        etree.SubElement(el2, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el2, util.nspath_eval('ogc:Literal', context.namespaces)).text = values[0]

        el3 = etree.SubElement(el, util.nspath_eval('ogc:PropertyIsGreaterThanOrEqualTo', context.namespaces))
        etree.SubElement(el3, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el3, util.nspath_eval('ogc:Literal', context.namespaces)).text = values[1]

    elif pvalue.startswith(']') and pvalue.endswith('['):
        # ]n1,n2[ equals to n1 < field < n2
        values = pvalue.lstrip(']').rstrip('[').split(',')
        el = etree.Element(util.nspath_eval('ogc:And', context.namespaces))

        el2 = etree.SubElement(el, util.nspath_eval('ogc:PropertyIsLessThan', context.namespaces))
        etree.SubElement(el2, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el2, util.nspath_eval('ogc:Literal', context.namespaces)).text = values[0]

        el3 = etree.SubElement(el, util.nspath_eval('ogc:PropertyIsGreaterThan', context.namespaces))
        etree.SubElement(el3, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el3, util.nspath_eval('ogc:Literal', context.namespaces)).text = values[1]

    elif pvalue.startswith('['):
        # [n1 equals to n1<= field
        el = etree.Element(util.nspath_eval('ogc:PropertyIsGreaterThanOrEqualTo', context.namespaces))
        etree.SubElement(el, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el, util.nspath_eval('ogc:Literal', context.namespaces)).text = pvalue.lstrip('[')

    elif pvalue.endswith(']'):
        # n2] equals to field <= n2
        el = etree.Element(util.nspath_eval('ogc:PropertyIsLessThanOrEqualTo', context.namespaces))
        etree.SubElement(el, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el, util.nspath_eval('ogc:Literal', context.namespaces)).text = pvalue.rstrip(']')

    elif pvalue.startswith('[') and pvalue.endswith('['):
        # [n1,n2[ equals to n1 <= field < n2
        values = pvalue.lstrip('[').rstrip('[').split(',')
        el = etree.Element(util.nspath_eval('ogc:And', context.namespaces))

        el2 = etree.SubElement(el, util.nspath_eval('ogc:PropertyIsLessThanOrEqualTo', context.namespaces))
        etree.SubElement(el2, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el2, util.nspath_eval('ogc:Literal', context.namespaces)).text = values[0]

        el3 = etree.SubElement(el, util.nspath_eval('ogc:PropertyIsGreaterThan', context.namespaces))
        etree.SubElement(el3, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el3, util.nspath_eval('ogc:Literal', context.namespaces)).text = values[1]

    elif pvalue.startswith(']') and pvalue.endswith(']'):
        # ]n1,n2] equal to n1 < field <= n2
        values = pvalue.lstrip(']').rstrip(']').split(',')
        el = etree.Element(util.nspath_eval('ogc:And', context.namespaces))

        el2 = etree.SubElement(el, util.nspath_eval('ogc:PropertyIsLessThan', context.namespaces))
        etree.SubElement(el2, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el2, util.nspath_eval('ogc:Literal', context.namespaces)).text = values[0]

        el3 = etree.SubElement(el, util.nspath_eval('ogc:PropertyIsGreaterThanOrEqualTo', context.namespaces))
        etree.SubElement(el3, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el3, util.nspath_eval('ogc:Literal', context.namespaces)).text = values[1]

    elif pvalue.startswith(']'):
        # ]n1 equals to n1 < field
        el = etree.Element(util.nspath_eval('ogc:PropertyIsGreaterThan', context.namespaces))
        etree.SubElement(el, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el, util.nspath_eval('ogc:Literal', context.namespaces)).text = pvalue.lstrip(']')

    elif pvalue.endswith('['):
        # n2[ equals to field < n2
        el = etree.Element(util.nspath_eval('ogc:PropertyIsLessThan', context.namespaces))
        etree.SubElement(el, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el, util.nspath_eval('ogc:Literal', context.namespaces)).text = pvalue.rstrip('[')

    else:
        # n1 equal to field = n1
        el = etree.Element(util.nspath_eval('ogc:PropertyIsEqualTo', context.namespaces))
        etree.SubElement(el, util.nspath_eval('ogc:PropertyName', context.namespaces)).text = pname
        etree.SubElement(el, util.nspath_eval('ogc:Literal', context.namespaces)).text = pvalue

    return el
Example #47
0
def parse(element, queryables, dbtype, nsmap, orm='sqlalchemy', language='english', fts=False):
    """OGC Filter object support"""

    boq = None
    is_pg = dbtype.startswith('postgresql')

    tmp = element.xpath('ogc:And|ogc:Or|ogc:Not', namespaces=nsmap)
    if len(tmp) > 0:  # this is binary logic query
        boq = ' %s ' % util.xmltag_split(tmp[0].tag).lower()
        LOGGER.debug('Binary logic detected; operator=%s' % boq)
        tmp = tmp[0]
    else:
        tmp = element

    pvalue_serial = [0]  # in list as python 2 has no nonlocal variable
    def assign_param():
        if orm == 'django':
            return '%s'
        param = ':pvalue%d' % pvalue_serial[0]
        pvalue_serial[0] += 1
        return param

    def _get_comparison_expression(elem):
        """return the SQL expression based on Filter query"""
        fname = None
        matchcase = elem.attrib.get('matchCase')
        wildcard = elem.attrib.get('wildCard')
        singlechar = elem.attrib.get('singleChar')
        expression = None

        if wildcard is None:
            wildcard = '%'

        if singlechar is None:
            singlechar = '_'

        if (elem.xpath('child::*')[0].tag ==
                util.nspath_eval('ogc:Function', nsmap)):
            LOGGER.debug('ogc:Function detected')
            if (elem.xpath('child::*')[0].attrib['name'] not in
                    MODEL['Functions']):
                raise RuntimeError('Invalid ogc:Function: %s' %
                                   (elem.xpath('child::*')[0].attrib['name']))
            fname = elem.xpath('child::*')[0].attrib['name']

            try:
                LOGGER.debug('Testing existence of ogc:PropertyName')
                pname = queryables[elem.find(util.nspath_eval('ogc:Function/ogc:PropertyName', nsmap)).text]['dbcol']
            except Exception as err:
                raise RuntimeError('Invalid PropertyName: %s.  %s' % (elem.find(util.nspath_eval('ogc:Function/ogc:PropertyName', nsmap)).text, str(err)))

        else:
            try:
                LOGGER.debug('Testing existence of ogc:PropertyName')
                pname = queryables[elem.find(
                    util.nspath_eval('ogc:PropertyName', nsmap)).text]['dbcol']
            except Exception as err:
                raise RuntimeError('Invalid PropertyName: %s.  %s' %
                                   (elem.find(util.nspath_eval('ogc:PropertyName',
                                   nsmap)).text, str(err)))

        if (elem.tag != util.nspath_eval('ogc:PropertyIsBetween', nsmap)):
            if elem.tag in [util.nspath_eval('ogc:%s' % n, nsmap) for n in
                MODEL['SpatialOperators']['values']]:
                boolean_true = '\'true\''
                boolean_false = '\'false\''
                if dbtype == 'mysql':
                    boolean_true = 'true'
                    boolean_false = 'false'

                return "%s = %s" % (_get_spatial_operator(queryables['pycsw:BoundingBox'], elem, dbtype, nsmap), boolean_true)
            else:
                pval = elem.find(util.nspath_eval('ogc:Literal', nsmap)).text

        com_op = _get_comparison_operator(elem)
        LOGGER.debug('Comparison operator: %s' % com_op)

        # if this is a case insensitive search
        # then set the DB-specific LIKE comparison operator

        LOGGER.debug('Setting csw:AnyText property')

        anytext = queryables['csw:AnyText']['dbcol']
        if ((matchcase is not None and matchcase == 'false') or
                pname == anytext):
            com_op = 'ilike' if is_pg else 'like'

        if (elem.tag == util.nspath_eval('ogc:PropertyIsBetween', nsmap)):
            com_op = 'between'
            lower_boundary = elem.find(
                util.nspath_eval('ogc:LowerBoundary/ogc:Literal',
                                 nsmap)).text
            upper_boundary = elem.find(
                util.nspath_eval('ogc:UpperBoundary/ogc:Literal',
                                 nsmap)).text
            expression = "%s %s %s and %s" % \
                           (pname, com_op, assign_param(), assign_param())
            values.append(lower_boundary)
            values.append(upper_boundary)
        else:
            if pname == anytext and is_pg and fts:
                LOGGER.debug('PostgreSQL FTS specific search')
                # do nothing, let FTS do conversion (#212)
                pvalue = pval
            else:
                LOGGER.debug('PostgreSQL non-FTS specific search')
                pvalue = pval.replace(wildcard, '%').replace(singlechar, '_')

                if pname == anytext:  # pad anytext with wildcards
                    LOGGER.debug('PostgreSQL non-FTS specific anytext search')
                    LOGGER.debug('old value: %s', pval)

                    pvalue = '%%%s%%' % pvalue.rstrip('%').lstrip('%')

                    LOGGER.debug('new value: %s', pvalue)

            values.append(pvalue)

            if boq == ' not ':
                if fname is not None:
                    expression = "%s is null or not %s(%s) %s %s" % \
                                   (pname, fname, pname, com_op, assign_param())
                elif pname == anytext and is_pg and fts:
                    LOGGER.debug('PostgreSQL FTS specific search')
                    expression = ("%s is null or not plainto_tsquery('%s', %s) @@ anytext_tsvector" %
                                  (anytext, language, assign_param()))
                else:
                    LOGGER.debug('PostgreSQL non-FTS specific search')
                    expression = "%s is null or not %s %s %s" % \
                                   (pname, pname, com_op, assign_param())
            else:
                if fname is not None:
                    expression = "%s(%s) %s %s" % \
                                   (fname, pname, com_op, assign_param())
                elif pname == anytext and is_pg and fts:
                    LOGGER.debug('PostgreSQL FTS specific search')
                    expression = ("plainto_tsquery('%s', %s) @@ anytext_tsvector" %
                                  (language, assign_param()))
                else:
                    LOGGER.debug('PostgreSQL non-FTS specific search')
                    expression = "%s %s %s" % (pname, com_op, assign_param())

        return expression

    queries = []
    queries_nested = []
    values = []

    LOGGER.debug('Scanning children elements')
    for child in tmp.xpath('child::*'):
        com_op = ''
        boolean_true = '\'true\''
        boolean_false = '\'false\''

        if dbtype == 'mysql':
            boolean_true = 'true'
            boolean_false = 'false'

        if child.tag == util.nspath_eval('ogc:Not', nsmap):
            LOGGER.debug('ogc:Not query detected')
            child_not = child.xpath('child::*')[0]
            if child_not.tag in \
                [util.nspath_eval('ogc:%s' % n, nsmap) for n in
                    MODEL['SpatialOperators']['values']]:
                LOGGER.debug('ogc:Not / spatial operator detected: %s' % child.tag)
                queries.append("%s = %s" %
                               (_get_spatial_operator(
                                   queryables['pycsw:BoundingBox'],
                                   child.xpath('child::*')[0], dbtype, nsmap),
                                   boolean_false))
            else:
                LOGGER.debug('ogc:Not / comparison operator detected: %s' % child.tag)
                queries.append('not %s' % _get_comparison_expression(child_not))

        elif child.tag in \
            [util.nspath_eval('ogc:%s' % n, nsmap) for n in
                MODEL['SpatialOperators']['values']]:
            LOGGER.debug('spatial operator detected: %s' % child.tag)
            if boq is not None and boq == ' not ':
                # for ogc:Not spatial queries in PostGIS we must explictly
                # test that pycsw:BoundingBox is null as well
                # TODO: Do we need the same for 'postgresql+postgis+native'???
                if dbtype == 'postgresql+postgis+wkt':
                    LOGGER.debug('Setting bbox is null test in PostgreSQL')
                    queries.append("%s = %s or %s is null" %
                                   (_get_spatial_operator(
                                       queryables['pycsw:BoundingBox'],
                                       child, dbtype, nsmap), boolean_false,
                                       queryables['pycsw:BoundingBox']))
                else:
                    queries.append("%s = %s" %
                                   (_get_spatial_operator(
                                       queryables['pycsw:BoundingBox'],
                                       child, dbtype, nsmap), boolean_false))
            else:
                queries.append("%s = %s" %
                               (_get_spatial_operator(
                                   queryables['pycsw:BoundingBox'],
                                   child, dbtype, nsmap), boolean_true))

        elif child.tag == util.nspath_eval('ogc:FeatureId', nsmap):
            LOGGER.debug('ogc:FeatureId filter detected')
            queries.append("%s = %s" % (queryables['pycsw:Identifier'], assign_param()))
            values.append(child.attrib.get('fid'))
        else:  # comparison operator
            LOGGER.debug('Comparison operator processing')
            tagname = ' %s ' % util.xmltag_split(child.tag).lower()
            if tagname in [' or ', ' and ']:  # this is a nested binary logic query
                LOGGER.debug('Nested binary logic detected; operator=%s' % tagname)
                for child2 in child.xpath('child::*'):
                    queries_nested.append(_get_comparison_expression(child2))
                queries.append('(%s)' % tagname.join(queries_nested))
            else:
                queries.append(_get_comparison_expression(child))

    where = boq.join(queries) if (boq is not None and boq != ' not ') \
        else queries[0]

    return where, values
Example #48
0
def _get_spatial_operator(geomattr, element, dbtype, nsmap, postgis_geometry_column='wkb_geometry'):
    """return the spatial predicate function"""
    property_name = element.find(util.nspath_eval('ogc:PropertyName', nsmap))
    distance = element.find(util.nspath_eval('ogc:Distance', nsmap))

    distance = 'false' if distance is None else distance.text

    LOGGER.debug('Scanning for spatial property name')

    if property_name is None:
        raise RuntimeError('Missing ogc:PropertyName in spatial filter')
    if (property_name.text.find('BoundingBox') == -1 and
            property_name.text.find('Envelope') == -1):
        raise RuntimeError('Invalid ogc:PropertyName in spatial filter: %s' %
                           property_name.text)

    geometry = gml3.Geometry(element, nsmap)

    #make decision to apply spatial ranking to results
    set_spatial_ranking(geometry)

    spatial_predicate = util.xmltag_split(element.tag).lower()

    LOGGER.debug('Spatial predicate: %s' % spatial_predicate)

    if dbtype == 'mysql':  # adjust spatial query for MySQL
        LOGGER.debug('Adjusting spatial query for MySQL')
        if spatial_predicate == 'bbox':
            spatial_predicate = 'intersects'

        if spatial_predicate == 'beyond':
            spatial_query = "ifnull(distance(geomfromtext(%s), \
            geomfromtext('%s')) > convert(%s, signed),false)" % \
                (geomattr, geometry.wkt, distance)
        elif spatial_predicate == 'dwithin':
            spatial_query = "ifnull(distance(geomfromtext(%s), \
            geomfromtext('%s')) <= convert(%s, signed),false)" % \
                (geomattr, geometry.wkt, distance)
        else:
            spatial_query = "ifnull(%s(geomfromtext(%s), \
            geomfromtext('%s')),false)" % \
                (spatial_predicate, geomattr, geometry.wkt)

    elif dbtype == 'postgresql+postgis+wkt':  # adjust spatial query for PostGIS with WKT geometry column
        LOGGER.debug('Adjusting spatial query for PostgreSQL+PostGIS+WKT')
        if spatial_predicate == 'bbox':
            spatial_predicate = 'intersects'

        if spatial_predicate == 'beyond':
            spatial_query = "not st_dwithin(st_geomfromtext(%s), \
            st_geomfromtext('%s'), %f)" % \
                (geomattr, geometry.wkt, float(distance))
        elif spatial_predicate == 'dwithin':
            spatial_query = "st_dwithin(st_geomfromtext(%s), \
            st_geomfromtext('%s'), %f)" % \
                (geomattr, geometry.wkt, float(distance))
        else:
            spatial_query = "st_%s(st_geomfromtext(%s), \
            st_geomfromtext('%s'))" % \
                (spatial_predicate, geomattr, geometry.wkt)

    elif dbtype == 'postgresql+postgis+native':  # adjust spatial query for PostGIS with native geometry
        LOGGER.debug('Adjusting spatial query for PostgreSQL+PostGIS+native')
        if spatial_predicate == 'bbox':
            spatial_predicate = 'intersects'

        if spatial_predicate == 'beyond':
            spatial_query = "not st_dwithin(%s, \
            st_geomfromtext('%s',4326), %f)" % \
                (postgis_geometry_column, geometry.wkt, float(distance))
        elif spatial_predicate == 'dwithin':
            spatial_query = "st_dwithin(%s, \
            st_geomfromtext('%s',4326), %f)" % \
                (postgis_geometry_column, geometry.wkt, float(distance))
        else:
            spatial_query = "st_%s(%s, \
            st_geomfromtext('%s',4326))" % \
                (spatial_predicate, postgis_geometry_column, geometry.wkt)

    else:
        LOGGER.debug('Adjusting spatial query')
        spatial_query = "query_spatial(%s,'%s','%s','%s')" % \
                        (geomattr, geometry.wkt, spatial_predicate, distance)

    return spatial_query
Example #49
0
    def response_csw2sru(self, element, environ):
        """transform a CSW response into an SRU response"""

        response_name = etree.QName(element).localname
        if response_name == 'Capabilities':  # explain
            node = etree.Element(util.nspath_eval('sru:explainResponse', self.namespaces), nsmap=self.namespaces)

            etree.SubElement(node, util.nspath_eval('sru:version', self.namespaces)).text = self.sru_version

            record = etree.SubElement(node, util.nspath_eval('sru:record', self.namespaces))

            etree.SubElement(record, util.nspath_eval('sru:recordPacking', self.namespaces)).text = 'XML'
            etree.SubElement(record, util.nspath_eval('sru:recordSchema', self.namespaces)).text = 'http://explain.z3950.org/dtd/2.1/'

            recorddata = etree.SubElement(record, util.nspath_eval('sru:recordData', self.namespaces))

            explain = etree.SubElement(recorddata, util.nspath_eval('zr:explain', self.namespaces))

            serverinfo = etree.SubElement(explain, util.nspath_eval('zr:serverInfo', self.namespaces), protocol='SRU', version=self.sru_version, transport='http', method='GET POST SOAP')

            etree.SubElement(serverinfo, util.nspath_eval('zr:host', self.namespaces)).text = environ.get('HTTP_HOST', environ["SERVER_NAME"])  # WSGI allows for either of these
            etree.SubElement(serverinfo, util.nspath_eval('zr:port', self.namespaces)).text = environ['SERVER_PORT']
            etree.SubElement(serverinfo, util.nspath_eval('zr:database', self.namespaces)).text = 'pycsw'

            databaseinfo = etree.SubElement(explain, util.nspath_eval('zr:databaseInfo', self.namespaces))

            etree.SubElement(databaseinfo, util.nspath_eval('zr:title', self.namespaces), lang='en', primary='true').text = element.xpath('//ows:Title|//ows20:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(databaseinfo, util.nspath_eval('zr:description', self.namespaces), lang='en', primary='true').text = element.xpath('//ows:Abstract|//ows20:Abstract', namespaces=self.context.namespaces)[0].text

            indexinfo = etree.SubElement(explain, util.nspath_eval('zr:indexInfo', self.namespaces))
            etree.SubElement(indexinfo, util.nspath_eval('zr:set', self.namespaces), name='dc', identifier='info:srw/cql-context-set/1/dc-v1.1')

            for key, value in sorted(self.mappings['csw:Record']['index'].items()):
                zrindex = etree.SubElement(indexinfo, util.nspath_eval('zr:index', self.namespaces), id=value)
                etree.SubElement(zrindex, util.nspath_eval('zr:title', self.namespaces)).text = key
                zrmap = etree.SubElement(zrindex, util.nspath_eval('zr:map', self.namespaces))
                etree.SubElement(zrmap, util.nspath_eval('zr:map', self.namespaces), set='dc').text = key

            zrindex = etree.SubElement(indexinfo, util.nspath_eval('zr:index', self.namespaces))
            zrmap = etree.SubElement(zrindex, util.nspath_eval('zr:map', self.namespaces))
            etree.SubElement(zrmap, util.nspath_eval('zr:name', self.namespaces), set='dc').text = 'title222'

            schemainfo = etree.SubElement(explain, util.nspath_eval('zr:schemaInfo', self.namespaces))
            zrschema = etree.SubElement(schemainfo, util.nspath_eval('zr:schema', self.namespaces), name='dc', identifier='info:srw/schema/1/dc-v1.1')
            etree.SubElement(zrschema, util.nspath_eval('zr:title', self.namespaces)).text = 'Simple Dublin Core'

            configinfo = etree.SubElement(explain, util.nspath_eval('zr:configInfo', self.namespaces))
            etree.SubElement(configinfo, util.nspath_eval('zr:default', self.namespaces), type='numberOfRecords').text = '0'

        elif response_name == 'GetRecordsResponse':

            recpos = int(element.xpath('//@nextRecord')[0]) - int(element.xpath('//@numberOfRecordsReturned')[0])

            node = etree.Element(util.nspath_eval('zs:searchRetrieveResponse', self.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('zs:version', self.namespaces)).text = self.sru_version
            etree.SubElement(node, util.nspath_eval('zs:numberOfRecords', self.namespaces)).text = element.xpath('//@numberOfRecordsMatched')[0]

            for rec in element.xpath('//csw:BriefRecord', namespaces=self.context.namespaces):
                record = etree.SubElement(node, util.nspath_eval('zs:record', self.namespaces))
                etree.SubElement(node, util.nspath_eval('zs:recordSchema', self.namespaces)).text = 'info:srw/schema/1/dc-v1.1'
                etree.SubElement(node, util.nspath_eval('zs:recordPacking', self.namespaces)).text = 'xml'

                recorddata = etree.SubElement(record, util.nspath_eval('zs:recordData', self.namespaces))
                rec.tag = util.nspath_eval('srw_dc:srw_dc', self.namespaces)
                recorddata.append(rec)

                etree.SubElement(record, util.nspath_eval('zs:recordPosition', self.namespaces)).text = str(recpos)
                recpos += 1

        elif response_name == 'ExceptionReport':
            node = self.exceptionreport2diagnostic(element)
        return node
Example #50
0
    def _csw3_2_os(self):
        """CSW 3.0.0 Capabilities to OpenSearch Description"""

        if util.xmltag_split(self.exml.tag) == 'GetRecordsResponse':

            startindex = int(self.exml.xpath('//@nextRecord')[0]) - int(
                        self.exml.xpath('//@numberOfRecordsReturned')[0])
            if startindex < 1:
                startindex = 1

            node = etree.Element(util.nspath_eval('atom:feed',
                       self.context.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('atom:id',
                       self.context.namespaces)).text = self.cfg.get('server', 'url')
            etree.SubElement(node, util.nspath_eval('atom:title',
                       self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'identification_title')
            author = etree.SubElement(node, util.nspath_eval('atom:author', self.context.namespaces))
            etree.SubElement(author, util.nspath_eval('atom:name', self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'provider_name')
            etree.SubElement(node, util.nspath_eval('atom:link',
                       self.context.namespaces), rel='search',
                           type='application/opensearchdescription+xml',
                           href='%smode=opensearch&service=CSW&version=3.0.0&request=GetCapabilities' % self.bind_url)

            etree.SubElement(node, util.nspath_eval('atom:updated',
                self.context.namespaces)).text = self.exml.xpath('//@timestamp')[0]

            etree.SubElement(node, util.nspath_eval('os:Query', self.context.namespaces), role='request')

            etree.SubElement(node, util.nspath_eval('os:totalResults',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsMatched')[0]
            etree.SubElement(node, util.nspath_eval('os:startIndex',
                        self.context.namespaces)).text = str(startindex)
            etree.SubElement(node, util.nspath_eval('os:itemsPerPage',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsReturned')[0]

            for rec in self.exml.xpath('//atom:entry',
                        namespaces=self.context.namespaces):
                node.append(rec)
        elif util.xmltag_split(self.exml.tag) == 'Capabilities':
            node = etree.Element(util.nspath_eval('os:OpenSearchDescription', self.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('os:ShortName', self.namespaces)).text = self.exml.xpath('//ows20:Title', namespaces=self.context.namespaces)[0].text[:16]
            etree.SubElement(node, util.nspath_eval('os:LongName', self.namespaces)).text = self.exml.xpath('//ows20:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Description', self.namespaces)).text = self.exml.xpath('//ows20:Abstract', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Tags', self.namespaces)).text = ' '.join(x.text for x in self.exml.xpath('//ows20:Keyword', namespaces=self.context.namespaces))

            # Requirement-022
            node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
            node1.set('type', 'application/xml')
            node1.set('template', '%sservice=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid}' % self.bind_url)

            # Requirement-023
            node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
            node1.set('type', 'application/atom+xml')
            node1.set('template', '%smode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&outputformat=application/atom%%2Bxml&&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid}' % self.bind_url)

            node1 = etree.SubElement(node, util.nspath_eval('os:Image', self.namespaces))
            node1.set('type', 'image/vnd.microsoft.icon')
            node1.set('width', '16')
            node1.set('height', '16')
            node1.text = 'http://pycsw.org/img/favicon.ico'

            os_query = etree.SubElement(node, util.nspath_eval('os:Query', self.namespaces), role='example')
            os_query.attrib[util.nspath_eval('geo:box', self.namespaces)] = '-180,-90,180,90'

            etree.SubElement(node, util.nspath_eval('os:Developer', self.namespaces)).text = self.exml.xpath('//ows20:IndividualName', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Contact', self.namespaces)).text = self.exml.xpath('//ows20:ElectronicMailAddress', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Attribution', self.namespaces)).text = self.exml.xpath('//ows20:ProviderName', namespaces=self.context.namespaces)[0].text
        elif util.xmltag_split(self.exml.tag) == 'ExceptionReport':
            node = self.exml
        else:  # GetRecordById output
            node = etree.Element(util.nspath_eval('atom:feed',
                       self.context.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('atom:id',
                       self.context.namespaces)).text = self.cfg.get('server', 'url')
            etree.SubElement(node, util.nspath_eval('atom:title',
                       self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'identification_title')
            #etree.SubElement(node, util.nspath_eval('atom:updated',
            #  self.context.namespaces)).text = self.exml.xpath('//@timestamp')[0]

            etree.SubElement(node, util.nspath_eval('os:totalResults',
                        self.context.namespaces)).text = '1'
            etree.SubElement(node, util.nspath_eval('os:startIndex',
                        self.context.namespaces)).text = '1'
            etree.SubElement(node, util.nspath_eval('os:itemsPerPage',
                        self.context.namespaces)).text = '1'

            for rec in self.exml.xpath('//atom:entry', namespaces=self.context.namespaces):
                #node.append(rec)
                node = rec
        return node
Example #51
0
    def cswrecord2atom(self, rec):
        entry = etree.Element(util.nspath_eval('atom:entry', self.namespaces))

        etree.SubElement(entry, util.nspath_eval('atom:id', self.context.namespaces)).text = rec.xpath('dc:identifier', namespaces=self.context.namespaces)[0].text
        etree.SubElement(entry, util.nspath_eval('dc:identifier', self.context.namespaces)).text = rec.xpath('dc:identifier', namespaces=self.context.namespaces)[0].text
        etree.SubElement(entry, util.nspath_eval('atom:title', self.context.namespaces)).text = rec.xpath('dc:title', namespaces=self.context.namespaces)[0].text

        dc_date = rec.xpath('dc:date', namespaces=self.context.namespaces)
        if dc_date:
            etree.SubElement(entry, util.nspath_eval('atom:updated', self.context.namespaces)).text = dc_date[0].text

        for s in rec.xpath('dc:subject', namespaces=self.context.namespaces):
            etree.SubElement(entry, util.nspath_eval('atom:category', self.context.namespaces), term=s.text)

        for d in rec.xpath('dct:references', namespaces=self.context.namespaces):
            link = etree.SubElement(entry, util.nspath_eval('atom:link', self.context.namespaces))
            link.attrib['href'] = d.text

            scheme = d.attrib.get('scheme')
            if scheme is not None:
                if scheme == 'enclosure':
                    link.attrib['rel'] = scheme
                    link.attrib['type'] = 'application/octet-stream'
                else:
                    link.attrib['type'] = scheme

        bbox = rec.xpath('ows:BoundingBox|ows20:BoundingBox', namespaces=self.context.namespaces)
        if bbox:
            where = etree.SubElement(entry, util.nspath_eval('georss:where', {'georss': 'http://www.georss.org/georss'}))
            envelope = etree.SubElement(where, util.nspath_eval('gml:Envelope', self.context.namespaces))
            envelope.attrib['srsName'] = bbox[0].attrib.get('crs')
            etree.SubElement(envelope, util.nspath_eval('gml:lowerCorner', self.context.namespaces)).text = bbox[0].xpath('ows:LowerCorner|ows20:LowerCorner', namespaces=self.context.namespaces)[0].text
            etree.SubElement(envelope, util.nspath_eval('gml:upperCorner', self.context.namespaces)).text = bbox[0].xpath('ows:UpperCorner|ows20:UpperCorner', namespaces=self.context.namespaces)[0].text

        return entry
Example #52
0
    def _get_comparison_expression(elem):
        """return the SQL expression based on Filter query"""
        fname = None
        matchcase = elem.attrib.get('matchCase')
        wildcard = elem.attrib.get('wildCard')
        singlechar = elem.attrib.get('singleChar')
        expression = None

        if wildcard is None:
            wildcard = '%'

        if singlechar is None:
            singlechar = '_'

        if (elem.xpath('child::*')[0].tag ==
                util.nspath_eval('ogc:Function', nsmap)):
            LOGGER.debug('ogc:Function detected')
            if (elem.xpath('child::*')[0].attrib['name'] not in
                    MODEL['Functions']):
                raise RuntimeError('Invalid ogc:Function: %s' %
                                   (elem.xpath('child::*')[0].attrib['name']))
            fname = elem.xpath('child::*')[0].attrib['name']

            try:
                LOGGER.debug('Testing existence of ogc:PropertyName')
                pname = queryables[elem.find(util.nspath_eval('ogc:Function/ogc:PropertyName', nsmap)).text]['dbcol']
            except Exception as err:
                raise RuntimeError('Invalid PropertyName: %s.  %s' % (elem.find(util.nspath_eval('ogc:Function/ogc:PropertyName', nsmap)).text, str(err)))

        else:
            try:
                LOGGER.debug('Testing existence of ogc:PropertyName')
                pname = queryables[elem.find(
                    util.nspath_eval('ogc:PropertyName', nsmap)).text]['dbcol']
            except Exception as err:
                raise RuntimeError('Invalid PropertyName: %s.  %s' %
                                   (elem.find(util.nspath_eval('ogc:PropertyName',
                                   nsmap)).text, str(err)))

        if (elem.tag != util.nspath_eval('ogc:PropertyIsBetween', nsmap)):
            if elem.tag in [util.nspath_eval('ogc:%s' % n, nsmap) for n in
                MODEL['SpatialOperators']['values']]:
                boolean_true = '\'true\''
                boolean_false = '\'false\''
                if dbtype == 'mysql':
                    boolean_true = 'true'
                    boolean_false = 'false'

                return "%s = %s" % (_get_spatial_operator(queryables['pycsw:BoundingBox'], elem, dbtype, nsmap), boolean_true)
            else:
                pval = elem.find(util.nspath_eval('ogc:Literal', nsmap)).text

        com_op = _get_comparison_operator(elem)
        LOGGER.debug('Comparison operator: %s' % com_op)

        # if this is a case insensitive search
        # then set the DB-specific LIKE comparison operator

        LOGGER.debug('Setting csw:AnyText property')

        anytext = queryables['csw:AnyText']['dbcol']
        if ((matchcase is not None and matchcase == 'false') or
                pname == anytext):
            com_op = 'ilike' if is_pg else 'like'

        if (elem.tag == util.nspath_eval('ogc:PropertyIsBetween', nsmap)):
            com_op = 'between'
            lower_boundary = elem.find(
                util.nspath_eval('ogc:LowerBoundary/ogc:Literal',
                                 nsmap)).text
            upper_boundary = elem.find(
                util.nspath_eval('ogc:UpperBoundary/ogc:Literal',
                                 nsmap)).text
            expression = "%s %s %s and %s" % \
                           (pname, com_op, assign_param(), assign_param())
            values.append(lower_boundary)
            values.append(upper_boundary)
        else:
            if pname == anytext and is_pg and fts:
                LOGGER.debug('PostgreSQL FTS specific search')
                # do nothing, let FTS do conversion (#212)
                pvalue = pval
            else:
                LOGGER.debug('PostgreSQL non-FTS specific search')
                pvalue = pval.replace(wildcard, '%').replace(singlechar, '_')

                if pname == anytext:  # pad anytext with wildcards
                    LOGGER.debug('PostgreSQL non-FTS specific anytext search')
                    LOGGER.debug('old value: %s', pval)

                    pvalue = '%%%s%%' % pvalue.rstrip('%').lstrip('%')

                    LOGGER.debug('new value: %s', pvalue)

            values.append(pvalue)

            if boq == ' not ':
                if fname is not None:
                    expression = "%s is null or not %s(%s) %s %s" % \
                                   (pname, fname, pname, com_op, assign_param())
                elif pname == anytext and is_pg and fts:
                    LOGGER.debug('PostgreSQL FTS specific search')
                    expression = ("%s is null or not plainto_tsquery('%s', %s) @@ anytext_tsvector" %
                                  (anytext, language, assign_param()))
                else:
                    LOGGER.debug('PostgreSQL non-FTS specific search')
                    expression = "%s is null or not %s %s %s" % \
                                   (pname, pname, com_op, assign_param())
            else:
                if fname is not None:
                    expression = "%s(%s) %s %s" % \
                                   (fname, pname, com_op, assign_param())
                elif pname == anytext and is_pg and fts:
                    LOGGER.debug('PostgreSQL FTS specific search')
                    expression = ("plainto_tsquery('%s', %s) @@ anytext_tsvector" %
                                  (language, assign_param()))
                else:
                    LOGGER.debug('PostgreSQL non-FTS specific search')
                    expression = "%s %s %s" % (pname, com_op, assign_param())

        return expression
Example #53
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
Example #54
0
    def _get_comparison_expression(elem):
        """return the SQL expression based on Filter query"""
        fname = None
        matchcase = elem.attrib.get('matchCase')
        wildcard = elem.attrib.get('wildCard')
        singlechar = elem.attrib.get('singleChar')
        expression = None

        if wildcard is None:
            wildcard = '%'

        if singlechar is None:
            singlechar = '_'

        if (elem.xpath('child::*')[0].tag == util.nspath_eval(
                'ogc:Function', nsmap)):
            LOGGER.debug('ogc:Function detected')
            if (elem.xpath('child::*')[0].attrib['name']
                    not in MODEL['Functions']):
                raise RuntimeError('Invalid ogc:Function: %s' %
                                   (elem.xpath('child::*')[0].attrib['name']))
            fname = elem.xpath('child::*')[0].attrib['name']

            try:
                LOGGER.debug('Testing existence of ogc:PropertyName')
                pname = queryables[elem.find(
                    util.nspath_eval('ogc:Function/ogc:PropertyName',
                                     nsmap)).text]['dbcol']
            except Exception as err:
                raise RuntimeError(
                    'Invalid PropertyName: %s.  %s' % (elem.find(
                        util.nspath_eval('ogc:Function/ogc:PropertyName',
                                         nsmap)).text, str(err)))

        else:
            try:
                LOGGER.debug('Testing existence of ogc:PropertyName')
                pname = queryables[elem.find(
                    util.nspath_eval('ogc:PropertyName', nsmap)).text]['dbcol']
            except Exception as err:
                raise RuntimeError(
                    'Invalid PropertyName: %s.  %s' %
                    (elem.find(util.nspath_eval('ogc:PropertyName',
                                                nsmap)).text, str(err)))

        if (elem.tag != util.nspath_eval('ogc:PropertyIsBetween', nsmap)):
            if elem.tag in [
                    util.nspath_eval('ogc:%s' % n, nsmap)
                    for n in MODEL['SpatialOperators']['values']
            ]:
                boolean_true = '\'true\''
                boolean_false = '\'false\''
                if dbtype == 'mysql':
                    boolean_true = 'true'
                    boolean_false = 'false'

                return "%s = %s" % (_get_spatial_operator(
                    queryables['pycsw:BoundingBox'], elem, dbtype,
                    nsmap), boolean_true)
            else:
                pval = elem.find(util.nspath_eval('ogc:Literal', nsmap)).text

        com_op = _get_comparison_operator(elem)
        LOGGER.debug('Comparison operator: %s' % com_op)

        # if this is a case insensitive search
        # then set the DB-specific LIKE comparison operator

        LOGGER.debug('Setting csw:AnyText property')

        anytext = queryables['csw:AnyText']['dbcol']
        if ((matchcase is not None and matchcase == 'false')
                or pname == anytext):
            com_op = 'ilike' if is_pg else 'like'

        if (elem.tag == util.nspath_eval('ogc:PropertyIsBetween', nsmap)):
            com_op = 'between'
            lower_boundary = elem.find(
                util.nspath_eval('ogc:LowerBoundary/ogc:Literal', nsmap)).text
            upper_boundary = elem.find(
                util.nspath_eval('ogc:UpperBoundary/ogc:Literal', nsmap)).text
            expression = "%s %s %s and %s" % \
                           (pname, com_op, assign_param(), assign_param())
            values.append(lower_boundary)
            values.append(upper_boundary)
        else:
            if pname == anytext and is_pg and fts:
                LOGGER.debug('PostgreSQL FTS specific search')
                # do nothing, let FTS do conversion (#212)
                pvalue = pval
            else:
                LOGGER.debug('PostgreSQL non-FTS specific search')
                pvalue = pval.replace(wildcard, '%').replace(singlechar, '_')

                if pname == anytext:  # pad anytext with wildcards
                    LOGGER.debug('PostgreSQL non-FTS specific anytext search')
                    LOGGER.debug('old value: %s', pval)

                    pvalue = '%%%s%%' % pvalue.rstrip('%').lstrip('%')

                    LOGGER.debug('new value: %s', pvalue)

            values.append(pvalue)

            if boq == ' not ':
                if fname is not None:
                    expression = "%s is null or not %s(%s) %s %s" % \
                                   (pname, fname, pname, com_op, assign_param())
                elif pname == anytext and is_pg and fts:
                    LOGGER.debug('PostgreSQL FTS specific search')
                    expression = (
                        "%s is null or not plainto_tsquery('%s', %s) @@ anytext_tsvector"
                        % (anytext, language, assign_param()))
                else:
                    LOGGER.debug('PostgreSQL non-FTS specific search')
                    expression = "%s is null or not %s %s %s" % \
                                   (pname, pname, com_op, assign_param())
            else:
                if fname is not None:
                    expression = "%s(%s) %s %s" % \
                                   (fname, pname, com_op, assign_param())
                elif pname == anytext and is_pg and fts:
                    LOGGER.debug('PostgreSQL FTS specific search')
                    expression = (
                        "plainto_tsquery('%s', %s) @@ anytext_tsvector" %
                        (language, assign_param()))
                else:
                    LOGGER.debug('PostgreSQL non-FTS specific search')
                    expression = "%s %s %s" % (pname, com_op, assign_param())

        return expression
    def _csw3_2_os(self):
        """CSW 3.0.0 Capabilities to OpenSearch Description"""

        if util.xmltag_split(self.exml.tag) == 'GetRecordsResponse':

            startindex = int(self.exml.xpath('//@nextRecord')[0]) - int(
                        self.exml.xpath('//@numberOfRecordsReturned')[0])
            if startindex < 1:
                startindex = 1

            node = etree.Element(util.nspath_eval('atom:feed',
                       self.context.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('atom:id',
                       self.context.namespaces)).text = self.cfg.get('server', 'url')
            etree.SubElement(node, util.nspath_eval('atom:title',
                       self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'identification_title')
            author = etree.SubElement(node, util.nspath_eval('atom:author', self.context.namespaces))
            etree.SubElement(author, util.nspath_eval('atom:name', self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'provider_name')
            etree.SubElement(node, util.nspath_eval('atom:link',
                       self.context.namespaces), rel='search',
                           type='application/opensearchdescription+xml',
                           href='%smode=opensearch&service=CSW&version=3.0.0&request=GetCapabilities' % self.bind_url)

            etree.SubElement(node, util.nspath_eval('atom:updated',
                self.context.namespaces)).text = self.exml.xpath('//@timestamp')[0]

            etree.SubElement(node, util.nspath_eval('os:Query', self.context.namespaces), role='request')

            etree.SubElement(node, util.nspath_eval('os:totalResults',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsMatched')[0]
            etree.SubElement(node, util.nspath_eval('os:startIndex',
                        self.context.namespaces)).text = str(startindex)
            etree.SubElement(node, util.nspath_eval('os:itemsPerPage',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsReturned')[0]

            for rec in self.exml.xpath('//atom:entry',
                        namespaces=self.context.namespaces):
                node.append(rec)
        elif util.xmltag_split(self.exml.tag) == 'Capabilities':
            node = etree.Element(util.nspath_eval('os:OpenSearchDescription', self.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('os:ShortName', self.namespaces)).text = self.exml.xpath('//ows20:Title', namespaces=self.context.namespaces)[0].text[:16]
            etree.SubElement(node, util.nspath_eval('os:LongName', self.namespaces)).text = self.exml.xpath('//ows20:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Description', self.namespaces)).text = self.exml.xpath('//ows20:Abstract', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Tags', self.namespaces)).text = ' '.join(x.text for x in self.exml.xpath('//ows20:Keyword', namespaces=self.context.namespaces))

            # Requirement-022
            node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
            node1.set('type', 'application/xml')
            node1.set('template', '%sservice=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&outputformat=application/xml&outputschema=http://www.opengis.net/cat/csw/3.0&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid}' % self.bind_url)

            # Requirement-023
            node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
            node1.set('type', 'application/atom+xml')
            node1.set('template', '%smode=opensearch&service=CSW&version=3.0.0&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&outputformat=application/atom+xml&&startposition={startIndex?}&maxrecords={count?}&recordids={geo:uid}' % self.bind_url)

            node1 = etree.SubElement(node, util.nspath_eval('os:Image', self.namespaces))
            node1.set('type', 'image/vnd.microsoft.icon')
            node1.set('width', '16')
            node1.set('height', '16')
            node1.text = 'http://pycsw.org/img/favicon.ico'

            os_query = etree.SubElement(node, util.nspath_eval('os:Query', self.namespaces), role='example')
            os_query.attrib[util.nspath_eval('geo:box', self.namespaces)] = '-180,-90,180,90'

            etree.SubElement(node, util.nspath_eval('os:Developer', self.namespaces)).text = self.exml.xpath('//ows20:IndividualName', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Contact', self.namespaces)).text = self.exml.xpath('//ows20:ElectronicMailAddress', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Attribution', self.namespaces)).text = self.exml.xpath('//ows20:ProviderName', namespaces=self.context.namespaces)[0].text
        elif util.xmltag_split(self.exml.tag) == 'ExceptionReport':
            node = self.exml
        else:  # GetRecordById output
            node = etree.Element(util.nspath_eval('atom:feed',
                       self.context.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('atom:id',
                       self.context.namespaces)).text = self.cfg.get('server', 'url')
            etree.SubElement(node, util.nspath_eval('atom:title',
                       self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'identification_title')
            #etree.SubElement(node, util.nspath_eval('atom:updated',
            #  self.context.namespaces)).text = self.exml.xpath('//@timestamp')[0]

            etree.SubElement(node, util.nspath_eval('os:totalResults',
                        self.context.namespaces)).text = '1'
            etree.SubElement(node, util.nspath_eval('os:startIndex',
                        self.context.namespaces)).text = '1'
            etree.SubElement(node, util.nspath_eval('os:itemsPerPage',
                        self.context.namespaces)).text = '1'

            for rec in self.exml.xpath('//atom:entry', namespaces=self.context.namespaces):
                #node.append(rec)
                node = rec
        return node
Example #56
0
def _get_spatial_operator(geomattr,
                          element,
                          dbtype,
                          nsmap,
                          postgis_geometry_column='wkb_geometry'):
    """return the spatial predicate function"""
    property_name = element.find(util.nspath_eval('ogc:PropertyName', nsmap))
    distance = element.find(util.nspath_eval('ogc:Distance', nsmap))

    distance = 'false' if distance is None else distance.text

    LOGGER.debug('Scanning for spatial property name')

    if property_name is None:
        raise RuntimeError('Missing ogc:PropertyName in spatial filter')
    if (property_name.text.find('BoundingBox') == -1
            and property_name.text.find('Envelope') == -1):
        raise RuntimeError('Invalid ogc:PropertyName in spatial filter: %s' %
                           property_name.text)

    geometry = gml3.Geometry(element, nsmap)

    #make decision to apply spatial ranking to results
    set_spatial_ranking(geometry)

    spatial_predicate = util.xmltag_split(element.tag).lower()

    LOGGER.debug('Spatial predicate: %s' % spatial_predicate)

    if dbtype == 'mysql':  # adjust spatial query for MySQL
        LOGGER.debug('Adjusting spatial query for MySQL')
        if spatial_predicate == 'bbox':
            spatial_predicate = 'intersects'

        if spatial_predicate == 'beyond':
            spatial_query = "ifnull(distance(geomfromtext(%s), \
            geomfromtext('%s')) > convert(%s, signed),false)"                                                              % \
                (geomattr, geometry.wkt, distance)
        elif spatial_predicate == 'dwithin':
            spatial_query = "ifnull(distance(geomfromtext(%s), \
            geomfromtext('%s')) <= convert(%s, signed),false)"                                                               % \
                (geomattr, geometry.wkt, distance)
        else:
            spatial_query = "ifnull(%s(geomfromtext(%s), \
            geomfromtext('%s')),false)"                                        % \
                (spatial_predicate, geomattr, geometry.wkt)

    elif dbtype == 'postgresql+postgis+wkt':  # adjust spatial query for PostGIS with WKT geometry column
        LOGGER.debug('Adjusting spatial query for PostgreSQL+PostGIS+WKT')
        if spatial_predicate == 'bbox':
            spatial_predicate = 'intersects'

        if spatial_predicate == 'beyond':
            spatial_query = "not st_dwithin(st_geomfromtext(%s), \
            st_geomfromtext('%s'), %f)"                                        % \
                (geomattr, geometry.wkt, float(distance))
        elif spatial_predicate == 'dwithin':
            spatial_query = "st_dwithin(st_geomfromtext(%s), \
            st_geomfromtext('%s'), %f)"                                        % \
                (geomattr, geometry.wkt, float(distance))
        else:
            spatial_query = "st_%s(st_geomfromtext(%s), \
            st_geomfromtext('%s'))"                                    % \
                (spatial_predicate, geomattr, geometry.wkt)

    elif dbtype == 'postgresql+postgis+native':  # adjust spatial query for PostGIS with native geometry
        LOGGER.debug('Adjusting spatial query for PostgreSQL+PostGIS+native')
        if spatial_predicate == 'bbox':
            spatial_predicate = 'intersects'

        if spatial_predicate == 'beyond':
            spatial_query = "not st_dwithin(%s, \
            st_geomfromtext('%s',4326), %f)"                                             % \
                (postgis_geometry_column, geometry.wkt, float(distance))
        elif spatial_predicate == 'dwithin':
            spatial_query = "st_dwithin(%s, \
            st_geomfromtext('%s',4326), %f)"                                             % \
                (postgis_geometry_column, geometry.wkt, float(distance))
        else:
            spatial_query = "st_%s(%s, \
            st_geomfromtext('%s',4326))"                                         % \
                (spatial_predicate, postgis_geometry_column, geometry.wkt)

    else:
        LOGGER.debug('Adjusting spatial query')
        spatial_query = "query_spatial(%s,'%s','%s','%s')" % \
                        (geomattr, geometry.wkt, spatial_predicate, distance)

    return spatial_query
    def _csw2_2_os(self):
        """CSW 2.0.2 Capabilities to OpenSearch Description"""

        if util.xmltag_split(self.exml.tag) == 'GetRecordsResponse':

            startindex = int(self.exml.xpath('//@nextRecord')[0]) - int(
                        self.exml.xpath('//@numberOfRecordsReturned')[0])
            if startindex < 1:
                startindex = 1

            node = etree.Element(util.nspath_eval('atom:feed',
                       self.context.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('atom:id',
                       self.context.namespaces)).text = self.cfg.get('server', 'url')
            etree.SubElement(node, util.nspath_eval('atom:title',
                       self.context.namespaces)).text = self.cfg.get('metadata:main',
                       'identification_title')
            #etree.SubElement(node, util.nspath_eval('atom:updated',
            #  self.context.namespaces)).text = self.exml.xpath('//@timestamp')[0]

            etree.SubElement(node, util.nspath_eval('os:totalResults',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsMatched')[0]
            etree.SubElement(node, util.nspath_eval('os:startIndex',
                        self.context.namespaces)).text = str(startindex)
            etree.SubElement(node, util.nspath_eval('os:itemsPerPage',
                        self.context.namespaces)).text = self.exml.xpath(
                        '//@numberOfRecordsReturned')[0]

            for rec in self.exml.xpath('//atom:entry',
                        namespaces=self.context.namespaces):
                node.append(rec)
        elif util.xmltag_split(self.exml.tag) == 'Capabilities':
            node = etree.Element(util.nspath_eval('os:OpenSearchDescription', self.namespaces), nsmap=self.namespaces)
            etree.SubElement(node, util.nspath_eval('os:ShortName', self.namespaces)).text = self.exml.xpath('//ows:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:LongName', self.namespaces)).text = self.exml.xpath('//ows:Title', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Description', self.namespaces)).text = self.exml.xpath('//ows:Abstract', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Tags', self.namespaces)).text = ' '.join(x.text for x in self.exml.xpath('//ows:Keyword', namespaces=self.context.namespaces))

            node1 = etree.SubElement(node, util.nspath_eval('os:Url', self.namespaces))
            node1.set('type', 'application/atom+xml')
            node1.set('method', 'get')
            node1.set('template', '%smode=opensearch&service=CSW&version=2.0.2&request=GetRecords&elementsetname=full&typenames=csw:Record&resulttype=results&q={searchTerms?}&bbox={geo:box?}&time={time:start?}/{time:end?}&startposition={startIndex?}&maxrecords={count?}' % self.bind_url)

            node1 = etree.SubElement(node, util.nspath_eval('os:Image', self.namespaces))
            node1.set('type', 'image/vnd.microsoft.icon')
            node1.set('width', '16')
            node1.set('height', '16')
            node1.text = 'http://pycsw.org/img/favicon.ico'

            etree.SubElement(node, util.nspath_eval('os:Developer', self.namespaces)).text = self.exml.xpath('//ows:IndividualName', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Context', self.namespaces)).text = self.exml.xpath('//ows:ElectronicMailAddress', namespaces=self.context.namespaces)[0].text
            etree.SubElement(node, util.nspath_eval('os:Attribution', self.namespaces)).text = self.exml.xpath('//ows:ProviderName', namespaces=self.context.namespaces)[0].text
        elif util.xmltag_split(self.exml.tag) == 'ExceptionReport':
            node = self.exml
        else:  # return Description document
            node = etree.Element(util.nspath_eval('os:Description', self.context.namespaces))

        return node
Example #58
0
def write_record(recobj, esn, context, url=None):
    ''' Return csw:SearchResults child as lxml.etree.Element '''
    typename = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Typename'])
    if esn == 'full' and typename == 'fgdc:metadata':
        # dump record as is and exit
        return etree.fromstring(util.getqattr(recobj, context.md_core_model['mappings']['pycsw:XML']), context.parser)

    node = etree.Element('metadata')
    node.attrib[util.nspath_eval('xsi:noNamespaceSchemaLocation', context.namespaces)] = \
    'http://www.fgdc.gov/metadata/fgdc-std-001-1998.xsd'

    idinfo = etree.SubElement(node, 'idinfo')
    # identifier
    etree.SubElement(idinfo, 'datasetid').text = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Identifier'])

    citation = etree.SubElement(idinfo, 'citation')
    citeinfo = etree.SubElement(citation, 'citeinfo')

    # title
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Title'])
    etree.SubElement(citeinfo, 'title').text = val

    # publisher
    publinfo = etree.SubElement(citeinfo, 'publinfo')
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Publisher']) or ''
    etree.SubElement(publinfo, 'publish').text = val

    # origin
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Creator']) or ''
    etree.SubElement(citeinfo, 'origin').text = val

    # keywords
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Keywords'])
    if val:
        keywords = etree.SubElement(idinfo, 'keywords')
        theme = etree.SubElement(keywords, 'theme')
        for v in val.split(','):
            etree.SubElement(theme, 'themekey').text = v

    # accessconstraints
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:AccessConstraints']) or ''
    etree.SubElement(idinfo, 'accconst').text = val

    # abstract
    descript = etree.SubElement(idinfo, 'descript')
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Abstract']) or ''
    etree.SubElement(descript, 'abstract').text = val

    # time
    datebegin = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:TempExtent_begin'])
    dateend = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:TempExtent_end'])
    if all([datebegin, dateend]):
        timeperd = etree.SubElement(idinfo, 'timeperd')
        timeinfo = etree.SubElement(timeperd, 'timeinfo')
        rngdates = etree.SubElement(timeinfo, 'timeinfo')
        begdate = etree.SubElement(rngdates, 'begdate').text = datebegin
        enddate = etree.SubElement(rngdates, 'enddate').text = dateend

    # bbox extent
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:BoundingBox'])
    bboxel = write_extent(val)
    if bboxel is not None:
        idinfo.append(bboxel)

    # contributor
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Contributor']) or ''
    etree.SubElement(idinfo, 'datacred').text = val

    # direct
    spdoinfo = etree.SubElement(idinfo, 'spdoinfo')
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Type']) or ''
    etree.SubElement(spdoinfo, 'direct').text = val

    # formname
    distinfo = etree.SubElement(node, 'distinfo')
    stdorder = etree.SubElement(distinfo, 'stdorder')
    digform = etree.SubElement(stdorder, 'digform')
    digtinfo = etree.SubElement(digform, 'digtinfo')
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Format']) or ''
    etree.SubElement(digtinfo, 'formname').text = val
    etree.SubElement(citeinfo, 'geoform').text = val

    # source
    lineage = etree.SubElement(node, 'lineage')
    srcinfo = etree.SubElement(lineage, 'srcinfo')
    srccite = etree.SubElement(srcinfo, 'srccite')
    sciteinfo = etree.SubElement(srccite, 'citeinfo')
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Source']) or ''
    etree.SubElement(sciteinfo, 'title').text = val

    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Relation']) or ''
    etree.SubElement(citeinfo, 'onlink').text = val

    # links
    rlinks = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Links'])
    if rlinks:
        for link in rlinks.split('^'):
            linkset = link.split(',')
            etree.SubElement(citeinfo, 'onlink', type=linkset[2]).text = linkset[-1]

    # metd
    metainfo = etree.SubElement(node, 'metainfo')
    val = util.getqattr(recobj, context.md_core_model['mappings']['pycsw:Modified']) or ''
    etree.SubElement(metainfo, 'metd').text = val

    return node