#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
# -*- coding: utf-8 -*-import xml.etree.ElementTree as ET
import json
from pathlib import Pathdef safe_get_text(element, tag, default=None):"""Safely extract text from an XML element."""child = element.find(tag)return child.text if child is not None else defaultdef safe_get_float(element, tag, default=None):"""Safely extract a float from an XML element."""text = safe_get_text(element, tag)try:return float(text) if text is not None else defaultexcept (ValueError, TypeError):return defaultdef main():# Sample XML data (GF-1 satellite metadata)xml_data = '''<?xml version="1.0" encoding="UTF-8" ?><ProductMetaData><SatelliteID>GF1</SatelliteID><ReceiveStationID>MYC</ReceiveStationID><SensorID>WFV4</SensorID><ReceiveTime>2024-09-24 02:20:48</ReceiveTime><OrbitID>61524</OrbitID><OrbitType>GPS</OrbitType><AttType>DMA</AttType><StripID>481726</StripID><ProduceType>STANDARD</ProduceType><SceneID>13576439</SceneID><DDSFlag>TRUE</DDSFlag><ProductID>13576439001</ProductID><ProductQuality /><ProductQualityReport /><ProductLevel>LEVEL1A</ProductLevel><ProductFormat>GEOTIFF</ProductFormat><ProduceTime>2024-09-24 22:30:59</ProduceTime><Bands>1,2,3,4</Bands><ScenePath>582</ScenePath><SceneRow>76</SceneRow><SatPath>589</SatPath><SatRow>75</SatRow><SceneCount>1</SceneCount><SceneShift>1</SceneShift><StartTime>2024-09-24 10:20:33</StartTime><EndTime>2024-09-24 10:21:03</EndTime><CenterTime>2024-09-24 10:20:48</CenterTime><StartLine /><EndLine /><ImageGSD>16.000000000000000</ImageGSD><WidthInPixels>12000</WidthInPixels><HeightInPixels>13400</HeightInPixels><WidthInMeters /><HeightInMeters /><RegionName>CH</RegionName><CloudPercent>0</CloudPercent><DataSize>1227</DataSize><RollViewingAngle>0.000000000000000</RollViewingAngle><PitchViewingAngle>0.000000000000000</PitchViewingAngle><RollSatelliteAngle>0.000016317655897</RollSatelliteAngle><PitchSatelliteAngle>-0.000021716054218</PitchSatelliteAngle><YawSatelliteAngle>2.543099866083802</YawSatelliteAngle><SolarAzimuth>166.871948556585039</SolarAzimuth><SolarZenith>48.060375213623047</SolarZenith><SatelliteAzimuth>286.730366229627975</SatelliteAzimuth><SatelliteZenith>26.500590498958282</SatelliteZenith><GainMode>G0,G0,G0,G0</GainMode><IntegrationTime>0.002257803868283</IntegrationTime><IntegrationLevel>S0,S0,S0,S0</IntegrationLevel><MapProjection /><EarthEllipsoid /><ZoneNo /><ResamplingKernel /><HeightMode /><EphemerisData>GPS</EphemerisData><AttitudeData>DMA</AttitudeData><RadiometricMethod>LAB</RadiometricMethod><MtfCorrection>LAB</MtfCorrection><Denoise>MOMENT</Denoise><RayleighCorrection>N</RayleighCorrection><UsedGCPNo>0</UsedGCPNo><CenterLatitude>46.702109160938569</CenterLatitude><CenterLongitude>133.070196050536879</CenterLongitude><TopLeftLatitude>47.885559023882131</TopLeftLatitude><TopLeftLongitude>132.107675516323695</TopLeftLongitude><TopRightLatitude>47.261740594511238</TopRightLatitude><TopRightLongitude>135.066865429476280</TopRightLongitude><BottomRightLatitude>45.459380058829218</BottomRightLatitude><BottomRightLongitude>134.210751915721147</BottomRightLongitude><BottomLeftLatitude>46.065768914899728</BottomLeftLatitude><BottomLeftLongitude>131.343463299378755</BottomLeftLongitude><TopLeftMapX /><TopLeftMapY /><TopRightMapX /><TopRightMapY /><BottomRightMapX /><BottomRightMapY /><BottomLeftMapX /><BottomLeftMapY /><DataArchiveFile /><BrowseFileLocation /><ThumbFileLocation /><SatOffNadir></SatOffNadir><ImageGSD></ImageGSD><L0DataTempDir></L0DataTempDir><L0DataArchiveDir></L0DataArchiveDir><SceneDataCount>1</SceneDataCount><SceneDate></SceneDate><AbsCeof>0.2148,0.1607,0.1317,0.1288</AbsCeof></ProductMetaData>'''try:# Parse XMLroot = ET.fromstring(xml_data)# Extract all propertiesproperties = {child.tag: child.text if child.text else Nonefor child in root}# Extract and validate coordinatescoordinate_pairs = [('TopLeftLongitude', 'TopLeftLatitude'),('TopRightLongitude', 'TopRightLatitude'),('BottomRightLongitude', 'BottomRightLatitude'),('BottomLeftLongitude', 'BottomLeftLatitude')]coordinates = []for lon_tag, lat_tag in coordinate_pairs:lon = safe_get_float(root, lon_tag)lat = safe_get_float(root, lat_tag)if lon is not None and lat is not None:coordinates.append([lon, lat])# Validate we have enough coordinatesif len(coordinates) < 4:raise ValueError("Insufficient valid coordinates to form a polygon")# Close the polygoncoordinates.append(coordinates[0])# Create GeoJSON structurefeature = {"type": "Feature","geometry": {"type": "Polygon","coordinates": [coordinates]},"properties": properties}feature_collection = {"type": "FeatureCollection","features": [feature]}# Write to fileoutput_path = Path("gf1_satellite_metadata.geojson")with output_path.open("w", encoding="utf-8") as f:json.dump(feature_collection, f, indent=2, ensure_ascii=False)print(f"Successfully generated GeoJSON file at: {output_path.resolve()}")except ET.ParseError as e:print(f"XML parsing error: {e}")except ValueError as e:print(f"Data validation error: {e}")except Exception as e:print(f"Unexpected error: {e}")if __name__ == "__main__":main()
