30 August 2015

Wir sind momentan dabei im Kanton Solothurn die AVGBS einzuführen. In einem Pilotprojekt sollen verschiedene Geschäftsfälle durchgespielt werden. Dafür müssen in der amtlichen Vermessung die Grundstücke das Attribut «EGRIS_EGRID» führen. Im Grundbuch wird der EGRID bereits geführt. Eine Liste aller Grundstücke (inkl. EGRID) kann vom Grundbuch als CSV-Datei exportiert werden. Die Frage lautet also nun: Wie kommen die EGRID aus dem Grundbuch in die amtliche Vermessung beim Nachführungsgeometer?

Eine Variante ist das manuelle Abfüllen des EGRID im AV-Erfassungssystem. Bei fast 2000 Grundstücken in der Pilotgemeinde macht das wenig Spass, ist fehleranfällig und wird ewig dauern. Mmmmh, es geht hier doch um AVGBS. Warum erstellen wir nicht eine AVGBS-Datei, die der Nachführungsgeometer in seinem System einlesen kann? Gesagt, getan. Mit einem kleinen Groovy-Skript und ili2pg wird das TOPIC Eigentumsverhaeltnis mit der CLASS Grundstueck erstellt, abgefüllt und anschliessend in einer INTERLIS-Datei dem Nachführungsgeometer zur Verfügung gestellt. Dieser kann die INTERLIS-Datei einlesen und der EGRID wird den Grundstücken in seinem System zugewiesen.

Der komplette Prozess kann in vier Schritte unterteilt werden:

  1. Erstellen der INTERLIS-Modellstruktur in der Datenbank

  2. Importieren der CSV-Datei mit den EGRID in die Datenbank

  3. Abfüllen der in Schritt (1) erstellten Tabellen mit den benötigten Informationen

  4. Exportieren der INTERLIS-Datei

@Grapes([
   @GrabResolver(name='catais.org', root='http://www.catais.org/maven/repository/release/', m2Compatible='true'),
   @Grab('org.postgresql:postgresql:9.4-1201-jdbc41'),
   @Grab('ch.interlis:ili2c:4.5.12'),
   @Grab('ch.interlis:ili2pg:2.1.4'),
   @GrabConfig(systemClassLoader = true)
])

import ch.ehi.ili2db.base.Ili2db
import ch.ehi.ili2db.base.Ili2dbException
import ch.ehi.ili2db.gui.Config
import ch.ehi.ili2pg.converter.PostgisGeometryConverter
import ch.ehi.sqlgen.generator_impl.jdbc.GeneratorPostgresql
import groovy.sql.*

def csv = "/Users/stefan/tmp/gb_egridexport150730_2407.csv"
def numberOfCsvRows = 3717
def municipality = "oensingen"
def fosnr = 2407

def dbhost = "localhost"
def dbport = "5432"
def dbdatabase = "xanadu2"
def dbusr = "stefan"
def dbpwd = "ziegler12"
def dbschema = "av_egrid"
def modelName = "GB2AV"

def dburl = "jdbc:postgresql://${dbhost}:${dbport}/${dbdatabase}?user=${dbusr}&password=${dbpwd}"

/*
* 1. Create empty database tables with ili2db.
*/
def query = "DROP SCHEMA IF EXISTS ${Sql.expand(dbschema)} CASCADE;"
def sql = Sql.newInstance(dburl)
sql.execute(query)

def config = new Config()
config.setDbhost(dbhost)
config.setDbdatabase(dbdatabase)
config.setDbport(dbport)
config.setDbusr(dbusr)
config.setDbpwd(dbpwd)
config.setDbschema(dbschema)
config.setDburl(dburl)

config.setModels(modelName);
config.setModeldir("http://models.geo.admin.ch/");

config.setGeometryConverter(PostgisGeometryConverter.class.getName())
config.setDdlGenerator(GeneratorPostgresql.class.getName())
config.setJdbcDriver("org.postgresql.Driver")

config.setNameOptimization("topic")
config.setMaxSqlNameLength("60")
config.setSqlNull("enable");

config.setDefaultSrsAuthority("EPSG")
config.setDefaultSrsCode("21781")

Ili2db.runSchemaImport(config, "")

/*
* 2. Create foreign table from CSV.
*/
query = """\
DROP FOREIGN TABLE IF EXISTS ${Sql.expand(dbschema)}.${Sql.expand(municipality)};

CREATE FOREIGN TABLE ${Sql.expand(dbschema)}.${Sql.expand(municipality)}  (
 bfsnr integer,
 kreisnr integer,
 grundstuecknummer varchar,
 grundstuecknummerzusatz varchar,
 grundstuecknummer3 varchar,
 grundstuecknummer4 varchar,
 egrid varchar(14)
) SERVER file_fdw_server
OPTIONS (format 'csv', header 'true',
         filename '${Sql.expand(csv)}',
         delimiter ',', null '');
"""
sql.execute(query)

// Check number of rows in foreign table.
query = "SELECT count(*) FROM ${Sql.expand(dbschema)}.${Sql.expand(municipality)};"
assert sql.firstRow(query).count == numberOfCsvRows

