40 |
getLayerBBox(layer, srs) |
getLayerBBox(layer, srs) |
41 |
|
|
42 |
isQueryable(layer) |
isQueryable(layer) |
|
|
|
|
get_srs_discrepancies() |
|
43 |
""" |
""" |
44 |
|
|
45 |
__version__ = "$Revision$" |
__version__ = "$Revision$" |
47 |
# $Id$ |
# $Id$ |
48 |
|
|
49 |
import xml.dom.minidom |
import xml.dom.minidom |
50 |
|
from xml.dom import Node |
51 |
|
|
52 |
from domutils import getElementsByName, getElementByName |
from domutils import getElementsByName, getElementByName |
53 |
|
|
54 |
|
from Thuban import _ |
55 |
|
|
56 |
class WMSCapabilitiesParser: |
class WMSCapabilitiesParser: |
57 |
""" |
""" |
58 |
Thuban class to parse capabilities supplied as large string. |
Thuban class to parse capabilities supplied as large string. |
68 |
fees = None |
fees = None |
69 |
access = None |
access = None |
70 |
formats = None |
formats = None |
71 |
srs_discrepancies = None |
error = None |
72 |
|
|
73 |
|
|
74 |
def __init__(self): |
def __init__(self): |
79 |
# Note that we must not initialise internal variables of the |
# Note that we must not initialise internal variables of the |
80 |
# class in a mutable way or it will be shared among all |
# class in a mutable way or it will be shared among all |
81 |
# instances. None is immutable, [] is not. |
# instances. None is immutable, [] is not. |
82 |
layers = [] |
self.error = [] |
83 |
|
|
84 |
|
|
85 |
def grok(self, data): |
def grok(self, data): |
90 |
Information should only be retrieved with the respective |
Information should only be retrieved with the respective |
91 |
get*() methods. |
get*() methods. |
92 |
""" |
""" |
93 |
root = xml.dom.minidom.parseString(data).documentElement |
xml_dom = xml.dom.minidom.parseString(data) |
94 |
|
root = xml_dom.documentElement |
95 |
|
|
96 |
# Extract the title |
# Extract the title |
97 |
foo = getElementByName(getElementByName(root, 'Service'), 'Title') |
foo = getElementByName(getElementByName(root, 'Service'), 'Title') |
106 |
# Extract fees information |
# Extract fees information |
107 |
foo = getElementByName(getElementByName(root, 'Service'), 'Fees') |
foo = getElementByName(getElementByName(root, 'Service'), 'Fees') |
108 |
if foo and len(foo.childNodes[0].data) \ |
if foo and len(foo.childNodes[0].data) \ |
109 |
and lower(foo.childNodes[0].data) != 'none': |
and foo.childNodes[0].data.lower() != 'none': |
110 |
self.fees = foo.childNodes[0].data |
self.fees = foo.childNodes[0].data |
111 |
|
|
112 |
# Extract access information |
# Extract access information |
113 |
foo = getElementByName(getElementByName(root, 'Service'), |
foo = getElementByName(getElementByName(root, 'Service'), |
114 |
'AccessConstraints') |
'AccessConstraints') |
115 |
if foo and len(foo.childNodes[0].data) \ |
if foo and len(foo.childNodes[0].data) \ |
116 |
and lower(foo.childNodes[0].data) != 'none': |
and foo.childNodes[0].data.lower() != 'none': |
117 |
self.access = foo.childNodes[0].data |
self.access = foo.childNodes[0].data |
118 |
|
|
119 |
# Extract output format information |
foo = getElementByName(getElementByName( |
120 |
foo = getElementsByName( |
root, 'Capability'), 'Request') |
121 |
getElementByName(getElementByName(getElementByName( |
|
122 |
root, 'Capability'), 'Request'), 'GetMap'), 'Format') |
# Need to distinguish between Map and GetMap for v1.0 and v1.1 |
123 |
self.formats = map((lambda i: i.childNodes[0].data), foo) |
bar = getElementByName(foo, 'GetMap') |
124 |
|
if bar: |
125 |
|
# WMS 1.1 |
126 |
|
foo = getElementsByName(bar, 'Format') |
127 |
|
self.formats = map((lambda i: i.childNodes[0].data), foo) |
128 |
|
else: |
129 |
|
# WMS 1.0 |
130 |
|
foo = getElementByName(getElementByName( |
131 |
|
foo, 'Map'), 'Format') |
132 |
|
for node in foo.childNodes: |
133 |
|
if node.nodeType == Node.ELEMENT_NODE: |
134 |
|
try: |
135 |
|
self.formats.append(node.nodeName) |
136 |
|
except AttributeError: |
137 |
|
self.formats = [node.nodeName] |
138 |
|
|
139 |
# Extract layer names |
# Extract layer names |
140 |
self.layers = [] |
self.layers = [] |
141 |
self.peekLayers(getElementByName(getElementByName( |
self.peekLayers(getElementByName(getElementByName( |
142 |
root, 'Capability'), 'Layer'), -1) |
root, 'Capability'), 'Layer'), -1) |
143 |
|
|
144 |
|
xml_dom.unlink() |
145 |
|
|
146 |
|
|
147 |
def peekLayers(self, top, parent): |
def peekLayers(self, top, parent): |
148 |
""" |
""" |
167 |
foo = getElementByName(top, 'Title') |
foo = getElementByName(top, 'Title') |
168 |
if foo and len(foo.childNodes[0].data): |
if foo and len(foo.childNodes[0].data): |
169 |
self.layers[index]['title'] = foo.childNodes[0].data |
self.layers[index]['title'] = foo.childNodes[0].data |
170 |
|
else: |
171 |
|
# A <Title> is required for each layer, <name> is optional |
172 |
|
# See OGC 01-068r3, 7.1.4.5.1 and 7.1.4.5.2 |
173 |
|
self.error.append(_("No title found for layer #%d") % index) |
174 |
|
|
175 |
foo = getElementByName(top, 'Name') |
foo = getElementByName(top, 'Name') |
176 |
if foo and len(foo.childNodes[0].data): |
if foo and len(foo.childNodes[0].data): |
182 |
if srs[0:5] == 'EPSG:': |
if srs[0:5] == 'EPSG:': |
183 |
srs = srs[5:] |
srs = srs[5:] |
184 |
try: |
try: |
185 |
self.layers[index]['srs'].append(srs) |
int(srs) |
186 |
except KeyError: |
try: |
187 |
self.layers[index]['srs'] = [srs] |
self.layers[index]['srs'].append(srs) |
188 |
|
except KeyError: |
189 |
|
self.layers[index]['srs'] = [srs] |
190 |
|
except ValueError: |
191 |
|
if srs[0:4].upper() == 'AUTO' \ |
192 |
|
or srs[0:4].upper() == 'NONE': |
193 |
|
try: |
194 |
|
self.layers[index]['_srs_'].append(srs) |
195 |
|
except KeyError: |
196 |
|
self.layers[index]['_srs_'] = [srs] |
197 |
|
else: |
198 |
|
self.error.append(_("SRS '%s' is not numerical and not" |
199 |
|
" AUTO/NONE in layer '%s'") \ |
200 |
|
% (srs, self.layers[index]['title'])) |
201 |
|
|
202 |
foo = getElementByName(top, 'LatLonBoundingBox') |
foo = getElementByName(top, 'LatLonBoundingBox') |
203 |
if foo is not None: |
if foo is not None: |
218 |
self.layers[index]['bbox'][srs][corner] \ |
self.layers[index]['bbox'][srs][corner] \ |
219 |
= foo.attributes.get(corner).nodeValue |
= foo.attributes.get(corner).nodeValue |
220 |
|
|
|
# Check for integrity |
|
|
self.checkLayerSRS(index) |
|
|
|
|
221 |
# Traverse subsidiary layers |
# Traverse subsidiary layers |
222 |
sublayer = getElementsByName(top, 'Layer') |
sublayer = getElementsByName(top, 'Layer') |
223 |
for l in sublayer: |
for l in sublayer: |
224 |
self.peekLayers(l, index) |
self.peekLayers(l, index) |
225 |
|
|
226 |
|
|
|
def checkLayerSRS(self, index): |
|
|
""" |
|
|
Checks the integrity of the underlying XML data. |
|
|
|
|
|
This is done by comparing the <SRS> elements with the |
|
|
calculated list from the BoundingBox elements. |
|
|
|
|
|
index -- position in the layers array to check |
|
|
""" |
|
|
|
|
|
pivot = index |
|
|
calculated = [] |
|
|
while pivot != -1: |
|
|
if 'bbox' in self.layers[pivot]: |
|
|
for srs in self.layers[pivot]['bbox'].keys(): |
|
|
if srs not in calculated: |
|
|
calculated.append(srs) |
|
|
pivot = self.layers[pivot]['parent'] |
|
|
|
|
|
pivot = index |
|
|
specified = [] |
|
|
while pivot != -1: |
|
|
if 'srs' in self.layers[pivot]: |
|
|
for srs in self.layers[pivot]['srs']: |
|
|
if srs not in specified: |
|
|
specified.append(srs) |
|
|
pivot = self.layers[pivot]['parent'] |
|
|
|
|
|
equal = True |
|
|
# Check for same number of elements |
|
|
if len(calculated) != len(specified): |
|
|
equal = False |
|
|
|
|
|
# Loop through all elements for existance |
|
|
for elm in calculated: |
|
|
if elm not in specified: |
|
|
equal = False |
|
|
|
|
|
if not equal: |
|
|
if self.srs_discrepancies is None: |
|
|
self.srs_discrepancies = [] |
|
|
if 'name' in self.layers[index]: |
|
|
id = "name:%s" % self.layers[index]['name'] |
|
|
else: |
|
|
id = "title:%s" % self.layers[index]['title'] |
|
|
self.srs_discrepancies.append(id) |
|
|
|
|
|
|
|
227 |
def getTitle(self): |
def getTitle(self): |
228 |
""" |
""" |
229 |
Returns the main title of the WMS object. |
Returns the main title of the WMS object. |
369 |
- Layers may optionally add to the global SRS list, or to the |
- Layers may optionally add to the global SRS list, or to the |
370 |
list inherited from a parent layer. |
list inherited from a parent layer. |
371 |
|
|
372 |
|
- A server which has the ability to transform data to |
373 |
|
different SRSes may choose not to provide an explicit |
374 |
|
BoundingBox for every possible SRS available for each Layer. |
375 |
|
Thus the list of <SRS> elements are authoritative. |
376 |
|
|
377 |
This implementation returns the list of SRS for the given |
This implementation returns the list of SRS for the given |
378 |
layer, calculated by looking at BoundingBoxes defined in the |
layer, calculated by looking at BoundingBoxes defined in the |
379 |
named layer and all layers higher in the hierarchy up to the |
named layer and all layers higher in the hierarchy up to the |
389 |
|
|
390 |
result = [] |
result = [] |
391 |
while pivot != -1: |
while pivot != -1: |
392 |
if 'bbox' in self.layers[pivot]: |
if 'srs' in self.layers[pivot]: |
393 |
for srs in self.layers[pivot]['bbox'].keys(): |
for srs in self.layers[pivot]['srs']: |
394 |
if srs not in result: |
if srs not in result: |
395 |
result.append(srs) |
result.append(srs) |
396 |
pivot = self.layers[pivot]['parent'] |
pivot = self.layers[pivot]['parent'] |
470 |
if srs in pivot['bbox']: |
if srs in pivot['bbox']: |
471 |
return pivot['bbox'][srs] |
return pivot['bbox'][srs] |
472 |
|
|
473 |
|
# No matching BBox found, let's see if it was EPSG:4326 |
474 |
|
if srs == '4326': |
475 |
|
return self.getLayerLatLonBBox(name) |
476 |
|
|
477 |
return None |
return None |
478 |
|
|
479 |
|
|
504 |
return 0 |
return 0 |
505 |
|
|
506 |
|
|
|
def get_srs_discrepancies(self): |
|
|
""" |
|
|
Returns a list of layer identifications where the denoted SRS |
|
|
values differ from the calculated ones through BoundingBox |
|
|
elements. |
|
|
""" |
|
|
return self.srs_discrepancies |
|
|
|
|
507 |
|
|
508 |
if __name__ == "__main__": |
if __name__ == "__main__": |
509 |
print "This module cannot be executed standalone." |
print "This module cannot be executed standalone." |
510 |
|
|
511 |
import os |
import os |
512 |
|
|
513 |
|
sample = "test/sample.xml" |
514 |
try: |
try: |
515 |
f = open("test/sample.xml", "r") |
f = open(sample, "r") |
516 |
except IOError: |
except IOError: |
517 |
try: |
try: |
518 |
f = open(os.path.dirname(__file__) + "/test/sample.xml", "r") |
f = open(os.path.dirname(__file__) + "/" + sample, "r") |
519 |
except IOError: |
except IOError: |
520 |
print "Cannot open sample.xml for reading" |
print "Cannot open %s for reading" % sample |
521 |
|
|
522 |
if f is not None: |
if f is not None: |
523 |
sample = f.read(); |
sample = f.read(); |