DOCUframe und Google Maps

Google stellt im Rahmen des Google Maps Dienstes auch die Google Maps Geocoding API zur Verfügung. Diese API ermöglicht neben der Ermittlung der geographischen Koordinaten einer Adresse auch eine einfache Adressprüfung und -korrektur. Zu einer falsch geschriebenen Adresse oder auch zu einem Adressfragment liefert Google Maps mögliche passende Adressen. So kann aus einer falsch geschriebenen Adresse meistens die richtig geschriebene Adresse ermittelt werden.

DOCUframe, DOCUcontrol und die Google Maps Geocoding API

Ein Beispiel:

Adresse mit Schreibfehler: Freidhofstr. 10, 96371 Cronack
Korrigierte Adresse durch Google Maps: Friedhofstr. 10, 96317 Kronach (= korrekte Adresse)

Wie kann man nun Google Maps und die Geocoding API in DOCUframe der Firma GSD nutzen? Im Wesentlichen werden dazu drei Komponenten des Gespanns DOCUframe und DOCUcontrol benötigt:

  1. Die DOCUcontrol-Funktion „HTTPGetResponse“ für die Nutzung der Google Maps API.
  2. Die XML-Funktionen von DOCUcontrol zum Parsen des Google Maps Ergebnisses.
  3. Das Dialogelement „HTML-Seite“ zur Kartendarstellung der gefundenen Adresse.

In einem Testdialog sieht das dann folgendermaßen aus:

DOCUframe und DOCUcontrol nutzen die Google Maps Geocoding API

DOCUcontrol-Funktion „HTTPGetResponse“

„HTTPGetResponse“ ermöglicht es eine HTTP-Anfrage abzusetzen und die Antwort des HTTP-Requests in einer String-Variable abzulegen. Google Maps ermöglicht es über den XML-Parameter im Request, dass die Antwort auf den Request in Form eines XML-Dokumentes zurückgeliefert wird.

Der benötigte HTTP-Request sieht dann folgendermaßen aus:

http://maps.googleapis.com/maps/api/geocode/xml?address=Lösstr. 20+96317,Cronack&sensor=false&language=de®ion=de&components=country:DE

Kurze Erklärung der zusätzlichen Parameter neben der angefragten Adresse:

sensor=false

Dieser Parameter ist inzwischen überflüssig geworden, schadet aber auch nicht. False zeigt an, dass – wie der Name schon andeutet – kein Sensor genutzt wird, um die Position des Aufrufers zu bestimmen.

language=de

Die Antwort von Google Maps soll in deutscher Sprache erfolgen.

region=de

Es werden Ergebnisse vorzugsweise aus Deutschland geliefert. Als Parameter hinter „region=“ ist die Top Level Domain der gewünschten Region anzugeben. Lässt man diesen Parameter weg, dann werden vorzugsweise Adressen aus USA angezeigt.

components=country:DE

Dient als zusätzlicher Filter der zurückgelieferten Adressen. Mit „country:DE“ werden nur Adressen aus Deutschland zurückgegeben.

Es gibt zahlreiche weitere Parameter in der Google Maps Geocoding API. Bei Google finden Sie im Developer-Bereich eine detaillierte Übersicht und eine Beschreibung zu jedem Parameter.

Ausschnittsweise sieht der Code für das „Klick“-Ereignis des Buttons „Adresssuche“ folgendermaßen aus:

...
  IF( Strasse != "" )
    HTMLRequest = Strasse;
  ENDIF
  IF( Ort != "" )
    IF( PLZ != "" )
      HTMLRequest += "+" + PLZ;
    ENDIF
    HTMLRequest += "," + Ort;
  ELSEIF ( PLZ != "" )
    HTMLRequest += "," + PLZ;
  ENDIF
  
  HTMLRequest += "&sensor=false&language=de&region=de&components=country:DE" ;
  
  StrAnsiToUtf8( HTMLRequest );
  Trace( HTMLRequest);
  HTTPGetResponse( "maps.googleapis.com", "/maps/api/geocode/xml?address=" + HTMLRequest, "", "text/plain", FALSE, HTMLResponse );

  StrUtf8ToAnsi( HTMLResponse );
...

Parsen der XML-Antwort mit den DOCUcontrol-XML-Funktionen