/*
* 3. Assign EGRID values to cadastral data and insert data into ili2db tables.
*/
query = """\
DELETE FROM ${Sql.expand(dbschema)}.eigentumsverhaeltnis_grundstueck;
DELETE FROM ${Sql.expand(dbschema)}.gb2av_grundstuecknummer;

WITH av AS (
 SELECT g.ogc_fid as av_id, g.nbident, g.nummer as av_nummer, l.flaechenmass, l.geometrie, l.gem_bfs, l.lieferdatum
 FROM av_avdpool_ch.liegenschaften_grundstueck as g, av_avdpool_ch.liegenschaften_liegenschaft as l
 WHERE g.gem_bfs = ${Sql.expand(fosnr)}
 AND l.gem_bfs = ${Sql.expand(fosnr)}
 AND g.tid = l.liegenschaft_von
),
gb AS (
 SELECT row_number() OVER () as gb_id, bfsnr, grundstuecknummer as gb_nummer, egrid
 FROM ${Sql.expand(dbschema)}.${Sql.expand(municipality)}
 WHERE grundstuecknummerzusatz IS NULL
),
eigentumsverhaeltnis_grundstueck AS (
 INSERT INTO ${Sql.expand(dbschema)}.eigentumsverhaeltnis_grundstueck (t_id, art)
 SELECT gb_id, 0::integer as art
 FROM av, gb
 WHERE av.av_nummer = gb.gb_nummer
)
INSERT INTO ${Sql.expand(dbschema)}.gb2av_grundstuecknummer(t_id, t_seq, egrid, nummer, gb2aveigntmsvrhltnis_grundstueck_nummer)
SELECT (gb_id+1000000) as t_id, 0::integer as t_seq, gb.egrid, gb.gb_nummer, gb_id
FROM av, gb
WHERE av.av_nummer = gb.gb_nummer;
"""
sql.execute(query)

// Check if we were able to assign an EGRID to all Liegenschaften from cadastral
// survyeing. If this is true the number of objects in all three tables is equal.
query = "SELECT count(*) FROM av_avdpool_ch.liegenschaften_liegenschaft WHERE gem_bfs = ${Sql.expand(fosnr)};"
def numberOfLiegenschaften = sql.firstRow(query).count

query = "SELECT count(*) FROM ${Sql.expand(dbschema)}.eigentumsverhaeltnis_grundstueck;"
def numberOfEigentumsverhaeltnisGrundstueck = sql.firstRow(query).count

query = "SELECT count(*) FROM ${Sql.expand(dbschema)}.gb2av_grundstuecknummer;"
def numberOfGrundstuecknummer = sql.firstRow(query).count

assert numberOfLiegenschaften == numberOfEigentumsverhaeltnisGrundstueck
assert numberOfLiegenschaften == numberOfGrundstuecknummer

// Close database connection.
sql.connection.close()
sql.close()

/*
* 4. Export data to an INTERLIS/XTF file.
*/
config.setXtffile("/Users/stefan/tmp/egrid_${municipality}.xtf")
Ili2db.runExport(config, "")

Zeilen 34 - 61: Im ersten Schritt wird das Schema, in dem die INTERLIS-Modellstruktur angelegt wird, gelöscht (falls es existiert). Anschliessend werden mit ili2pg die leeren Tabellen in der Datenbank angelegt. Mehr Informationen zu den Konfigurationsparametern gibts hier.

Zeilen 66 - 86: Die Daten aus der CSV-Datei müssen in die Datenbank importiert werden, um anschliessend Abfragen durchführen zu können. Ein eleganter Weg die Daten zu importieren, ist die Verwendung eines Foreign Data Wrappers für Textdateien. Die Kenntnis über die Struktur (also die Spalten der CSV-Datei und das verwendete Trennzeichen) reicht, um mit einem CREATE FOREIGN TABLE die Daten zu "importieren". Mit assert wird geprüft, ob auch wirklich alles importiert wurde.

Zeilen 91 - 136: Anschliessend können mit SQL-Befehlen die AV-Daten mit den importierten Grundbuchdaten verknüpft werden und das gewünschte Ergebnis in die passenden Tabellen (aus Schritt 1) gespeichert werden. Verwendet werden Common Table Expressions. Somit fallen die x-fach verschachtelten Subqueries weg.

Aus dem TOPIC Eigentumsverhaeltnis interessiert eigentlich nur die CLASS Grundstueck. Die Klasse verwendet jedoch eine STRUCTURE, die in der relationalen Datenbank in einer weiteren Tabelle abgebildet wird. So müssen Daten in zwei Tabellen geschrieben werden.

Auch hier überprüfen wir wieder auf Vollständigkeit: In beiden Tabellen, in die wir Daten geschrieben haben, müssen genau gleich viele Objekte vorhanden sein, wie in der Ausgangstabelle (Liegenschaften der amtlichen Vermessung).

Die selbständigen und dauerenden Rechte fehlen in der Abfrage, können aber genau gleich behandelt werden.

Zeilen 141 - 142: Zu guter Letzt exportieren wird unsere Arbeit in eine INTERLIS/XTF-Datei.

Die Log-Informationen des Exportprozesses sehen schon mal gut aus:

ili2pg export log

Ein kurzer Blick in die INTERLIS/XTF-Datei zeigt das gewünschte Resultat:

egrid xtf

Posted by Stefan Ziegler. | INTERLIS , ili2pg , Java , Groovy , AVGBS