]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge remote-tracking branch 'upstream/master'
authorSarah Hoffmann <lonvia@denofr.de>
Fri, 10 Apr 2020 21:09:16 +0000 (23:09 +0200)
committerSarah Hoffmann <lonvia@denofr.de>
Fri, 10 Apr 2020 21:09:16 +0000 (23:09 +0200)
.travis.yml
lib/ClassTypes.php
lib/setup/SetupClass.php
lib/template/deletable-html.php [new file with mode: 0644]
lib/template/polygons-html.php [new file with mode: 0644]
sql/functions/placex_triggers.sql
sql/functions/ranking.sql [new file with mode: 0644]
sql/functions/utils.sql
test/php/Nominatim/ClassTypesTest.php
website/deletable.php
website/polygons.php

index 0ee3859249b9085f6cc54f8576e79f604e07e40b..f53447422c303ed9740a02edbd18a41acbd768e6 100644 (file)
@@ -1,5 +1,5 @@
 ---
-sudo: required
+os: linux
 dist: xenial
 language: python
 python:
index 91066a1ffb1d3b2dacba3834aa78e9a2221952ea..60f18d959aca35252d6851529da36cb0f4991cb3 100644 (file)
@@ -79,12 +79,13 @@ function getList()
             'boundary:administrative:1' => array('label' => 'Continent', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
             'boundary:administrative:2' => array('label' => 'Country', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
             'place:country' => array('label' => 'Country', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defzoom' => 6, 'defdiameter' => 15),
-            'boundary:administrative:3' => array('label' => 'State', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
+            'boundary:administrative:3' => array('label' => 'Region', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
             'boundary:administrative:4' => array('label' => 'State', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
             'place:state' => array('label' => 'State', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defzoom' => 8, 'defdiameter' => 5.12),
+            'place:province' => array('label' => 'Province', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defzoom' => 8, 'defdiameter' => 5.12),
             'boundary:administrative:5' => array('label' => 'State District', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
             'boundary:administrative:6' => array('label' => 'County', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
-            'boundary:administrative:7' => array('label' => 'County', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
+            'boundary:administrative:7' => array('label' => 'Municipality', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
             'place:county' => array('label' => 'County', 'frequency' => 108, 'icon' => 'poi_boundary_administrative', 'defzoom' => 10, 'defdiameter' => 1.28),
             'boundary:administrative:8' => array('label' => 'City', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
             'place:city' => array('label' => 'City', 'frequency' => 66, 'icon' => 'poi_place_city', 'defzoom' => 12, 'defdiameter' => 0.32),
index aa1b291d1a54eda111bb7740ed2b15b2771bbad3..ac0f8f02f89e33ccc6d0cae4a23c14fb042f98cb 100755 (executable)
@@ -695,6 +695,7 @@ class SetupFunctions
         $sBasePath = CONST_BasePath.'/sql/functions/';
         $sTemplate = file_get_contents($sBasePath.'utils.sql');
         $sTemplate .= file_get_contents($sBasePath.'normalization.sql');
+        $sTemplate .= file_get_contents($sBasePath.'ranking.sql');
         $sTemplate .= file_get_contents($sBasePath.'importance.sql');
         $sTemplate .= file_get_contents($sBasePath.'address_lookup.sql');
         $sTemplate .= file_get_contents($sBasePath.'interpolation.sql');
diff --git a/lib/template/deletable-html.php b/lib/template/deletable-html.php
new file mode 100644 (file)
index 0000000..8cc53e8
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+    header("content-type: text/html; charset=UTF-8");
+    include(CONST_BasePath.'/lib/template/includes/html-header.php');
+?>
+    <title>Nominatim Deleted Data</title>    
+    <meta name="description" content="List of OSM data that has been deleted" lang="en-US" />
+</head>
+
+<body>
+<div class="container">
+    <h1>Deletable</h1>
+    <p>
+        <?php echo sizeof($aPolygons) ?> objects have been deleted in OSM but are still in the Nominatim database.
+        Also available in <a href="<?php echo CONST_Website_BaseURL; ?>deletable.php?format=json">JSON format</a>.
+    </p>
+
+    <table class="table table-striped table-hover">
+<?php
+
+if (!empty($aPolygons)) {
+    echo '<tr>';
+    foreach (array_keys($aPolygons[0]) as $sCol) {
+        echo '<th>'.$sCol.'</th>';
+    }
+    echo '</tr>';
+    foreach ($aPolygons as $aRow) {
+        echo '<tr>';
+        foreach ($aRow as $sCol => $sVal) {
+            switch ($sCol) {
+                case 'osm_id':
+                    echo '<td>'.osmLink($aRow).'</td>';
+                    break;
+                case 'place_id':
+                    echo '<td>'.detailsLink($aRow).'</td>';
+                    break;
+                default:
+                    echo '<td>'.($sVal?$sVal:'&nbsp;').'</td>';
+                    break;
+            }
+        }
+        echo '</tr>';
+    }
+}
+?>
+    </table>
+</div>
+</body>
+</html>
diff --git a/lib/template/polygons-html.php b/lib/template/polygons-html.php
new file mode 100644 (file)
index 0000000..7d485d9
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+    header("content-type: text/html; charset=UTF-8");
+    include(CONST_BasePath.'/lib/template/includes/html-header.php');
+?>
+    <title>Nominatim Broken Polygon Data</title>    
+    <meta name="description" content="List of broken OSM polygon data by date" lang="en-US" />
+</head>
+
+<body>
+
+<div class="container">
+    <h1>Broken polygons</h1>
+
+    <p>
+        Total number of broken polygons: <?php echo $iTotalBroken ?>.
+        Also available in <a href="<?php echo CONST_Website_BaseURL; ?>polygons.php?format=json">JSON format</a>.
+    </p>
+
+    <table class="table table-striped table-hover">
+
+<?php
+if (!empty($aPolygons)) {
+
+    echo '<tr>';
+    //var_dump($aPolygons[0]);
+    foreach (array_keys($aPolygons[0]) as $sCol) {
+        echo '<th>'.$sCol.'</th>';
+    }
+    echo '<th>&nbsp;</th>';
+    echo '</tr>';
+    $aSeen = array();
+    foreach ($aPolygons as $aRow) {
+        if (isset($aSeen[$aRow['osm_type'].$aRow['osm_id']])) continue;
+        $aSeen[$aRow['osm_type'].$aRow['osm_id']] = 1;
+
+        echo '<tr>';
+        $sOSMType = formatOSMType($aRow['osm_type']);
+        foreach ($aRow as $sCol => $sVal) {
+            switch ($sCol) {
+                case 'errormessage':
+                    if (preg_match('/Self-intersection\\[([0-9.\\-]+) ([0-9.\\-]+)\\]/', $sVal, $aMatch)) {
+                        $aRow['lat'] = $aMatch[2];
+                        $aRow['lon'] = $aMatch[1];
+                        $sUrl = sprintf('https://www.openstreetmap.org/?lat=%f&lon=%f&zoom=18&layers=M&%s=%d',
+                                $aRow['lat'],
+                                $aRow['lon'],
+                                $sOSMType,
+                                $aRow['osm_id']);
+                        echo '<td><a href="'.$sUrl.'">'.($sVal?$sVal:'&nbsp;').'</a></td>';
+                    } else {
+                        echo '<td>'.($sVal?$sVal:'&nbsp;').'</td>';
+                    }
+                    break;
+                case 'osm_id':
+                    echo '<td>'.osmLink(array('osm_type' => $aRow['osm_type'], 'osm_id' => $aRow['osm_id'])).'</td>';
+                    break;
+                default:
+                    echo '<td>'.($sVal?$sVal:'&nbsp;').'</td>';
+                    break;
+            }
+        }
+        $sJosmUrl = 'http://localhost:8111/import?url=https://www.openstreetmap.org/api/0.6/'.$sOSMType.'/'.$aRow['osm_id'].'/full';
+        echo '<td><a href="'.$sJosmUrl.'" target="josm">josm</a></td>';
+        echo '</tr>';
+    }
+    echo '</table>';
+}
+?>
+</div>
+</body>
+</html>
\ No newline at end of file
index c04aef286855ee12dd078d18e83b18daf5e36931..0151162eb74d192f7f86115276a41cc327154ce6 100644 (file)
@@ -1,45 +1,5 @@
 -- Trigger functions for the placex table.
 
-CREATE OR REPLACE FUNCTION get_rel_node_members(members TEXT[], memberLabels TEXT[])
-  RETURNS SETOF BIGINT
-  AS $$
-DECLARE
-  i INTEGER;
-BEGIN
-  FOR i IN 1..ARRAY_UPPER(members,1) BY 2 LOOP
-    IF members[i+1] = ANY(memberLabels)
-       AND upper(substring(members[i], 1, 1))::char(1) = 'N'
-    THEN
-      RETURN NEXT substring(members[i], 2)::bigint;
-    END IF;
-  END LOOP;
-
-  RETURN;
-END;
-$$
-LANGUAGE plpgsql IMMUTABLE;
-
--- copy 'name' to or from the default language (if there is a default language)
-CREATE OR REPLACE FUNCTION add_default_place_name(country_code VARCHAR(2),
-                                                  INOUT name HSTORE)
-  AS $$
-DECLARE
-  default_language VARCHAR(10);
-BEGIN
-  IF name is not null AND array_upper(akeys(name),1) > 1 THEN
-    default_language := get_country_language_code(country_code);
-    IF default_language IS NOT NULL THEN
-      IF name ? 'name' AND NOT name ? ('name:'||default_language) THEN
-        name := name || hstore(('name:'||default_language), (name -> 'name'));
-      ELSEIF name ? ('name:'||default_language) AND NOT name ? 'name' THEN
-        name := name || hstore('name', (name -> ('name:'||default_language)));
-      END IF;
-    END IF;
-  END IF;
-END;
-$$
-LANGUAGE plpgsql IMMUTABLE;
-
 -- Find the parent road of a POI.
 --
 -- \returns Place ID of parent object or NULL if none
@@ -538,25 +498,7 @@ BEGIN
       END IF;
     ELSE
       -- mark nearby items for re-indexing, where 'nearby' depends on the features rank_search and is a complete guess :(
-      diameter := 0;
-      -- 16 = city, anything higher than city is effectively ignored (polygon required!)
-      IF NEW.type='postcode' THEN
-        diameter := 0.05;
-      ELSEIF NEW.rank_search < 16 THEN
-        diameter := 0;
-      ELSEIF NEW.rank_search < 18 THEN
-        diameter := 0.1;
-      ELSEIF NEW.rank_search < 20 THEN
-        diameter := 0.05;
-      ELSEIF NEW.rank_search = 21 THEN
-        diameter := 0.001;
-      ELSEIF NEW.rank_search < 24 THEN
-        diameter := 0.02;
-      ELSEIF NEW.rank_search < 26 THEN
-        diameter := 0.002; -- 100 to 200 meters
-      ELSEIF NEW.rank_search < 28 THEN
-        diameter := 0.001; -- 50 to 100 meters
-      END IF;
+      diameter := update_place_diameter(NEW.rank_search);
       IF diameter > 0 THEN
   --      RAISE WARNING 'placex point insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,diameter;
         IF NEW.rank_search >= 26 THEN
diff --git a/sql/functions/ranking.sql b/sql/functions/ranking.sql
new file mode 100644 (file)
index 0000000..ecd31e9
--- /dev/null
@@ -0,0 +1,116 @@
+-- Functions related to search and address ranks
+
+-- Return an approximate search radius according to the search rank.
+CREATE OR REPLACE FUNCTION reverse_place_diameter(rank_search SMALLINT)
+  RETURNS FLOAT
+  AS $$
+BEGIN
+  IF rank_search <= 4 THEN
+    RETURN 5.0;
+  ELSIF rank_search <= 8 THEN
+    RETURN 1.8;
+  ELSIF rank_search <= 12 THEN
+    RETURN 0.6;
+  ELSIF rank_search <= 17 THEN
+    RETURN 0.16;
+  ELSIF rank_search <= 18 THEN
+    RETURN 0.08;
+  ELSIF rank_search <= 19 THEN
+    RETURN 0.04;
+  END IF;
+
+  RETURN 0.02;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+
+-- Return an approximate update radius according to the search rank.
+CREATE OR REPLACE FUNCTION update_place_diameter(rank_search SMALLINT)
+  RETURNS FLOAT
+  AS $$
+BEGIN
+  -- postcodes
+  IF rank_search = 11 or rank_search = 5 THEN
+    RETURN 0.05;
+  -- anything higher than city is effectively ignored (polygon required)
+  ELSIF rank_search < 16 THEN
+    RETURN 0;
+  ELSIF rank_search < 18 THEN
+    RETURN 0.1;
+  ELSIF rank_search < 20 THEN
+    RETURN 0.05;
+  ELSIF rank_search = 21 THEN
+    RETURN 0.001;
+  ELSIF rank_search < 24 THEN
+    RETURN 0.02;
+  ELSIF rank_search < 26 THEN
+    RETURN 0.002;
+  ELSIF rank_search < 28 THEN
+    RETURN 0.001;
+  END IF;
+
+  RETURN 0;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
+
+
+-- Guess a ranking for postcodes from country and postcode format.
+CREATE OR REPLACE FUNCTION get_postcode_rank(country_code VARCHAR(2), postcode TEXT,
+                                             OUT rank_search SMALLINT,
+                                             OUT rank_address SMALLINT)
+AS $$
+DECLARE
+  part TEXT;
+BEGIN
+    rank_search := 30;
+    rank_address := 30;
+    postcode := upper(postcode);
+
+    IF country_code = 'gb' THEN
+        IF postcode ~ '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9][A-Z][A-Z])$' THEN
+            rank_search := 25;
+            rank_address := 5;
+        ELSEIF postcode ~ '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])$' THEN
+            rank_search := 23;
+            rank_address := 5;
+        ELSEIF postcode ~ '^([A-Z][A-Z]?[0-9][0-9A-Z])$' THEN
+            rank_search := 21;
+            rank_address := 5;
+        END IF;
+
+    ELSEIF country_code = 'sg' THEN
+        IF postcode ~ '^([0-9]{6})$' THEN
+            rank_search := 25;
+            rank_address := 11;
+        END IF;
+
+    ELSEIF country_code = 'de' THEN
+        IF postcode ~ '^([0-9]{5})$' THEN
+            rank_search := 21;
+            rank_address := 11;
+        END IF;
+
+    ELSE
+        -- Guess at the postcode format and coverage (!)
+        IF postcode ~ '^[A-Z0-9]{1,5}$' THEN -- Probably too short to be very local
+            rank_search := 21;
+            rank_address := 11;
+        ELSE
+            -- Does it look splitable into and area and local code?
+            part := substring(postcode from '^([- :A-Z0-9]+)([- :][A-Z0-9]+)$');
+
+            IF part IS NOT NULL THEN
+                rank_search := 25;
+                rank_address := 11;
+            ELSEIF postcode ~ '^[- :A-Z0-9]{6,}$' THEN
+                rank_search := 21;
+                rank_address := 11;
+            END IF;
+        END IF;
+    END IF;
+
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
index 6371e9adb739f3fdb7e868219fed02ca9804c7dd..61033fb4d3a5db50118f66fa93a6a7378c4f5660 100644 (file)
@@ -38,85 +38,58 @@ END;
 $$
 LANGUAGE plpgsql IMMUTABLE;
 
-
-CREATE OR REPLACE FUNCTION reverse_place_diameter(rank_search SMALLINT)
-  RETURNS FLOAT
+-- Return the node members with a given label from a relation member list
+-- as a set.
+--
+-- \param members      Member list in osm2pgsql middle format.
+-- \param memberLabels Array of labels to accept.
+--
+-- \returns Set of OSM ids of nodes that are found.
+--
+CREATE OR REPLACE FUNCTION get_rel_node_members(members TEXT[],
+                                                memberLabels TEXT[])
+  RETURNS SETOF BIGINT
   AS $$
+DECLARE
+  i INTEGER;
 BEGIN
-  IF rank_search <= 4 THEN
-    RETURN 5.0;
-  ELSIF rank_search <= 8 THEN
-    RETURN 1.8;
-  ELSIF rank_search <= 12 THEN
-    RETURN 0.6;
-  ELSIF rank_search <= 17 THEN
-    RETURN 0.16;
-  ELSIF rank_search <= 18 THEN
-    RETURN 0.08;
-  ELSIF rank_search <= 19 THEN
-    RETURN 0.04;
-  END IF;
+  FOR i IN 1..ARRAY_UPPER(members,1) BY 2 LOOP
+    IF members[i+1] = ANY(memberLabels)
+       AND upper(substring(members[i], 1, 1))::char(1) = 'N'
+    THEN
+      RETURN NEXT substring(members[i], 2)::bigint;
+    END IF;
+  END LOOP;
 
-  RETURN 0.02;
+  RETURN;
 END;
 $$
 LANGUAGE plpgsql IMMUTABLE;
 
-
-CREATE OR REPLACE FUNCTION get_postcode_rank(country_code VARCHAR(2), postcode TEXT,
-                                             OUT rank_search SMALLINT,
-                                             OUT rank_address SMALLINT)
-AS $$
+-- Copy 'name' to or from the default language.
+--
+-- \param country_code     Country code of the object being named.
+-- \param[inout] name      List of names of the object.
+--
+-- If the country named by country_code has a single default language,
+-- then a `name` tag is copied to `name:<country_code>` if this tag does
+-- not yet exist and vice versa.
+CREATE OR REPLACE FUNCTION add_default_place_name(country_code VARCHAR(2),
+                                                  INOUT name HSTORE)
+  AS $$
 DECLARE
-  part TEXT;
+  default_language VARCHAR(10);
 BEGIN
-    rank_search := 30;
-    rank_address := 30;
-    postcode := upper(postcode);
-
-    IF country_code = 'gb' THEN
-        IF postcode ~ '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9][A-Z][A-Z])$' THEN
-            rank_search := 25;
-            rank_address := 5;
-        ELSEIF postcode ~ '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])$' THEN
-            rank_search := 23;
-            rank_address := 5;
-        ELSEIF postcode ~ '^([A-Z][A-Z]?[0-9][0-9A-Z])$' THEN
-            rank_search := 21;
-            rank_address := 5;
-        END IF;
-
-    ELSEIF country_code = 'sg' THEN
-        IF postcode ~ '^([0-9]{6})$' THEN
-            rank_search := 25;
-            rank_address := 11;
-        END IF;
-
-    ELSEIF country_code = 'de' THEN
-        IF postcode ~ '^([0-9]{5})$' THEN
-            rank_search := 21;
-            rank_address := 11;
-        END IF;
-
-    ELSE
-        -- Guess at the postcode format and coverage (!)
-        IF postcode ~ '^[A-Z0-9]{1,5}$' THEN -- Probably too short to be very local
-            rank_search := 21;
-            rank_address := 11;
-        ELSE
-            -- Does it look splitable into and area and local code?
-            part := substring(postcode from '^([- :A-Z0-9]+)([- :][A-Z0-9]+)$');
-
-            IF part IS NOT NULL THEN
-                rank_search := 25;
-                rank_address := 11;
-            ELSEIF postcode ~ '^[- :A-Z0-9]{6,}$' THEN
-                rank_search := 21;
-                rank_address := 11;
-            END IF;
-        END IF;
+  IF name is not null AND array_upper(akeys(name),1) > 1 THEN
+    default_language := get_country_language_code(country_code);
+    IF default_language IS NOT NULL THEN
+      IF name ? 'name' AND NOT name ? ('name:'||default_language) THEN
+        name := name || hstore(('name:'||default_language), (name -> 'name'));
+      ELSEIF name ? ('name:'||default_language) AND NOT name ? 'name' THEN
+        name := name || hstore('name', (name -> ('name:'||default_language)));
+      END IF;
     END IF;
-
+  END IF;
 END;
 $$
 LANGUAGE plpgsql IMMUTABLE;
@@ -509,22 +482,7 @@ BEGIN
         AND rank_search > rank and indexed_status = 0 and ST_geometrytype(placex.geometry) != 'ST_Point' and (rank_search < 28 or name is not null or (rank >= 16 and address ? 'place'));
       END LOOP;
     ELSE
-        diameter := 0;
-        IF rank = 11 THEN
-          diameter := 0.05;
-        ELSEIF rank < 18 THEN
-          diameter := 0.1;
-        ELSEIF rank < 20 THEN
-          diameter := 0.05;
-        ELSEIF rank = 21 THEN
-          diameter := 0.001;
-        ELSEIF rank < 24 THEN
-          diameter := 0.02;
-        ELSEIF rank < 26 THEN
-          diameter := 0.002; -- 100 to 200 meters
-        ELSEIF rank < 28 THEN
-          diameter := 0.001; -- 50 to 100 meters
-        END IF;
+        diameter := update_place_diameter(rank);
         IF diameter > 0 THEN
           IF rank >= 26 THEN
             -- roads may cause reparenting for >27 rank places
index 8d8481f54630823175f5907044ddd3b7be4e769d..cec3b82ad5a09fb40034a150b1b0efde08ebd343 100644 (file)
@@ -18,9 +18,9 @@ class ClassTypesTest extends \PHPUnit\Framework\TestCase
                    'rank_address' => 14
         );
 
-        $this->assertEquals('County', ClassTypes\getInfo($aPlace)['label']);
-        $this->assertEquals('County', ClassTypes\getFallbackInfo($aPlace)['label']);
-        $this->assertEquals('County', ClassTypes\getProperty($aPlace, 'label'));
+        $this->assertEquals('Municipality', ClassTypes\getInfo($aPlace)['label']);
+        $this->assertEquals('Municipality', ClassTypes\getFallbackInfo($aPlace)['label']);
+        $this->assertEquals('Municipality', ClassTypes\getProperty($aPlace, 'label'));
 
         // 2) No admin level
         // Eiffel Tower
index ac4294bab6d8a293367cb9b6652c5601ce257c7f..2d7ee7e9b804db7d94b82a8f5f7227d33dda2248 100644 (file)
@@ -5,7 +5,9 @@ require_once(CONST_BasePath.'/lib/log.php');
 require_once(CONST_BasePath.'/lib/output.php');
 ini_set('memory_limit', '200M');
 
-$sOutputFormat = 'html';
+$oParams = new Nominatim\ParameterParser();
+$sOutputFormat = $oParams->getSet('format', array('html', 'json'), 'html');
+set_exception_handler_by_format($sOutputFormat);
 
 $oDB = new Nominatim\DB();
 $oDB->connect();
@@ -21,86 +23,8 @@ if (CONST_Debug) {
     exit;
 }
 
-?>
-<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="utf-8"/>
-    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
-    
-    <title>Nominatim Deleted Data</title>
-    
-    <meta name="description" content="List of OSM data that has been deleted" lang="en-US" />
-
-</head>
-
-<body>
-<style type="text/css">
-table {
-    border-width: 1px;
-    border-spacing: 0px;
-    border-style: solid;
-    border-color: gray;
-    border-collapse: collapse;
-    background-color: white;
-    margin: 10px;
-}
-table th {
-    border-width: 1px;
-    padding: 2px;
-    border-style: inset;
-    border-color: gray;
-    border-left-color: #ddd;
-    border-right-color: #ddd;
-    background-color: #eee;
-    -moz-border-radius: 0px 0px 0px 0px;
-}
-table td {
-    border-width: 1px;
-    padding: 2px;
-    border-style: inset;
-    border-color: gray;
-    border-left-color: #ddd;
-    border-right-color: #ddd;
-    background-color: white;
-    -moz-border-radius: 0px 0px 0px 0px;
-}
-</style>
-
-<p>Objects in this table have been deleted in OSM but are still in the Nominatim database.</p>
-
-<table>
-<?php
-
-if (!$aPolygons) exit;
-echo '<tr>';
-// var_dump($aPolygons[0]);
-foreach ($aPolygons[0] as $sCol => $sVal) {
-    echo '<th>'.$sCol.'</th>';
+if ($sOutputFormat == 'json') {
+    echo javascript_renderData($aPolygons);
+} else {
+    include(CONST_BasePath.'/lib/template/deletable-html.php');
 }
-echo '</tr>';
-foreach ($aPolygons as $aRow) {
-    echo '<tr>';
-    foreach ($aRow as $sCol => $sVal) {
-        switch ($sCol) {
-            case 'osm_id':
-                echo '<td>'.osmLink($aRow).'</td>';
-                break;
-            case 'place_id':
-                echo '<td>'.detailsLink($aRow).'</td>';
-                break;
-            default:
-                echo '<td>'.($sVal?$sVal:'&nbsp;').'</td>';
-                break;
-        }
-    }
-    echo '</tr>';
-}
-
-?>
-</table>
-
-
-
-</body>
-</html>
index 29fc5c2760a18f6abaaa34319b35efa0d729ac60..c5fbafc22a44f635ccee70131561db5cbc783b4b 100644 (file)
@@ -6,8 +6,9 @@ require_once(CONST_BasePath.'/lib/output.php');
 ini_set('memory_limit', '200M');
 
 $oParams = new Nominatim\ParameterParser();
+$sOutputFormat = $oParams->getSet('format', array('html', 'json'), 'html');
+set_exception_handler_by_format($sOutputFormat);
 
-$sOutputFormat = 'html';
 $iDays = $oParams->getInt('days', false);
 $bReduced = $oParams->getBool('reduced', false);
 $sClass = $oParams->getString('class', false);
@@ -15,13 +16,13 @@ $sClass = $oParams->getString('class', false);
 $oDB = new Nominatim\DB();
 $oDB->connect();
 
-$iTotalBroken = (int) $oDB->getOne('select count(*) from import_polygon_error');
+$iTotalBroken = (int) $oDB->getOne('SELECT count(*) FROM import_polygon_error');
 
 $aPolygons = array();
 while ($iTotalBroken && empty($aPolygons)) {
-    $sSQL = 'select osm_type as "type",osm_id as "id",class as "key",type as "value",name->\'name\' as "name",';
-    $sSQL .= 'country_code as "country",errormessage as "error message",updated';
-    $sSQL .= ' from import_polygon_error';
+    $sSQL = 'SELECT osm_type, osm_id, class, type, name->\'name\' as "name",';
+    $sSQL .= 'country_code, errormessage, updated';
+    $sSQL .= ' FROM import_polygon_error';
 
     $aWhere = array();
     if ($iDays) {
@@ -33,10 +34,10 @@ while ($iTotalBroken && empty($aPolygons)) {
     if ($sClass) $sWhere[] = "class = '".pg_escape_string($sClass)."'";
 
     if (!empty($aWhere)) {
-        $sSQL .= ' where '.join(' and ', $aWhere);
+        $sSQL .= ' WHERE '.join(' and ', $aWhere);
     }
 
-    $sSQL .= ' order by updated desc limit 1000';
+    $sSQL .= ' ORDER BY updated desc LIMIT 1000';
     $aPolygons = $oDB->getAll($sSQL);
 }
 
@@ -45,93 +46,8 @@ if (CONST_Debug) {
     exit;
 }
 
-?>
-<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="utf-8"/>
-    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
-    
-    <title>Nominatim Broken Polygon Data</title>
-    
-    <meta name="description" content="List of broken OSM polygon data by date" lang="en-US" />
-
-</head>
-
-<body>
-<style type="text/css">
-table {
-    border-width: 1px;
-    border-spacing: 0px;
-    border-style: solid;
-    border-color: gray;
-    border-collapse: collapse;
-    background-color: white;
-    margin: 10px;
-}
-table th {
-    border-width: 1px;
-    padding: 2px;
-    border-style: inset;
-    border-color: gray;
-    border-left-color: #ddd;
-    border-right-color: #ddd;
-    background-color: #eee;
-    -moz-border-radius: 0px 0px 0px 0px;
+if ($sOutputFormat == 'json') {
+    echo javascript_renderData($aPolygons);
+} else {
+    include(CONST_BasePath.'/lib/template/polygons-html.php');
 }
-table td {
-    border-width: 1px;
-    padding: 2px;
-    border-style: inset;
-    border-color: gray;
-    border-left-color: #ddd;
-    border-right-color: #ddd;
-    background-color: white;
-    -moz-border-radius: 0px 0px 0px 0px;
-}
-</style>
-
-<?php
-
-echo "<p>Total number of broken polygons: $iTotalBroken</p>";
-if (!$aPolygons) exit;
-echo '<table>';
-echo '<tr>';
-//var_dump($aPolygons[0]);
-foreach ($aPolygons[0] as $sCol => $sVal) {
-    echo '<th>'.$sCol.'</th>';
-}
-echo '<th>&nbsp;</th>';
-echo '</tr>';
-$aSeen = array();
-foreach ($aPolygons as $aRow) {
-    if (isset($aSeen[$aRow['type'].$aRow['id']])) continue;
-    $aSeen[$aRow['type'].$aRow['id']] = 1;
-    echo '<tr>';
-    foreach ($aRow as $sCol => $sVal) {
-        switch ($sCol) {
-            case 'error message':
-                if (preg_match('/Self-intersection\\[([0-9.\\-]+) ([0-9.\\-]+)\\]/', $sVal, $aMatch)) {
-                    $aRow['lat'] = $aMatch[2];
-                    $aRow['lon'] = $aMatch[1];
-                    echo '<td><a href="https://www.openstreetmap.org/?lat='.$aMatch[2].'&lon='.$aMatch[1].'&zoom=18&layers=M&'.$sOSMType.'='.$aRow['id'].'">'.($sVal?$sVal:'&nbsp;').'</a></td>';
-                } else {
-                    echo '<td>'.($sVal?$sVal:'&nbsp;').'</td>';
-                }
-                break;
-            case 'id':
-                echo '<td>'.osmLink(array('osm_type' => $aRow['type'], 'osm_id' => $aRow['id'])).'</td>';
-                break;
-            default:
-                echo '<td>'.($sVal?$sVal:'&nbsp;').'</td>';
-                break;
-        }
-    }
-    echo '<td><a href="http://localhost:8111/import?url=https://www.openstreetmap.org/api/0.6/'.$sOSMType.'/'.$aRow['id'].'/full" target="josm">josm</a></td>';
-    echo '</tr>';
-}
-echo '</table>';
-
-?>
-</body>
-</html>