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 = etree.parse(os.path.join(self.context.pycsw_home, 'plugins', 'profiles', 'apiso', 'schemas', 'ogc', 'iso', '19139', '20060504', 'gmd', 'identification.xsd')).getroot() node1.append(schema) node2 = etree.Element( util.nspath_eval('csw:SchemaComponent', self.context.namespaces), schemaLanguage='XMLSCHEMA', targetNamespace=self.namespace, parentSchema='gmd.xsd') schema = etree.parse(os.path.join(self.context.pycsw_home, 'plugins', 'profiles', 'apiso', 'schemas', 'ogc', 'iso', '19139', '20060504', 'srv', 'serviceMetadata.xsd')).getroot() node2.append(schema) return [node1, node2]
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, err: raise RuntimeError('Invalid PropertyName: %s. %s' % (elem.find(util.nspath_eval('ogc:Function/ogc:PropertyName', nsmap)).text, str(err)))
def gen_sitemap(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) URLSET.attrib[util.nspath_eval('xsi:schemaLocation', CONTEXT.namespaces)] = \ '%s http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd' % \ CONTEXT.namespaces['sitemap'] # get all records COUNT, RECORDS = REPOS.query(constraint={}, maxrecords=99999999) 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 with open(OUTPUT_FILE, 'w') as of: of.write(etree.tostring(URLSET, pretty_print=1, encoding='utf8', xml_declaration=1))
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
def gen_sitemap(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) URLSET.attrib[util.nspath_eval("xsi:schemaLocation", CONTEXT.namespaces)] = ( "%s http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" % CONTEXT.namespaces["sitemap"] ) # get all records COUNT, RECORDS = REPOS.query(constraint={}, maxrecords=99999999) 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 with open(OUTPUT_FILE, "w") as of: of.write(etree.tostring(URLSET, pretty_print=1, encoding="utf8", xml_declaration=1))
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
def write_extent(bbox, nsmap): ''' Generate BBOX extent ''' from shapely.wkt import loads if bbox is not None: if bbox.find('SRID') != -1: # it's EWKT; chop off 'SRID=\d+;' bbox2 = loads(bbox.split(';')[-1]).envelope.bounds else: bbox2 = loads(bbox).envelope.bounds 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
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]))
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, err: raise RuntimeError( 'Invalid PropertyName: %s. %s' % (elem.find( util.nspath_eval('ogc:Function/ogc:PropertyName', nsmap)).text, str(err)))
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]))
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.find(util.nspath_eval('ows:Exception/ows:ExceptionText', self.context.namespaces)).text etree.SubElement(diagnostic, util.nspath_eval('zd:details', self.namespaces)).text = \ element.find(util.nspath_eval('ows:Exception', self.context.namespaces)).attrib.get('exceptionCode') return node
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
def write_record(self, result, esn, outputschema, queryables): ''' Return csw:SearchResults child as lxml.etree.Element ''' typename = util.getqattr(result, self.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, self.context.md_core_model['mappings']['pycsw:XML'])) if typename == 'csw:Record': # transform csw:Record -> atom:entry model mappings util.transform_mappings(queryables, self.repository['mappings']['csw:Record']) node = etree.Element(util.nspath_eval('atom:entry', self.namespaces)) node.attrib[util.nspath_eval('xsi:schemaLocation', self.context.namespaces)] = \ '%s %s?service=CSW&version=2.0.2&request=DescribeRecord&typename=atom:entry' % (self.namespaces['atom'], self.url) # author val = util.getqattr(result, queryables['atom:author']['dbcol']) if val: etree.SubElement(node, util.nspath_eval('atom:author', self.namespaces)).text = util.getqattr(result, queryables['atom:author']['dbcol']) # category val = util.getqattr(result, queryables['atom:category']['dbcol']) if val: for kw in val.split(','): etree.SubElement(node, util.nspath_eval('atom:category', self.namespaces)).text = kw for qval in ['contributor', 'id']: val = util.getqattr(result, queryables['atom:%s' % qval]['dbcol']) if val: etree.SubElement(node, util.nspath_eval('atom:%s' % qval, self.namespaces)).text = util.getqattr(result, queryables['atom:%s' % qval]['dbcol']) rlinks = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Links']) if rlinks: for link in rlinks.split('^'): linkset = link.split(',') url2 = etree.SubElement(node, util.nspath_eval('atom:link', self.namespaces), href=linkset[-1], type=linkset[2], title=linkset[1]) etree.SubElement(node, util.nspath_eval('atom:link', self.namespaces), href='%s?service=CSW&version=2.0.2&request=GetRepositoryItem&id=%s' % (self.url, util.getqattr(result, queryables['atom:id']['dbcol']))) for qval in ['published', 'rights', 'source', 'summary', 'title', 'updated']: val = util.getqattr(result, queryables['atom:%s' % qval]['dbcol']) if val: etree.SubElement(node, util.nspath_eval('atom:%s' % qval, self.namespaces)).text = util.getqattr(result, queryables['atom:%s' % qval]['dbcol']) # bbox extent val = util.getqattr(result, queryables['georss:where']['dbcol']) bboxel = write_extent(val, self.context.namespaces) if bboxel is not None: node.append(bboxel) return node
def response_csw2opensearch(self, element, cfg): """transform a CSW response into an OpenSearch response""" LOGGER.debug('RESPONSE: %s', util.xmltag_split(element.tag)) if util.xmltag_split(element.tag) == 'GetRecordsResponse': startindex = int(element.xpath('//@nextRecord')[0]) - int( element.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 = cfg.get('server', 'url') etree.SubElement(node, util.nspath_eval('atom:title', self.context.namespaces)).text = cfg.get('metadata:main', 'identification_title') #etree.SubElement(node, util.nspath_eval('atom:updated', # self.context.namespaces)).text = element.xpath('//@timestamp')[0] etree.SubElement(node, util.nspath_eval('os:totalResults', self.context.namespaces)).text = element.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 = element.xpath( '//@numberOfRecordsReturned')[0] for rec in element.xpath('//atom:entry', namespaces=self.context.namespaces): node.append(rec) elif util.xmltag_split(element.tag) == 'Capabilities': node = etree.Element('OpenSearchDescription', nsmap={None: self.namespaces['os']}) etree.SubElement(node, 'ShortName').text = element.xpath('//ows:Title', namespaces=self.context.namespaces)[0].text etree.SubElement(node, 'LongName').text = element.xpath('//ows:Title', namespaces=self.context.namespaces)[0].text etree.SubElement(node, 'Description').text = element.xpath('//ows:Abstract', namespaces=self.context.namespaces)[0].text etree.SubElement(node, 'Tags').text = ' '.join(x.text for x in element.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', '%s?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?}' % element.xpath('//ows:Get/@xlink:href', namespaces=self.context.namespaces)[0]) 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 = element.xpath('//ows:IndividualName', namespaces=self.context.namespaces)[0].text etree.SubElement(node, 'Contact').text = element.xpath('//ows:ElectronicMailAddress', namespaces=self.context.namespaces)[0].text etree.SubElement(node, 'Attribution').text = element.xpath('//ows:ProviderName', namespaces=self.context.namespaces)[0].text elif util.xmltag_split(element.tag) == 'ExceptionReport': node = element else: # return Description document node = etree.Element(util.nspath_eval('os:Description', self.context.namespaces)) return node
def write_extent(bbox, nsmap): ''' Generate BBOX extent ''' if bbox is not None: try: bbox2 = util.wkt2geom(bbox, bounds=False) except: return None where = etree.Element(util.nspath_eval('georss:where', NAMESPACES)) polygon = etree.SubElement(where, util.nspath_eval('gml:Polygon', nsmap), srsName='urn:x-ogc:def:crs:EPSG:6.11:4326') exterior = etree.SubElement(polygon, util.nspath_eval('gml:exterior', nsmap)) lring = etree.SubElement(exterior, util.nspath_eval('gml:LinearRing', nsmap)) poslist = etree.SubElement(lring, util.nspath_eval('gml:posList', nsmap)).text = \ ' '.join(['%s %s' % (str(i[1]), str(i[0])) for i in list(bbox2.exterior.coords)]) return where return None
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'])) 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: etree.SubElement(node, util.nspath_eval('atom:author', 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)).text = 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 rlinks = util.getqattr(result, context.md_core_model['mappings']['pycsw:Links']) if rlinks: for link in rlinks.split('^'): linkset = link.split(',') url2 = etree.SubElement(node, util.nspath_eval('atom:link', NAMESPACES), href=linkset[-1], type=linkset[2], title=linkset[1]) 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']))) for qval in ['pycsw:PublicationDate', 'pycsw:AccessConstraints', 'pycsw:Source', 'pycsw:Abstract', 'pycsw:Title', 'pycsw:Modified']: 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
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
def write_extent(bbox, nsmap): ''' Generate BBOX extent ''' from shapely.wkt import loads if bbox is not None: if bbox.find('SRID') != -1: # it's EWKT; chop off 'SRID=\d+;' bbox2 = loads(bbox.split(';')[-1]) else: bbox2 = loads(bbox) where = etree.Element(util.nspath_eval('georss:where', NAMESPACES)) polygon = etree.SubElement(where, util.nspath_eval('gml:Polygon', nsmap), srsName='urn:x-ogc:def:crs:EPSG:6.11:4326') exterior = etree.SubElement(polygon, util.nspath_eval('gml:exterior', nsmap)) lring = etree.SubElement(exterior, util.nspath_eval('gml:LinearRing', nsmap)) poslist = etree.SubElement(lring, util.nspath_eval('gml:posList', nsmap)).text = \ ' '.join(['%s %s' % (str(i[1]), str(i[0])) for i in list(bbox2.exterior.coords)]) return where return None
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))
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)
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)
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)
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))
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', 'dif', 'schemas', 'dif', 'dif.xsd')).getroot() node.append(schema) return [node]
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])
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', 'atom', 'schemas', 'atom', 'atom.xsd')).getroot() node.append(schema) return [node]
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.find(util.nspath_eval('ows:Exception/ows:ExceptionText', self.context.namespaces)).text etree.SubElement(diagnostic, util.nspath_eval('zd:details', self.namespaces)).text = \ element.find(util.nspath_eval('ows:Exception', self.context.namespaces)).attrib.get('exceptionCode') return node
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", "fgdc", "schemas", "fgdc", "fgdc-std-001-1998.xsd" ) ).getroot() node.append(schema) return [node]
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.iteritems(): if v[1] == elname: value = k break el.text = value
def response_csw2opensearch(self, element, cfg): """transform a CSW response into an OpenSearch response""" if util.xmltag_split(element.tag) == 'GetRecordsResponse': startindex = int(element.xpath('//@nextRecord')[0]) - int( element.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 = cfg.get( 'server', 'url') etree.SubElement( node, util.nspath_eval('atom:title', self.context.namespaces)).text = cfg.get( 'metadata:main', 'identification_title') #etree.SubElement(node, util.nspath_eval('atom:updated', self.context.namespaces)).text = element.xpath('//@timestamp')[0] etree.SubElement( node, util.nspath_eval( 'opensearch:totalResults', self.context.namespaces)).text = element.xpath( '//@numberOfRecordsMatched')[0] etree.SubElement( node, util.nspath_eval( 'opensearch:startIndex', self.context.namespaces)).text = str(startindex) etree.SubElement( node, util.nspath_eval( 'opensearch:itemsPerPage', self.context.namespaces)).text = element.xpath( '//@numberOfRecordsReturned')[0] for rec in element.xpath('//atom:entry', namespaces=self.context.namespaces): node.append(rec) return node
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.iteritems(): if v[1] == elname: value = k break el.text = value
def kvp2filterxml(kvp, context): filter_xml = "" valid_xml = "" # Count parameters par_count = 0 for p in ['q','bbox','time']: if p in kvp: 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: 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)) try: el.text = "%s %s" % (bbox_list[0], bbox_list[1]) except Exception, 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, err: errortext = 'Exception: OpenSearch bbox not valid.\nError: %s.' % str(err) LOGGER.debug(errortext)
def response_csw2opensearch(self, element, cfg): """transform a CSW response into an OpenSearch response""" if util.xmltag_split(element.tag) == 'GetRecordsResponse': startindex = int(element.xpath('//@nextRecord')[0]) - int(element.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 = cfg.get('server', 'url') etree.SubElement(node, util.nspath_eval('atom:title', self.context.namespaces)).text = cfg.get('metadata:main', 'identification_title') #etree.SubElement(node, util.nspath_eval('atom:updated', self.context.namespaces)).text = element.xpath('//@timestamp')[0] etree.SubElement(node, util.nspath_eval('opensearch:totalResults', self.context.namespaces)).text = element.xpath('//@numberOfRecordsMatched')[0] etree.SubElement(node, util.nspath_eval('opensearch:startIndex', self.context.namespaces)).text = str(startindex) etree.SubElement(node, util.nspath_eval('opensearch:itemsPerPage', self.context.namespaces)).text = element.xpath('//@numberOfRecordsReturned')[0] for rec in element.xpath('//atom:entry', namespaces=self.context.namespaces): node.append(rec) return node
def response(self, response, kvp, repository, server_url): """process OAI-PMH request""" mode = kvp.pop('mode', None) if 'config' in kvp: config_val = kvp.pop('config') url = '%smode=oaipmh' % util.bind_url(server_url) node = etree.Element(util.nspath_eval('oai:OAI-PMH', self.namespaces), nsmap=self.namespaces) node.set( util.nspath_eval('xsi:schemaLocation', self.namespaces), '%s http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd' % self.namespaces['oai']) LOGGER.info(etree.tostring(node)) etree.SubElement(node, util.nspath_eval( 'oai:responseDate', self.namespaces)).text = util.get_today_and_now() etree.SubElement(node, util.nspath_eval('oai:request', self.namespaces), attrib=kvp).text = url if 'verb' not in kvp: etree.SubElement( node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = 'Missing \'verb\' parameter' return node if kvp['verb'] not in self.request_model.keys(): etree.SubElement( node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = 'Unknown verb \'%s\'' % kvp['verb'] return node if util.xmltag_split(response.tag) == 'ExceptionReport': etree.SubElement(node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = response.xpath( '//ows:ExceptionText', namespaces=self.context.namespaces)[0].text return node verb = kvp.pop('verb') if verb in ['GetRecord', 'ListIdentifiers', 'ListRecords']: if 'metadataprefix' not in kvp: etree.SubElement(node, util.nspath_eval('oai:error', self.namespaces), code='badArgument' ).text = 'Missing metadataPrefix parameter' return node elif kvp['metadataprefix'] not in self.metadata_formats.keys(): etree.SubElement(node, util.nspath_eval('oai:error', self.namespaces), code='badArgument' ).text = 'Invalid metadataPrefix parameter' return node for key, value in kvp.iteritems(): if key != 'mode' and key not in self.request_model[verb]: etree.SubElement( node, util.nspath_eval('oai:error', self.namespaces), code='badArgument').text = 'Illegal parameter \'%s\'' % key return node verbnode = etree.SubElement( node, util.nspath_eval('oai:%s' % verb, self.namespaces)) if verb == 'Identify': etree.SubElement( verbnode, util.nspath_eval('oai:repositoryName', self.namespaces)).text = self.config.get( 'metadata:main', 'identification_title') etree.SubElement(verbnode, util.nspath_eval('oai:baseURL', self.namespaces)).text = url etree.SubElement( verbnode, util.nspath_eval('oai:protocolVersion', self.namespaces)).text = '2.0' etree.SubElement( verbnode, util.nspath_eval('oai:adminEmail', self.namespaces)).text = self.config.get( 'metadata:main', 'contact_email') etree.SubElement( verbnode, util.nspath_eval( 'oai:earliestDatestamp', self.namespaces)).text = repository.query_insert('min') etree.SubElement( verbnode, util.nspath_eval('oai:deletedRecord', self.namespaces)).text = 'no' etree.SubElement( verbnode, util.nspath_eval( 'oai:granularity', self.namespaces)).text = 'YYYY-MM-DDThh:mm:ssZ' elif verb == 'ListSets': for key, value in self.metadata_sets.iteritems(): setnode = etree.SubElement( verbnode, util.nspath_eval('oai:set', self.namespaces)) etree.SubElement( setnode, util.nspath_eval('oai:setSpec', self.namespaces)).text = key etree.SubElement( setnode, util.nspath_eval('oai:setName', self.namespaces)).text = value[0] elif verb == 'ListMetadataFormats': for key, value in self.metadata_formats.iteritems(): mdfnode = etree.SubElement( verbnode, util.nspath_eval('oai:metadataFormat', self.namespaces)) etree.SubElement( mdfnode, util.nspath_eval('oai:metadataPrefix', self.namespaces)).text = key etree.SubElement( mdfnode, util.nspath_eval('oai:schema', self.namespaces)).text = value['schema'] etree.SubElement( mdfnode, util.nspath_eval( 'oai:metadataNamespace', self.namespaces)).text = value['namespace'] elif verb in ['GetRecord', 'ListIdentifiers', 'ListRecords']: if verb == 'GetRecord': # GetRecordById records = response.getchildren() else: # GetRecords records = response.getchildren()[1].getchildren() for child in records: recnode = etree.SubElement( verbnode, util.nspath_eval('oai:record', self.namespaces)) header = etree.SubElement( recnode, util.nspath_eval('oai:header', self.namespaces)) self._transform_element(header, response, 'oai:identifier') self._transform_element(header, response, 'oai:dateStamp') self._transform_element(header, response, 'oai:setSpec') if verb in ['GetRecord', 'ListRecords']: metadata = etree.SubElement( recnode, util.nspath_eval('oai:metadata', self.namespaces)) if 'metadataprefix' in kvp and kvp[ 'metadataprefix'] == 'oai_dc': child.tag = util.nspath_eval('oai_dc:dc', self.namespaces) metadata.append(child) if verb != 'GetRecord': complete_list_size = response.xpath( '//@numberOfRecordsMatched')[0] next_record = response.xpath('//@nextRecord')[0] cursor = str(int(complete_list_size) - int(next_record) - 1) resumption_token = etree.SubElement( verbnode, util.nspath_eval('oai:resumptionToken', self.namespaces), completeListSize=complete_list_size, cursor=cursor).text = next_record return node
def write_record(self, result, esn, outputschema, queryables): ''' Return csw:SearchResults child as lxml.etree.Element ''' typename = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Typename']) if (esn == 'full' and typename == 'gmd:MD_Metadata'): # dump record as is and exit return etree.fromstring(util.getqattr(result, self.context.md_core_model['mappings']['pycsw:XML'])) if typename == 'csw:Record': # transform csw:Record -> gmd:MD_Metadata model mappings util.transform_mappings(queryables, self.repository['mappings']['csw:Record']) node = etree.Element(util.nspath_eval('gmd:MD_Metadata', self.namespaces)) node.attrib[util.nspath_eval('xsi:schemaLocation', self.context.namespaces)] = \ '%s %s/csw/2.0.2/profiles/apiso/1.0.0/apiso.xsd' % (self.namespace, self.ogc_schemas_base) # identifier idval = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Identifier']) identifier = etree.SubElement(node, util.nspath_eval('gmd:fileIdentifier', self.namespaces)) etree.SubElement(identifier, util.nspath_eval('gco:CharacterString', self.namespaces)).text = idval if esn in ['summary', 'full']: # language val = util.getqattr(result, queryables['apiso:Language']['dbcol']) lang = etree.SubElement(node, util.nspath_eval('gmd:language', self.namespaces)) etree.SubElement(lang, util.nspath_eval('gco:CharacterString', self.namespaces)).text = val # hierarchyLevel mtype = util.getqattr(result, queryables['apiso:Type']['dbcol']) or None if mtype is not None: hierarchy = etree.SubElement(node, util.nspath_eval('gmd:hierarchyLevel', self.namespaces)) hierarchy.append(_write_codelist_element('gmd:MD_ScopeCode', mtype, self.namespaces)) if esn in ['summary', 'full']: # contact val = util.getqattr(result, queryables['apiso:OrganisationName']['dbcol']) contact = etree.SubElement(node, util.nspath_eval('gmd:contact', self.namespaces)) if val: CI_resp = etree.SubElement(contact, util.nspath_eval('gmd:CI_ResponsibleParty', self.namespaces)) org_name = etree.SubElement(CI_resp, util.nspath_eval('gmd:organisationName', self.namespaces)) etree.SubElement(org_name, util.nspath_eval('gco:CharacterString', self.namespaces)).text = val # date val = util.getqattr(result, queryables['apiso:Modified']['dbcol']) date = etree.SubElement(node, util.nspath_eval('gmd:dateStamp', self.namespaces)) if val and val.find('T') != -1: dateel = 'gco:DateTime' else: dateel = 'gco:Date' etree.SubElement(date, util.nspath_eval(dateel, self.namespaces)).text = val metadatastandardname = 'ISO19115' metadatastandardversion = '2003/Cor.1:2006' if mtype == 'service': metadatastandardname = 'ISO19119' metadatastandardversion = '2005/PDAM 1' # metadata standard name standard = etree.SubElement(node, util.nspath_eval('gmd:metadataStandardName', self.namespaces)) etree.SubElement(standard, util.nspath_eval('gco:CharacterString', self.namespaces)).text = metadatastandardname # metadata standard version standardver = etree.SubElement(node, util.nspath_eval('gmd:metadataStandardVersion', self.namespaces)) etree.SubElement(standardver, util.nspath_eval('gco:CharacterString', self.namespaces)).text = metadatastandardversion # title val = util.getqattr(result, queryables['apiso:Title']['dbcol']) or '' identification = etree.SubElement(node, util.nspath_eval('gmd:identificationInfo', self.namespaces)) if mtype == 'service': restagname = 'srv:SV_ServiceIdentification' else: restagname = 'gmd:MD_DataIdentification' resident = etree.SubElement(identification, util.nspath_eval(restagname, self.namespaces), id=idval) tmp2 = etree.SubElement(resident, util.nspath_eval('gmd:citation', self.namespaces)) tmp3 = etree.SubElement(tmp2, util.nspath_eval('gmd:CI_Citation', self.namespaces)) tmp4 = etree.SubElement(tmp3, util.nspath_eval('gmd:title', self.namespaces)) etree.SubElement(tmp4, util.nspath_eval('gco:CharacterString', self.namespaces)).text = val # creation date val = util.getqattr(result, queryables['apiso:CreationDate']['dbcol']) if val is not None: tmp3.append(_write_date(val, 'creation', self.namespaces)) # publication date val = util.getqattr(result, queryables['apiso:PublicationDate']['dbcol']) if val is not None: tmp3.append(_write_date(val, 'publication', self.namespaces)) # revision date val = util.getqattr(result, queryables['apiso:RevisionDate']['dbcol']) or util.getqattr(result, queryables['apiso:Modified']['dbcol']) if val is not None: tmp3.append(_write_date(val, 'revision', self.namespaces)) if esn in ['summary', 'full']: # abstract val = util.getqattr(result, queryables['apiso:Abstract']['dbcol']) or '' tmp = etree.SubElement(resident, util.nspath_eval('gmd:abstract', self.namespaces)) etree.SubElement(tmp, util.nspath_eval('gco:CharacterString', self.namespaces)).text = val # keywords kw = util.getqattr(result, queryables['apiso:Subject']['dbcol']) if kw is not None: md_keywords = etree.SubElement(resident, util.nspath_eval('gmd:descriptiveKeywords', self.namespaces)) md_keywords.append(write_keywords(kw, self.namespaces)) # spatial resolution val = util.getqattr(result, queryables['apiso:Denominator']['dbcol']) if val: tmp = etree.SubElement(resident, util.nspath_eval('gmd:spatialResolution', self.namespaces)) tmp2 = etree.SubElement(tmp, util.nspath_eval('gmd:MD_Resolution', self.namespaces)) tmp3 = etree.SubElement(tmp2, util.nspath_eval('gmd:equivalentScale', self.namespaces)) tmp4 = etree.SubElement(tmp3, util.nspath_eval('gmd:MD_RepresentativeFraction', self.namespaces)) tmp5 = etree.SubElement(tmp4, util.nspath_eval('gmd:denominator', self.namespaces)) etree.SubElement(tmp5, util.nspath_eval('gco:Integer', self.namespaces)).text = str(val) # resource language val = util.getqattr(result, queryables['apiso:ResourceLanguage']['dbcol']) tmp = etree.SubElement(resident, util.nspath_eval('gmd:language', self.namespaces)) etree.SubElement(tmp, util.nspath_eval('gco:CharacterString', self.namespaces)).text = val # topic category val = util.getqattr(result, queryables['apiso:TopicCategory']['dbcol']) if val: for v in val.split(','): tmp = etree.SubElement(resident, util.nspath_eval('gmd:topicCategory', self.namespaces)) etree.SubElement(tmp, util.nspath_eval('gmd:MD_TopicCategoryCode', self.namespaces)).text = val # bbox extent val = util.getqattr(result, queryables['apiso:BoundingBox']['dbcol']) bboxel = write_extent(val, self.namespaces) if bboxel is not None and mtype != 'service': resident.append(bboxel) # service identification if mtype == 'service': # service type # service type version val = util.getqattr(result, queryables['apiso:ServiceType']['dbcol']) val2 = util.getqattr(result, queryables['apiso:ServiceTypeVersion']['dbcol']) if val is not None: tmp = etree.SubElement(resident, util.nspath_eval('srv:serviceType', self.namespaces)) etree.SubElement(tmp, util.nspath_eval('gco:LocalName', self.namespaces)).text = val tmp = etree.SubElement(resident, util.nspath_eval('srv:serviceTypeVersion', self.namespaces)) etree.SubElement(tmp, util.nspath_eval('gco:CharacterString', self.namespaces)).text = val2 kw = util.getqattr(result, queryables['apiso:Subject']['dbcol']) if kw is not None: srv_keywords = etree.SubElement(resident, util.nspath_eval('srv:keywords', self.namespaces)) srv_keywords.append(write_keywords(kw, self.namespaces)) if bboxel is not None: bboxel.tag = util.nspath_eval('srv:extent', self.namespaces) resident.append(bboxel) val = util.getqattr(result, queryables['apiso:CouplingType']['dbcol']) if val is not None: couplingtype = etree.SubElement(resident, util.nspath_eval('srv:couplingType', self.namespaces)) etree.SubElement(couplingtype, util.nspath_eval('srv:SV_CouplingType', self.namespaces), codeListValue=val, codeList='%s#SV_CouplingType' % CODELIST).text = val if esn in ['summary', 'full']: # all service resources as coupled resources coupledresources = util.getqattr(result, queryables['apiso:OperatesOn']['dbcol']) operations = util.getqattr(result, queryables['apiso:Operation']['dbcol']) if coupledresources: for val2 in coupledresources.split(','): coupledres = etree.SubElement(resident, util.nspath_eval('srv:coupledResource', self.namespaces)) svcoupledres = etree.SubElement(coupledres, util.nspath_eval('srv:SV_CoupledResource', self.namespaces)) opname = etree.SubElement(svcoupledres, util.nspath_eval('srv:operationName', self.namespaces)) etree.SubElement(opname, util.nspath_eval('gco:CharacterString', self.namespaces)).text = _get_resource_opname(operations) sid = etree.SubElement(svcoupledres, util.nspath_eval('srv:identifier', self.namespaces)) etree.SubElement(sid, util.nspath_eval('gco:CharacterString', self.namespaces)).text = val2 # service operations if operations: for i in operations.split(','): oper = etree.SubElement(resident, util.nspath_eval('srv:containsOperations', self.namespaces)) tmp = etree.SubElement(oper, util.nspath_eval('srv:SV_OperationMetadata', self.namespaces)) tmp2 = etree.SubElement(tmp, util.nspath_eval('srv:operationName', self.namespaces)) etree.SubElement(tmp2, util.nspath_eval('gco:CharacterString', self.namespaces)).text = i tmp3 = etree.SubElement(tmp, util.nspath_eval('srv:DCP', self.namespaces)) etree.SubElement(tmp3, util.nspath_eval('srv:DCPList', self.namespaces), codeList='%s#DCPList' % CODELIST, codeListValue='HTTPGet').text = 'HTTPGet' tmp4 = etree.SubElement(tmp, util.nspath_eval('srv:DCP', self.namespaces)) etree.SubElement(tmp4, util.nspath_eval('srv:DCPList', self.namespaces), codeList='%s#DCPList' % CODELIST, codeListValue='HTTPPost').text = 'HTTPPost' connectpoint = etree.SubElement(tmp, util.nspath_eval('srv:connectPoint', self.namespaces)) onlineres = etree.SubElement(connectpoint, util.nspath_eval('gmd:CI_OnlineResource', self.namespaces)) linkage = etree.SubElement(onlineres, util.nspath_eval('gmd:linkage', self.namespaces)) etree.SubElement(linkage, util.nspath_eval('gmd:URL', self.namespaces)).text = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Source']) # operates on resource(s) if coupledresources: for i in coupledresources.split(','): operates_on = etree.SubElement(resident, util.nspath_eval('srv:operatesOn', self.namespaces), uuidref=i) operates_on.attrib[util.nspath_eval('xlink:href', self.namespaces)] = '%sservice=CSW&version=2.0.2&request=GetRecordById&outputschema=http://www.isotc211.org/2005/gmd&id=%s-%s' % (util.bind_url(self.url), idval, i) rlinks = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Links']) if rlinks: distinfo = etree.SubElement(node, util.nspath_eval('gmd:distributionInfo', self.namespaces)) distinfo2 = etree.SubElement(distinfo, util.nspath_eval('gmd:MD_Distribution', self.namespaces)) transopts = etree.SubElement(distinfo2, util.nspath_eval('gmd:transferOptions', self.namespaces)) dtransopts = etree.SubElement(transopts, util.nspath_eval('gmd:MD_DigitalTransferOptions', self.namespaces)) for link in rlinks.split('^'): linkset = link.split(',') online = etree.SubElement(dtransopts, util.nspath_eval('gmd:onLine', self.namespaces)) online2 = etree.SubElement(online, util.nspath_eval('gmd:CI_OnlineResource', self.namespaces)) linkage = etree.SubElement(online2, util.nspath_eval('gmd:linkage', self.namespaces)) etree.SubElement(linkage, util.nspath_eval('gmd:URL', self.namespaces)).text = linkset[-1] protocol = etree.SubElement(online2, util.nspath_eval('gmd:protocol', self.namespaces)) etree.SubElement(protocol, util.nspath_eval('gco:CharacterString', self.namespaces)).text = linkset[2] name = etree.SubElement(online2, util.nspath_eval('gmd:name', self.namespaces)) etree.SubElement(name, util.nspath_eval('gco:CharacterString', self.namespaces)).text = linkset[0] desc = etree.SubElement(online2, util.nspath_eval('gmd:description', self.namespaces)) etree.SubElement(desc, util.nspath_eval('gco:CharacterString', self.namespaces)).text = linkset[1] return node
def write_extent(bbox, nsmap): ''' Generate BBOX extent ''' from shapely.wkt import loads if bbox is not None: extent = etree.Element(util.nspath_eval('gmd:extent', nsmap)) ex_extent = etree.SubElement(extent, util.nspath_eval('gmd:EX_Extent', nsmap)) ge = etree.SubElement(ex_extent, util.nspath_eval('gmd:geographicElement', nsmap)) gbb = etree.SubElement(ge, util.nspath_eval('gmd:EX_GeographicBoundingBox', nsmap)) west = etree.SubElement(gbb, util.nspath_eval('gmd:westBoundLongitude', nsmap)) east = etree.SubElement(gbb, util.nspath_eval('gmd:eastBoundLongitude', nsmap)) south = etree.SubElement(gbb, util.nspath_eval('gmd:southBoundLatitude', nsmap)) north = etree.SubElement(gbb, util.nspath_eval('gmd:northBoundLatitude', nsmap)) if bbox.find('SRID') != -1: # it's EWKT; chop off 'SRID=\d+;' bbox2 = loads(bbox.split(';')[-1]).envelope.bounds else: bbox2 = loads(bbox).envelope.bounds etree.SubElement(west, util.nspath_eval('gco:Decimal', nsmap)).text = str(bbox2[0]) etree.SubElement(south, util.nspath_eval('gco:Decimal', nsmap)).text = str(bbox2[1]) etree.SubElement(east, util.nspath_eval('gco:Decimal', nsmap)).text = str(bbox2[2]) etree.SubElement(north, util.nspath_eval('gco:Decimal', nsmap)).text = str(bbox2[3]) return extent return None
def write_record(self, result, esn, outputschema, queryables): ''' Return csw:SearchResults child as lxml.etree.Element ''' typename = util.getqattr( result, self.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, self.context.md_core_model['mappings']['pycsw:XML'])) if typename == 'csw:Record': # transform csw:Record -> atom:entry model mappings util.transform_mappings(queryables, self.repository['mappings']['csw:Record']) node = etree.Element(util.nspath_eval('atom:entry', self.namespaces)) node.attrib[util.nspath_eval('xsi:schemaLocation', self.context.namespaces)] = \ '%s %s?service=CSW&version=2.0.2&request=DescribeRecord&typename=atom:entry' % (self.namespaces['atom'], self.url) # author val = util.getqattr(result, queryables['atom:author']['dbcol']) if val: etree.SubElement( node, util.nspath_eval('atom:author', self.namespaces)).text = util.getqattr( result, queryables['atom:author']['dbcol']) # category val = util.getqattr(result, queryables['atom:category']['dbcol']) if val: for kw in val.split(','): etree.SubElement( node, util.nspath_eval('atom:category', self.namespaces)).text = kw for qval in ['contributor', 'id']: val = util.getqattr(result, queryables['atom:%s' % qval]['dbcol']) if val: etree.SubElement( node, util.nspath_eval('atom:%s' % qval, self.namespaces)).text = util.getqattr( result, queryables['atom:%s' % qval]['dbcol']) rlinks = util.getqattr( result, self.context.md_core_model['mappings']['pycsw:Links']) if rlinks: for link in rlinks.split('^'): linkset = link.split(',') url2 = etree.SubElement(node, util.nspath_eval( 'atom:link', self.namespaces), href=linkset[-1], type=linkset[2], title=linkset[1]) etree.SubElement( node, util.nspath_eval('atom:link', self.namespaces), href='%s?service=CSW&version=2.0.2&request=GetRepositoryItem&id=%s' % (self.url, util.getqattr(result, queryables['atom:id']['dbcol']))) for qval in [ 'published', 'rights', 'source', 'summary', 'title', 'updated' ]: val = util.getqattr(result, queryables['atom:%s' % qval]['dbcol']) if val: etree.SubElement( node, util.nspath_eval('atom:%s' % qval, self.namespaces)).text = util.getqattr( result, queryables['atom:%s' % qval]['dbcol']) # bbox extent val = util.getqattr(result, queryables['georss:where']['dbcol']) bboxel = write_extent(val, self.context.namespaces) if bboxel is not None: node.append(bboxel) return node
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'])) 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
def write_record(self, result, esn, outputschema, queryables): ''' Return csw:SearchResults child as lxml.etree.Element ''' identifier = util.getqattr( result, self.context.md_core_model['mappings']['pycsw:Identifier']) typename = util.getqattr( result, self.context.md_core_model['mappings']['pycsw:Typename']) if esn == 'full' and typename == 'rim:RegistryObject': # dump record as is and exit return etree.fromstring( util.getqattr(result, queryables['pycsw:XML']['dbcol'])) if typename == 'csw:Record': # transform csw:Record -> rim:RegistryObject model mappings util.transform_mappings(queryables, self.repository['mappings']['csw:Record']) node = etree.Element( util.nspath_eval('rim:ExtrinsicObject', self.namespaces)) node.attrib[util.nspath_eval('xsi:schemaLocation', self.context.namespaces)] = \ '%s %s/csw/2.0.2/profiles/ebrim/1.0/csw-ebrim.xsd' % (self.namespaces['wrs'], self.ogc_schemas_base) node.attrib['id'] = identifier node.attrib['lid'] = identifier node.attrib['objectType'] = str( util.getqattr( result, self.context.md_core_model['mappings']['pycsw:Type'])) node.attrib[ 'status'] = 'urn:oasis:names:tc:ebxml-regrep:StatusType:Submitted' etree.SubElement(node, util.nspath_eval('rim:VersionInfo', self.namespaces), versionName='') if esn == 'summary': etree.SubElement(node, util.nspath_eval('rim:ExternalIdentifier', self.namespaces), value=identifier, identificationScheme='foo', registryObject=str( util.getqattr( result, self.context.md_core_model['mappings'] ['pycsw:Relation'])), id=identifier) name = etree.SubElement( node, util.nspath_eval('rim:Name', self.namespaces)) etree.SubElement( name, util.nspath_eval('rim:LocalizedString', self.namespaces), value=unicode( util.getqattr(result, queryables['pycsw:Title']['dbcol']))) description = etree.SubElement( node, util.nspath_eval('rim:Description', self.namespaces)) etree.SubElement(description, util.nspath_eval('rim:LocalizedString', self.namespaces), value=unicode( util.getqattr( result, queryables['pycsw:Abstract']['dbcol']))) val = util.getqattr( result, self.context.md_core_model['mappings']['pycsw:BoundingBox']) bboxel = server.write_boundingbox(val) if bboxel is not None: bboxslot = etree.SubElement( node, util.nspath_eval('rim:Slot', self.namespaces), slotType='urn:ogc:def:dataType:ISO-19107:2003:GM_Envelope') valuelist = etree.SubElement( bboxslot, util.nspath_eval('rim:ValueList', self.namespaces)) value = etree.SubElement( valuelist, util.nspath_eval('rim:Value', self.namespaces)) value.append(bboxel) rkeywords = util.getqattr( result, self.context.md_core_model['mappings']['pycsw:Keywords']) if rkeywords is not None: subjectslot = etree.SubElement( node, util.nspath_eval('rim:Slot', self.namespaces), name='http://purl.org/dc/elements/1.1/subject') valuelist = etree.SubElement( subjectslot, util.nspath_eval('rim:ValueList', self.namespaces)) for keyword in rkeywords.split(','): etree.SubElement( valuelist, util.nspath_eval('rim:Value', self.namespaces)).text = keyword return node
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, 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, 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)): 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')
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 = gml.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 response_csw2sru(self, element, environ): """transform a CSW response into an SRU response""" if util.xmltag_split(element.tag) == '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', 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', 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 self.mappings['csw:Record']['index'].iteritems(): 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 util.xmltag_split(element.tag) == '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 util.xmltag_split(element.tag) == 'ExceptionReport': node = self.exceptionreport2diagnostic(element) return node
def kvp2filterxml(kvp, context): filter_xml = "" valid_xml = "" # Count parameters par_count = 0 for p in ['q','bbox','time']: if p in kvp: 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: 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)) 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: 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 = kvp['q'] anytext_element.append(el) # time to FilterXML if 'time' in kvp: time_list = kvp['time'].split("/") time_element = None if (len(time_list) == 2): # This is a normal request if '' not in time_list: # 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: # One of two is empty if 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 == 1): # Only one OpenSearch parameter exists if 'bbox' in kvp: root.append(bbox_element) elif 'time' in kvp: root.append(time_element) elif 'q' in kvp: root.append(anytext_element) elif (par_count > 1): # Since more than 1 parameter, append the AND logical operator logical_and = etree.Element(util.nspath_eval('ogc:And', context.namespaces)) if 'bbox' in kvp: logical_and.append(bbox_element) if 'time' in kvp: logical_and.append(time_element) if 'q' in kvp: logical_and.append(anytext_element) root.append(logical_and) # Render etree to string XML return etree.tostring(root)
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'])) 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
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 == 'dif:DIF': # dump record as is and exit return etree.fromstring( util.getqattr(result, context.md_core_model['mappings']['pycsw:XML'])) node = etree.Element(util.nspath_eval('dif:DIF', NAMESPACES)) node.attrib[util.nspath_eval('xsi:schemaLocation', context.namespaces)] = \ '%s http://gcmd.gsfc.nasa.gov/Aboutus/xml/dif/dif.xsd' % NAMESPACE # identifier etree.SubElement(node, util.nspath_eval( 'dif:Entry_ID', NAMESPACES)).text = util.getqattr( result, context.md_core_model['mappings']['pycsw:Identifier']) # title val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Title']) if not val: val = '' etree.SubElement(node, util.nspath_eval('dif:Entry_Title', NAMESPACES)).text = val # citation citation = etree.SubElement( node, util.nspath_eval('dif:Data_Set_Citation', NAMESPACES)) # creator val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Creator']) etree.SubElement(citation, util.nspath_eval('dif:Dataset_Creator', NAMESPACES)).text = val # date val = util.getqattr( result, context.md_core_model['mappings']['pycsw:PublicationDate']) etree.SubElement(citation, util.nspath_eval('dif:Dataset_Release_Date', NAMESPACES)).text = val # publisher val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Publisher']) etree.SubElement(citation, util.nspath_eval('dif:Dataset_Publisher', NAMESPACES)).text = val # format val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Format']) etree.SubElement( citation, util.nspath_eval('dif:Data_Presentation_Form', NAMESPACES)).text = val # iso topic category val = util.getqattr( result, context.md_core_model['mappings']['pycsw:TopicCategory']) etree.SubElement(node, util.nspath_eval('dif:ISO_Topic_Category', NAMESPACES)).text = val # keywords val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Keywords']) if val: for kw in val.split(','): etree.SubElement(node, util.nspath_eval('dif:Keyword', NAMESPACES)).text = kw # temporal temporal = etree.SubElement( node, util.nspath_eval('dif:Temporal_Coverage', NAMESPACES)) val = util.getqattr( result, context.md_core_model['mappings']['pycsw:TempExtent_begin']) val2 = util.getqattr( result, context.md_core_model['mappings']['pycsw:TempExtent_end']) etree.SubElement(temporal, util.nspath_eval('dif:Start_Date', NAMESPACES)).text = val etree.SubElement(temporal, util.nspath_eval('dif:End_Date', NAMESPACES)).text = val2 # bbox extent val = util.getqattr(result, context.md_core_model['mappings']['pycsw:BoundingBox']) bboxel = write_extent(val, NAMESPACES) if bboxel is not None: node.append(bboxel) # access constraints val = util.getqattr( result, context.md_core_model['mappings']['pycsw:AccessConstraints']) etree.SubElement(node, util.nspath_eval('dif:Access_Constraints', NAMESPACES)).text = val # language val = util.getqattr( result, context.md_core_model['mappings']['pycsw:ResourceLanguage']) etree.SubElement(node, util.nspath_eval('dif:Data_Set_Language', NAMESPACES)).text = val # contributor val = util.getqattr( result, context.md_core_model['mappings']['pycsw:OrganizationName']) etree.SubElement(node, util.nspath_eval('dif:Originating_Center', NAMESPACES)).text = val # abstract val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Abstract']) if not val: val = '' etree.SubElement(node, util.nspath_eval('dif:Summary', NAMESPACES)).text = val # date val = util.getqattr( result, context.md_core_model['mappings']['pycsw:CreationDate']) etree.SubElement(node, util.nspath_eval('dif:DIF_Creation_Date', NAMESPACES)).text = val # URL val = util.getqattr(result, context.md_core_model['mappings']['pycsw:Relation']) url = etree.SubElement(node, util.nspath_eval('dif:Related_URL', NAMESPACES)) etree.SubElement(url, util.nspath_eval('dif:URL', NAMESPACES)).text = val rlinks = util.getqattr(result, context.md_core_model['mappings']['pycsw:Links']) if rlinks: for link in rlinks.split('^'): linkset = link.split(',') url2 = etree.SubElement( node, util.nspath_eval('dif:Related_URL', NAMESPACES)) urltype = etree.SubElement( url2, util.nspath_eval('dif:URL_Content_Type', NAMESPACES)) etree.SubElement(urltype, util.nspath_eval('dif:Type', NAMESPACES)).text = linkset[2] etree.SubElement(url2, util.nspath_eval('dif:URL', NAMESPACES)).text = linkset[-1] etree.SubElement(url2, util.nspath_eval('dif:Description', NAMESPACES)).text = linkset[1] etree.SubElement(node, util.nspath_eval('dif:Metadata_Name', NAMESPACES)).text = 'CEOS IDN DIF' etree.SubElement(node, util.nspath_eval('dif:Metadata_Version', NAMESPACES)).text = '9.7' return node
def write_record(self, result, esn, outputschema, queryables): ''' Return csw:SearchResults child as lxml.etree.Element ''' identifier = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Identifier']) typename = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Typename']) if esn == 'full' and typename == 'rim:RegistryObject': # dump record as is and exit return etree.fromstring(util.getqattr(result, queryables['pycsw:XML']['dbcol'])) if typename == 'csw:Record': # transform csw:Record -> rim:RegistryObject model mappings util.transform_mappings(queryables, self.repository['mappings']['csw:Record']) node = etree.Element(util.nspath_eval('rim:ExtrinsicObject', self.namespaces)) node.attrib[util.nspath_eval('xsi:schemaLocation', self.context.namespaces)] = \ '%s %s/csw/2.0.2/profiles/ebrim/1.0/csw-ebrim.xsd' % (self.namespaces['wrs'], self.ogc_schemas_base) node.attrib['id'] = identifier node.attrib['lid'] = identifier node.attrib['objectType'] = str(util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Type'])) node.attrib['status'] = 'urn:oasis:names:tc:ebxml-regrep:StatusType:Submitted' etree.SubElement(node, util.nspath_eval('rim:VersionInfo', self.namespaces), versionName='') if esn == 'summary': etree.SubElement(node, util.nspath_eval('rim:ExternalIdentifier', self.namespaces), value=identifier, identificationScheme='foo', registryObject=str(util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Relation'])), id=identifier) name = etree.SubElement(node, util.nspath_eval('rim:Name', self.namespaces)) etree.SubElement(name, util.nspath_eval('rim:LocalizedString', self.namespaces), value=unicode(util.getqattr(result, queryables['pycsw:Title']['dbcol']))) description = etree.SubElement(node, util.nspath_eval('rim:Description', self.namespaces)) etree.SubElement(description, util.nspath_eval('rim:LocalizedString', self.namespaces), value=unicode(util.getqattr(result, queryables['pycsw:Abstract']['dbcol']))) val = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:BoundingBox']) bboxel = server.write_boundingbox(val) if bboxel is not None: bboxslot = etree.SubElement(node, util.nspath_eval('rim:Slot', self.namespaces), slotType='urn:ogc:def:dataType:ISO-19107:2003:GM_Envelope') valuelist = etree.SubElement(bboxslot, util.nspath_eval('rim:ValueList', self.namespaces)) value = etree.SubElement(valuelist, util.nspath_eval('rim:Value', self.namespaces)) value.append(bboxel) rkeywords = util.getqattr(result, self.context.md_core_model['mappings']['pycsw:Keywords']) if rkeywords is not None: subjectslot = etree.SubElement(node, util.nspath_eval('rim:Slot', self.namespaces), name='http://purl.org/dc/elements/1.1/subject') valuelist = etree.SubElement(subjectslot, util.nspath_eval('rim:ValueList', self.namespaces)) for keyword in rkeywords.split(','): etree.SubElement(valuelist, util.nspath_eval('rim:Value', self.namespaces)).text = keyword return node