diff --git a/pkg/wfs200/capabilities.go b/pkg/wfs200/capabilities.go
index d09e083..ea36d12 100644
--- a/pkg/wfs200/capabilities.go
+++ b/pkg/wfs200/capabilities.go
@@ -123,12 +123,12 @@ type FeatureTypeList struct {
// FeatureType struct for the WFS 2.0.0
type FeatureType struct {
- Name string `xml:"Name" yaml:"name"`
- Title string `xml:"Title" yaml:"title"`
- Abstract string `xml:"Abstract" yaml:"abstract"`
- Keywords *wsc110.Keywords `xml:"ows:Keywords" yaml:"keywords"`
- DefaultCRS *wsc110.CRS `xml:"DefaultCRS" yaml:"defaultcrs"`
- OtherCRS *[]wsc110.CRS `xml:"OtherCRS" yaml:"othercrs"`
+ Name string `xml:"Name" yaml:"name"`
+ Title string `xml:"Title" yaml:"title"`
+ Abstract string `xml:"Abstract" yaml:"abstract"`
+ Keywords *[]wsc110.Keywords `xml:"ows:Keywords" yaml:"keywords"`
+ DefaultCRS *CRS `xml:"DefaultCRS" yaml:"defaultcrs"`
+ OtherCRS *[]CRS `xml:"OtherCRS" yaml:"othercrs"`
OutputFormats struct {
Format []string `xml:"Format" yaml:"format"`
} `xml:"OutputFormats" yaml:"outputformats"`
diff --git a/pkg/wfs200/crs.go b/pkg/wfs200/crs.go
new file mode 100644
index 0000000..52a2693
--- /dev/null
+++ b/pkg/wfs200/crs.go
@@ -0,0 +1,44 @@
+package wfs200
+
+import (
+ "regexp"
+ "strconv"
+)
+
+//
+const (
+ codeSpace = `urn:ogc:def:crs:EPSG:`
+)
+
+// CRS struct with namespace/authority/registry and code
+type CRS struct {
+ Namespace string //TODO maybe AuthorityType is a better name...?
+ Code int
+}
+
+// String of the EPSGCode
+func (c *CRS) String() string {
+ return c.Namespace + `:` + strconv.Itoa(c.Code)
+}
+
+// Identifier returns the EPSG
+func (c *CRS) Identifier() string {
+ return codeSpace + strconv.Itoa(c.Code)
+}
+
+// ParseString build CRS struct from input string
+func (c *CRS) ParseString(s string) {
+ c.parseString(s)
+}
+
+func (c *CRS) parseString(s string) {
+ regex := regexp.MustCompile(`(^.*):([0-9]+)`)
+ code := regex.FindStringSubmatch(s)
+ if len(code) == 3 { // code[0] is the full match, the other the parts
+ c.Namespace = codeSpace
+
+ // the regex already checks if it [0-9]
+ i, _ := strconv.Atoi(code[2])
+ c.Code = i
+ }
+}
diff --git a/pkg/wfs200/crs_test.go b/pkg/wfs200/crs_test.go
new file mode 100644
index 0000000..9175737
--- /dev/null
+++ b/pkg/wfs200/crs_test.go
@@ -0,0 +1,60 @@
+package wfs200
+
+import (
+ "testing"
+
+ "gopkg.in/yaml.v3"
+)
+
+func TestCRSParseString(t *testing.T) {
+ var tests = []struct {
+ input string
+ expectedCRS CRS
+ }{
+ 0: {}, // Empty input == empty struct
+ 1: {input: `urn:ogc:def:crs:EPSG::4326`, expectedCRS: CRS{Code: 4326, Namespace: `urn:ogc:def:crs:EPSG:`}},
+ 2: {input: `EPSG:4326`, expectedCRS: CRS{Code: 4326, Namespace: `urn:ogc:def:crs:EPSG:`}},
+ }
+
+ for k, test := range tests {
+ var crs CRS
+ crs.parseString(test.input)
+
+ if crs.Code != test.expectedCRS.Code || crs.Namespace != test.expectedCRS.Namespace {
+ t.Errorf("test: %d, expected: %v,\n got: %v", k, test.expectedCRS, crs)
+ }
+ }
+}
+
+func TestUnmarshalYAMLCrs(t *testing.T) {
+
+ var stringYAML = `defaultcrs: urn:ogc:def:crs:EPSG::4326
+othercrs:
+- EPSG:4258
+- urn:ogc:def:crs:EPSG::3857`
+
+ type FeatureType struct {
+ DefaultCRS CRS `yaml:"defaultcrs"`
+ OtherCRS []CRS `yaml:"othercrs"`
+ }
+
+ var tests = []struct {
+ yaml []byte
+ expectedcrs CRS
+ }{
+ 0: {yaml: []byte(stringYAML), expectedcrs: CRS{Code: 4326, Namespace: codeSpace}},
+ 1: {yaml: []byte(`defaultcrs: urn:ogc:def:crs:EPSG::4326`), expectedcrs: CRS{Code: 4326, Namespace: codeSpace}},
+ 2: {yaml: []byte(`defaultcrs: EPSG:4326`), expectedcrs: CRS{Code: 4326, Namespace: codeSpace}},
+ }
+ for k, test := range tests {
+ var ftl FeatureType
+ err := yaml.Unmarshal(test.yaml, &ftl)
+ if err != nil {
+ t.Errorf("test: %d, yaml.UnMarshal failed with '%s'\n", k, err)
+ } else {
+ if ftl.DefaultCRS.Code != test.expectedcrs.Code || ftl.DefaultCRS.Namespace != test.expectedcrs.Namespace {
+ t.Errorf("test: %d, expected: %v+,\n got: %v+", k, test.expectedcrs, ftl.DefaultCRS)
+ }
+ }
+ }
+}
diff --git a/pkg/wfs200/crs_xml.go b/pkg/wfs200/crs_xml.go
new file mode 100644
index 0000000..9238966
--- /dev/null
+++ b/pkg/wfs200/crs_xml.go
@@ -0,0 +1,36 @@
+package wfs200
+
+import (
+ "encoding/xml"
+ "fmt"
+)
+
+// MarshalXML Position
+func (c *CRS) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
+ var s = ``
+ if c.Namespace != `` {
+ s = fmt.Sprintf("%s:%d", c.Namespace, c.Code)
+ }
+
+ return e.EncodeElement(s, start)
+}
+
+// UnmarshalXML Position
+func (c *CRS) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
+ var crs CRS
+ for {
+ token, err := d.Token()
+ if err != nil {
+ return err
+ }
+ switch el := token.(type) {
+ case xml.CharData:
+ crs.parseString(string([]byte(el)))
+ case xml.EndElement:
+ if el == start.End() {
+ *c = crs
+ return nil
+ }
+ }
+ }
+}
diff --git a/pkg/wfs200/crs_yaml.go b/pkg/wfs200/crs_yaml.go
new file mode 100644
index 0000000..f040a09
--- /dev/null
+++ b/pkg/wfs200/crs_yaml.go
@@ -0,0 +1,16 @@
+package wfs200
+
+// UnmarshalYAML CRS
+func (c *CRS) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var s string
+ if err := unmarshal(&s); err != nil {
+ return err
+ }
+
+ var crs CRS
+ crs.parseString(s)
+
+ *c = crs
+
+ return nil
+}
diff --git a/pkg/wms130/capabilities.go b/pkg/wms130/capabilities.go
index fbcd069..cbb3a48 100644
--- a/pkg/wms130/capabilities.go
+++ b/pkg/wms130/capabilities.go
@@ -211,7 +211,7 @@ func (c *Capabilities) GetLayer(layername string) (Layer, Exceptions) {
// RequestType containing the formats and DCPTypes available
type RequestType struct {
Format []string `xml:"Format" yaml:"format"`
- DCPType DCPType `xml:"DCPType" yaml:"dcptype"`
+ DCPType *DCPType `xml:"DCPType" yaml:"dcptype"`
}
// Identifier in struct for repeatability
diff --git a/pkg/wms130/getmap_benchmark_test.go b/pkg/wms130/getmap_benchmark_test.go
index 585b84e..f54a8cc 100644
--- a/pkg/wms130/getmap_benchmark_test.go
+++ b/pkg/wms130/getmap_benchmark_test.go
@@ -159,7 +159,7 @@ func BenchmarkGetMapValidate(b *testing.B) {
Request: Request{
GetMap: RequestType{
Format: []string{`image/jpeg`},
- DCPType: DCPType{},
+ DCPType: &DCPType{},
},
},
Layer: []Layer{
@@ -251,7 +251,7 @@ func BenchmarkGetMapParseValidate(b *testing.B) {
Request: Request{
GetMap: RequestType{
Format: []string{`image/jpeg`},
- DCPType: DCPType{},
+ DCPType: &DCPType{},
},
},
Layer: []Layer{
diff --git a/pkg/wms130/getmap_test.go b/pkg/wms130/getmap_test.go
index efe1ffc..b2d861e 100644
--- a/pkg/wms130/getmap_test.go
+++ b/pkg/wms130/getmap_test.go
@@ -328,18 +328,18 @@ func TestGetMapParseQueryParameters(t *testing.T) {
BGCOLOR: {`0x7F7F7F`},
},
exception: InvalidParameterValue(`zzzz`, TRANSPARENT),
- },
+ },
//REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&LAYERS=Rivers,Roads,Houses&STYLES=CenterLine,CenterLine,Outline&CRS=EPSG:4326&BBOX=-180.0,-90.0,180.0,90.0&WIDTH=1024&HEIGHT=512&FORMAT=image/jpeg&EXCEPTIONS=XML
4: {query: map[string][]string{REQUEST: {getmap}, SERVICE: {Service}, VERSION: {Version},
- LAYERS: {`Rivers,Roads,Houses`},
- STYLES: {`CenterLine,CenterLine,Outline`},
- "CRS": {`EPSG:4326`},
- BBOX: {`-180.0,-90.0,180.0,90.0`},
- WIDTH: {`1024`},
- HEIGHT: {`512`},
- FORMAT: {`image/jpeg`},
- EXCEPTIONS: {`XML`},
- BGCOLOR: {`0x7F7F7F`},
+ LAYERS: {`Rivers,Roads,Houses`},
+ STYLES: {`CenterLine,CenterLine,Outline`},
+ "CRS": {`EPSG:4326`},
+ BBOX: {`-180.0,-90.0,180.0,90.0`},
+ WIDTH: {`1024`},
+ HEIGHT: {`512`},
+ FORMAT: {`image/jpeg`},
+ EXCEPTIONS: {`XML`},
+ BGCOLOR: {`0x7F7F7F`},
},
excepted: GetMapRequest{
BaseRequest: BaseRequest{
@@ -365,15 +365,15 @@ func TestGetMapParseQueryParameters(t *testing.T) {
}},
//REQUEST=GetMap&SERVICE=WMS&VERSION=1.3.0&LAYERS=Rivers&STYLES=&CRS=EPSG:4326&BBOX=-180.0,-90.0,180.0,90.0&WIDTH=1024&HEIGHT=512&FORMAT=image/jpeg&EXCEPTIONS=XML
5: {query: map[string][]string{REQUEST: {getmap}, SERVICE: {Service}, VERSION: {Version},
- LAYERS: {`Rivers`},
- STYLES: {``},
- "CRS": {`EPSG:4326`},
- BBOX: {`-180.0,-90.0,180.0,90.0`},
- WIDTH: {`1024`},
- HEIGHT: {`512`},
- FORMAT: {`image/jpeg`},
- EXCEPTIONS: {`XML`},
- BGCOLOR: {`0x7F7F7F`},
+ LAYERS: {`Rivers`},
+ STYLES: {``},
+ "CRS": {`EPSG:4326`},
+ BBOX: {`-180.0,-90.0,180.0,90.0`},
+ WIDTH: {`1024`},
+ HEIGHT: {`512`},
+ FORMAT: {`image/jpeg`},
+ EXCEPTIONS: {`XML`},
+ BGCOLOR: {`0x7F7F7F`},
},
excepted: GetMapRequest{
BaseRequest: BaseRequest{
@@ -666,7 +666,7 @@ func TestGetMapValidate(t *testing.T) {
Request: Request{
GetMap: RequestType{
Format: []string{`image/jpeg`},
- DCPType: DCPType{},
+ DCPType: &DCPType{},
},
},
Layer: []Layer{
diff --git a/pkg/wmts100/capabilities_test.go b/pkg/wmts100/capabilities_test.go
index 47936c7..9c4cc76 100644
--- a/pkg/wmts100/capabilities_test.go
+++ b/pkg/wmts100/capabilities_test.go
@@ -51,8 +51,8 @@ var contentsWithLegend = Contents{
func TestBuildStyleWithLegend(t *testing.T) {
expected := ``
output, _ := xml.MarshalIndent(contentsWithLegend.Layer[0].Style, "", " ")
@@ -91,8 +91,8 @@ var contentsWithoutLegend = Contents{
func TestBuildStyleWithoutLegend(t *testing.T) {
expected := ``
output, _ := xml.MarshalIndent(contentsWithoutLegend.Layer[0].Style, "", " ")
if string(output) != expected {
diff --git a/pkg/wmts100/getcapabilities_response.go b/pkg/wmts100/getcapabilities_response.go
index 45ea9bc..18d51a6 100644
--- a/pkg/wmts100/getcapabilities_response.go
+++ b/pkg/wmts100/getcapabilities_response.go
@@ -38,11 +38,11 @@ func (gc GetCapabilitiesResponse) ToXML() []byte {
type GetCapabilitiesResponse struct {
XMLName xml.Name `xml:"Capabilities"`
Namespaces `yaml:"namespaces"`
- ServiceIdentification ServiceIdentification `xml:"ows:ServiceIdentification" yaml:"serviceidentification"`
- ServiceProvider wsc110.ServiceProvider `xml:"ows:ServiceProvider,omitempty" yaml:"serviceprovider"`
- OperationsMetadata *OperationsMetadata `xml:"ows:OperationsMetadata,omitempty" yaml:"operationsmetadata"`
- Contents Contents `xml:"Contents" yaml:"contents"`
- ServiceMetadataURL *ServiceMetadataURL `xml:"ServiceMetadataURL,omitempty" yaml:"servicemetadataurl"`
+ ServiceIdentification ServiceIdentification `xml:"ows:ServiceIdentification" yaml:"serviceidentification"`
+ ServiceProvider *wsc110.ServiceProvider `xml:"ows:ServiceProvider,omitempty" yaml:"serviceprovider"`
+ OperationsMetadata *OperationsMetadata `xml:"ows:OperationsMetadata,omitempty" yaml:"operationsmetadata"`
+ Contents Contents `xml:"Contents" yaml:"contents"`
+ ServiceMetadataURL *ServiceMetadataURL `xml:"ServiceMetadataURL,omitempty" yaml:"servicemetadataurl"`
}
// Namespaces struct containing the namespaces needed for the XML document
@@ -97,13 +97,13 @@ type Method struct {
// ServiceIdentification struct should only be fill by the "template" configuration wmts100.yaml
type ServiceIdentification struct {
- Title string `xml:"ows:Title" yaml:"title"`
- Abstract string `xml:"ows:Abstract" yaml:"abstract"`
- Keywords wsc110.Keywords `xml:"ows:Keywords,omitempty" yaml:"keywords"`
- ServiceType string `xml:"ows:ServiceType" yaml:"servicetype"`
- ServiceTypeVersion string `xml:"ows:ServiceTypeVersion" yaml:"servicetypeversion"`
- Fees string `xml:"ows:Fees" yaml:"fees"`
- AccessConstraints string `xml:"ows:AccessConstraints" yaml:"accessconstraints"`
+ Title string `xml:"ows:Title" yaml:"title"`
+ Abstract string `xml:"ows:Abstract" yaml:"abstract"`
+ Keywords *wsc110.Keywords `xml:"ows:Keywords,omitempty" yaml:"keywords"`
+ ServiceType string `xml:"ows:ServiceType" yaml:"servicetype"`
+ ServiceTypeVersion string `xml:"ows:ServiceTypeVersion" yaml:"servicetypeversion"`
+ Fees string `xml:"ows:Fees" yaml:"fees"`
+ AccessConstraints string `xml:"ows:AccessConstraints" yaml:"accessconstraints"`
}
// ServiceMetadataURL in struct for repeatability
diff --git a/pkg/wsc110/keywords.go b/pkg/wsc110/keywords.go
index 3077915..7eeb266 100644
--- a/pkg/wsc110/keywords.go
+++ b/pkg/wsc110/keywords.go
@@ -2,6 +2,9 @@ package wsc110
// Keywords in struct for repeatability
type Keywords struct {
- Keyword []string `xml:"ows:Keyword" yaml:"keyword"`
- Type string `xml:"ows:Type,omitempty" yaml:"type"`
+ Keyword []string `xml:"ows:Keyword"`
+ Type *struct {
+ Text string `xml:",chardata"`
+ CodeSpace *string `xml:"codeSpace,attr,omitempty"`
+ } `xml:"ows:Type"`
}