Source code for sos.sosparser

# -*- coding: utf-8 -*-
"""
 SOS...Parser classes
 All classes to parse SOS or O&M XML data
"""

from PyQt4.QtCore import QVariant, Qt, QDateTime
from xmlparser import * #@UnusedWildImport
from gmlparser import * #@UnusedWildImport
from itertools import chain
from qgis.core import QgsOgcUtils as GMLParser, QgsRectangle, QgsField, QgsCoordinateReferenceSystem, QgsPoint, QgsGeometry
import sos
from qgstime import QgsTime


__all__ = ['XMLParserFactory',
           'SOSCapabilitiesParser',
           'SOSServiceIdentificationParser',
           'SOSServiceProviderParser',
           'SOSObservationOfferingParser',
           'SOSOperationMetadataParser',
           'SOSFilterCapabilitiesParser',
           'SOSObservationsParser']

[docs]class SOSCapabilitiesParser (XMLParser): def __init__(self): self.capabilities = sos.SOSCapabilities()
[docs] def parse (self, xml): self.capabilities.xml = xml xml = XMLParser.parse(self, self.capabilities.xml) node, version = self.searchFirst (xml, "@version") if not node or not node.localName() == "Capabilities" or not version in ["1.0", "1.0.0"]: if node.localName() == "ExceptionReport": node, exceptionCode = self.searchFirst(node, "Exception@exceptionCode") _, exceptionText = self.searchFirst(node, "ExceptionText") raise sos.ExceptionReport (exceptionCode, exceptionText) raise ValueError ("{} version {}".format(node.localName(), version)) self.capabilities.version = version for node, value in self.search (xml, "*"): if value == "ServiceIdentification": self.capabilities.serviceIdentification = XMLParserFactory.getInstance ("SOSServiceIdentification")().parse(node) elif value == "ServiceProvider": self.capabilities.serviceProvider = XMLParserFactory.getInstance ("SOSServiceProvider")().parse(node) elif value == "OperationsMetadata": opParser = XMLParserFactory.getInstance ("SOSOperationMetadata") for opNode, opName in self.search (node, "Operation@name"): self.capabilities.operationsMetadata[str(opName)] = opParser().parse(opNode) elif value == "Filter_Capabilities": self.capabilities.filterCapabilities = XMLParserFactory.getInstance ("SOSFilterCapabilities")().parse(node) elif value == "Contents": ooParser = XMLParserFactory.getInstance ("SOSObservationOffering") for ooNode, ooId in self.search (node, "ObservationOfferingList/ObservationOffering@id"): self.capabilities.observationOfferingList[str(ooId)] = ooParser().parse(ooNode) return self.capabilities
[docs]class SOSServiceIdentificationParser (XMLParser): def __init__(self): self.identification = sos.SOSServiceIdentification ()
[docs] def parse (self, xml): xml = XMLParser.parse(self, xml) _, self.identification.title = self.searchFirst (xml, "Title") _, self.identification.abstract = self.searchFirst (xml, "Abstract") for _, value in self.search (xml, "Keywords/Keyword"): self.identification.keywords.append(value) _, self.identification.serviceType = self.searchFirst (xml, "ServiceType") _, self.identification.serviceTypeVersion = self.searchFirst (xml, "ServiceTypeVersion") return self.identification
[docs]class SOSServiceProviderParser (XMLParser): def __init__(self): self.provider = sos.SOSServiceProvider ()
[docs] def parse (self, xml): xml = XMLParser.parse(self, xml) _, self.provider.providerName = self.searchFirst (xml, "ProviderName") node, self.provider.providerSite = self.searchFirst (xml, "ProviderSite@href") contactInfo, value = self.searchFirst (xml, "ServiceContact/ContactInfo") for node, value in self.search (contactInfo, "Phone/*"): self.provider.phones[str(node.localName())] = value for node, value in self.search (contactInfo, "Address/*"): self.provider.address[str(node.localName())] = value return self.provider
[docs]class SOSObservationOfferingParser (XMLParser): def __init__(self): self.offering = sos.SOSObservationOffering ()
[docs] def parse (self, xml): xml = XMLParser.parse(self, xml) _, self.offering.id = self.searchFirst (xml, "@id") _, self.offering.name = self.searchFirst (xml, "name") _, self.offering.description = self.searchFirst (xml, "description") boundedByNode, boundedByType = self.searchFirst (xml, "boundedBy/*") _, self.offering.srsName = self.searchFirst (boundedByNode, "@srsName") if boundedByType == "Envelope": self.offering.boundedBy = GMLParser.rectangleFromGMLEnvelope(boundedByNode) elif boundedByType == "Box": self.offering.boundedBy = GMLParser.rectangleFromGMLBox(boundedByNode) else: geo = GMLParser.geometryFromGML(boundedByNode) if geo: self.offering.boundedBy = geo.boundingBox() else: self.offering.boundedBy = QgsRectangle() timeNode, timePrimitive = self.searchFirst (xml, "time/*") if timePrimitive: try: gmlTimeParser = XMLParserFactory.getInstance ("GML" + timePrimitive) self.offering.time = gmlTimeParser().parse(timeNode) except NotImplementedError: self.offering.time = QgsTime() self.offering.proceduresList = [] for _, value in self.search (xml, "procedure@href"): self.offering.proceduresList.append(value) self.offering.observedPropertiesList = [] for _, value in self.search (xml, "observedProperty@href"): self.offering.observedPropertiesList.append(value) self.offering.featureOfInterestList = [] for _, value in self.search (xml, "featureOfInterest@href"): self.offering.featureOfInterestList.append(value) for _, value in self.search (xml, "responseFormat"): if value in ['text/xml;subtype="om/1.0.0"']: self.offering.responseFormat = value break for _, value in self.search (xml, "resultModel"): self.offering.resultModel.append(value) for _, value in self.search (xml, "responseMode"): if value in ['inline']: self.offering.responseMode = value break return self.offering
[docs]class SOSOperationMetadataParser (XMLParser): def __init__(self): self.operation = sos.SOSOperationMetadata()
[docs] def parse (self, xml): xml = XMLParser.parse(self, xml) _, self.operation.name = self.searchFirst (xml, "name") methods = [] for node, name in self.search(xml, "DCP/HTTP/*"): _, href = self.searchFirst(node, "@href") methods.append((name,href)) self.operation.methods = dict(methods) parameters = [] for node, name in self.search(xml, "Parameter@name"): parameters.append((name,[val for _,val in self.search(node, "AllowedValues/Value")])) self.operation.parameters = dict(parameters) return self.operation
[docs]class SOSFilterCapabilitiesParser (XMLParser): def __init__(self): self.capabilities = sos.SOSFilterCapabilities ()
[docs] def parse (self, xml): xml = XMLParser.parse(self, xml) # Spatial_Capabilities self.capabilities.spatial_operands = [op for _, op in self.search(xml, "Spatial_Capabilities/GeometryOperands/GeometryOperand")] self.capabilities.spatial_operators = [op for _, op in self.search(xml, "Spatial_Capabilities/SpatialOperators/SpatialOperator@name")] # Temporal_Capabilities self.capabilities.temporal_operands = [op for _, op in self.search(xml, "Temporal_Capabilities/TemporalOperands/TemporalOperand")] self.capabilities.temporal_operators = [op for _, op in self.search(xml, "Temporal_Capabilities/TemporalOperators/TemporalOperator@name")] # Scalar_Capabilities self.capabilities.scalar_operators = [op for _,op in self.search(xml, "Scalar_Capabilities/ComparisonOperators/ComparisonOperator")] return self.capabilities
[docs]class SOSObservationsParser (XMLParser): def __init__(self): self.provider = sos.SOSProvider()
[docs] def parse (self, xml): xml = XMLParser.parse(self, xml) node,_ = self.searchFirst (xml, "") if not node or not node.localName() == "ObservationCollection": if node.localName() == "ExceptionReport": node, exceptionCode = self.searchFirst(node, "Exception@exceptionCode") _, exceptionText = self.searchFirst(node, "ExceptionText") raise sos.ExceptionReport (exceptionCode, exceptionText) raise ValueError (node.localName()) boundedByNode, boundedByType = self.searchFirst (xml, "boundedBy/*") _, self.provider.srsName = self.searchFirst (boundedByNode, "@srsName") crs = QgsCoordinateReferenceSystem() if crs.createFromUserInput(self.provider.srsName): yx = crs.axisInverted() else: yx = (self.provider.srsName == 'urn:ogc:def:crs:EPSG:0') #Hack para meteogalicia if boundedByType == "Envelope": self.provider.extent = GMLParser.rectangleFromGMLEnvelope(boundedByNode) elif boundedByType == "Box": self.provider.extent = GMLParser.rectangleFromGMLBox(boundedByNode) else: geo = GMLParser.geometryFromGML(boundedByNode) if geo: self.provider.extent = geo.boundingBox() _, tag = self.searchFirst(xml, 'member/*') omParser = XMLParserFactory.getInstance(tag)(self.provider, yx) components = omParser.parse(xml) components = filter(lambda f: f != None, components.values()) hasTime = False for i, f in enumerate(components): if f.name() == "Time" or f.name() == "SamplingTime": components.pop (i) f.setName("Time") self.provider.fields.append(f) hasTime = True break if not hasTime: self.provider.fields.append(QgsField ("Time", QVariant.String, '')) self.provider.fields.extend(components) return self.provider
class ObservationParser (XMLParser): def __init__(self, provider, axisInverted): self.provider = provider self.yx = axisInverted self.timeParser = XMLParserFactory.getInstance ("GMLTime")() def parse (self, xml): def _float (value): try: return float(value) except: return None components = {} for member, _ in self.search(xml, "member"): for node, tag in self.search (member, "Observation/*"): if tag == "samplingTime": samplingTime = self.timeParser.parse(node) elif tag == "observedProperty": _, prop = self.searchFirst(node, "@href") if prop: if not prop in components: components[prop] = None else: for _, prop in self.search (node, "CompositePhenomenon/component@href"): if not prop in components: components[prop] = None elif tag == "featureOfInterest": hasSamplingPoint = False for point, foi_id in chain(self.search (node, "FeatureCollection/featureMember/SamplingPoint@id"),self.search (node, "SamplingPoint@id"),self.search (node, "SamplingPointAtDepth@id")): hasSamplingPoint = True _, name = self.searchFirst (point, "name") pointGeo, _ = self.searchFirst(point, "position") pointGeo = GMLParser.geometryFromGML(pointGeo) if self.yx: pointGeo = pointGeo.asPoint() pointGeo = QgsGeometry.fromPoint(QgsPoint (pointGeo.y(),pointGeo.x())) self.provider.features [foi_id] = (name, pointGeo) if point.localName () == "SamplingPointAtDepth": _, depth = self.searchFirst (point, "depth") foi_id = (foi_id, depth) if not hasSamplingPoint: for _, foi_id in self.search (node, "FeatureCollection/featureMember@href"): self.provider.features [foi_id] = (foi_id, None) elif tag == "result": node, tag = self.searchFirst(node, "*") if tag == "DataArray": simpleDataRecord = [] for fieldNode, field in chain(self.search(node, "elementType/SimpleDataRecord/field@name"),self.search(node, "elementType/DataRecord/field@name")): simpleDataRecord.append(field) fieldNode, definition = self.searchFirst(fieldNode, "*/@definition") if definition in components and components[definition] == None: if fieldNode.localName () == "Quantity": fieldType = QVariant.Double _, definition = self.searchFirst (fieldNode, "uom@code") elif fieldNode.localName () == "Time": fieldType = QVariant.String else: fieldType = QVariant.String components[definition] = QgsField (field, fieldType, definition) encoding, _ = self.searchFirst (node, "encoding") _, blockSeparator = self.searchFirst (encoding, "TextBlock@blockSeparator") _, tokenSeparator = self.searchFirst (encoding, "TextBlock@tokenSeparator") _, values = self.searchFirst (node, "values") try: indexes = map(simpleDataRecord.index, ["feature", "Time"]) except: indexes = None if not indexes: try: indexes = map(simpleDataRecord.index, ["FeatureOfInterest","SamplingTime"]) except: indexes = None if not indexes: raise ValueError('SimpleDataRecord = ' + str(simpleDataRecord)) map(simpleDataRecord.pop, indexes) for block in filter (lambda x: len(x), values.split (blockSeparator)): observation = block.split(tokenSeparator) observationKeys = map(observation.pop, indexes) map (lambda prop, value: self.provider.setObservation (unicode(observationKeys[0]), QDateTime.fromString(observationKeys[1], Qt.ISODate), unicode(prop), str(value)), simpleDataRecord, observation) return components class MeasurementParser (XMLParser): def __init__(self, provider, axisInverted): self.provider = provider self.yx = axisInverted self.timeParser = XMLParserFactory.getInstance ("GMLTime")() def parse (self, xml): def _float (value): try: return float(value) except: return None components = {} for member, _ in self.search(xml, "member"): for node, tag in self.search (member, "Measurement/*"): if tag == "samplingTime": samplingTime = self.timeParser.parse(node) elif tag == "observedProperty": _, prop = self.searchFirst(node, "@href") if not prop in components: components[prop] = None elif tag == "featureOfInterest": hasSamplingPoint = False for point, foi_id in chain(self.search (node, "FeatureCollection/featureMember/SamplingPoint@id"),self.search (node, "SamplingPoint@id"),self.search (node, "SamplingPointAtDepth@id")): hasSamplingPoint = True _, name = self.searchFirst (point, "name") pointGeo, _ = self.searchFirst(point, "position") pointGeo = GMLParser.geometryFromGML(pointGeo) if self.yx: pointGeo = pointGeo.asPoint() pointGeo = QgsGeometry.fromPoint(QgsPoint (pointGeo.y(),pointGeo.x())) self.provider.features [foi_id] = (name, pointGeo) if point.localName () == "SamplingPointAtDepth": _, depth = self.searchFirst (point, "depth") foi_id = (foi_id, depth) if not hasSamplingPoint: for _, foi_id in self.search (node, "FeatureCollection/featureMember@href"): self.provider.features [foi_id] = (foi_id, None) elif node.localName () == "result": self.provider.setObservation (unicode(foi_id), QDateTime.fromString(str(samplingTime), Qt.ISODate), unicode(prop), str(tag)) if prop in components and components[prop] == None: components[prop] = QgsField (prop, QVariant.Double if _float(tag) else QVariant.String, node.attribute("uom")) return components