#!/usr/bin/env python3
-*- coding: utf-8 -*-
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import json
from pathlib import Path
def 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 default
def 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 default
except (ValueError, TypeError):
return default
def 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 XML
root = ET.fromstring(xml_data)
# Extract all properties
properties = {
child.tag: child.text if child.text else None
for child in root
}
# Extract and validate coordinates
coordinate_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 coordinates
if len(coordinates) < 4:
raise ValueError("Insufficient valid coordinates to form a polygon")
# Close the polygon
coordinates.append(coordinates[0])
# Create GeoJSON structure
feature = {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [coordinates]
},
"properties": properties
}
feature_collection = {
"type": "FeatureCollection",
"features": [feature]
}
# Write to file
output_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()