django-gisserver 1.5.0__py3-none-any.whl → 2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. {django_gisserver-1.5.0.dist-info → django_gisserver-2.1.dist-info}/METADATA +34 -8
  2. django_gisserver-2.1.dist-info/RECORD +68 -0
  3. {django_gisserver-1.5.0.dist-info → django_gisserver-2.1.dist-info}/WHEEL +1 -1
  4. gisserver/__init__.py +1 -1
  5. gisserver/compat.py +23 -0
  6. gisserver/conf.py +7 -0
  7. gisserver/crs.py +401 -0
  8. gisserver/db.py +126 -51
  9. gisserver/exceptions.py +132 -4
  10. gisserver/extensions/__init__.py +4 -0
  11. gisserver/{parsers/fes20 → extensions}/functions.py +131 -31
  12. gisserver/extensions/queries.py +266 -0
  13. gisserver/features.py +253 -181
  14. gisserver/geometries.py +64 -311
  15. gisserver/management/__init__.py +0 -0
  16. gisserver/management/commands/__init__.py +0 -0
  17. gisserver/management/commands/loadgeojson.py +311 -0
  18. gisserver/operations/base.py +130 -312
  19. gisserver/operations/wfs20.py +399 -375
  20. gisserver/output/__init__.py +14 -49
  21. gisserver/output/base.py +198 -144
  22. gisserver/output/csv.py +78 -75
  23. gisserver/output/geojson.py +37 -37
  24. gisserver/output/gml32.py +287 -259
  25. gisserver/output/iters.py +207 -0
  26. gisserver/output/results.py +73 -61
  27. gisserver/output/stored.py +143 -0
  28. gisserver/output/utils.py +81 -169
  29. gisserver/output/xmlschema.py +85 -46
  30. gisserver/parsers/__init__.py +10 -10
  31. gisserver/parsers/ast.py +426 -0
  32. gisserver/parsers/fes20/__init__.py +89 -31
  33. gisserver/parsers/fes20/expressions.py +172 -58
  34. gisserver/parsers/fes20/filters.py +116 -45
  35. gisserver/parsers/fes20/identifiers.py +66 -28
  36. gisserver/parsers/fes20/lookups.py +146 -0
  37. gisserver/parsers/fes20/operators.py +417 -161
  38. gisserver/parsers/fes20/sorting.py +113 -34
  39. gisserver/parsers/gml/__init__.py +17 -25
  40. gisserver/parsers/gml/base.py +36 -15
  41. gisserver/parsers/gml/geometries.py +105 -44
  42. gisserver/parsers/ows/__init__.py +25 -0
  43. gisserver/parsers/ows/kvp.py +198 -0
  44. gisserver/parsers/ows/requests.py +160 -0
  45. gisserver/parsers/query.py +179 -0
  46. gisserver/parsers/values.py +87 -4
  47. gisserver/parsers/wfs20/__init__.py +39 -0
  48. gisserver/parsers/wfs20/adhoc.py +253 -0
  49. gisserver/parsers/wfs20/base.py +148 -0
  50. gisserver/parsers/wfs20/projection.py +103 -0
  51. gisserver/parsers/wfs20/requests.py +483 -0
  52. gisserver/parsers/wfs20/stored.py +193 -0
  53. gisserver/parsers/xml.py +261 -0
  54. gisserver/projection.py +367 -0
  55. gisserver/static/gisserver/index.css +20 -4
  56. gisserver/templates/gisserver/base.html +12 -0
  57. gisserver/templates/gisserver/index.html +9 -15
  58. gisserver/templates/gisserver/service_description.html +12 -6
  59. gisserver/templates/gisserver/wfs/2.0.0/get_capabilities.xml +9 -9
  60. gisserver/templates/gisserver/wfs/feature_field.html +3 -3
  61. gisserver/templates/gisserver/wfs/feature_type.html +35 -13
  62. gisserver/templatetags/gisserver_tags.py +20 -0
  63. gisserver/types.py +445 -313
  64. gisserver/views.py +227 -62
  65. django_gisserver-1.5.0.dist-info/RECORD +0 -54
  66. gisserver/parsers/base.py +0 -149
  67. gisserver/parsers/fes20/query.py +0 -285
  68. gisserver/parsers/tags.py +0 -102
  69. gisserver/queries/__init__.py +0 -37
  70. gisserver/queries/adhoc.py +0 -185
  71. gisserver/queries/base.py +0 -186
  72. gisserver/queries/projection.py +0 -240
  73. gisserver/queries/stored.py +0 -206
  74. gisserver/templates/gisserver/wfs/2.0.0/describe_stored_queries.xml +0 -20
  75. gisserver/templates/gisserver/wfs/2.0.0/list_stored_queries.xml +0 -14
  76. {django_gisserver-1.5.0.dist-info → django_gisserver-2.1.dist-info/licenses}/LICENSE +0 -0
  77. {django_gisserver-1.5.0.dist-info → django_gisserver-2.1.dist-info}/top_level.txt +0 -0
