7 Anwendungsprogrammierung 7.1 Kopplung von SQL mit Programmiersprachen 7.2 Postgres und JDBC 7.3 Oracle Spatial und JDBC 7.4 Verarbeitung von GMLbasierten Daten 7.5 Funktionales Programmieren mit Polygonen 7.6 Zusammenfassung aus: [KGB04] Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 577 Anwendungsprogrammierung →“Kern-SQL” ist auch mit räumlichen Erweiterungen nicht berechnungsuniversell →zahlreiche Anwendungen (z.B. Formvereinfachungen) sind jedoch ohne Berechnungsuniversalität nicht oder nur sehr umständlich lösbar →für geometrische/räumliche Anwendungen ist Kopplung zwischen SQL und Programmiersprachen nötig Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 578 7.1 Kopplung von SQL mit Programmiersprachen →aktuelle SQL-Programmschnittstellen sind Einbettung Call-Schnittstelle →beide Schnittstellen müssen den “Impedance Mismatch” überbrücken (satzorien‐ tierte Programmiersprache vs. mengenorientierte Datenbanksprache) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 579 Kopplung von SQL mit Programmiersprachen →Einbettung (Embedded SQL) beide Sprachen (SQL und Programmiersprache) bleiben weitgehend unverändert SQL-Anweisungen werden durch Präfix gekennzeichnet (EXEC SQL) Bearbeitung durch Precompiler Variablen der Program‐ miersprache in SQL werden durch “:” gekennzeichnet SQL Communication Area enthält Statusinformationen über Ergebnis von SQL-Anweisung Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 580 Kopplung von SQL mit Programmiersprachen →alle SQL-DML-Anweisungen können eingebettet werden, außerdem noch Deklarations-Anweisungen Kursor-Anweisungen weitere Anweisungen, die es nur in Embedded SQL und nicht im interaktiven SQL gibt Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 581 Kopplung von SQL mit Programmiersprachen →Beispiel (Embedded SQL und C) /* C-Includes zur Ein-/Ausgabe */ /* und Stringverarbeitung */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* Include zur Interaktion mit der Datenbank */ #include <sqlenv.h> /* Deklaration der SQL Communication Area */ EXEC SQL INCLUDE SQLCA; Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 582 Kopplung von SQL mit Programmiersprachen main() { /* Deklaration der C-Variablen, die in */ /* SQL-Anweisungen verwendet werden */ EXEC SQL BEGIN DECLARE SECTION; char name[20]; char fachgebiet[20]; EXEC SQL END DECLARE SECTION; /* Cursor-Deklaration fuer Anfrage */ EXEC SQL DECLARE C1 CURSOR FOR SELECT name, fachgebiet FROM professoren ORDER BY name; Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 583 Kopplung von SQL mit Programmiersprachen /* Verbindungsaufbau zur benutzten Datenbank */ /* und oeffnen des Cursors */ EXEC SQL CONNECT TO unidb; EXEC SQL OPEN C1; /* solange noch Tupel vorhanden ... */ while(strncmp(sqlca.sqlstate, "02000", 5)) { /* Tupelattribute in C-Variablen schreiben */ /* und Werte der Variablen ausgeben */ EXEC SQL FETCH C1 INTO :name, :fachgebiet; printf("%s %s\n", name, fachgebiet); } Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 584 Kopplung von SQL mit Programmiersprachen /* Cursor schliessen und */ /* Datenbankverbindung abbauen */ EXEC SQL CLOSE C1; EXEC SQL DISCONNECT CURRENT; return; } Beigl Informatik Bender Mathematik Eick Mathematik Fekete Informatik Kemnitz Mathematik Kreiss Mathematik Wolf Informatik Zimmermann Mathematik Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 585 Kopplung von SQL mit Programmiersprachen →Embedded SQL erlaubt auch Konstruktion von Anfragen zur Laufzeit (Dynamic SQL) Anfrage wird dazu als Wert einer Textvariable im Anwendungsprogramm konstruiert Anweisung PREPARE übersetzt Anfrage in ausführbaren Objektcode und schreibt sie in SQL-Variable vom Typ STATEMENT EXECUTE führt übersetzte Anfrage aus Schemainformationen werden zur Laufzeit mit DESCRIBE ermittelt Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 586 Kopplung von SQL mit Programmiersprachen →Struktur der SQL Description Area (SQLDA) relativ kompliziert Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 587 Kopplung von SQL mit Programmiersprachen →SQLJ ist ein “eingebettetes SQL für Java” direkte Einbettung von (statischen) SQL-Anweisungen in Java-Code ANSI-Standard, entstanden in Zusammenarbeit mehrerer Firmen eingebettete SQL-Anweisungen können zur Übersetzungszeit syntaktisch und semantisch überprüft werden (auch gegen das Schema einer Datenbank) aus: http://www.oracle.com/ SQL-Anweisungen werden durch Präfix “#sql” gekennzeichnet Benutzung von Variablen wie beim statischen Embedded SQL als Ergebnis einer Anfrage wird ein SQLJIterator erzeugt Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 588 Kopplung von SQL mit Programmiersprachen →SQLJ-Systemkomponenten aus: [SaS03] Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 589 Kopplung von SQL mit Programmiersprachen →SQLJ-Beispiel #sql public iterator BookIter(String titel, double preis); try{ // Verbindungsaufbau Connection con = DriverManager.getConnection(url, user, passwd); DefaultContext ctx = newDefaultContext(con); DefaultContext.setDefaultContext(ctx); // Anfrageausfuehrung BookIter iter; #sql iter= SELECT titel, preis FROM buch; while(iter.next()) System.out.println(iter.titel() + ", " + iter.preis()); } catch (SQLException exc) {System.out.println(exc);} Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 590 Kopplung von SQL mit Programmiersprachen →Call-Schnittstelle (Call Level Interface, CLI) Datenbankfunktionen werden aus Anwendungsprogramm durch externe Prozeduren (Methoden) realisiert grobe Unterscheidung in 6 Gruppen • An/Abmelden, Passwort/Identifikation • Bekanntgabe von Programmvariablen • Übersetzen/Ausführen von SQL-Anweisungen • Ergebnisverarbeitung • Fehlerbehandlung • Transaktionsverwaltung Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 aus: http://publib.boulder.ibm.com/ 591 Kopplung von SQL mit Programmiersprachen →aktuelle Call-Schnittstelle für Java: JDBC (Java Database Connectivity) →setzt auf Java-Basisklassen auf →bietet Methoden für Zugriff aus JavaApplikationen auf beliebige (relationale) Datenbanksysteme aus: http://www.developersbook.com Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 592 Kopplung von SQL mit Programmiersprachen →Java-Package java.sql mit Klassen DriverManager: Einstiegspunkt, Laden von Treibern Connection: Datenbankverbindung Statement: Ausführung von Anweisungen über eine Verbindung ResultSet: verwaltet Ergebnisse einer Anfrage, Zugriff auf einzelne Tupel und Attribute Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 593 Kopplung von SQL mit Programmiersprachen →Treiberkonzept Treibermanager abstrakte Klassen für Datenbankzugriff dynamisches Laden von Treibern Auswahl des geeigneten Treibers über Verbindungsdaten Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 594 Kopplung von SQL mit Programmiersprachen →typischer Ablauf Aufbau einer Verbindung zur Datenbank • Angabe der Verbindungsinformationen • Auswahl und Laden des DriverManager Treibers senden einer SQL-Anweisung • Definition der Anweisung • Belegung von Parametern verarbeiten der Anfrageergebnisse Statement • Navigation in Ergebnistupeln • Zugriff auf Attribute Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 getConnection() Connection createStatement() Statement Statement executeQuery() ResultSet 595 Kopplung von SQL mit Programmiersprachen →JDBC-Beispiel import java.sql.*; public class Sample { static final String pad=" "; public static void main(String args[]) { ResultSet rs=null; Statement stmt=null; Connection con=null; try { // Treiber fuer postgresql laden: Class.forName("org.postgresql.Driver"); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 596 Kopplung von SQL mit Programmiersprachen // Verbindung zur Datenbank ’sample’ auf Postgres // auf dem Rechner it177.idb.cs.tm-cu.de und dem // Port 4742 aufbauen con=DriverManager.getConnection( "jdbc:postgresql://it177.idb.cs.tm-cu.de:4742/sample", "mueller", // Benutzername "pwmller"); // Passwort // Ein neues Statement erzeugen stmt=con.createStatement(); // Namen, Plz und Staedte aller Personen nach Name // sortiert abfragen rs=stmt.executeQuery("SELECT name, plz, stadt "+ "FROM personen "+ "ORDER BY name"); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 597 Kopplung von SQL mit Programmiersprachen // Ergebnis auf Bildschirm bringen if (!rs.next()) { // keine Ergebniszeilen // wer hat die Daten geloescht??? System.out.println( "\nWer hat die Daten aus der DB geloescht?\n"+ "Bitte wieder welche eintragen!!!\n\n(Attribute: \n"+ "name text not null\nplz int not null\nstadt "+ "text not null)"); } else { // Normalfall... // Ein kleiner Header... System.out.println("\nName |"+ |"+ " PLZ Stadt"); System.out.println("--------------------------+"+ "-----------------------------------------"); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 598 Kopplung von SQL mit Programmiersprachen // Alle Datensaetze ausgeben - da rs.next() // schon aufgerufen wurde, // koennen wir direkt erst einmal Datensaetze ausgeben do { String name=rs.getString("name")+pad; System.out.println(name.substring(0,25)+" | "+ rs.getInt("plz")+" "+ rs.getString(3)); } while (rs.next()); // noch eine Leerzeile ... System.out.println(); } } catch (ClassNotFoundException c) { System.err.println( "\nEine Klasse konnte nicht gefunden werden "+ Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 599 Kopplung von SQL mit Programmiersprachen "(Fehlermeldung:\n\n\t"+c.getMessage()+"\n\n)\n\n"+ "Ist das Java Archiv ’/usr/dblocal/java/classes/"+ "pg815.jdbc3.jar’ mit\nim CLASSPATH (\"echo "+ "$CLASSPATH\")?\n"); } catch (SQLException se) { System.err.println( "\nAchtung: Es gab einen (unerwarteten?) SQL-Fehler!"+ "\n\nFehlermeldung:\n\n\t"+se.getMessage()+"\n"); } // schliessen von ResultSet, Statement, Connection try { rs.close(); } catch (Exception ex) { } try { stmt.close(); } catch (Exception ex) { } try { con.close(); } catch (Exception ex) { } } Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 } 600 7.2 Postgres und JDBC →Postgres ist relationales Datenbanksystem mit räumlichen Datentypen und entsprechenden SQL-Erweiterungen (vgl. Abschnitt 4.5) →es bietet u.a. die Datentypen point (float, float) box (point, point) lseg (point, point) line (point1, point2, ..., pointn) polygon (point1, point2, ..., pointn) circle (point, float) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 601 Postgres und JDBC →dazu zahlreiche geometrische Prädikate und Funktionen →räumliche Datentypen können wie gewohnt für Attribute genutzt CREATE TABLE Gebäude (Id CHAR(25), Nutzung CHAR(25), werden Grundriss POLYGON(50), PRIMARY KEY(Id)); →Werte räumlicher Datentypen werden als entsprechende Zeichenketten angegeben INSERT INTO Gebäude VALUES ( ’G4211’,’Polizei’, ’((12125,1333),(13430,1560),(13260,2497), (14111,2695),(14111,2638),(16040,3092), (15303,6468),(13345,5958),(13771,3943), (12948,3773),(12948,3887),(11671,3631))’); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 602 Postgres und JDBC →zur Verarbeitung geometrischer Attribute werden spezielle Java-Klassen und Methoden angeboten →sind Unterklassen der Klasse “PGobject” public class Pgobject extends java.lang.Object implements java.io.Serializable, java.lang.Cloneable →Unterklassen sind PGpoint, PGbox, PGlseg, PGline, PGpolygon, PGcircle →jede Unterklasse enthält u.a. Methoden Konstruktor equals vergleicht zwei Objekte gleichen Typs getValue liefert Objekt als Zeichenkette Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 603 Postgres und JDBC →Beispiel: Konstruktor für Circle /** * @param c PGpoint describing * the circle’s center * @param r radius of circle */ public PGcircle(PGpoint c, double r) { this(); this.center = c; this.radius = r; } Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 604 Postgres und JDBC →Beispiel: equals für Polygon /** * @param obj Object to compare with * @return true if the two polygons are identical */ public boolean equals(Object obj) { if (obj instanceof PGpolygon) { PGpolygon p = (PGpolygon)obj; if (p.points.length != points.length) return false; for (int i = 0;i < points.length;i++) if (!points[i].equals(p.points[i])) return false; return true; } return false; } Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 605 Postgres und JDBC →Beispiel: getValue für Polygon /** * @return the PGpolygon in the syntax expected * by org.postgresql */ public String getValue() { StringBuffer b = new StringBuffer(); b.append("("); for (int p = 0;p < points.length;p++) { if (p > 0) b.append(","); b.append(points[p].toString()); } b.append(")"); return b.toString(); } Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 606 Postgres und JDBC →zum Transferieren von nichträumlichen Tupelattributen in Java-Variable gibt es spezielle Methoden (der Klasse ResultSet), u.a.: getBoolean, getByte, getDate, getDouble, getFloat, getInt, getObject, getString, getTime →allerdings gibt es kein getPoint, getBox, getLseg, getLine, getPolygon, getCircle →zum Transferieren von räumlichen Tupelattributen wird daher Methode “getObject” mit dem entsprechenden Casting auf die passende Unterklasse von “PGobject” benutzt Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 607 Postgres und JDBC →Beispiel eines Anwendungsprogrammes mit räumlichen Datentypen, Postgres und JDBC import java.sql.*; // es werden die raeumlichen Datentypen // point und circle benutzt import org.postgresql.geometric.PGpoint; import org.postgresql.geometric.PGcircle; public class GeometricTest { // in der main-Methode wird // - Treiber fuer postgresql geladen // - Verbindung zur Datenbank ’test’ auf Postgres // auf Server localhost und Port 5432 aufgebaut // - Relation geomtest eingerichtet Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 608 Postgres und JDBC // - Methoden insertCircle und retrieveCircle aufgerufen // - Verbindung zur Datenbank geschlossen public static void main(String args[]) throws Exception { Class.forName("org.postgresql.Driver"); String url = "jdbc:postgresql://localhost:5432/test"; Connection conn = DriverManager.getConnection(url,"test",""); Statement stmt = conn.createStatement(); // Relation geomtest hat nur das Attribut mycirc // mit dem Datentyp circle stmt.execute("CREATE TEMP TABLE geomtest(mycirc circle)"); stmt.close(); insertCircle(conn); retrieveCircle(conn); conn.close(); } Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 609 Postgres und JDBC // die Methode insertCircle fuegt einen Kreis // in die Relation mycirc ein (ein Tupel mit einem Attributwert) private static void insertCircle(Connection conn) throws SQLException { // Konstruktion des Kreises aus center und radius PGpoint center = new PGpoint(1, 2.5); double radius = 4; PGcircle circle = new PGcircle(center, radius); // vorbereiten des Einfuegens mit "?" als Parameter PreparedStatement ps = conn.prepareStatement( "INSERT INTO geomtest(mycirc) VALUES (?)"); // setzen des Parameters und ausfuehren der Anweisung ps.setObject(1, circle); ps.executeUpdate(); ps.close(); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 610 } Postgres und JDBC // die Methode retrieveCircle holt einen Kreis // mit dessen berechneter Flaeche aus der Relation mycirc // und gibt diese Daten aus private static void retrieveCircle(Connection conn) throws SQLException { Statement stmt = conn.createStatement(); // Anfrage fuer Kreis und Kreisflaeche ResultSet rs = stmt.executeQuery( "SELECT mycirc, area(mycirc) FROM geomtest"); rs.next(); // Kreisdaten holen per getObject und casten auf PGcircle PGcircle circle = (PGcircle)rs.getObject(1); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 611 Postgres und JDBC // berechnete Kreisflaeche holen per getDouble double area = rs.getDouble(2); // center und radius extrahieren PGpoint center = circle.center; double radius = circle.radius; // alle Daten ausgeben System.out.println("Center (X, Y) = (" + center.x + ", " + center.y + ")"); System.out.println("Radius = " + radius); System.out.println("Area = " + area); } } Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 612 7.3 Oracle Spatial und JDBC →Erweiterung des Oracle-Datenbanksystems →zentraler, sehr spezieller geometrischer Datentyp (vgl. Abschnitt 4.5) CREATE TYPE sdo_geometry AS OBJECT ( SDO_GTYPE NUMBER, SDO_SRID NUMBER, SDO_POINT SDO_POINT_TYPE, SDO_ELEM_INFO MDSYS.SDO_ELEM_INFO_ARRAY, SDO_ORDINATES MDSYS.SDO_ORDINATE_ARRAY); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 613 Oracle Spatial und JDBC →Übersicht über die Komponenten von Oracle Spatial aus: [KGB04] Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 614 Oracle Spatial und JDBC →räumlicher Datentyp kann wie gewohnt für Attribute genutzt CREATE TABLE Gebäude (Id CHAR(25), Nutzung CHAR(25), werden Grundriss SDO_GEOMETRY, PRIMARY KEY(Id)); →Werte des räumlichen Datentypen werden als entsprechende Zeichenketten angegeben INSERT INTO Gebäude VALUES (’G4211’,’Polizei’, SDO_GEOMETRY(SDO_GTYPE = 1003, SDO_SRID = NULL, SDO_POINT = NULL, SDO_ELEM INFO = (1,1003,1), SDO_ORDINATES = (12125,1333,13430,1560,13260, 2497,14111,2695,14111,2638,16040,3092,15303,6468, 13345,5958,13771,3943,12948,3773,12948,3887,11671,3631))); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 615 Oracle Spatial und JDBC →zur Verarbeitung geometrischer Attribute wird spezielle Java-Klasse “JGeometry” angeboten →JGeometry bildet den Datentyp SDO_GEOMETRY als Struktur (STRUCT) ab →bietet zahlreiche Basismethoden zum Zugriff auf räumliche Informationen, u.a. createCircle, createPoint, createLinearPolygon, equals, getDimensions, getElemInfo, getFirstPoint, getJavaPoint, getJavaPoints, getLastPoint, getNumPoints, getOrdinatesArray, getSize, getType, isCircle, isPoint, isRectangle, load, setType, store, toString Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 616 Oracle Spatial und JDBC →Rahmen-Beispiel // Geometrie von Datenbank lesen ResultSet rs = statement.executeQuery( "SELECT geometry FROM states where name = ’Florida’"); STRUCT st = (oracle.sql.STRUCT) rs.getObject(1); // STRUCT in JGeometry kovertieren JGeometry j_geom = JGeometry.load(st); // ... Geometrie handhaben oder neue Geometrie erzeugen ... // Geometrie zurueck in Datenbank schreiben PreparedStatement ps = connection.prepareStatement( "UPDATE states set geometry=? where name=’Florida’"); //JGeometry in STRUCT kovertieren STRUCT obj = JGeometry.store(j_geom, connection); ps.setObject(1, obj); ps.execute(); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 617 Oracle Spatial und JDBC →Zugriff auf geometrische Attribute über STRUCT und JGeometry ist ziemlich kompliziert →einfacher und klarer ist die Benutzung der Klasse “oracle.sdoapi” →bietet ähnliche Geometrie-Klassen wie Simple Features (OGC) bzw. SQL/MM Spatial Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 aus: http://www.geodbs.de/ 618 Oracle Spatial und JDBC →Umwandlung zwischen Datenbankrepräsentation (STRUCT) und passender Geometrieklasse durch Schnittstelle “GeometryAdapter” →Methoden “importGeometry” und “exportGeometry” →vordefinierte Adapter in der Klasse “OraSpatialManager” Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 aus: http://www.geo.unizh.ch/ 619 Oracle Spatial und JDBC →Einlesen von Geoobjekten mit oracle.sdoapi (Quelle: http://www.geodbs.de/) import java.sql.*; // Import der JDBC-Klassen import oracle.sql.STRUCT; // Import von STRUCT // Import der Klassen des SDO-API: import oracle.sdoapi.OraSpatialManager; import oracle.sdoapi.adapter.GeometryAdapter; import oracle.sdoapi.geom.*; public class SdoapiReadExample { public static void main (String[] args) { try { Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 620 Oracle Spatial und JDBC // Verbindung zur Datenbank aufbauen Class.forName("oracle.jdbc.driver.OracleDriver"); String url = "jdbc:oracle:thin:@"+DBHOST+":"+ DBPORT+":"+DBNAME; Connection db = DriverManager.getConnection( url, DBUSER, DBPASSWORD); // GeometryAdapter holen GeometryAdapter adapter = OraSpatialManager.getGeometryAdapter ("SDO", "8.1.6", STRUCT.class, null, null, db); if (adapter == null) { db.close(); throw new ClassNotFoundException("Kein GeometryAdapter!"); } // Anfrage ausfuehren, // es wird ein Tupel der Relation "Gemeinden" geholt, Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 621 Oracle Spatial und JDBC // Definition der Relation: // CREATE TABLE Gemeinden ( // gkz DECIMAL(8), -- Gemeindeschluessel // name VARCHAR(30) NOT NULL, -- Gemeindename // einw DECIMAL(7) DEFAULT 0, -- Einwohnerzahl // centrum SDO_GEOMETRY, -- Zentrumspunkt // gebiet SDO_GEOMETRY, -- Gebietspolygon // CONSTRAINT pk_gem PRIMARY KEY (gkz)); Statement statement = db.createStatement(); String sql = "SELECT * FROM Gemeinden WHERE gkz = 3403000"; ResultSet result = statement.executeQuery(sql); if (result.next()) { System.out.print(result.getString("name") + " - "); Point centrum = (Point)adapter.importGeometry(result.getObject("centrum")); System.out.println(centrum.getX() + " / " + centrum.getY()); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 622 Oracle Spatial und JDBC Polygon pol = (Polygon)adapter.importGeometry(result.getObject("gebiet")); CurveString outerRing = pol.getExteriorRing(); System.out.println("#Eckpunkte: " + outerRing.getNumPoints()); } result.close(); statement.close(); // Verbindung schliessen db.close(); } // try // Fehlerbehandlung catch (Exception ex) { System.err.println("SdoapiReadExample.main: " + ex); } } // main } // class Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 623 7.4 Verarbeitung von GML-basierten Daten →GML ist wichtiger XML-basierter Standard zum Austausch von Geodaten (vgl. Abschnitt 6.3) →einlesen, verarbeiten und ausgeben von GML-Daten kann typische Sequenz im GISKontext sein →Beispiel: Platzierung von Symbolsignaturen in GMLkodierten Gebäude-Polygonen (vgl. Abschnitt 3.4) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 624 Verarbeitung von GML-basierten Daten →Verarbeitung von XML-Dokumenten mit Java meist per SAX oder DOM SAX (Simple API for XML) • ereignisbasierte Programmierschnittstelle • stellt über Eventhandler Methoden zum Erkennen von “Dokument-Ereignissen” bereit (z.B. startDocument, startElement, characters) aus: http://www.xml.com/ DOM (Document Object Model) • objektbasierte Programmierschnittstelle • stellt Klassen zur Handhabung von Dokumenten bereit (u.a. Node, NodeList, Element, Text) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 625 Verarbeitung von GML-basierten Daten →Benutzung des Document Object Models bietet sich an bei wahlfreiem, direkten Zugriff auf Dokument Transformationen des Dokumentes Navigation im Dokumentenbaum genügend Hauptspeicher aus: http://www.xml.com/ →Verarbeitung in zwei Schritten parsen des Dokumentes und Aufbau eines entsprechend strukturierten Objektes navigieren, bearbeiten, ändern des Objektes Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 626 Verarbeitung von GML-basierten Daten →Methoden des DOM-API erlauben Navigation zwischen den einzelnen Knoten eines Dokuments erzeugen, verschieben, löschen von Knoten auslesen, ändern, löschen von Textinhalten →wichtige Methoden zum Navigieren boolean node.hasChildNodes gibt an, ob Knoten Kinder besitzt Node node.getFirstChild gibt Knoten am Anfang der Kinderliste Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 627 Verarbeitung von GML-basierten Daten String node.getNodeName gibt Namen des Knoten short node.getNodeType gibt den Typ des Knoten →wichtige Methoden zum Erweitern von Dokumenten node.appendChild(Node newChild) hängt neue Knoten an node.removeChild(Node oldChild) entfernt Knoten Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 628 Verarbeitung von GML-basierten Daten node.replaceChild(Node newChild, Node oldChild) ersetzt Knoten node.insertBefore(Node newChild, Node refChild) fügt neuen Knoten ein node.setNodeValue(String nodeValue) setzt Wert des Knoten Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 629 Verarbeitung von GML-basierten Daten →typisches System zum Parsen von XML-Dokumenten und zum Aufbau einer DOM-Repräsentation ist “Xerces” zum Arbeiten mit Xerces notwendige Pakete • import org.w3c.dom.*; • import org.xml.sax.SAXException; • import org.apache.xerces.parsers.DOMParser; nächste Schritte sind bilden einer Instanz des DOMParsers, parsen des Dokumentes der Eingabedatei, erzeugen eines geparsten DOM-Objektes • DOMParser parser = new DOMParser(); • parser.parse(Name der XML-Quelldatei); • Document doc = parser.getDocument(); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 630 Verarbeitung von GML-basierten Daten →als (stark vereinfachtes) Beispiel im Folgenden ein (stark gekürzter) Ausschnitt zum Verarbeiten von GML-basierten Gebäudedaten ALKIS-Bestandsdatenauszüge liegen als GML-Daten vor enthalten typischerweise jeweils ca. 10.000 Objekte (Gebäude, Flurstücke, Grenzpunkte usw.) bei Ableitung von Liegenschaftskarte bei manchen Gebäuden zusätzliche Platzierung von Symbolsignaturen nötig Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 631 Verarbeitung von GML-basierten Daten →zum Platzieren von Signaturen u.a. folgende Schritte nötig <gml:featureMember> <AP_PPO gml:id="DEBWL00100000fAW"> parsen von <lebenszeitintervall> ... </lebenszeitintervall> Gebäuden <anlass>000000</anlass> <position> feststellen, dass <gml:Point> kein Präsenta<gml:pos>3540847.175 5805897.864</gml:pos> tionsobjekt zuge- </gml:Point> </position> ordnet ist (vgl. <signaturnummer>3316</signaturnummer> <dientZurDarstellungVon Abschnitt 3.4) xlink:href="urn:adv:oid:DEBWL00100000jwR"/> berechnen der <drehwinkel>67.000</drehwinkel> </AP_PPO> optimalen </gml:featureMember> Position erzeugen eines neuen Präsentationsobjektes Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 632 Verarbeitung von GML-basierten Daten →im Folgenden Ausschnitt aus der Methode zum Parsen von Gebäuden, die bereits in einer DOMStruktur vorliegen ein Exemplar der Objektklasse “AX_Gebaeude” <AX_Gebaeude gml:id="DEHHSERV00001FN1"> (vereinfacht) ... <position> <gml:Polygon> <gml:exterior> <gml:Ring> ... <gml:pos>3567807.047 5930017.550</gml:pos> <gml:pos>3567810.850 5930024.755</gml:pos> ... <gml:pos>3567807.047 5930017.550</gml:pos> ... </gml:Ring> </gml:exterior> </gml:Polygon> </position> <gebaeudefunktion>2000 </gebaeudefunktion> <weitereGebaeudefunktion> 1170 </weitereGebaeudefunktion> <bauweise>2100</bauweise> <anzahlDerOberirdischenGeschosse> 1 </anzahlDerOberirdischenGeschosse> <anzahlDerUnterirdischenGeschosse> 1 </anzahlDerUnterirdischenGeschosse> <dachform>3100</dachform> </AX_Gebaeude> Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 633 Verarbeitung von GML-basierten Daten static public void parseGebaeude()throws SAXException, IOException, ParserConfigurationException { // alle Gebaeude in eine Liste; // ein Bestandsdateauszug liegt schon als Wurzel vor NodeList GebaeudeListe = Wurzel.getElementsByTagName("AX_Gebaeude"); // alle Gebaeude einzeln bearbeiten for(int k=0; k< GebaeudeListe.getLength();k++){ Element Gebaeude = (Element)GebaeudeListe.item(k); // Gebaudefunktion initialisieren int gebfkt = 0; // Weiteregebaudefunktionen initialisieren // (es kann mehrere geben) Vector<Integer> wgebfkt = new Vector<Integer>(); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 634 Verarbeitung von GML-basierten Daten // Gebaeude-Id lesen String ID = Gebaeude.getAttribute("gml:id"); // Gebaudefunktion lesen // (kann auch leer sein) NodeList fnNodeList = Gebaeude.getElementsByTagName("gebaeudefunktion"); if(fnNodeList.getLength()!=0){ Text fnText = (Text)((Element)fnNodeList.item(0)).getFirstChild(); gebfkt=Integer.parseInt(fnText.getNodeValue()); } // Weiteregebaudefunktionen lesen fnNodeList= Gebaeude.getElementsByTagName("weitereGebaeudefunktion"); Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 635 Verarbeitung von GML-basierten Daten if(fnNodeList.getLength()!=0){ for(int l=0; l<fnNodeList.getLength() ;l++){ Text fnText = (Text)((Element)fnNodeList.item(l)).getFirstChild(); int wgf=Integer.parseInt(fnText.getNodeValue()); wgebfkt.addElement(wgf); } } // weitere Gebaeudeattribute lesen; // z.B. die Geometriedaten des Positions-Knoten ... ... ... } // Ende: alle Gebaeude } Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 636 7.5 Funktionales Programmieren mit Polygonen →funktionale Programmiersprachen deutlich weniger verbreitet als imperative Programmiersprachen →Trennung zwischen ausführbarem Programm und (präziser) Spezifikation einer Problemlösung bei funktionalen Programmiersprachen annähernd aufgehoben →besonders “rekursive Probleme” sehr direkt lösbar →darunter viele geometrische Anwendungen Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 637 Funktionales Programmieren mit Polygonen →funktionale Programmiersprachen beruhen auf Lambda-Kalkül (Church, 30er Jahre) Programm ist Menge von Ausdrücken, die Funktionen definieren Konstruktion von komplexen Funktionen durch Kombination von einfacheren wichtigstes Konstruktionsprinzip ist Rekursion Berechnung ist Anwendung einer Funktion auf Liste von Argumenten hauptsächlich durch Interpreter realisiert Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 638 Funktionales Programmieren mit Polygonen →Scheme eine Variante der funktionalen Sprache LISP (List Processing Language, 60er Jahre) freie Interpreter Teil vieler Unix-Systeme KN@is42:273 scheme MIT/GNU Scheme running under GNU/Linux Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Massachusetts Institute of Technology This is free software; see the source for copying conditions. aus: http://kinder.wetter.com/ 1 ]=> (/ 40030.0 (* 2.0 6371.0)) ;Value: 3.141579029979595 1 ]=> (exit) KN@is42:274 Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 639 Funktionales Programmieren mit Polygonen →Grundelemente sind Präfixausdrücke mit einem Operator und mehreren Operanden →spezielle Operatoren für Namensgebung und zur Definition von Funktionen: (define pi 3.1415927) (define quadrat (lambda (x) (* x x))) (define punkt-abstand (lambda (p1 p2) (sqrt (+ (quadrat (- (x-koord p2) (x-koord p1))) (quadrat (- (y-koord p2) (y-koord p1))))))) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 640 Funktionales Programmieren mit Polygonen →Hauptdatenstruktur sind Paare (und Listen) (define paar (cons a b)) (define liste (cons a (cons b (cons c...(cons y ())))...) →ein Punkt wird als Paar von Koordinaten dargestellt (define konstr-punkt (lambda (x y) (cons x y))) (define x-koord (lambda (xy) (car xy))) (define y-koord (lambda (xy) (cdr xy))) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 641 Funktionales Programmieren mit Polygonen →ein Polygon wird wird als Liste von Koordinaten dargestellt (define quadrat1 (cons 2025 (cons 2925 (cons 2925 ... (cons 2925 ()))...) Kurzform: (define quadrat1 ’(2025 2925 2925 2925 2925 3825 2025 3825 2025 2925)) →einfache Operationen Punkt hinzufügen (define ad-punkt (lambda (poly punkt) (if (null? poly) (list (x-koord punkt) (y-koord punkt)) (cons (car poly) (ad-punkt (cdr poly) punkt))))) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 642 Funktionales Programmieren mit Polygonen erster Punkt (define punkt1 (lambda (poly) (konstr-punkt (car poly) (car (cdr poly))))) um einen Punkt kürzen (define trunc-poly (lambda (poly) (cdr (cdr poly)))) zweiter Punkt (define punkt2 (lambda (poly) (punkt1 (trunc-poly poly)))) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 643 Funktionales Programmieren mit Polygonen →Umfang von Polygonen (define umfang (lambda (poly) (if (not (null? (trunc-poly poly))) (+ (punkt-abstand (punkt1 poly) (punkt2 poly)) (umfang (trunc-poly poly))) 0))) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 644 Funktionales Programmieren mit Polygonen →Tiefpassfilter (vgl. Abschnitt 3.3) (define tiefpass (lambda (poly) (define lok-tiefpass (lambda (poly) (if (not (null? (trunc-poly poly))) (ad-punkt (lok-tiefpass (trunc-poly poly)) (mittelpunkt (punkt1 poly) (punkt2 poly))) ()))) (ad-punkt (lok-tiefpass poly) (punkt1 (lok-tiefpass poly))))) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 645 Funktionales Programmieren mit Polygonen →Douglas/Peucker-Algorithmus 1. Gegeben: Linienzug L und Grenzwert g, 2. bestimme Gerade zwischen Anfangs- und Endpunkt, 3. bestimme Punkt mit größtem Abstand zur Geraden, 4. falls Abstand > g dann Punkt signifikant, wiederhole Verfahren für beide Teillinienzüge, sonst entferne alle Punkte zwischen Anfangs- und Endpunkt. Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 646 Funktionales Programmieren mit Polygonen (define douglas-peucker (lambda (poly g) (if (> (anzahl-punkte poly) 2) (sequence (define map (max-abstand-punkt poly)) (if (> (gerade-punkt-abstand (punkt1 poly) (letzter-punkt poly) map) g) (concat-poly (douglas-peucker (teil1 poly map) g) (douglas-peucker (teil2 poly map) g)) (ad-punkt (ad-punkt () (punkt1 poly)) (letzter-punkt poly)))) poly))) Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 647 7.6 Zusammenfassung →Kopplung von SQL mit Programmiersprachen Embedded SQL SQLJ Call-Schnittstelle JDBC →Postgres und JDBC Klasse “PGobject” Unterklassen “PGpoint”, “PGbox” etc. →Oracle Spatial und JDBC Klasse “JGeometry” Paket “oracle.sdoapi” Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 648 Zusammenfassung →Verarbeitung von GML-basierten Daten SAX (Simple API for XML) DOM (Document Object Model) Navigation im Dokument-Baum Beispiel: GMLbasierte Gebäudedaten →Funktionales Programmieren mit Polygonen Scheme Polygon als Liste von Koordinaten Umfang von Polygonen Tiefpassfilter Douglas/PeuckerAlgorithmus Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 649 Zusammenfassung erfassen GIS präsentieren verwalten analysieren SQL + höhere Programmiersprache SQLJ Objekte GML JDBC Thematik Geometrie Vektor funktionales Programmie ren Spatial Databases und GISe, Kap.7 / K.N., S.T. / SomSem 2009 Embedded SQL 650