diff --git a/src/mcgibs/capabilities.py b/src/mcgibs/capabilities.py index 8151797..c37fc96 100644 --- a/src/mcgibs/capabilities.py +++ b/src/mcgibs/capabilities.py @@ -117,25 +117,44 @@ def _parse_bbox(layer_el: ET.Element) -> BBox | None: return BBox(west=west, south=south, east=east, north=north) +def _extract_colormap_id_from_href(href: str) -> str | None: + """Extract the colormap identifier from a GIBS colormap URL. + + GIBS metadata hrefs look like: + https://gibs.earthdata.nasa.gov/colormaps/v1.3/AMSR2_Sea_Ice_Concentration.xml + + Multiple resolution layers often share a single colormap file, so the + colormap filename may differ from the layer identifier. + """ + if not href: + return None + filename = href.rstrip("/").rsplit("/", 1)[-1] + if filename.endswith(".xml"): + return filename[:-4] + return None + + def _detect_colormap(layer_el: ET.Element, identifier: str) -> tuple[bool, str | None]: """Detect whether a layer has a colormap. GIBS layers with colormaps typically have: + - Metadata with xlink:role containing "colormap" (includes the URL) - A LegendURL element inside a Style - - Metadata with xlink:role containing "colormap" - Returns (has_colormap, colormap_id). + Returns (has_colormap, colormap_id). The colormap_id is extracted from + the metadata href when available, falling back to the layer identifier. """ - # Check for LegendURL in any Style - for style in _findall(layer_el, "Style", _WMTS_URI): - if _find(style, "LegendURL", _WMTS_URI) is not None: - return True, identifier - - # Check metadata for colormap hints + # Check metadata first — the href carries the actual colormap filename for meta in _findall(layer_el, "Metadata", _OWS_URI): role = meta.get(f"{{{_XLINK_URI}}}role", "") href = meta.get(f"{{{_XLINK_URI}}}href", "") if "colormap" in role.lower() or "colormap" in href.lower(): + colormap_id = _extract_colormap_id_from_href(href) or identifier + return True, colormap_id + + # Fallback: check for LegendURL in any Style + for style in _findall(layer_el, "Style", _WMTS_URI): + if _find(style, "LegendURL", _WMTS_URI) is not None: return True, identifier return False, None diff --git a/src/mcgibs/colormaps.py b/src/mcgibs/colormaps.py index 8e7dd2d..48ec349 100644 --- a/src/mcgibs/colormaps.py +++ b/src/mcgibs/colormaps.py @@ -209,9 +209,13 @@ def parse_colormap(xml_text: str) -> ColorMapSet: title = cm_elem.get("title", "") units = cm_elem.get("units", "") - # Parse entries + # Parse entries — GIBS v1.3 wraps them in , but some + # documents have as direct children of . entries: list[ColorMapEntry] = [] - for entry_elem in cm_elem.findall("ColorMapEntry"): + entry_elements = cm_elem.findall("Entries/ColorMapEntry") + if not entry_elements: + entry_elements = cm_elem.findall("ColorMapEntry") + for entry_elem in entry_elements: rgb_raw = entry_elem.get("rgb", "0,0,0") entries.append( ColorMapEntry( diff --git a/tests/fixtures/colormap_sample.xml b/tests/fixtures/colormap_sample.xml index 05420a5..b8f584b 100644 --- a/tests/fixtures/colormap_sample.xml +++ b/tests/fixtures/colormap_sample.xml @@ -1,20 +1,22 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -24,7 +26,9 @@ - + + +