@@ -1,18 +1,31 @@
1
+ """The FES elements that handle sorting."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  from dataclasses import dataclass
4
6
  from enum import Enum
5
7
 
6
8
  from gisserver.exceptions import InvalidParameterValue
9
+ from gisserver.parsers.ast import AstNode, expect_children, expect_tag, tag_registry
7
10
  from gisserver.parsers.fes20 import ValueReference
11
+ from gisserver.parsers.ows import KVPRequest
12
+ from gisserver.parsers.query import CompiledQuery
13
+ from gisserver.parsers.xml import NSElement, xmlns
14
+
15
+ FES_SORT_ORDER = xmlns.fes20.qname("SortOrder")
8
16
 
9
17
 
10
18
  class SortOrder(Enum):
19
+ #: Ascending order
11
20
  ASC = ""
21
+ #: Descrending order
12
22
  DESC = "-"
13
23
 
14
- # Support WFS 1 names for clients that still use this.
24
+ # Support WFS 1 names for clients that still use this:
25
+
26
+ #: WFS 1 name that clients still use for ascending.
15
27
  A = ASC
28
+ #: WFS 1 name that clients still use for descending.
16
29
  D = DESC
17
30
 
18
31
  @classmethod
@@ -24,52 +37,118 @@ class SortOrder(Enum):
24
37
  "Expect ASC/DESC ordering direction", locator="sortby"
25
38
  ) from None
26
39
 
40
+ @classmethod
41
+ @expect_tag(xmlns.fes20, "SortOrder")
42
+ def from_xml(cls, element: NSElement):
43
+ return SortOrder.from_string(element.text)
44
+
27
45
 
28
46
  @dataclass
29
- class SortProperty:
30
- """This class name is based on the WFS spec."""
47
+ @tag_registry.register("SortProperty", xmlns.fes20)
48
+ class SortProperty(AstNode):
49
+ """This class name is based on the WFS spec.
50
+
51
+ This parses and handles the syntax::
52
+
53
+ <fes:SortProperty>
54
+ <fes:ValueReference>name</fes:ValueReference>
55
+ <fes:SortOrder>ASC</fes:SortOrder>
56
+ </fes:SortProperty>
57
+ """
31
58
 
32
59
  value_reference: ValueReference
33
60
  sort_order: SortOrder = SortOrder.ASC
34
61
 
62
+ def __post_init__(self):
63
+ if "[" in self.value_reference.xpath:
64
+ raise InvalidParameterValue(
65
+ "Sorting with XPath attribute selectors is not supported.", locator="sortby"
66
+ )
67
+
68
+ @classmethod
69
+ @expect_tag(xmlns.fes20, "SortProperty")
70
+ @expect_children(1, ValueReference, FES_SORT_ORDER)
71
+ def from_xml(cls, element: NSElement) -> SortProperty:
72
+ """Parse the incoming XML"""
73
+ sort_order = element.find(FES_SORT_ORDER)
74
+ return cls(
75
+ value_reference=ValueReference.from_xml(element[0]),
76
+ sort_order=(
77
+ SortOrder.from_xml(sort_order) if sort_order is not None else SortOrder.ASC
78
+ ),
79
+ )
80
+
81
+ @classmethod
82
+ def from_string(cls, value: str, ns_aliases: dict[str, str]) -> SortProperty:
83
+ """Parse the incoming GET parameter."""
84
+ xpath, _, direction = value.partition(" ")
85
+ return SortProperty(
86
+ value_reference=ValueReference(xpath, ns_aliases),
87
+ sort_order=SortOrder.from_string(direction) if direction else SortOrder.ASC,
88
+ )
89
+
90
+ def as_kvp(self):
91
+ """Translate the POST request into KVP GET parameters. This is needed for pagination."""
92
+ if self.sort_order == SortOrder.ASC:
93
+ return self.value_reference.xpath
94
+ else:
95
+ return f"{self.value_reference.xpath} {self.sort_order.name}"
96
+
35
97
 
36
98
  @dataclass
37
- class SortBy:
38
- """The sortBy clause."""
99
+ @tag_registry.register("SortBy", xmlns.fes20)
100
+ class SortBy(AstNode):
101
+ """The sortBy clause.
102
+
103
+ This parses and handles the syntax::
104
+
105
+ <fes:SortBy>
106
+ <fes:SortProperty>
107
+ <fes:ValueReference>name</fes:ValueReference>
108
+ <fes:SortOrder>ASC</fes:SortOrder>
109
+ </fes:SortProperty>
110
+ </fes:SortBy>
39
111
 
