changeset 1679:2dc7768be0e4

Waterway axis import: More on reading data from WFS. TODO: Parse to concrete features.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 26 Dec 2018 21:01:29 +0100
parents 8fdb57173e3f
children de8089944b19
files cmd/wfs/dump.go pkg/imports/wx.go pkg/wfs/capabilities.go
diffstat 3 files changed, 115 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/cmd/wfs/dump.go	Wed Dec 26 10:54:52 2018 +0100
+++ b/cmd/wfs/dump.go	Wed Dec 26 21:01:29 2018 +0100
@@ -18,6 +18,7 @@
 	"errors"
 	"fmt"
 	"io"
+	"log"
 	"os"
 
 	"gemma.intevation.de/gemma/pkg/wfs"
@@ -40,13 +41,19 @@
 			crsName = defaultCRS
 		}
 		fmt.Printf("CRS: %s\n", crsName)
-		types := map[string]struct{}{}
+		epsg, err := wfs.CRSToEPSG(crsName)
+		if err != nil {
+			log.Printf("error: %v\n", err)
+		} else {
+			fmt.Printf("EPSG: %d\n", epsg)
+		}
+		types := map[string]int{}
 		for _, feature := range rfc.Features {
-			types[feature.Geometry.Type] = struct{}{}
+			types[feature.Geometry.Type]++
 		}
 		fmt.Printf("found types in %d features:\n", len(rfc.Features))
-		for typ := range types {
-			fmt.Printf("\t%s\n", typ)
+		for typ, cnt := range types {
+			fmt.Printf("\t%s: %d\n", typ, cnt)
 		}
 		return nil
 	})
--- a/pkg/imports/wx.go	Wed Dec 26 10:54:52 2018 +0100
+++ b/pkg/imports/wx.go	Wed Dec 26 21:01:29 2018 +0100
@@ -16,8 +16,13 @@
 import (
 	"context"
 	"database/sql"
+	"fmt"
+	"io"
+	"strings"
+	"time"
 
 	"gemma.intevation.de/gemma/pkg/common"
+	"gemma.intevation.de/gemma/pkg/wfs"
 )
 
 type WaterwayAxis struct {
@@ -68,6 +73,90 @@
 	feedback Feedback,
 ) (interface{}, error) {
 
-	// TODO: Implement me!
+	start := time.Now()
+
+	feedback.Info("Import waterway axis")
+
+	feedback.Info("Loading capabilities from %s", wx.URL)
+	caps, err := wfs.GetCapabilities(wx.URL)
+	if err != nil {
+		feedback.Error("Loading capabilities failed: %v", err)
+		return nil, err
+	}
+
+	ft := caps.FindFeatureType(wx.FeatureType)
+	if ft == nil {
+		err := fmt.Errorf("Unknown feature type '%s'", wx.FeatureType)
+		feedback.Error("%v", err)
+		return nil, err
+	}
+
+	urls, err := wfs.GetFeaturesGET(
+		caps, wx.FeatureType, "application/json", wx.SortBy)
+	if err != nil {
+		feedback.Error("Cannot create GetFeature URLs. %v", err)
+		return nil, err
+	}
+
+	var crsName string
+
+	unsupportedTypes := map[string]int{}
+
+	if err := wfs.DownloadURLs(urls, func(r io.Reader) error {
+		rfc, err := wfs.ParseRawFeatureCollection(r)
+		if err != nil {
+			return err
+		}
+		if crsName != "" && rfc.CRS != nil {
+			crsName = rfc.CRS.Properties.Name
+		}
+
+		// No features -> ignore.
+		if rfc.Features == nil {
+			return nil
+		}
+		for _, feature := range rfc.Features {
+			switch feature.Geometry.Type {
+			case "LineString":
+				// TODO: Parse concrete features.
+			case "MultiLineString":
+				// TODO: Parse concrete features.
+			default:
+				unsupportedTypes[feature.Geometry.Type]++
+			}
+		}
+		return nil
+	}); err != nil {
+		feedback.Error("Downloading features failed: %v", err)
+		return nil, err
+	}
+
+	if len(unsupportedTypes) != 0 {
+		var b strings.Builder
+		for t, c := range unsupportedTypes {
+			if b.Len() > 0 {
+				b.WriteString(", ")
+			}
+			b.WriteString(fmt.Sprintf("%s: %d", t, c))
+		}
+		feedback.Warn("Unsupported types found: %s", b.String())
+	}
+
+	if crsName == "" {
+		crsName = ft.DefaultCRS
+	}
+
+	epsg, err := wfs.CRSToEPSG(crsName)
+	if err != nil {
+		feedback.Error("Unsupported CRS name '%s'", crsName)
+		return nil, err
+	}
+
+	feedback.Info("using ESPG: %d", epsg)
+
+	// TODO: Store extracted features.
+
+	feedback.Info("Storing took %s", time.Since(start))
+
 	return nil, nil
 }
--- a/pkg/wfs/capabilities.go	Wed Dec 26 10:54:52 2018 +0100
+++ b/pkg/wfs/capabilities.go	Wed Dec 26 21:01:29 2018 +0100
@@ -15,6 +15,7 @@
 
 import (
 	"encoding/xml"
+	"errors"
 	"io"
 	"regexp"
 	"strconv"
@@ -315,6 +316,19 @@
 	return max
 }
 
+var (
+	ErrInvalidCRS = errors.New("Invalid CRS string")
+	crsRe         = regexp.MustCompile(`urn:ogc:def:crs:EPSG:[^:]*:(\d+)`)
+)
+
+func CRSToEPSG(s string) (int, error) {
+	m := crsRe.FindStringSubmatch(s)
+	if m == nil {
+		return 0, ErrInvalidCRS
+	}
+	return strconv.Atoi(m[1])
+}
+
 func ParseCapabilities(r io.Reader) (*Capabilities, error) {
 
 	decoder := xml.NewDecoder(r)