In der String-Variablen „HTMLResponse“ steht nun die Antwort von Google Maps als XML-Dokument, das nun im zweiten Schritt ausgewertet werden muss.

In unserem Beispiel erhält man das folgende XML-Dokument:

<?xml version="1.0" encoding="UTF-8"?>
<GeocodeResponse>
 <status>OK</status>
 <result>
  <type>street_address</type>
  <formatted_address>Friedhofstraße 10, 96317 Kronach, Deutschland</formatted_address>
  <address_component>
   <long_name>10</long_name>
   <short_name>10</short_name>
   <type>street_number</type>
  </address_component>
  <address_component>
   <long_name>Friedhofstraße</long_name>
   <short_name>Friedhofstraße</short_name>
   <type>route</type>
  </address_component>
  <address_component>
   <long_name>Kronach</long_name>
   <short_name>Kronach</short_name>
   <type>locality</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Oberfranken</long_name>
   <short_name>Oberfranken</short_name>
   <type>administrative_area_level_2</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Bayern</long_name>
   <short_name>BY</short_name>
   <type>administrative_area_level_1</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Deutschland</long_name>
   <short_name>DE</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>96317</long_name>
   <short_name>96317</short_name>
   <type>postal_code</type>
  </address_component>
  <geometry>
   <location>
    <lat>50.2381800</lat>
    <lng>11.3290300</lng>
   </location>
   <location_type>ROOFTOP</location_type>
   <viewport>
    <southwest>
     <lat>50.2368310</lat>
     <lng>11.3276810</lng>
    </southwest>
    <northeast>
     <lat>50.2395290</lat>
     <lng>11.3303790</lng>
    </northeast>
   </viewport>
  </geometry>
  <partial_match>true</partial_match>
  <place_id>ChIJuXC83Yh7oUcRmymr5-ZQXPg</place_id>
 </result>
</GeocodeResponse>

Das folgende benannte Makro extrahiert nun aus dem XML-Dokument die ermittelten Adressen:

BOOL OFGetAddressFromGoogleMaps( STRING XML, DBSTRINGSET &FormattedAddresses )
  
  HANDLE Doc, Node, Sibling, SubSibling, SubNode;
  STRING FormattedAddress, Street, StreetNumber, City, ZipCode, Country, Loca-tion, AdminLevel1;
  BOOL Ok;
  
  Doc = XMLDocumentConstruct();
  Node = XMLNodeConstruct();
  Sibling = XMLNodeConstruct();
  SubSibling = XMLNodeConstruct();
  SubNode = XMLNodeConstruct();

  XMLDocumentLoadXML( Doc, XML );
  XMLNodeSelectSingleNode( Doc, "GeocodeResponse/status", Node );
  Ok = ( XMLNodeGetText( Node ) == "OK" );
  
  IF( Ok )
    XMLNodeSelectSingleNode( Doc, "GeocodeResponse", Node );
    XMLNodeGetFirstChild( Node, Sibling, XMLNODE_ELEMENT );
    REPEAT
      IF( XMLNodeGetName( Sibling ) == "result" )
        Location = Street = StreetNumber = ZipCode = City = Country = "";
        XMLNodeGetFirstChild( Sibling, SubSibling, XMLNODE_ELEMENT );
        REPEAT
          XMLNodeGetName( SubSibling );
          IF( XMLNodeGetName( SubSibling ) == "address_component" )
            XMLNodeSelectSingleNode( SubSibling, "type", SubNode );
            IF( XMLNodeGetText( SubNode ) == "route" )
              XMLNodeSelectSingleNode( SubSibling, "long_name", SubNode );
              Street = XMLNodeGetText( SubNode ); 
            ELSEIF( XMLNodeGetText( SubNode ) == "street_number" )
              XMLNodeSelectSingleNode( SubSibling, "long_name", SubNode );
              StreetNumber = XMLNodeGetText( SubNode );
            ELSEIF( XMLNodeGetText( SubNode ) == "locality" )
              XMLNodeSelectSingleNode( SubSibling, "long_name", SubNode );
              City = XMLNodeGetText( SubNode );
            ELSEIF( XMLNodeGetText( SubNode ) == "postal_code" )
              XMLNodeSelectSingleNode( SubSibling, "long_name", SubNode );
              ZipCode = XMLNodeGetText( SubNode ); 
            ELSEIF( XMLNodeGetText( SubNode ) == "country" )
              XMLNodeSelectSingleNode( SubSibling, "long_name", SubNode );
              Country = XMLNodeGetText( SubNode );
            ELSEIF( XMLNodeGetText( SubNode ) == "location" || XMLNodeGetText( SubNode ) == "point_of_interest" )
              XMLNodeSelectSingleNode( SubSibling, "long_name", SubNode );
              Location += XMLNodeGetText( SubNode );
            ELSEIF( XMLNodeGetText( SubNode ) == "administrative_area_level_1" )
              XMLNodeSelectSingleNode( SubSibling, "long_name", SubNode );
              AdminLevel1 = XMLNodeGetText( SubNode );
            ENDIF
          ENDIF
          XMLNodeGetNextSibling( SubSibling, SubSibling, XMLNODE_ELEMENT );
        UNTIL ( XMLNodeIsEmpty( SubSibling ) );
        StrReplaceStr( Location, ",", " " );
        FormattedAddress = Location + ", " + Street + " " + StreetNumber + ", " + ZipCode + ", " + City + ", " + AdminLevel1+ ", " + Country;
        IF( FormattedAddress != "" )
          DBStrAdd( FormattedAddresses, FormattedAddress );
        ENDIF
      ENDIF
      XMLNodeGetNextSibling( Sibling, Sibling, XMLNODE_ELEMENT );
    UNTIL ( XMLNodeIsEmpty( Sibling ) );
  ENDIF
  
  XMLNodeDestruct( SubNode );
  XMLNodeDestruct( SubSibling );
  XMLNodeDestruct( Sibling );
  XMLNodeDestruct( Node );
  XMLDocumentDestruct( Doc );
  