112
+ It also supports the SORTBY parameter for GET requests.
113
+ """
114
+
115
+ #: The ``<fes:SortProperty>`` elements.
40
116
  sort_properties: list[SortProperty]
41
117
 
42
118
  @classmethod
43
- def from_string(cls, value: str):
44
- """Construct the SortBy object from a KVP "SORTBY" parameter."""
45
- props = []
46
- for field in value.split(","):
47
- if "[" in field:
48
- raise InvalidParameterValue(
49
- "sortby", "Sorting with XPath attribute selectors is not supported."
50
- )
51
-
52
- if " " in field:
53
- xpath, direction = field.split(" ", 1)
54
- props.append(
55
- SortProperty(
56
- value_reference=ValueReference(xpath),
57
- sort_order=SortOrder.from_string(direction),
58
- )
59
- )
60
- else:
61
- props.append(SortProperty(value_reference=ValueReference(field)))
62
-
63
- return cls(sort_properties=props)
64
-
65
- def build_ordering(self, feature_type=None) -> list[str]:
119
+ @expect_children(1, SortProperty)
120
+ def from_xml(cls, element: NSElement) -> SortBy:
121
+ """Parse the XML tag."""
122
+ return cls(
123
+ sort_properties=[
124
+ # The from_xml() validates that the child node is a <fes:SortProperty>
125
+ SortProperty.from_xml(child)
126
+ for child in element
127
+ ]
128
+ )
129
+
130
+ @classmethod
131
+ def from_kvp_request(cls, kvp: KVPRequest) -> SortBy | None:
132
+ """Construct the SortBy object from a KVP "SORTBY" parameter, and considering NAMESPACES."""
133
+ value = kvp.get_str("SortBy", default=None)
134
+ if value is None:
135
+ return None
136
+
137
+ return cls(
138
+ sort_properties=[
139
+ SortProperty.from_string(field, kvp.ns_aliases) for field in value.split(",")
140
+ ]
141
+ )
142
+
143
+ def as_kvp(self) -> str:
144
+ """Translate the POST request into KVP GET parameters. This is needed for pagination."""
145
+ return ",".join(sort_property.as_kvp() for sort_property in self.sort_properties)
146
+
147
+ def build_ordering(self, compiler: CompiledQuery):
66
148
  """Build the ordering for the Django ORM call."""
67
149
  ordering = []
68
150
  for prop in self.sort_properties:
69
- if feature_type is not None:
70
- orm_path = prop.value_reference.parse_xpath(feature_type).orm_path
71
- else:
72
- orm_path = prop.value_reference.xpath.replace("/", "__")
73
-
151
+ orm_path = prop.value_reference.parse_xpath(compiler.feature_types).orm_path
74
152
  ordering.append(f"{prop.sort_order.value}{orm_path}")
75
- return ordering
153
+
154
+ compiler.add_ordering(ordering)
@@ -1,54 +1,46 @@
1
- """Generic support for various GML versions.
1
+ """Additional parsing logic for GML values.
2
2
 
3
- These functions locate GML objects, and redirect to the proper parser.
3
+ Most GML elements are parsed through GeoDjango by using the GEOSGeometry element.
4
4
  """
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
- from xml.etree.ElementTree import Element
9
-
10
- from defusedxml.ElementTree import fromstring
11
-
12
8
  from gisserver.exceptions import ExternalParsingError
