/* Copyright (C) 2001, 2006 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved. */ package gov.nasa.worldwind.wms; import gov.nasa.worldwind.util.Logging; import org.w3c.dom.*; import javax.xml.XMLConstants; import javax.xml.xpath.*; import java.util.*; import java.util.logging.Level; /** * @author tag * @version $Id: Capabilities.java 3601 2007-11-21 03:23:23Z tgaskins $ */ public abstract class Capabilities { protected Document doc; protected Element service; protected Element capability; protected XPath xpath; public static Capabilities parse(Document doc) { XPathFactory xpFactory = XPathFactory.newInstance(); XPath xpath = xpFactory.newXPath(); SimpleNamespaceContext nsc = new SimpleNamespaceContext(); nsc.addNamespace(XMLConstants.DEFAULT_NS_PREFIX, "http://www.opengis.net/wms"); xpath.setNamespaceContext(new SimpleNamespaceContext()); try { String version = xpath.evaluate(altPaths("*/@wms:version"), doc); if (version == null || version.length() == 0) return null; if (version.compareTo("1.3") < 0) return new CapabilitiesV111(doc, xpath); else return new CapabilitiesV130(doc, xpath); } catch (XPathExpressionException e) { Logging.logger().log(Level.SEVERE, "WMS.ParsingError", e); return null; } } protected Capabilities(Document doc, XPath xpath) { this.doc = doc; this.xpath = xpath; try { this.service = (Element) this.xpath.evaluate(altPaths("*/wms:Service"), doc, XPathConstants.NODE); if (this.service == null) { Logging.logger().severe("WMS.NoServiceElement"); throw new IllegalArgumentException(Logging.getMessage("WMS.NoServiceElement")); } this.capability = (Element) this.xpath.evaluate(altPaths("*/wms:Capability"), doc, XPathConstants.NODE); if (this.capability == null) { Logging.logger().severe("WMS.NoCapabilityElement"); throw new IllegalArgumentException(Logging.getMessage("WMS.NoCapabilityElement")); } } catch (XPathExpressionException e) { Logging.logger().log(Level.SEVERE, "WMS.ParsingError", e); } } private static String altPaths(String path) { return path != null ? path + "|" + path.replaceAll("wms:", "") : null; } protected String getText(String path) { return this.getText(null, path); } protected String getText(Element context, String path) { try { return this.xpath.evaluate(altPaths(path), context != null ? context : doc); } catch (XPathExpressionException e) { return null; } } protected String[] getTextArray(Element context, String path) { try { NodeList nodes = (NodeList) this.xpath.evaluate(altPaths(path), context != null ? context : doc, XPathConstants.NODESET); if (nodes == null || nodes.getLength() == 0) return null; String[] strings = new String[nodes.getLength()]; for (int i = 0; i < nodes.getLength(); i++) { strings[i] = nodes.item(i).getTextContent(); } return strings; } catch (XPathExpressionException e) { return null; } } protected String[] getUniqueText(Element context, String path) { String[] strings = this.getTextArray(context, path); if (strings == null) return null; ArrayList<String> sarl = new ArrayList<String>(); for (String s : strings) { if (!sarl.contains(s)) sarl.add(s); } return sarl.toArray(new String[1]); } protected Element getElement(Element context, String path) { try { Node node = (Node) this.xpath.evaluate(altPaths(path), context != null ? context : doc, XPathConstants.NODE); if (node == null) return null; return node instanceof Element ? (Element) node : null; } catch (XPathExpressionException e) { return null; } } protected Element[] getElements(Element context, String path) { try { NodeList nodes = (NodeList) this.xpath.evaluate(altPaths(path), context != null ? context : doc, XPathConstants.NODESET); if (nodes == null || nodes.getLength() == 0) return null; Element[] elements = new Element[nodes.getLength()]; for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node instanceof Element) elements[i] = (Element) node; } return elements; } catch (XPathExpressionException e) { return null; } } public Element[] getUniqueElements(Element context, String path, String uniqueTag) { Element[] elements = this.getElements(context, path); if (elements == null) return null; HashMap<String, Element> styles = new HashMap<String, Element>(); for (Element e : elements) { String name = this.getText(e, uniqueTag); if (name != null) styles.put(name, e); } return styles.values().toArray(new Element[1]); } private HashMap<Element, Layer> namedLayerElements = new HashMap<Element, Layer>(); private HashMap<String, Layer> namedLayers = new HashMap<String, Layer>(); private void fillLayerList() { if (this.namedLayers.size() == 0) { Element[] nels = this.getElements(this.capability, "descendant::wms:Layer[wms:Name]"); if (nels == null || nels.length == 0) return; for (Element le : nels) { String name = this.getLayerName(le); if (name != null) { Layer layer = new Layer(le); this.namedLayers.put(name, layer); this.namedLayerElements.put(le, layer); } } } } public Element[] getNamedLayers() { if (this.namedLayerElements.size() == 0) this.fillLayerList(); return this.namedLayerElements.keySet().toArray(new Element[this.namedLayerElements.size()]); } public Element getLayerByName(String layerName) { if (this.namedLayers.size() == 0) this.fillLayerList(); Layer l = this.namedLayers.get(layerName); return l != null ? l.element : null; } // ********* Document Items ********* // public String getVersion() { return this.getText("*/@wms:version"); } public String getUpdateSequence() { return this.getText("*/@wms:updateSequence"); } // ********* Service Items ********* // public String getAbstract() { return this.getText(this.service, "wms:Abstract"); } public String getAccessConstraints() { return this.getText(this.service, "wms:AccessConstraints"); } public String getContactOrganization() { return this.getText( this.service, "wms:ContactInformation/wms:ContactPersonPrimary/wms:ContactOrganization"); } public String getContactPerson() { return this.getText( this.service, "wms:ContactInformation/wms:ContactPersonPrimary/wms:ContactPerson"); } public String getFees() { return this.getText(this.service, "wms:Fees"); } public String[] getKeywordList() { return this.getTextArray(this.service, "wms:KeywordList/wms:Keyword"); } public String getLayerLimit() { return this.getText(this.service, "wms:LayerLimit"); } public String getMaxWidth() { return this.getText(this.service, "wms:MaxWidth"); } public String getMaxHeight() { return this.getText(this.service, "wms:MaxHeight"); } public String getName() { return this.getText(this.service, "wms:Name"); } public String getTitle() { return this.getText(this.service, "wms:Title"); } // ********* Capability Items ********* // public String getOnlineResource() { return this.getText(this.capability, "wms:OnlineResource/@xlink:href"); } public String[] getGetCapabilitiesFormats() { return this.getTextArray(this.capability, "wms:Request/wms:GetCapabilities/wms:Format"); } public String getGetCapabilitiesRequestGetURL() { return this.getText(this.capability, "wms:Request/wms:GetCapabilities/wms:DCPType/wms:HTTP/wms:Get/wms:OnlineResource/@xlink:href"); } public String getGetCapabilitiesRequestPostURL() { return this.getText(this.capability, "wms:Request/wms:GetCapabilities/wms:DCPType/wms:HTTP/wms:Post/wms:OnlineResource/@xlink:href"); } public String[] getExceptionFormats() { return this.getTextArray(this.capability, "wms:Exception/wms:Format"); } public String getFeatureInfoRequestGetURL() { return this.getText(this.capability, "wms:Request/wms:GetFeatureInfo/wms:DCPType/wms:HTTP/wms:Get/wms:OnlineResource/@xlink:href"); } public String getFeatureInfoRequestPostURL() { return this.getText(this.capability, "wms:Request/wms:GetFeatureInfo/wms:DCPType/wms:HTTP/wms:Post/wms:OnlineResource/@xlink:href"); } public String[] getGetMapFormats() { return this.getTextArray(this.capability, "wms:Request/wms:GetMap/wms:Format"); } public String getGetMapRequestGetURL() { return this.getText(this.capability, "wms:Request/wms:GetMap/wms:DCPType/wms:HTTP/wms:Get/wms:OnlineResource/@xlink:href"); } public String getGetMapRequestPostURL() { return this.getText(this.capability, "wms:Request/wms:GetMap/wms:DCPType/wms:HTTP/wms:Post/wms:OnlineResource/@xlink:href"); } public String getVendorSpecificCapabilities() { return this.getText(this.capability, "wms:VendorSpecificCapabilities"); } public Element getLayer() { return this.getElement(this.capability, "wms:Layer"); } // ********* Layer Items ********* // protected static class Layer { protected HashMap<Element, Style> styleElements = new HashMap<Element, Style>(); protected final Element element; protected Layer layer; protected String name; protected String title; public Layer(Element element) { this.element = element; } } public String getLayerAbstract(Element layer) { return this.getText(layer, "wms:Abstract"); } public String getLayerAttributionTitle(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:Title"); } public String getLayerAttributionURL(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:OnlineResource/@xlink:href"); } public String getLayerAttributionLogoFormat(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:LogoURL/wms:Format"); } public String getLayerAttributionLogoHeight(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:LogoURL/@wms:height"); } public String getLayerAttributionLogoURL(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:LogoURL/wms:OnlineResource/@xlink:href"); } public String getLayerAttributionLogoWidth(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/wms:Attribution/wms:LogoURL/@wms:width"); } public Element[] getLayerAuthorityURLs(Element layer) { return this.getUniqueElements(layer, "ancestor-or-self::wms:Layer/wms:AuthorityURL", "@wms:type"); } public abstract BoundingBox[] getLayerBoundingBoxes(Element layer); public String getLayerCascaded(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/@cascaded"); } public String[] getLayerCRS(Element layer) { return this.getUniqueText(layer, "ancestor-or-self::wms:Layer/wms:CRS"); } public String getLayerDataURLFormat(Element layer) { return this.getText(layer, "wms:DataURL/wms:Format"); } public String getLayerDataURL(Element layer) { return this.getText(layer, "wms:DataURL/wms:OnlineResource/@xlink:href"); } public Element[] getLayerDimensions(Element layer) { Element[] dims = this.getElements(layer, "ancestor-or-self::wms:Layer/wms:Dimension"); if (dims == null || dims.length == 0) return null; ArrayList<Element> uniqueDims = new ArrayList<Element>(); ArrayList<String> dimNames = new ArrayList<String>(); for (Element e : dims) { // Filter out dimensions with same name. // Keep all those with a null name, even though wms says they're invalid. Let the app decide. String name = this.getDimensionName(e); if (name != null && dimNames.contains(name)) continue; uniqueDims.add(e); dimNames.add(name); } return uniqueDims.toArray(new Element[uniqueDims.size()]); } public Element[] getLayerExtents(Element layer) { Element[] extents = this.getElements(layer, "ancestor-or-self::wms:Layer/wms:Extent"); if (extents == null || extents.length == 0) return null; ArrayList<Element> uniqueExtents = new ArrayList<Element>(); ArrayList<String> extentNames = new ArrayList<String>(); for (Element e : extents) { // Filter out dimensions with same name. // Keep all those with a null name, even though wms says they're invalid. Let the app decide. String name = this.getDimensionName(e); if (name != null && extentNames.contains(name)) continue; uniqueExtents.add(e); extentNames.add(name); } return uniqueExtents.toArray(new Element[uniqueExtents.size()]); } public abstract BoundingBox getLayerGeographicBoundingBox(Element layer); public String getLayerFeatureListFormat(Element layer) { return this.getText(layer, "wms:FeatureListURL/wms:Format"); } public String getLayerFeatureListURL(Element layer) { return this.getText(layer, "wms:FeatureListURL/wms:OnlineResource/@xlink:href"); } public String getLayerFixedHeight(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/@fixedHeight"); } public String getLayerFixedWidth(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/@fixedWidth"); } public Element[] getLayerIdentifiers(Element layer) { return this.getUniqueElements(layer, "wms:Identifier", "wms:authority"); } public String[] getLayerKeywordList(Element layer) { return this.getTextArray(layer, "wms:KeywordList/wms:Keyword"); } public abstract String getLayerMaxScaleDenominator(Element layer); public Element[] getLayerMetadataURLs(Element layer) { return this.getElements(layer, "wms:MetadataURL"); } public abstract String getLayerMinScaleDenominator(Element layer); public String getLayerName(Element layerElement) { Layer layer = this.namedLayerElements.get(layerElement); return layer != null && layer.name != null ? layer.name : this.getText(layerElement, "wms:Name"); } public String getLayerNoSubsets(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/@noSubsets"); } public String getLayerOpaque(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/@opaque"); } public String getLayerQueryable(Element layer) { return this.getText(layer, "ancestor-or-self::wms:Layer/@queryable"); } public String[] getLayerSRS(Element layer) { return this.getUniqueText(layer, "ancestor-or-self::wms:Layer/wms:SRS"); } public Element[] getLayerStyles(Element layerElement) { Layer layer = this.namedLayerElements.get(layerElement); if (layer == null) return null; if (layer.styleElements != null) return layer.styleElements.keySet().toArray(new Element[1]); Element[] styleElements = this.getUniqueElements(layerElement, "ancestor-or-self::wms:Layer/wms:Style", "Name"); if (styleElements == null) return null; layer.styleElements = new HashMap<Element, Style>(); for (Element se : styleElements) { Style style = new Style(se, layer); layer.styleElements.put(se, style); this.styleElements.put(se, style); } return layer.styleElements.keySet().toArray(new Element[1]); } public Element[] getLayerSubLayers(Element layer) { return this.getElements(layer, "wms:Layer"); } public String getLayerTitle(Element layerElement) { Layer layer = this.namedLayerElements.get(layerElement); if (layer == null) return null; return layer.title != null ? layer.title : (layer.title = this.getText(layerElement, "wms:Title")); } public Element getLayerStyleByName(Element layerElement, String styleName) { Layer layer = this.namedLayerElements.get(layerElement); if (layer == null) return null; if (layer.styleElements == null || layer.styleElements.size() == 0) { // Initialize the layer's style list. this.getLayerStyles(layerElement); if (layer.styleElements == null || layer.styleElements.size() == 0) return null; } Collection<Style> styles = layer.styleElements.values(); for (Style s : styles) { if (s != null && s.equals(styleName)) return s.element; } return null; } // ********* Style Items ********* // protected HashMap<Element, Style> styleElements = new HashMap<Element, Style>(); protected static class Style { protected final Layer layer; protected final Element element; protected String name; protected String title; public Style(Element element, Layer layer) { this.element = element; this.layer = layer; } } public String getStyleAbstract(Element styleElement) { return this.getText(styleElement, "wms:Abstract"); } public String getStyleLegendFormat(Element styleElement) { return this.getText(styleElement, "wms:LegendURL/wms:Format"); } public String getStyleLegendHeight(Element styleElement) { return this.getText(styleElement, "wms:LegendURL/@height"); } public String getStyleLegendURL(Element styleElement) { return this.getText(styleElement, "wms:LegendURL/wms:OnlineResource/@xlink:href"); } public String getStyleLegendWidth(Element styleElement) { return this.getText(styleElement, "wms:LegendURL/@width"); } public String getStyleName(Element styleElement) { Style style = this.styleElements.get(styleElement); return style != null && style.title != null ? style.title : this.getText(styleElement, "wms:Name"); } public String getStyleName(Element layerElement, Element styleElement) { Layer layer = this.namedLayerElements.get(layerElement); if (layer == null || layer.styleElements == null) return this.getStyleName(layerElement, styleElement); Style style = layer.styleElements.get(styleElement); return style != null && style.name != null ? style.title : this.getText(styleElement, "wms:Name"); } public String getStyleSheetURLFormat(Element styleElement) { return this.getText(styleElement, "wms:StyleSheetURL/wms:Format"); } public String getStyleSheetURL(Element styleElement) { return this.getText(styleElement, "wms:StyleSheetURL/wms:OnlineResource/@xlink:href"); } public String getStyleTitle(Element styleElement) { Style style = this.styleElements.get(styleElement); return style != null && style.title != null ? style.title : this.getText(styleElement, "wms:Title"); } public String getStyleTitle(Element layerElement, Element styleElement) { Layer layer = this.namedLayerElements.get(layerElement); if (layer == null || layer.styleElements == null) return this.getStyleTitle(styleElement); Style style = this.styleElements.get(styleElement); return style != null && style.title != null ? style.title : this.getText(styleElement, "wms:Title"); } public String getStyleURL(Element styleElement) { return this.getText(styleElement, "wms:StyleURL/wms:OnlineResource/@xlink:href"); } public String getStyleURLFormat(Element styleElement) { return this.getText(styleElement, "wms:StyleURL/wms:Format"); } // ********* Authority Items ********* // public String getAuthorityName(Element authority) { return this.getText(authority, "@wms:name"); } public String getAuthorityURL(Element authority) { return this.getText(authority, "wms:OnlineResource/@xlink:href"); } // ********* Identifier Items ********* // public String getIdentifier(Element identifier) { return this.getText(identifier, "."); } public String getIdentifierAuthority(Element identifier) { return this.getText(identifier, "@wms:authority"); } // ********* Metadata Items ********* // public String getMetadataFormat(Element metadata) { return this.getText(metadata, "wms:Format"); } public String getMetadataURL(Element metadata) { return this.getText(metadata, "wms:OnlineResource/@xlink:href"); } public String getMetadataType(Element metadata) { return this.getText(metadata, "@wms:type"); } // ********* EX_GeographicBoundingBox Items ********* // public String getWestBoundLongitude(Element bbox) { return this.getText(bbox, "wms:westBoundLongitude"); } public String getEastBoundLongitude(Element bbox) { return this.getText(bbox, "wms:eastBoundLongitude"); } public String getSouthBoundLatitude(Element bbox) { return this.getText(bbox, "wms:southBoundLatitude"); } public String getNorthBoundLatitude(Element bbox) { return this.getText(bbox, "wms:northBoundLatitude"); } // ********* BoundingBox Items ********* // public String getBoundingBoxCRS(Element bbox) { return this.getText(bbox, "@wms:CRS"); } public String getBoundingBoxMinx(Element bbox) { return this.getText(bbox, "@wms:minx"); } public String getBoundingBoxMiny(Element bbox) { return this.getText(bbox, "@wms:miny"); } public String getBoundingBoxMaxx(Element bbox) { return this.getText(bbox, "@wms:maxx"); } public String getBoundingBoxMaxy(Element bbox) { return this.getText(bbox, "@wms:maxy"); } public String getBoundingBoxResx(Element bbox) { return this.getText(bbox, "@wms:resx"); } public String getBoundingBoxResy(Element bbox) { return this.getText(bbox, "@wms:resy"); } public String getBoundingBoxSRS(Element bbox) { return this.getText(bbox, "@wms:SRS"); } // ********* Dimension Items ********* // public String getDimensionName(Element dimension) { return this.getText(dimension, "@wms:name"); } public String getDimensionUnits(Element dimension) { return this.getText(dimension, "@wms:units"); } public String getDimensionUnitSymbol(Element dimension) { return this.getText(dimension, "@wms:unitSymbol"); } public String getDimensionDefault(Element dimension) { return this.getText(dimension, "@wms:default"); } public String getDimensionMultipleValues(Element dimension) { return this.getText(dimension, "@wms:multipleValues"); } public String getDimensionNearestValue(Element dimension) { return this.getText(dimension, "@wms:nearestValue"); } public String getDimensionCurrent(Element dimension) { return this.getText(dimension, "@wms:current"); } public String getDimensionExtent(Element dimension) { return this.getText(dimension, "."); } // ********* Extent Items, wms 1.1 only ********* // public String getExtentName(Element dimension) { return this.getText(dimension, "@wms:name"); } public String getExtentDefault(Element dimension) { return this.getText(dimension, "@wms:default"); } public String getExtentMultipleValues(Element dimension) { return this.getText(dimension, "@wms:multipleValues"); } public String getExtentNearestValue(Element dimension) { return this.getText(dimension, "@wms:nearestValue"); } public String getExtentCurrent(Element dimension) { return this.getText(dimension, "@wms:current"); } public String getExtentText(Element dimension) { return this.getText(dimension, "."); } }