Zum Inhalt

CSW Schnittstelle

Allgemeines

Offizielle Dokumentation

Weiterführende Informationen zu Installation und Konfiguration finden sich in der offiziellen pycsw-Dokumentation.

Die CSW-Schnittstelle stellt Metadaten im InGrid-System über den OGC CSW 2.0.2 AP ISO 1.0-Standard bereit und eignet sich als eigenständiger Metadatenkatalog innerhalb einer InGrid-Infrastruktur. Umgesetzt wird sie mit pycsw, einem quelloffenen CSW-Server auf Python-Basis.

In der InGrid-Umgebung dient pycsw als zentrales Katalog-Ziel für einliefernde Komponenten (Editor, Harvester) und stellt Metadaten via CSW-Schnittstelle für abfragende Komponenten wie das Portal bereit.


Systemvoraussetzungen

Systembestandteil Anforderung
Software PostgreSQL 15 oder höher (via Docker)

Installation

Docker

Für den Betrieb wird eine PostgreSQL-Datenbank empfohlen.

Beispiel docker-compose.yml
services:

    pycsw:
    image: geopython/pycsw
    restart: unless-stopped
    environment:
        - PYCSW_CONFIG=/etc/pycsw/pycsw.yml
    volumes:
        - ./pycsw/pycsw.yml:/etc/pycsw/pycsw.yml
    ports:
        - "8000:8000"
    depends_on:
        pycsw-db:
        condition: service_healthy
    networks:
        - ingrid-network

    pycsw-db:
    image: postgres:15
    restart: unless-stopped
    environment:
        - POSTGRES_DB=pycsw
        - POSTGRES_USER=pycsw
        - POSTGRES_PASSWORD=pycsw
    volumes:
        - pycsw-data:/var/lib/postgresql/data
    networks:
        - ingrid-network

volumes:
    pycsw-data:

networks:
    ingrid-network:

Konfiguration

pycsw wird über eine YAML-Konfigurationsdatei (pycsw.yml) konfiguriert. Eine vollständige Referenz aller Parameter ist in der offiziellen Konfigurationsdokumentation verfügbar.

Beispiel pycsw.yml
server:
  url: http://<host>:8000
  mimetype: application/xml; charset=UTF-8
  encoding: UTF-8
  language: de
  maxrecords: 10
  pretty_print: true

manager:
  transactions: "true"
  allowed_ips: 127.0.0.1,<IP-Adresse-Editor>,<IP-Adresse-Harvester>

metadata:
  identification:
    title: Mein Metadatenkatalog
    description: OGC CSW-Katalog auf Basis von pycsw
    keywords:
      - pycsw
      - Metadaten
      - CSW
    keywords_type: theme
    fees: None
    accessconstraints: None
  provider:
    name: Meine Organisation
    url: https://www.meine-organisation.de
  contact:
    name: Kontaktname
    position: Datenmanagement
    email: kontakt@meine-organisation.de
    role: pointOfContact

repository:
  database: postgresql://pycsw:pycsw@pycsw-db/pycsw
  table: records

Die wichtigsten Einstellungen im Überblick:

Einstellung Beschreibung Dokumentation
server.url Öffentliche URL des CSW-Endpunkts server
server.maxrecords Maximale Anzahl zurückgegebener Datensätze pro Anfrage server
manager.transactions CSW-T aktivieren (true/false) manager
manager.allowed_ips IP-Adressen mit Schreibzugriff (CSW-T) manager
repository.database Datenbankverbindung (PostgreSQL oder SQLite) repository
repository.table Tabellenname im Datenbankschema repository

CSW-T Sicherheit

CSW-T ermöglicht das Schreiben, Aktualisieren und Löschen von Metadatensätzen. Stellen Sie sicher, dass unter manager.allowed_ips ausschließlich autorisierte IP-Adressen eingetragen sind.

Authentifizierung