13
- from gisserver.parsers.base import tag_registry
9
+ from gisserver.parsers.ast import tag_registry
10
+ from gisserver.parsers.xml import NSElement, parse_xml_from_string
14
11
 
15
12
  from .base import AbstractGeometry, GM_Envelope, GM_Object, TM_Object
16
- from .geometries import is_gml_element # also do tag registration
17
-
18
- # All known root nodes as GML object:
19
- FES_GML_NODES = (GM_Object, GM_Envelope, TM_Object)
13
+ from .geometries import GEOSGMLGeometry, is_gml_element # also do tag registration
20
14
 
21
15
  __all__ = [
22
16
  "GM_Object",
23
17
  "GM_Envelope",
24
18
  "TM_Object",
25
19
  "AbstractGeometry",
20
+ "GEOSGMLGeometry",
26
21
  "parse_gml",
27
22
  "parse_gml_node",
28
23
  "find_gml_nodes",
29
24
  ]
30
25
 
31
26
 
32
- def parse_gml(text: str | bytes) -> FES_GML_NODES:
27
+ def parse_gml(text: str | bytes) -> GM_Object | GM_Envelope | TM_Object:
33
28
  """Parse an XML <gml:...> string."""
34
- root_element = fromstring(text)
29
+ root_element = parse_xml_from_string(text)
35
30
  return parse_gml_node(root_element)
36
31
 
37
32
 
38
- def parse_gml_node(element: Element) -> FES_GML_NODES:
39
- """Parse the element"""
33
+ def parse_gml_node(element: NSElement) -> GM_Object | GM_Envelope | TM_Object:
34
+ """Parse the GML element."""
40
35
  if not is_gml_element(element):
41
36
  raise ExternalParsingError(f"Expected GML namespace for {element.tag}")
42
37
 
43
- return tag_registry.from_child_xml(element, allowed_types=FES_GML_NODES)
44
-
38
+ # All known root nodes as GML object:
39
+ return tag_registry.node_from_xml(element, allowed_types=(GM_Object, GM_Envelope, TM_Object))
45
40
 
46
- def find_gml_nodes(element: Element) -> list[Element]:
47
- """Find all gml elements in a node"""
48
- result = []
49
- for child in element:
50
- # This selects all GML elements, including 2.1
51
- if is_gml_element(child):
52
- result.append(child)
53
41
 
54
- return result
42
+ def find_gml_nodes(element: NSElement) -> list[NSElement]:
43
+ """Find all ``<gml:...>`` elements in a node.
44
+ This selects all GML elements, including GML 2.1 tags.
45
+ """
46
+ return [child for child in element if is_gml_element(child)]
@@ -4,28 +4,37 @@ See "Table D.2" in the GML 3.2.1 spec, showing how the UML names
4
4
  map to the GML implementations. These names are referenced by the FES spec.
5
5
  """
6
6
 
7
- from gisserver.parsers.base import BaseNode
7
+ from __future__ import annotations
8
8
 
9
+ from gisserver.parsers.ast import AstNode
10
+ from gisserver.parsers.query import CompiledQuery
9
11
 
10
- class AbstractGeometry(BaseNode):
11
- """Abstract base classes for all GML objects, regardless of their version.
12
+ __all__ = (
13
+ "GM_Object",
14
+ "GM_Envelope",
15
+ "TM_Object",
16
+ "AbstractTimeObject",
17
+ "AbstractTimePrimitive",
18
+ "Envelope",
19
+ "AbstractGeometry",
20
+ )
12
21
 