RETURN(Ok);

Anzeige der ausgewählten Adresse in einem DOCUframe-HTML-Dialogelement

Die ermittelten Adressen werden abschließend über eine Dropdown-Box auswählbar gemacht:

SetDialogFieldTextComboBox( Dialog, "_OFListe", Auswahl );

Um die einzelnen Felder mit den Adressbestandteilen zu füllen, wird die ausgewählte Adresse wieder in seine Bestandteile aufgesplittet und mit Hilfe eines HTML-Dialogelement grafisch in einer GoogleMaps-Landkarte dargestellt:

Anzeige der korrigierten Adresse in einer Google Maps Karte

Das dafür notwendige benannte Makro „OFShowGoogleMap“ sieht folgendermaßen aus:

VOID OFShowGoogleMap( HANDLE Dialog, STRING Name, STRING Address )

  STRING HTMLText =
    "<!doctype html>
    <html lang=\"de\">
    <head>
    <meta charset=\"utf-8\">
    <title>Google Map Address</title>
    <script src=\"http://code.jquery.com/jquery-latest.min.js\" type=\"text/javascript\"></script>
    <script type=\"text/javascript\" src=\"http://maps.google.com/maps/api/js?sensor=false\"></script>
    <script type=\"text/javascript\">

    var geocoder = new google.maps.Geocoder();
    var address = \"%Adresse\";

    geocoder.geocode( { 'address': address}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
        var latitude = results[0].geometry.location.lat();
        var longitude = results[0].geometry.location.lng();
        initialize(latitude,longitude);
                } 
        }); 

    function initialize(latitude,longitude) {
        var latlng = new google.maps.LatLng(latitude,longitude);
        var myOptions = {
          zoom: 16,
          center: latlng,
          mapTypeId: google.maps.MapTypeId.ROADMAP,
          mapTypeControl: true,
          scrollwheel: true
        };
        var map = new google.maps.Map(document.getElementById(\"map_canvas\"),myOptions);
        var marker = new google.maps.Marker({
          position: latlng, 
          map: map, 
          title:\"location : Ermittelte Adresse\"
        }); 
      }
    </script>
    </head>
    <body>
    <div id=\"map_canvas\" style=\"width:700px; height:300px\"></div>   
    </body>
    </html>
  ";
  
StrReplaceStr( HTMLText, "%Adresse", Address ); 
DialogFieldShowHTML( Dialog, Name, HTMLText );

RETURN();

Viel Spass mit DOCUframe, DOCUcontrol und GoogleMaps!

[of_autor]

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert