Mercurial > gemma
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)