13
- <gml:AbstractGeometry> implements the ISO 19107 GM_Object.
14
- """
15
22
 
16
- def build_rhs(self, compiler):
17
- # Allow the value to be used in a binary operator
23
+ class GM_Object(AstNode):
24
+ """Abstract base classes for all GML objects, regardless of their version."""
25
+
26
+ def build_rhs(self, compiler: CompiledQuery):
27
+ """Required function to implement.
28
+ This allows using the value to be used in a binary operator.
29
+ """
18
30
  raise NotImplementedError()
19
31
 
20
32
 
21
- class Envelope(BaseNode):
22
- """Abstract base classes for all GML objects, regardless of their version.
33
+ class GM_Envelope(AstNode):
34
+ """Abstract base classes for the GML envelope, regardless of their version."""
23
35
 
24
- <gml:Envelope> implements ISO 19107 GM_Envelope (see D.2.3.4 and ISO 19107:2003, 6.4.3).
25
- """
26
36
 
27
-
28
- class TM_Object(BaseNode):
37
+ class TM_Object(AstNode):
29
38
  """Abstract base classes for temporal GML objects, regardless of their version.
30
39
 
31
40
  See ISO 19108 TM_Object (see D.2.5.2 and ISO 19108:2002, 5.2.2)
@@ -33,5 +42,17 @@ class TM_Object(BaseNode):
33
42
 
34
43
 
35
44
  # Instead of polluting the MRO with unneeded base classes, create aliases:
36
- GM_Object = AbstractGeometry
37
- GM_Envelope = Envelope
45
+
46
+ #: The ``<gml:AbstractGeometry>`` definition implements the ISO 19107 GM_Object.
47
+ AbstractGeometry = GM_Object
48
+
49
+ #: The ``<gml:Envelope>`` implements ISO 19107 GM_Envelope (see D.2.3.4 and ISO 19107:2003, 6.4.3).
50
+ Envelope = GM_Envelope
51
+
52
+ # See https://www.mediamaps.ch/ogc/schemas-xsdoc/sld/1.1.0/temporal_xsd.html
53
+
54
+ #: The base class for all time objects
55
+ AbstractTimeObject = TM_Object
56
+
57
+ #: The base classes for time primitives.
58
+ AbstractTimePrimitive = AbstractTimeObject
@@ -4,16 +4,18 @@ Overview of GML 3.2 changes: https://mapserver.org/el/development/rfc/ms-rfc-105
4
4
  """
5
5
 
6
6
  from dataclasses import dataclass
7
- from xml.etree.ElementTree import Element, tostring
7
+ from xml.etree.ElementTree import tostring
8
8
 
9
- from django.contrib.gis.geos import GEOSGeometry
9
+ from django.contrib.gis.gdal import AxisOrder
10
+ from django.contrib.gis.geos import GEOSGeometry, Polygon
10
11
 
11
- from gisserver.geometries import CRS
12
- from gisserver.parsers.base import tag_registry
13
- from gisserver.parsers.tags import get_attribute
14
- from gisserver.types import GML21, GML32
12
+ from gisserver.crs import CRS
13
+ from gisserver.exceptions import ExternalParsingError
14
+ from gisserver.parsers.ast import tag_registry
15
+ from gisserver.parsers.query import CompiledQuery
16
+ from gisserver.parsers.xml import NSElement, xmlns
15
17
 
16
- from .base import AbstractGeometry, TM_Object
18
+ from .base import AbstractGeometry, AbstractTimePrimitive
17
19
 
18
20
  _ANY_GML_NS = "{http://www.opengis.net/gml/"
19
21
 
@@ -24,18 +26,20 @@ def is_gml_element(element) -> bool:
24
26
 
25
27
 
26
28
  @dataclass(repr=False)
27
- @tag_registry.register("Polygon", GML21)
28
- @tag_registry.register("LineString", GML32)
29
- @tag_registry.register("LinearRing", GML32)
30
- @tag_registry.register("MultiLineString", GML32)
31
- @tag_registry.register("MultiPoint", GML32)
32
- @tag_registry.register("MultiPolygon", GML32)
33
- @tag_registry.register("MultiSurface", GML32)
34
- @tag_registry.register("Point", GML32)
35
- @tag_registry.register("Polygon", GML32)
36
- @tag_registry.register("Envelope", GML32)
29
+ @tag_registry.register("Polygon", xmlns.gml21)
30
+ @tag_registry.register("LineString", xmlns.gml32)
31
+ @tag_registry.register("LinearRing", xmlns.gml32)
32
+ @tag_registry.register("MultiLineString", xmlns.gml32)
33
+ @tag_registry.register("MultiPoint", xmlns.gml32)
34
+ @tag_registry.register("MultiPolygon", xmlns.gml32)
35
+ @tag_registry.register("MultiSurface", xmlns.gml32)
36
+ @tag_registry.register("Point", xmlns.gml32)
37
+ @tag_registry.register("Polygon", xmlns.gml32)
38
+ @tag_registry.register("Envelope", xmlns.gml32)
37
39
  class GEOSGMLGeometry(AbstractGeometry):
38
- """Convert the incoming GML into a Django GEOSGeometry"""
40
+ """Convert the incoming GML into a Django GEOSGeometry.
41
+ This tag parses all ``<gml:...>`` geometry elements within the query.
42
+ """
39
43
 
40
44
  # Not implemented:
41
45
  # - Curve
@@ -43,30 +47,54 @@ class GEOSGMLGeometry(AbstractGeometry):
43
47
  # - MultiGeometry
44
48
  # - Surface
45
49
 
46
- xml_ns = ...
47
-
48
50
  srs: CRS
49
51
  geos_data: GEOSGeometry
50
52
 
51
53
  @classmethod
52
- def from_xml(cls, element: Element):
54
+ def from_bbox(cls, bbox_value: str):
55
+ """Parse the bounding box from an input string.
56
+
57
+ It can either be 4 coordinates, or 4 coordinates with a special reference system.
58
+ """
59
+ bbox = bbox_value.split(",")
60
+ if not (4 <= len(bbox) <= 5):
61
+ raise ExternalParsingError(
62
+ f"Input does not contain bounding box, expected 4 or 5 values, not {bbox}."
63
+ )
64
+
65
+ polygon = Polygon.from_bbox(
66
+ (float(bbox[0]), float(bbox[1]), float(bbox[2]), float(bbox[3]))
67
+ )
68
+ if len(bbox) == 5:
69
+ crs = CRS.from_string(bbox[4])
70
+ polygon.srid = crs.srid
71
+ else:
72
+ crs = None # will be resolved
73
+
74
+ # Wrap in an element that the filter can use.
75
+ CRS.tag_geometry(polygon, axis_order=AxisOrder.AUTHORITY)
76
+ return cls(srs=crs, geos_data=polygon)
77
+
78
+ @classmethod
79
+ def from_xml(cls, element: NSElement):
53
80
  """Push the whole <gml:...> element into the GEOS parser.