pycsw bietet keine eingebaute Benutzerauthentifizierung. Die Absicherung erfolgt auf zwei Ebenen:

  • CSW-T (Schreibzugriff): Über manager.allowed_ips werden nur explizit erlaubte IP-Adressen zum Schreiben zugelassen.
  • CSW (Lesezugriff): Für einen komplett nicht-öffentlichen Katalog empfiehlt sich ein vorgeschalteter Reverse Proxy mit HTTP Basic Auth.

Info

Basic Auth schützt alle Anfragen – GET und POST gleichermaßen. Eine Einschränkung auf nur schreibende Methoden ist nicht möglich, da CSW-Lese- und Schreiboperationen beide per POST übertragen werden und sich auf HTTP-Ebene nicht unterscheiden lassen.

Reverse Proxy mit HTTP Basic Auth (Apache)

Eine Passwortdatei kann mit htpasswd erstellt werden:

htpasswd -c /etc/apache2/.htpasswd <benutzername>

Beispielkonfiguration für Apache:

<VirtualHost *:80>
    ServerName <pycsw-host>

    ProxyPass        / http://pycsw:8000/
    ProxyPassReverse / http://pycsw:8000/

    <Location />
        AuthType Basic
        AuthName "CSW Katalog"
        AuthUserFile /etc/apache2/.htpasswd
        Require valid-user
    </Location>
</VirtualHost>

Erforderliche Apache-Module:

a2enmod proxy proxy_http auth_basic authn_file

Info

Einliefernde Komponenten (Editor, Harvester) müssen bei aktivierter Basic Auth die Credentials in ihrer Verbindungskonfiguration hinterlegen.

Response Transformation

TODO

InGrid Editor

Der InGrid Editor kann Metadatensätze via CSW-T direkt in pycsw einliefern. Damit der Editor gegen pycsw publizieren kann, müssen folgende Voraussetzungen erfüllt sein:

  1. In pycsw ist die CSW-T-Transaktion aktiviert (manager.transactions: "true")
  2. Die IP-Adresse des Editors ist unter manager.allowed_ips eingetragen
  3. Im Editor ist die Export-Konfiguration auf den pycsw-Endpunkt gesetzt

Der CSW-T-Endpunkt von pycsw ist erreichbar unter:

http://<pycsw-host>:<port>

Ein Beispiel-Request für das Einfügen eines Datensatzes:

curl --location 'http://<pycsw-host>' \
  --header 'Content-Type: application/xml' \
  --data-raw '<?xml version="1.0" encoding="UTF-8"?>
<csw:Transaction service="CSW" version="2.0.2"
    xmlns:csw="http://www.opengis.net/cat/csw/2.0.2"
    xmlns:gmd="http://www.isotc211.org/2005/gmd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-publication.xsd">
    <csw:Insert>
        <!-- vollständiges ISO 19139 Metadatendokument -->
    </csw:Insert>
</csw:Transaction>'

InGrid Harvester

Der InGrid Harvester kann pycsw als CSW-Katalogziel verwenden. Dabei werden geerntete Metadaten per CSW-T an pycsw übertragen.

Einrichtung in der Harvester-Konfiguration:

  1. In der Harvester-Oberfläche eine neue Katalog-Verbindung vom Typ CSW anlegen
  2. Als Endpunkt den pycsw-Endpunkt eintragen: http://<pycsw-host>:<port>
  3. Sicherstellen, dass die IP-Adresse des Harvesters in manager.allowed_ips von pycsw eingetragen ist

Info

Weitere Informationen zur Einrichtung von Katalogzielen finden sich im Leitfaden Harvester-Katalog.

InGrid Portal

Das InGrid Portal kann Metadaten über die CSW-Schnittstelle von pycsw abfragen und zur Darstellung aufbereiten.

Die CSW-Abfrage-URL lautet:

http://<pycsw-host>:<port>

Diese URL wird in der Portal-Konfiguration als CSW-Endpunkt hinterlegt. Über die Umgebungsvariable INGRID_API verweist das Portal auf die InGrid API, die als Vermittler zwischen Portal und den angebundenen Datenquellen agiert.

Eine vollständige Übersicht aller Portal-Konfigurationsoptionen ist in der Portal-Dokumentation beschrieben.


FAQ

Ausgabeformat

