Source code for landsgemeinde.views.opendata_swiss

from io import BytesIO
from onegov.core.security import Public
from onegov.landsgemeinde import _
from onegov.landsgemeinde import LandsgemeindeApp
from onegov.landsgemeinde.layouts import DefaultLayout
from onegov.landsgemeinde.models import Assembly
from onegov.org.models import Organisation
from sedate import as_datetime
from webob.exc import HTTPNotImplemented
from xml.etree.ElementTree import Element
from xml.etree.ElementTree import ElementTree
from xml.etree.ElementTree import SubElement


from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from onegov.landsgemeinde.request import LandsgemeindeRequest
    from webob.response import Response


[docs] def sub( parent: Element, tag: str, attrib: dict[str, str] | None = None, text: str | None = None ) -> Element: element = SubElement(parent, tag, attrib=attrib or {}) element.text = text or '' return element
@LandsgemeindeApp.view( model=Organisation, name='catalog.rdf', permission=Public )
[docs] def view_rdf( self: Organisation, request: 'LandsgemeindeRequest' ) -> bytes: """ Returns an XML / RDF / DCAT-AP for Switzerland format for opendata.swiss. See https://handbook.opendata.swiss/de/content/glossar/bibliothek/ dcat-ap-ch.html and https://dcat-ap.ch/ for more information. """ publisher_mail = self.ogd_publisher_mail publisher_id = self.ogd_publisher_id publisher_name = self.ogd_publisher_name if not publisher_id or not publisher_name or not publisher_mail: raise HTTPNotImplemented() @request.after def set_headers(response: 'Response') -> None: response.headers['Content-Type'] = 'application/rdf+xml; charset=UTF-8' layout = DefaultLayout(self, request) rdf = Element('rdf:RDF', attrib={ 'xmlns:dct': 'http://purl.org/dc/terms/', 'xmlns:dc': 'http://purl.org/dc/elements/1.1/', 'xmlns:dcat': 'http://www.w3.org/ns/dcat#', 'xmlns:foaf': 'http://xmlns.com/foaf/0.1/', 'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema#', 'xmlns:rdfs': 'http://www.w3.org/2000/01/rdf-schema#', 'xmlns:rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'xmlns:vcard': 'http://www.w3.org/2006/vcard/ns#', 'xmlns:odrs': 'http://schema.theodi.org/odrs#', 'xmlns:schema': 'http://schema.org/', }) catalog = sub(rdf, 'dcat:Catalog') session = request.session items = session.query(Assembly).all() for item in sorted(items, key=lambda i: i.date, reverse=True): if item.state != 'completed': continue # IDs item_id = f'landsgemeinde-{item.date}' ds = sub(catalog, 'dcat:dataset') ds = sub(ds, 'dcat:Dataset', { 'rdf:about': f'https://{publisher_id}/{item_id}' }) sub(ds, 'dct:identifier', {}, f'{item_id}@{publisher_id}') # Dates sub( ds, 'dct:issued', {'rdf:datatype': 'http://www.w3.org/2001/XMLSchema#dateTime'}, as_datetime(item.date).isoformat() ) last_modified = item.last_modified or as_datetime(item.date) sub( ds, 'dct:modified', {'rdf:datatype': 'http://www.w3.org/2001/XMLSchema#dateTime'}, last_modified.replace(microsecond=0).isoformat() ) sub( ds, 'dct:accrualPeriodicity', {'rdf:resource': 'http://publications.europa.eu/resource/' 'authority/frequency/IRREG'} ) # Theme sub( ds, 'dcat:theme', {'rdf:resource': 'http://publications.europa.eu/resource/' 'authority/data-theme/GOVE'} ) # Landing page sub(ds, 'dcat:landingPage', {'rdf:resource': request.link(item)}) # Keywords keyword = request.translate(_('Assembly')) sub(ds, 'dcat:keyword', {'xml:lang': 'de'}, keyword) # Title title = request.translate(layout.assembly_title(item)) sub(ds, 'dct:title', {'xml:lang': 'de'}, title) # Description description = request.translate(_( 'Results from the ${title}, structured as json', mapping={'title': title} )) sub(ds, 'dct:description', {'xml:lang': 'de'}, description) # Format description # label = request.translate(_("Format Description")) # url = request.link(self, 'open-data') # fmt_des = sub(ds, 'dct:relation') # fmt_des = sub(fmt_des, 'rdf:Description', {'rdf:about': url}) # sub(fmt_des, 'rdfs:label', {}, label) # Publisher pub = sub(ds, 'dct:publisher') pub = sub(pub, 'foaf:Organization', { 'rdf:about': f'https://{publisher_id}' }) sub(pub, 'foaf:name', {}, publisher_name) # Contact point mail = sub(ds, 'dcat:contactPoint') mail = sub(mail, 'vcard:Organization') sub(mail, 'vcard:fn', {}, publisher_name) sub(mail, 'vcard:hasEmail', { 'rdf:resource': 'mailto:{}'.format(publisher_mail) }) # Date date = sub(ds, 'dct:temporal') date = sub(date, 'dct:PeriodOfTime') sub( date, 'schema:startDate', {'rdf:datatype': 'http://www.w3.org/2001/XMLSchema#date'}, item.date.isoformat() ) sub( date, 'schema:endDate', {'rdf:datatype': 'http://www.w3.org/2001/XMLSchema#date'}, item.date.isoformat() ) # Distribution dist = sub(ds, 'dcat:distribution') dist = sub(dist, 'dcat:Distribution', { 'rdf:about': f'http://{publisher_id}/{item_id}/json' }) sub( dist, 'dct:issued', {'rdf:datatype': 'http://www.w3.org/2001/XMLSchema#dateTime'}, item.created.replace(microsecond=0).isoformat() ) sub( dist, 'dct:modified', {'rdf:datatype': 'http://www.w3.org/2001/XMLSchema#dateTime'}, last_modified.replace(microsecond=0).isoformat() ) url = request.link(item, 'json') sub(dist, 'dcat:accessURL', {'rdf:resource': url}) sub(dist, 'dcat:downloadURL', {'rdf:resource': url}) sub( dist, 'dct:license', { 'rdf:resource': 'http://dcat-ap.ch/vocabulary/licenses/terms_by' }) sub(dist, 'dcat:mediaType', { 'rdf:resource': 'https://www.iana.org/assignments/media-types/' 'application/json' }) sub(dist, 'dcat:format', { 'rdf:resource': 'http://publications.europa.eu/resource/' 'authority/file-type/JSON' }) out = BytesIO() ElementTree(rdf).write(out, encoding='utf-8', xml_declaration=True) return out.getvalue()