Coverage for gws-app/gws/base/ows/server/filter.py: 0%
44 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
1"""Search filters"""
3import re
5import gws
6import gws.gis.bounds
7import gws.base.shape
8import gws.lib.xmlx as xmlx
11class Error(gws.Error):
12 pass
15"""
16OGC fes 2.0 filter
18http://docs.opengeospatial.org/is/09-026r2/09-026r2.html
20Supports
22 - Minimum Standard Filter
23 PropertyIsEqualTo, PropertyIsNotEqualTo, PropertyIsLessThan, PropertyIsGreaterThan,
24 PropertyIsLessThanOrEqualTo, PropertyIsGreaterThanOrEqualTo.
25 Implements the logical operators. Does not implement any additional functions.
27 - Minimum Spatial Filter
28 Implements only the BBOX spatial operator.
29"""
31_SUPPORTED_OPS = {
32 'propertyisequalto': '=',
33 'propertyisnotequalto': '!=',
34 'propertyislessthan': '<',
35 'propertyisgreaterthan': '>',
36 'propertyislessthanorequalto': '=<',
37 'propertyisgreaterthanorequalto': '>=',
38 'bbox': 'bbox',
39}
42def from_fes_string(src: str) -> gws.SearchFilter:
43 try:
44 el = xmlx.from_string(src)
45 except Exception as exc:
46 raise Error('invalid XML') from exc
47 return from_fes_element(el)
50def from_fes_element(el: gws.XmlElement) -> gws.SearchFilter:
51 op = el.tag.lower()
53 if op == 'filter':
54 # root element, only allow a single child predicate
55 if len(el) != 1:
56 raise Error(f'invalid root predicate')
57 return from_fes_element(el.children[0])
59 if op in ('and', 'or'):
60 return gws.SearchFilter(operator=op, sub=[from_fes_element(c) for c in el.children])
62 if op not in _SUPPORTED_OPS:
63 raise Error(f'unsupported filter operation {el.name!r}')
65 f = gws.SearchFilter(
66 operator=_SUPPORTED_OPS[op],
67 )
69 # @TODO support "prop = prop"
71 v = el.first('ValueReference', 'PropertyName')
72 if not v or not v.text:
73 raise Error(f'invalid property name')
75 # we only support `propName` or `ns:propName`
76 m = re.match(r'^(\w+:)?(\w+)$', v.text)
77 if not m:
78 raise Error(f'invalid property name {v.text!r}')
79 f.name = m.group(2)
81 if op == 'bbox':
82 v = el.first('Envelope')
83 if v:
84 bounds = gws.gis.bounds.from_gml_envelope_element()
85 f.shape = gws.base.shape.from_bounds(bounds)
86 return f
88 v = el.first('Literal')
89 if v:
90 f.value = v.text.strip()
91 return f
93 raise Error(f'unsupported filter')