Alle GetRecords- und GetRecordById-Beispiele verwenden ISO 19139 (http://www.isotc211.org/2005/gmd) als outputSchema. Dieses Format wird für den Austausch von Geodaten-Metadaten im InGrid-Kontext vorausgesetzt.

Grundlegende Abfragen

GetCapabilities: Wie kann die CSW-Schnittstelle getestet werden?

Der einfachste Smoke-Test ist ein GetCapabilities-Request. Er gibt die Fähigkeiten des Servers zurück und zeigt an, ob pycsw erreichbar ist.

Zum Testen eignen sich Tools wie Postman oder vergleichbare REST-Clients. Bei POST-Anfragen muss der Content-Type application/xml gesetzt werden.

GET

http://<pycsw-host>/csw?SERVICE=CSW&REQUEST=GetCapabilities&VERSION=2.0.2

POST XML

<?xml version="1.0" encoding="UTF-8"?>
<GetCapabilities xmlns="http://www.opengis.net/cat/csw/2.0.2"
    service="CSW" version="2.0.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.opengis.net/cat/csw/2.0.2" />
GetRecords: Wie werden alle Datensätze paginiert abgerufen?

Mit startPosition wird der Cursor verschoben, mit maxRecords die Seitengröße festgelegt. Der Antwortparameter numberOfRecordsMatched liefert die Gesamttrefferanzahl und dient als Abbruchbedingung.

GET

http://<pycsw-host>/csw?service=CSW&version=2.0.2&request=GetRecords&elementSetName=full&resultType=results&outputSchema=http://www.isotc211.org/2005/gmd&startPosition=1&maxRecords=10&typeNames=csw:Record

POST XML

<?xml version="1.0" encoding="UTF-8"?>
<csw:GetRecords xmlns:csw="http://www.opengis.net/cat/csw/2.0.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.opengis.net/cat/csw/2.0.2"
    service="CSW" version="2.0.2"
    resultType="results"
    outputFormat="application/xml"
    outputSchema="http://www.isotc211.org/2005/gmd"
    startPosition="1" maxRecords="10">
    <csw:Query typeNames="csw:Record">
        <csw:ElementSetName>full</csw:ElementSetName>
    </csw:Query>
</csw:GetRecords>
GetRecordById: Wie wird ein einzelner Datensatz per ID abgerufen?

GET

http://<pycsw-host>/csw?service=CSW&version=2.0.2&request=GetRecordById&outputSchema=http://www.isotc211.org/2005/gmd&elementSetName=full&id=<UUID>

POST XML

<?xml version="1.0" encoding="UTF-8"?>
<csw:GetRecordById xmlns:csw="http://www.opengis.net/cat/csw/2.0.2"
    service="CSW" version="2.0.2"
    outputSchema="http://www.isotc211.org/2005/gmd"
    elementSetName="full">
    <csw:Id><UUID></csw:Id>
</csw:GetRecordById>

Filterabfragen

GetRecords: Wie wird nach Partner gefiltert?

InGrid-spezifisch

Die Filterung nach Partner und Anbieter basiert auf einer InGrid-Konvention: Einliefernde Komponenten (Editor, Harvester) schreiben die Zugehörigkeit als strukturiertes Schlagwort in das Feld apiso:Subject. Diese Keywords sind kein Bestandteil des CSW- oder ISO-Standards.

In InGrid werden Partner als Schlagwort im Feld apiso:Subject mit dem Präfix organisation: gespeichert. Da das Feld die gesamte kommagetrennte Schlagwortliste enthält, muss PropertyIsLike für die Teilsuche verwendet werden – PropertyIsEqualTo würde den vollständigen Spalteninhalt auf exakte Übereinstimmung prüfen und damit keine Treffer liefern.

GET (CQL_TEXT)

http://<pycsw-host>/csw?service=CSW&version=2.0.2&request=GetRecords&elementSetName=full&resultType=results&outputSchema=http://www.isotc211.org/2005/gmd&startPosition=1&maxRecords=100&typeNames=csw:Record&constraint=apiso:Subject like '%organisation:bund%'&constraintLanguage=CQL_TEXT

POST XML (OGC Filter)

<csw:GetRecords xmlns:csw="http://www.opengis.net/cat/csw/2.0.2"
    xmlns:ogc="http://www.opengis.net/ogc"
    service="CSW" version="2.0.2"
    resultType="results"
    outputSchema="http://www.isotc211.org/2005/gmd">
    <csw:Query typeNames="csw:Record">
        <csw:ElementSetName>full</csw:ElementSetName>
        <csw:Constraint version="1.1.0">
            <ogc:Filter>
                <ogc:PropertyIsLike wildCard="%" singleChar="_" escapeChar="\">
                    <ogc:PropertyName>apiso:Subject</ogc:PropertyName>
                    <ogc:Literal>%organisation:bund%</ogc:Literal>
                </ogc:PropertyIsLike>
            </ogc:Filter>
        </csw:Constraint>
    </csw:Query>
</csw:GetRecords>
GetRecords: Wie wird nach Anbieter gefiltert?

Anbieter werden mit dem Präfix sub_organisation: als Schlagwort abgelegt. Das Abfragemuster ist identisch mit der Partnerabfrage:

GET (CQL_TEXT)

http://<pycsw-host>/csw?service=CSW&version=2.0.2&request=GetRecords&elementSetName=full&resultType=results&outputSchema=http://www.isotc211.org/2005/gmd&startPosition=1&maxRecords=100&typeNames=csw:Record&constraint=apiso:Subject like '%sub_organisation:ni%'&constraintLanguage=CQL_TEXT

POST XML (OGC Filter)

<csw:GetRecords xmlns:csw="http://www.opengis.net/cat/csw/2.0.2"
    xmlns:ogc="http://www.opengis.net/ogc"
    service="CSW" version="2.0.2"
    resultType="results"
    outputSchema="http://www.isotc211.org/2005/gmd">
    <csw:Query typeNames="csw:Record">
        <csw:ElementSetName>full</csw:ElementSetName>
        <csw:Constraint version="1.1.0">
            <ogc:Filter>
                <ogc:PropertyIsLike wildCard="%" singleChar="_" escapeChar="\">
                    <ogc:PropertyName>apiso:Subject</ogc:PropertyName>
                    <ogc:Literal>%sub_organisation:ni%</ogc:Literal>
                </ogc:PropertyIsLike>
            </ogc:Filter>
        </csw:Constraint>
    </csw:Query>
</csw:GetRecords>
GetRecords: Wie wird nach ResourceIdentifier gefiltert?

Um Datensätze einer bestimmten Datenquelle über ihren eindeutigen Ressourcenbezeichner abzufragen:

GET (CQL_TEXT)

http://<pycsw-host>/csw?service=CSW&version=2.0.2&request=GetRecords&elementSetName=full&resultType=results&outputSchema=http://www.isotc211.org/2005/gmd&startPosition=1&maxRecords=10&typeNames=csw:Record&constraint=apiso:ResourceIdentifier='7988c147-7523-45bb-8f18-7f39d0d20541'&constraintLanguage=CQL_TEXT

POST XML (OGC Filter)

<csw:GetRecords xmlns:csw="http://www.opengis.net/cat/csw/2.0.2"
    xmlns:ogc="http://www.opengis.net/ogc"
    service="CSW" version="2.0.2"
    resultType="results"
    outputSchema="http://www.isotc211.org/2005/gmd"
    startPosition="1" maxRecords="10">
    <csw:Query typeNames="csw:Record">
        <csw:ElementSetName>full</csw:ElementSetName>
        <csw:Constraint version="1.1.0">
            <ogc:Filter>
                <ogc:PropertyIsEqualTo>
                    <ogc:PropertyName>apiso:ResourceIdentifier</ogc:PropertyName>
                    <ogc:Literal>7988c147-7523-45bb-8f18-7f39d0d20541</ogc:Literal>
                </ogc:PropertyIsEqualTo>
            </ogc:Filter>
        </csw:Constraint>
    </csw:Query>
</csw:GetRecords>