54
81
  This avoids having to support the whole GEOS logic.
55
82
 
56
83
  GML is a complex beast with many different forms for the same thing:
57
84
  http://erouault.blogspot.com/2014/04/gml-madness.html
58
85
  """
59
- srs = CRS.from_string(get_attribute(element, "srsName"))
86
+ srs = CRS.from_string(element.get_str_attribute("srsName"))
60
87
 
61
88
  # Push the whole <gml:...> element into the GEOS parser.
62
89
  # This avoids having to support the whole GEOS logic.
63
90
  geos_data = GEOSGeometry.from_gml(tostring(element))
64
91
  geos_data.srid = srs.srid
92
+ CRS.tag_geometry(geos_data, axis_order=AxisOrder.AUTHORITY)
65
93
  return cls(srs=srs, geos_data=geos_data)
66
94
 
67
95
  def __repr__(self):
68
96
  # Better rendering for unit test debugging
69
- return f"GMLGEOSGeometry(srs={self.srs!r}, geos_data=GEOSGeometry({self.geos_data.wkt!r}))"
97
+ return f"{self.__class__.__name__}(srs={self.srs!r}, geos_data=GEOSGeometry({self.geos_data.wkt!r}))"
70
98
 
71
99
  @property
72
100
  def wkt(self) -> str:
@@ -77,24 +105,57 @@ class GEOSGMLGeometry(AbstractGeometry):
77
105
  def json(self):
78
106
  return self.geos_data.json
79
107
 
80
- def build_rhs(self, compiler):
81
- return self.geos_data
82
-
83
-
84
- @tag_registry.register("After", GML32)
85
- @tag_registry.register("Before", GML32)
86
- @tag_registry.register("Begins", GML32)
87
- @tag_registry.register("BegunBy", GML32)
88
- @tag_registry.register("TContains", GML32)
89
- @tag_registry.register("TEquals", GML32)
90
- @tag_registry.register("TOverlaps", GML32)
91
- @tag_registry.register("During", GML32)
92
- @tag_registry.register("Meets", GML32)
93
- @tag_registry.register("OverlappedBy", GML32)
94
- @tag_registry.register("MetBy", GML32)
95
- @tag_registry.register("EndedBy", GML32)
96
- @tag_registry.register("AnyInteracts", GML32)
97
- class TM_GeometricPrimitive(TM_Object):
98
- """Not implemented: the whole GML temporal logic"""
99
-
100
- xml_ns = GML32
108
+ def build_rhs(self, compiler: CompiledQuery):
109
+ # Perform final validation during the construction of the query.
110
+ if self.srs is None:
111
+ # When the feature type is known, apply its default CRS.
112
+ # This is not possible in XML parsing, but may happen for BBOX parsing.
113
+ self.srs = compiler.feature_types[0].crs
114
+ self.geos_data.srid = self.srs.srid # assign default CRS to geometry
115
+ elif compiler.feature_types: # for unit tests
116
+ self.srs = compiler.feature_types[0].resolve_crs(self.srs, locator="bbox")
117
+
118
+ # Make sure the data is suitable for processing by the ORM.
119
+ # The database needs the geometry in traditional (x/y) ordering.
120
+ if self.srs.is_north_east_order:
121
+ return self.srs.apply_to(self.geos_data, clone=True, axis_order=AxisOrder.TRADITIONAL)
122
+ else:
123
+ return self.geos_data
124
+
125
+
126
+ @tag_registry.register("TimeInstant", hidden=True)
127
+ @tag_registry.register("TimePeriod", hidden=True)
128
+ class AbstractTimeGeometricPrimitive(AbstractTimePrimitive):
129
+ """Not implemented: the whole GML temporal logic.
130
+
131
+ Examples for GML time elements include::
132
+
133
+ <gml:TimeInstant gml:id="TI1">
134
+ <gml:timePosition>2005-05-19T09:28:40Z</gml:timePosition>
135
+ </gml:TimeInstant>
136
+
137
+ and::
138
+
139
+ <gml:TimePeriod gml:id="TP1">
140
+ <gml:begin>
141
+ <gml:TimeInstant gml:id="TI1">
142
+ <gml:timePosition>2005-05-17T00:00:00Z</gml:timePosition>
143
+ </gml:TimeInstant>
144
+ </gml:begin>
145
+ <gml:end>
146
+ <gml:TimeInstant gml:id="TI2">
147
+ <gml:timePosition>2005-05-23T00:00:00Z</gml:timePosition>
148
+ </gml:TimeInstant>
149
+ </gml:end>
150
+ </gml:TimePeriod>
151
+ """
152
+
153
+ xml_ns = xmlns.gml32
154
+
155
+
156
+ @tag_registry.register("TimeNode", hidden=True)
157
+ @tag_registry.register("TimeEdge", hidden=True)
158
+ class AbstractTimeTopologyPrimitiveType(AbstractTimePrimitive):
159
+ """Not implemented: GML temporal logic for TimeNode/TimeEdge."""
160
+
161
+ xml_ns = xmlns.gml32
@@ -0,0 +1,25 @@
1
+ """Generic Open Web Services (OWS) protocol bits to handle incoming requests.
2
+
3
+ This is the common logic between WFS, WMS and other protocols.
4
+
5
+ These translate both request-syntax formats in the same internal objects
6
+ that the rest of the controller/view logic can use.
7
+ """
8
+
9
+ from .kvp import KVPRequest
10
+ from .requests import (
11
+ BaseOwsRequest,
12
+ parse_get_request,
13
+ parse_post_request,
14
+ resolve_kvp_parser_class,
15
+ resolve_xml_parser_class,
16
+ )
17
+
18
+ __all__ = (
19
+ "KVPRequest",
20
+ "BaseOwsRequest",
21
+ "resolve_kvp_parser_class",
22
+ "resolve_xml_parser_class",
23
+ "parse_get_request",
24
+ "parse_post_request",
25
+ )