def handleLayer(self, ns, layerEl, nodes, endpoint, parentId, commonData, antecedentKeywordData, idMap): """Processes a layer. Determines whether the layer has sublayers, in which case this method is called recursively, or if it is a leaf, in which case a node is added to the node list. """ subLayers = xml_util.getChildrenByNameNS(layerEl, ns, 'Layer') isLeaf = len(subLayers) == 0 layer = WmsLayer() layer.populateFromLayerElement(ns, layerEl, commonData) log.debug("Layer %s %s" % (layer.name, layer.title)) self.setLayerId(layer, parentId, isLeaf) # Merge all keyword data applicable to the layer. keywordData = self.getLayerDataFromEndpoint(endpoint, layer) if antecedentKeywordData: mergedKeywordData = antecedentKeywordData.copy() mergedKeywordData.update(keywordData) else: mergedKeywordData = keywordData log.debug("keywordData: %s" % mergedKeywordData) layer.generateDimensionDisplayValues(mergedKeywordData.get('dimension_format', None), mergedKeywordData.get('dimension_reverse', None)) treeInfo = self.makeTreeInfo(endpoint, layer, isLeaf, keywordData) # Look for sublayers - if there any any, call this method recursively to add them to the tree, # otherwise just add a leaf node. children = [] node = Node(layer.id, layer, children, treeInfo, keywordData) #idMap[layer.id] = node nodes.append(node) if isLeaf: log.debug("Found layer: title '%s' (ID=%s)", layer.title, layer.id) else: for lyr in subLayers: self.handleLayer(ns, lyr, children, endpoint, layer.id, commonData, antecedentKeywordData, idMap)
def getLayers(self, endpoint, parentId, idMap, keywordData, forceRefresh): """Returns a list of 'endpoint_hierarchy_builder.Node's for the layers of an endpoint in a WMC document. Also, adds nodes to a map from node ID to node. """ log.debug("getLayers called for %s", endpoint['wmsurl']) log.debug(" keywordData: %s" % keywordData) wmsUrl = self.makeProxiedUrl(endpoint['wmsurl']) wmcDoc = self.wmsCapabilityCache.getWmsCapabilities(wmsUrl, True) dom = xml.dom.minidom.parseString(wmcDoc) # Get the namespace URI for the document root element. ns = dom.documentElement.namespaceURI # Get the version the WMS server responded with. wmsVersion = dom.documentElement.getAttribute('version') nodes = [] capability = xml_util.getSingleChildByNameNS(dom.documentElement, ns, 'Capability') if capability == None: return None getCapabilitiesUrlEl = xml_util.getSingleChildByPathNS(capability, [(ns, 'Request'), (ns, 'GetCapabilities'), (ns, 'DCPType'), (ns, 'HTTP'), (ns, 'Get'), (ns, 'OnlineResource')]) getCapabilitiesUrl = getCapabilitiesUrlEl.getAttributeNS(XLINK_URI, 'href') if not getCapabilitiesUrl: getCapabilitiesUrl = xml_util.getAttributeByLocalName(getCapabilitiesUrlEl, 'href') log.debug("GetCapabilities URL: %s", getCapabilitiesUrl) getCapabilitiesUrl = parseEndpointString(getCapabilitiesUrl, {'REQUEST':'GetCapabilities', 'SERVICE':'WMS'}) getFeatureInfoOnlineResourceEl = xml_util.getSingleChildByPathNS(capability, [(ns, 'Request'), (ns, 'GetFeatureInfo'), (ns, 'DCPType'), (ns, 'HTTP'), (ns, 'Get'), (ns, 'OnlineResource')]) if getFeatureInfoOnlineResourceEl: getFeatureInfoUrl = getFeatureInfoOnlineResourceEl.getAttributeNS(XLINK_URI, 'href') if not getFeatureInfoUrl: getFeatureInfoUrl = xml_util.getAttributeByLocalName(getFeatureInfoOnlineResourceEl, 'href') log.debug("GetFeatureInfo URL: %s", getFeatureInfoUrl) getFeatureInfoUrl = getFeatureInfoUrl.rstrip('?&') else: getFeatureInfoUrl = None getMapOnlineResourceEl = xml_util.getSingleChildByPathNS(capability, [(ns, 'Request'), (ns, 'GetMap'), (ns, 'DCPType'), (ns, 'HTTP'), (ns, 'Get'), (ns, 'OnlineResource')]) getMapUrl = getMapOnlineResourceEl.getAttributeNS(XLINK_URI, 'href') if not getMapUrl: getMapUrl = xml_util.getAttributeByLocalName(getMapOnlineResourceEl, 'href') log.debug("GetMap URL: %s", getMapUrl) getMapUrl = getMapUrl.rstrip('?&') getMapUrl = self.makeProxiedUrl(getMapUrl) commonData = { 'getCapabilitiesUrl': getCapabilitiesUrl, 'getFeatureInfoUrl': getFeatureInfoUrl, 'getMapUrl': getMapUrl, 'wmsVersion': wmsVersion } if 'wcsurl' in endpoint: commonData['getCoverageUrl'] = endpoint['wcsurl'] for layer in xml_util.getChildrenByNameNS(capability, ns, 'Layer'): self.handleLayer(ns, layer, nodes, endpoint, parentId, commonData, keywordData, idMap) # Break internal references to facilitate garbage collection. dom.unlink() return nodes
def populateFromLayerElement(self, ns, layerEl, commonData): """Populates a WmsLayer instance from a WMS capabilities Layer element @param ns: namespace in capabilities document @param layerEl: Layer element @param commonData: dict of capabilities data that is not specific to the layer """ self.title = xml_util.getSingleChildTextByNameNS(layerEl, ns, 'Title') self.name = xml_util.getSingleChildTextByNameNS(layerEl, ns, 'Name') self.abstract = xml_util.getSingleChildTextByNameNS(layerEl, ns, 'Abstract') self.getMapUrl = commonData['getMapUrl'] self.getCapabilitiesUrl = commonData['getCapabilitiesUrl'] self.getFeatureInfoUrl = commonData['getFeatureInfoUrl'] self.wmsVersion = commonData['wmsVersion'] self.getCoverageUrl = commonData['getCoverageUrl'] # Parse Dimension element into attributes and list of values. # First look for pre-WMS 1.3.0 Extent elements. extents = {} for extentEl in xml_util.getChildrenByNameNS(layerEl, ns, 'Extent'): name = extentEl.getAttribute('name') extentData = extentEl.firstChild if extentData != None: extentStr = extentEl.firstChild.data.strip() extentValues = extentStr.split(',') extents[name] = extentValues # Find the Dimension elements. self.dimensions = [] for dimensionEl in xml_util.getChildrenByNameNS(layerEl, ns, 'Dimension'): name = dimensionEl.getAttribute('name') units = dimensionEl.getAttribute('units') unitSymbol = dimensionEl.getAttribute('unitSymbol') default = dimensionEl.getAttribute('default') dimensionData = dimensionEl.firstChild if dimensionData != None: dimensionStr = dimensionEl.firstChild.data.strip() dimensionValues = dimensionStr.split(',') elif name in extents: dimensionValues = extents[name] else: dimensionValues = None if dimensionValues: dimension = { 'name': name, 'units': units, 'unitSymbol': unitSymbol, 'default': default, 'dimensionValues': dimensionValues } self.dimensions.append(dimension) # Parse Style element into list of values. self.styles = [] for styleEl in xml_util.getChildrenByNameNS(layerEl, ns, 'Style'): name = xml_util.getSingleChildTextByNameNS(styleEl, ns, 'Name') title = xml_util.getSingleChildTextByNameNS(styleEl, ns, 'Title') style = { 'name': name, 'title': title, } legendUrlEl = xml_util.getSingleChildByNameNS(styleEl, ns, 'LegendURL') if legendUrlEl != None: width = legendUrlEl.getAttribute('width') height = legendUrlEl.getAttribute('height') onlineResourceEl = xml_util.getSingleChildByNameNS(legendUrlEl, ns, 'OnlineResource') legendURL = onlineResourceEl.getAttributeNS(XLINK_URI, 'href') style['legendURL'] = { 'width': width, 'height': height, 'onlineResource': legendURL } self.styles.append(style) self.getDisplayOptionsUrl = None for metadataUrlEl in xml_util.getChildrenByNameNS(layerEl, ns, 'MetadataURL'): metadataUrlType = metadataUrlEl.getAttribute('type') if metadataUrlType and (metadataUrlType == 'display_options') : if xml_util.getSingleChildTextByNameNS(metadataUrlEl, ns, 'Format') == 'application/json': onlineResourceEl = xml_util.getSingleChildByNameNS(metadataUrlEl, ns, 'OnlineResource') if onlineResourceEl: self.getDisplayOptionsUrl = onlineResourceEl.getAttributeNS(XLINK_URI, 'href')