shamim237 commited on
Commit
baf9496
1 Parent(s): 0c05ff5

Upload 11 files

Browse files
Files changed (11) hide show
  1. README.md +2 -8
  2. app.py +63 -0
  3. bez_dict.json +255 -0
  4. flurstueck.py +213 -0
  5. guby.py +131 -0
  6. kat.py +92 -0
  7. main.py +42 -0
  8. nutflu.py +29 -0
  9. nutzung.py +115 -0
  10. requirements.txt +77 -0
  11. ver.py +159 -0
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: NAS ALKIS Conversion
3
- emoji: 🔥
4
- colorFrom: gray
5
- colorTo: gray
6
  sdk: gradio
7
  sdk_version: 4.44.0
8
- app_file: app.py
9
- pinned: false
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: NAS-ALKIS_CONVERSION
3
+ app_file: app.py
 
 
4
  sdk: gradio
5
  sdk_version: 4.44.0
 
 
6
  ---
 
 
app.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import subprocess
3
+ import os
4
+ import time
5
+
6
+ def run_script(script_name, *args):
7
+ command = ['python', script_name] + list(args)
8
+ start_time = time.time()
9
+ result = subprocess.run(command, capture_output=True, text=True)
10
+ end_time = time.time()
11
+ elapsed_time = end_time - start_time
12
+ if result.returncode != 0:
13
+ return f"Error running {script_name}: {result.stderr}"
14
+ else:
15
+ pass
16
+
17
+ def process_files(xml_file, output_path):
18
+ # Define file paths
19
+ bez_dict_file = "bez_dict.json"
20
+ flurstueck_shapefile = os.path.join(output_path, "flurstueck.shp")
21
+ nutzung_shapefile = os.path.join(output_path, "nutzung.shp")
22
+ nutzung_flurstueck_shapefile = os.path.join(output_path, "nutzungFlurstueck.shp")
23
+ gebauede_bauwerk_shapefile = os.path.join(output_path, "gebauedeBauwerk.shp")
24
+ verwaltungs_einheit_shapefile = os.path.join(output_path, "verwaltungsEinheit.shp")
25
+ kataster_bezirk_shapefile = os.path.join(output_path, "katasterBezirk.shp")
26
+
27
+ # Ensure the output directory exists
28
+ os.makedirs(output_path, exist_ok=True)
29
+
30
+ # Run scripts in the correct order
31
+ results = []
32
+ results.append(run_script('flurstueck.py', xml_file, flurstueck_shapefile))
33
+ results.append(f"Generated: {flurstueck_shapefile}")
34
+ results.append(run_script('nutzung.py', xml_file, bez_dict_file, nutzung_shapefile))
35
+ results.append(f"Generated: {nutzung_shapefile}")
36
+ results.append(run_script('nutflu.py', flurstueck_shapefile, nutzung_shapefile, nutzung_flurstueck_shapefile))
37
+ results.append(f"Generated: {nutzung_flurstueck_shapefile}")
38
+ results.append(run_script('guby.py', xml_file, gebauede_bauwerk_shapefile))
39
+ results.append(f"Generated: {gebauede_bauwerk_shapefile}")
40
+ results.append(run_script('ver.py', flurstueck_shapefile, xml_file, verwaltungs_einheit_shapefile))
41
+ results.append(f"Generated: {verwaltungs_einheit_shapefile}")
42
+ results.append(run_script('kat.py', flurstueck_shapefile, kataster_bezirk_shapefile))
43
+ results.append(f"Generated: {kataster_bezirk_shapefile}")
44
+
45
+ results.append("CONVERSION COMPLETED")
46
+
47
+ return "\n".join(results)
48
+
49
+ # Create Gradio interface
50
+ iface = gr.Interface(
51
+ fn=process_files,
52
+ inputs=[
53
+ gr.File(label="Input XML File"),
54
+ gr.Textbox(label="Output Path", placeholder="Enter the output directory path")
55
+ ],
56
+ outputs="text",
57
+ title="NAS-ALKIS Conversion",
58
+ description="Upload an XML file and specify the output path to generate conversion."
59
+ )
60
+
61
+ # Launch the app
62
+ if __name__ == "__main__":
63
+ iface.launch(share=True)
bez_dict.json ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "2620": "Abfallbehandlungsanlage",
3
+ "7000": "Abraum",
4
+ "1010": "Ackerland",
5
+ "8220": "Altarm",
6
+ "8210": "Altwasser",
7
+ "2014": "Andesit",
8
+ "5002": "Anhydritstein",
9
+ "5630": "Anlegestelle",
10
+ "3010": "Antimon",
11
+ "1450": "Ausstellung, Messe",
12
+ "4260": "Autokino, Freilichtkino",
13
+ "8500": "Bach",
14
+ "8640": "Baggersee",
15
+ "1420": "Bank, Kredit",
16
+ "2013": "Basalt, Diabas",
17
+ "1031": "Baumschule",
18
+ "1000": "Vegetationslose Fläche",
19
+ "1110": "Verwaltung",
20
+ "1460": "Beherbergung",
21
+ "1002": "Bentonit",
22
+ "2000": "Steine, Gestein, Festgestein",
23
+ "2710": "Betrieb",
24
+ "1780": "Betriebliche Sozialeinrichtung",
25
+ "2502": "Industrie und Gewerbefläche",
26
+ "2532": "Betriebsfläche Versorgungsanlage, Elektrizität",
27
+ "2582": "Betriebsfläche Versorgungsanlage, Funkund Fernmeldewesen",
28
+ "2562": "Betriebsfläche Versorgungsanlage, Gas",
29
+ "2522": "Betriebsfläche Versorgungsanlage, Wasser",
30
+ "2572": "Betriebsfläche Versorgungsanlage, Wärme",
31
+ "2552": "Betriebsfläche Versorgungsanlage, Öl",
32
+ "2602": "Betriebsfläche, Entsorgungsanlage",
33
+ "2622": "Betriebsfläche, Entsorgungsanlage Abfallbeseitigung",
34
+ "2612": "Betriebsfläche, Entsorgungsanlage Abwasserbeseitigung",
35
+ "2623": "Betriebsfläche, Entsorgungsanlage Schlamm",
36
+ "1120": "Unbebaute Gewässerbegleitfläche",
37
+ "3004": "Blei",
38
+ "4430": "Botanischer Garten",
39
+ "1200": "Stadtbahn",
40
+ "4021": "Braunkohle",
41
+ "3002": "Buntmetallerze",
42
+ "1310": "Laubwald mit Nadelholz",
43
+ "4330": "Campingplatz",
44
+ "2630": "Deponie (oberirdisch)",
45
+ "2640": "Deponie (untertägig)",
46
+ "2006": "Dolomitstein",
47
+ "3011": "Edelmetallerze",
48
+ "4160": "Eis-, Rollschuhbahn",
49
+ "3001": "Eisen",
50
+ "1100": "Öffentliche Zwecke",
51
+ "2600": "Entsorgung",
52
+ "4000": "Treib- und Brennstoffe",
53
+ "4300": "Erholungsfläche",
54
+ "3000": "Kohle",
55
+ "5210": "Fahrweg",
56
+ "1011": "Streuobstacker",
57
+ "5009": "Feldspat",
58
+ "5350": "Festplatz",
59
+ "8410": "Fleet",
60
+ "8230": "Flussmündungstrichter",
61
+ "5510": "Flughafen",
62
+ "8200": "Fluss",
63
+ "5006": "Flusspat",
64
+ "1760": "Forschung",
65
+ "7600": "Forstwirtschaftliche Betriebsfläche",
66
+ "4250": "Freilichtmuseum",
67
+ "4240": "Freilichttheater",
68
+ "4200": "Freizeitanlage",
69
+ "4230": "Freizeitpark",
70
+ "9403": "Friedhof (Park)",
71
+ "9402": "Friedhof (ohne Gebäude)",
72
+ "2580": "Funk- und Fernmeldeanlage",
73
+ "5130": "Fußgängerzone",
74
+ "5220": "Fußweg",
75
+ "5640": "Fähranlage",
76
+ "5230": "Gang",
77
+ "4460": "Garten",
78
+ "1030": "Geröll",
79
+ "2560": "Gaswerk",
80
+ "2341": "Gebäude- Freifläche zu Verkehrsanlagen, Schifffahrt",
81
+ "2601": "Gebäude- und Freifläche Entsorgungsanlage",
82
+ "2610": "Kläranlage, Klärwerk",
83
+ "2621": "Gebäude- und Freifläche Entsorgungsanlage, Abfallbeseitigung",
84
+ "2611": "Gebäude- und Freifläche Entsorgungsanlage, Abwasserbeseitigung",
85
+ "4301": "Gebäude- und Freifläche Erholung",
86
+ "4321": "Gebäude- und Freifläche, Bad",
87
+ "4431": "Gebäude- und Freifläche, Erholung, Botanik",
88
+ "4331": "Gebäude- und Freifläche, Camping",
89
+ "4101": "Gebäude- und Freifläche Erholung, Sport",
90
+ "9401": "Gebäude- und Freifläche Friedhof",
91
+ "1701": "Gebäude- und Freifläche Industrie und Gewerbe",
92
+ "2700": "Gebäude- und Freifläche Land- und Forstwirtschaft",
93
+ "2501": "Gebäude- und Freifläche Versorgungsanlage",
94
+ "2521": "Gebäude- und Freifläche Versorgungsanlage, Wasser",
95
+ "2531": "Gebäude- und Freifläche Versorgungsanlage, Elektrizität",
96
+ "2581": "Gebäude- und Freifläche Versorgungsanlage, Funk- und Fernmeldesystem",
97
+ "2561": "Gebäude- und Freifläche Versorgungsanlage, Gas",
98
+ "2571": "Gebäude- und Freifläche Versorgungsanlage, Wärme",
99
+ "2551": "Gebäude- und Freifläche Versorgungsanlage, Öl",
100
+ "5501": "Gebäude- und Freifläche zu Verkehrsanlagen, Luftfahrt",
101
+ "2321": "Gebäude- und Freifläche zu Verkehrsanlagen, Schiene",
102
+ "2311": "Gebäude- und Freifläche zu Verkehrsanlagen, Straße",
103
+ "4211": "Gebäude- und Freifläche, Zoologie",
104
+ "2100": "Gebäude- und Freifläche, Mischnutzung mit Wohnen",
105
+ "1150": "Gesundheit, Kur",
106
+ "2160": "Gewerbe und Industrie mit Wohnen",
107
+ "5001": "Gipsstein",
108
+ "2012": "Gneis",
109
+ "4110": "Golfplatz",
110
+ "8400": "Graben",
111
+ "2016": "Granit",
112
+ "2017": "Granodiorit",
113
+ "5011": "Graphit",
114
+ "2010": "Grauwacke",
115
+ "1770": "Grundstoff",
116
+ "4400": "Grünanlage",
117
+ "4410": "Grünfläche",
118
+ "1020": "Grünland",
119
+ "1490": "Gärtnerei",
120
+ "1102": "Güterverkehr",
121
+ "5610": "Hafenanlage (Landfläche)",
122
+ "9999": "Tagebau, Grube, Steinbruch",
123
+ "1440": "Handel",
124
+ "1400": "Handel und Dienstleistung",
125
+ "2150": "Handel und Dienstleistungen mit Wohnen",
126
+ "1720": "Handwerk",
127
+ "5211": "Hauptwirtschaftsweg",
128
+ "2570": "Heizwerk",
129
+ "1300": "Seilbahn, Bergbahn",
130
+ "9404": "Historischer Friedhof",
131
+ "1012": "Quarzsand",
132
+ "5530": "Hubschrauberflugplatz",
133
+ "4280": "Hundeübungsplatz",
134
+ "1700": "Industrie und Gewerbe",
135
+ "5000": "Schutt",
136
+ "5511": "Internationaler Flughafen",
137
+ "5004": "Kalisalz",
138
+ "1007": "Kalk, Kalktuff, Kreide",
139
+ "5005": "Kalkspat",
140
+ "2005": "Kalkstein",
141
+ "8300": "Kanal",
142
+ "1003": "Kaolin",
143
+ "8000": "Schrott, Altmaterial",
144
+ "1009": "Kies, Kiessand",
145
+ "1013": "Spargel",
146
+ "4440": "Kleingarten",
147
+ "4020": "Kohle",
148
+ "2530": "Kraftwerk",
149
+ "1130": "Kultur",
150
+ "3003": "Kupfer",
151
+ "8710": "Küstengewässer",
152
+ "1740": "Lagerplatz",
153
+ "5540": "Landeplatz, Sonderlandeplatz",
154
+ "6800": "Landwirtschaftliche Betriebsfläche",
155
+ "2020": "Lavaschlacke",
156
+ "1004": "Lehm",
157
+ "1005": "Löß, Lößlehm",
158
+ "1600": "Magnetschwebebahn",
159
+ "3009": "Mangan",
160
+ "5340": "Marktplatz",
161
+ "2008": "Marmor",
162
+ "1006": "Mergel",
163
+ "2004": "Mergelstein",
164
+ "2003": "Metamorphe Schiefer",
165
+ "4290": "Modellflugplatz",
166
+ "1320": "Schlossanlage",
167
+ "1051": "Obstbaumplantage",
168
+ "1050": "Obstplantage",
169
+ "1052": "Obststrauchplantage",
170
+ "4420": "Park",
171
+ "5310": "Parkplatz",
172
+ "5010": "Pegmatitsand",
173
+ "2015": "Porphyr, Quarzporphyr",
174
+ "1710": "Produktion",
175
+ "5008": "Quarz",
176
+ "2011": "Quarzit",
177
+ "5250": "Rad- und Fußweg",
178
+ "5240": "Radweg",
179
+ "2550": "Raffinerie",
180
+ "5320": "Rastplatz",
181
+ "5330": "Raststätte",
182
+ "5512": "Regionalflughafen",
183
+ "41400": "Reitplatz",
184
+ "5260": "Reitweg",
185
+ "1140": "Religiöse Einrichtung",
186
+ "4130": "Rennbahn",
187
+ "1470": "Restauration",
188
+ "1104": "S-Bahn",
189
+ "4220": "Safaripark, Wildpark",
190
+ "1008": "Sand",
191
+ "1040": "Weingarten",
192
+ "2009": "Sandstein",
193
+ "2002": "Schiefer, Dachschiefer",
194
+ "4150": "Schießanlage",
195
+ "6000": "Schlacke",
196
+ "5620": "Schleuse (Landfläche)",
197
+ "5007": "Schwerspat",
198
+ "4320": "Schwimmbad, Freibad",
199
+ "8610": "See",
200
+ "5550": "Segelfluggelände",
201
+ "1170": "Sicherheit und Ordnung",
202
+ "1160": "Soziales",
203
+ "8631": "Speicherbecken",
204
+ "4470": "Spielplatz, Bolzplatz",
205
+ "4100": "Sportanlage",
206
+ "8810": "Sporthafenbecken",
207
+ "4120": "Sportplatz",
208
+ "1302": "Standseilbahn",
209
+ "8630": "Stausee",
210
+ "4022": "Steinkohle",
211
+ "5003": "Steinsalz",
212
+ "1201": "Straßenbahn",
213
+ "2313": "Straßenentwässerungsanlage",
214
+ "1021": "Streuobstwiese",
215
+ "2021": "Talkschiefer, Speckstein",
216
+ "1730": "Tankstelle",
217
+ "8620": "Teich",
218
+ "4170": "Tennisplatz",
219
+ "1001": "Ton",
220
+ "2001": "Tonstein",
221
+ "4010": "Torf",
222
+ "1750": "Transport",
223
+ "2019": "Trass",
224
+ "2007": "Travertin",
225
+ "2018": "Tuff, Bimsstein",
226
+ "1202": "U-Bahn",
227
+ "2540": "Umspannstation",
228
+ "3008": "Uran",
229
+ "1480": "Vergnügung",
230
+ "2322": "Verkehrsbegleitfläche Bahnverkehr",
231
+ "2312": "Verkehrsbegleitfläche Straße",
232
+ "5520": "Verkehrslandeplatz",
233
+ "4270": "Verkehrsübungsplatz",
234
+ "1430": "Versicherung",
235
+ "2500": "Versorgungsanlage",
236
+ "1410": "Verwaltung, freie Berufe",
237
+ "2520": "Wasserwerk",
238
+ "22000": "Weg",
239
+ "1790": "Werft",
240
+ "5212": "Wirtschaftsweg",
241
+ "3007": "Wismut, Kobaldt, Nickel",
242
+ "4310": "Wochenend- und Ferienhausfläche",
243
+ "4450": "Wochenendplatz",
244
+ "2720": "Wohnen",
245
+ "2130": "Wohnen mit Gewerbe und Industrie",
246
+ "2120": "Wohnen mit Handel und Dienstleistungen",
247
+ "2110": "Wohnen mit Öffentlich",
248
+ "2730": "Wohnen und Betrieb",
249
+ "1301": "Zahnradbahn",
250
+ "3005": "Zink",
251
+ "3006": "Zinn",
252
+ "4210": "Zoo",
253
+ "2140": "Öffentlich mit Wohnen",
254
+ "4030": "Ölschiefer"
255
+ }
flurstueck.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ import geopandas as gpd
3
+ from shapely.geometry import Polygon
4
+ import xml.etree.ElementTree as ET
5
+ import multiprocessing as mp
6
+ import sys
7
+
8
+ # Parse the XML file correctly
9
+ def parse_xml(file_path):
10
+ tree = ET.parse(file_path) # Parse the entire XML file
11
+ root = tree.getroot() # Get the root element
12
+ return root
13
+
14
+ # Extract coordinates in bulk
15
+ def extract_coordinates(posList):
16
+ coordinates = [float(x) for x in posList.strip().split()]
17
+ return [(coordinates[i], coordinates[i + 1]) for i in range(0, len(coordinates), 2)]
18
+
19
+ # Create flurstnr based on zaehler and nenner
20
+ def create_flurstnr(zaehler, nenner=None):
21
+ return f"{zaehler}/{nenner}" if nenner else zaehler
22
+
23
+ # Create gmdschl by merging land, kreis, regierungsbezirk, and gemeinde
24
+ def create_gmdschl(land, regierungsbezirk, kreis, gemeinde):
25
+ return f"{land}{regierungsbezirk}{kreis}{gemeinde}"
26
+
27
+ # Find and extract kreis values
28
+ def find_kreis(root, namespaces):
29
+ kreis_dict = {}
30
+ for kreis_region in root.findall('.//adv:AX_KreisRegion', namespaces):
31
+ schluessel_gesamt = kreis_region.find('.//adv:schluesselGesamt', namespaces)
32
+ if schluessel_gesamt is not None:
33
+ kreis_dict[schluessel_gesamt.text] = kreis_region.find('.//adv:bezeichnung', namespaces).text
34
+ return kreis_dict
35
+
36
+ # Find and extract regbezirk values
37
+ def find_regbezirk(root, namespaces):
38
+ regbezirk_dict = {}
39
+ for regbezirk in root.findall('.//adv:AX_Regierungsbezirk', namespaces):
40
+ schluessel_gesamt = regbezirk.find('.//adv:schluesselGesamt', namespaces)
41
+ bezeichnung = regbezirk.find('.//adv:bezeichnung', namespaces)
42
+ if schluessel_gesamt is not None and bezeichnung is not None:
43
+ regbezirk_dict[schluessel_gesamt.text] = bezeichnung.text
44
+ return regbezirk_dict
45
+
46
+ # Create lookup dictionary
47
+ def create_lookup_dict(root, tag, key_path, value_path, namespaces):
48
+ lookup_dict = {}
49
+ for element in root.findall(f'.//adv:{tag}', namespaces):
50
+ key = element.find(key_path, namespaces)
51
+ value = element.find(value_path, namespaces)
52
+ if key is not None and value is not None:
53
+ lookup_dict[key.text] = value.text
54
+ return lookup_dict
55
+
56
+ # Create lagebeztxt lookup dictionary
57
+ def create_lagebeztxt_dict(root, namespaces):
58
+ lagebeztxt_dict = {}
59
+ for tag in ['AX_LagebezeichnungMitHausnummer', 'AX_LagebezeichnungOhneHausnummer']:
60
+ for element in root.findall(f'.//adv:{tag}', namespaces):
61
+ gml_id = element.get('{http://www.opengis.net/gml/3.2}id')
62
+ unverschluesselt = element.find('.//adv:unverschluesselt', namespaces)
63
+ hausnummer = element.find('.//adv:hausnummer', namespaces)
64
+
65
+ if unverschluesselt is not None:
66
+ if hausnummer is not None:
67
+ lagebeztxt_dict[gml_id] = f"{unverschluesselt.text} {hausnummer.text}"
68
+ else:
69
+ lagebeztxt_dict[gml_id] = unverschluesselt.text
70
+ else:
71
+ lagebeztxt_dict[gml_id] = "<null>"
72
+
73
+ return lagebeztxt_dict
74
+
75
+ # Process a single AX_Flurstueck element
76
+ def process_single_flurstueck(flurstueck, namespaces, lookup_dicts):
77
+ # Extracting coordinates in bulk
78
+ polygon_coords = [coord for posList in flurstueck.findall('.//gml:posList', namespaces)
79
+ for coord in extract_coordinates(posList.text)]
80
+ polygon = Polygon(polygon_coords)
81
+
82
+ # Extract attributes in a single pass
83
+ flaeche = flurstueck.find('.//adv:amtlicheFlaeche', namespaces)
84
+ flaeche = flaeche.text if flaeche is not None else None
85
+
86
+ flstkennz = flurstueck.find('.//adv:flurstueckskennzeichen', namespaces)
87
+ flstkennz = flstkennz.text if flstkennz is not None else None
88
+
89
+ zaehler = flurstueck.find('.//adv:zaehler', namespaces).text
90
+ nenner = flurstueck.find('.//adv:nenner', namespaces)
91
+ flurstnr = create_flurstnr(zaehler, nenner.text if nenner is not None else None)
92
+
93
+ # Gemeindeschlüssel extraction
94
+ gemeindekennzeichen = flurstueck.find('.//adv:AX_Gemeindekennzeichen', namespaces)
95
+ if gemeindekennzeichen is not None:
96
+ land = gemeindekennzeichen.find('.//adv:land', namespaces).text
97
+ kreis = gemeindekennzeichen.find('.//adv:kreis', namespaces).text
98
+ regierungsbezirk = gemeindekennzeichen.find('.//adv:regierungsbezirk', namespaces).text
99
+ gemeinde_code = gemeindekennzeichen.find('.//adv:gemeinde', namespaces).text
100
+ gmdschl = create_gmdschl(land, regierungsbezirk, kreis, gemeinde_code)
101
+ else:
102
+ gmdschl = None
103
+ land = None
104
+ regierungsbezirk = None
105
+ gemeinde_code = None
106
+
107
+ # Use the lookup dictionaries for faster data retrieval
108
+ merged_value = f"{land}{regierungsbezirk}{kreis}"
109
+ kreis_bezeichnung = lookup_dicts['kreis'].get(merged_value, "<null>")
110
+
111
+ regbezirk_key = f"{land}{regierungsbezirk}" if land and regierungsbezirk else None
112
+ regbezirk_bezeichnung = lookup_dicts['regbezirk'].get(regbezirk_key, "<null>")
113
+
114
+ gemeinde = lookup_dicts['gemeinde'].get(merged_value + gemeinde_code, "<null>") if gemeindekennzeichen is not None else "<null>"
115
+ land_name = lookup_dicts['land'].get(land, "<null>") if land else "<null>"
116
+
117
+ gemarkungsnummer = flurstueck.find('.//adv:AX_Gemarkung_Schluessel/adv:gemarkungsnummer', namespaces)
118
+ gemarkung = lookup_dicts['gemarkung'].get(f"{land}{gemarkungsnummer.text}", "<null>") if land is not None and gemarkungsnummer is not None else "<null>"
119
+
120
+ # Extract lagebeztxt using the lookup dictionary
121
+ weist_auf = flurstueck.find('.//adv:weistAuf[@xlink:href]', namespaces)
122
+ zeigt_auf = flurstueck.find('.//adv:zeigtAuf[@xlink:href]', namespaces)
123
+
124
+ if weist_auf is not None:
125
+ href = weist_auf.get('{http://www.w3.org/1999/xlink}href')
126
+ lagebeztxt = lookup_dicts['lagebeztxt'].get(href.split(":")[-1], "<null>")
127
+ elif zeigt_auf is not None:
128
+ href = zeigt_auf.get('{http://www.w3.org/1999/xlink}href')
129
+ lagebeztxt = lookup_dicts['lagebeztxt'].get(href.split(":")[-1], "<null>")
130
+ else:
131
+ lagebeztxt = "<null>"
132
+
133
+ # Return the extracted data as a dictionary
134
+ return {
135
+ 'geometry': polygon,
136
+ 'flaeche': flaeche,
137
+ 'flstkennz': flstkennz,
138
+ 'flur': 'Flur',
139
+ 'flurstnr': flurstnr,
140
+ 'gmdschl': gmdschl,
141
+ 'regbezirk': regbezirk_bezeichnung,
142
+ 'kreis': kreis_bezeichnung,
143
+ 'gemeinde': gemeinde,
144
+ 'land': land_name,
145
+ 'gemarkung': gemarkung,
146
+ 'lagebeztxt': lagebeztxt
147
+ }
148
+
149
+ # Process all AX_Flurstueck tags with optimizations
150
+ def process_flurstueck(root):
151
+ namespaces = {'gml': 'http://www.opengis.net/gml/3.2',
152
+ 'adv': 'http://www.adv-online.de/namespaces/adv/gid/6.0',
153
+ 'xlink': 'http://www.w3.org/1999/xlink'}
154
+
155
+ # Create lookup dictionaries
156
+ lookup_dicts = {
157
+ 'kreis': find_kreis(root, namespaces),
158
+ 'regbezirk': find_regbezirk(root, namespaces),
159
+ 'gemeinde': create_lookup_dict(root, 'AX_Gemeinde', './/adv:schluesselGesamt', './/adv:bezeichnung', namespaces),
160
+ 'land': create_lookup_dict(root, 'AX_Bundesland', './/adv:schluesselGesamt', './/adv:bezeichnung', namespaces),
161
+ 'gemarkung': create_lookup_dict(root, 'AX_Gemarkung', './/adv:schluesselGesamt', './/adv:bezeichnung', namespaces),
162
+ 'lagebeztxt': create_lagebeztxt_dict(root, namespaces)
163
+ }
164
+
165
+ # Use multiprocessing to process Flurstueck elements in parallel
166
+ with mp.Pool() as pool:
167
+ data = pool.starmap(
168
+ process_single_flurstueck,
169
+ [(flurstueck, namespaces, lookup_dicts) for flurstueck in root.findall('.//adv:AX_Flurstueck', namespaces)]
170
+ )
171
+
172
+ return data
173
+
174
+ # Main function
175
+ def main(xml_file, output_shapefile):
176
+ start_time = time.time()
177
+ root = parse_xml(xml_file)
178
+ data = process_flurstueck(root)
179
+
180
+ # Create a GeoDataFrame
181
+ gdf = gpd.GeoDataFrame(data)
182
+ gdf.set_crs(epsg=25832, inplace=True) # Set appropriate CRS
183
+
184
+ # Save to a shapefile
185
+ gdf.to_file(output_shapefile, driver='ESRI Shapefile')
186
+
187
+ # Save the .prj file with the specified projection
188
+ prj_content = ('PROJCS["ETRS89 / UTM zone 32N",'
189
+ 'GEOGCS["ETRS89",'
190
+ 'DATUM["European_Terrestrial_Reference_System_1989",'
191
+ 'SPHEROID["GRS 1980",6378137,298.257222101]],'
192
+ 'PRIMEM["Greenwich",0],'
193
+ 'UNIT["degree",0.0174532925199433]],'
194
+ 'PROJECTION["Transverse_Mercator"],'
195
+ 'PARAMETER["latitude_of_origin",0],'
196
+ 'PARAMETER["central_meridian",9],'
197
+ 'PARAMETER["scale_factor",0.9996],'
198
+ 'PARAMETER["false_easting",500000],'
199
+ 'PARAMETER["false_northing",0],'
200
+ 'UNIT["metre",1]]')
201
+
202
+ prj_file = output_shapefile.replace('.shp', '.prj')
203
+ with open(prj_file, 'w') as prj:
204
+ prj.write(prj_content)
205
+
206
+ end_time = time.time()
207
+ print(f"Processing complete. Shapefile saved as '{output_shapefile}'. Time taken: {end_time - start_time:.2f} seconds.")
208
+
209
+ # Example usage
210
+ if __name__ == "__main__":
211
+ xml_file = sys.argv[1]
212
+ output_shapefile = sys.argv[2]
213
+ main(xml_file, output_shapefile)
guby.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import xml.etree.ElementTree as ET
2
+ import shapefile
3
+ import sys
4
+
5
+ # Input XML file
6
+ input_xml = sys.argv[1]
7
+
8
+ # Output shapefile
9
+ output_shapefile = sys.argv[2]
10
+
11
+ # Create shapefile writer
12
+ w = shapefile.Writer(output_shapefile)
13
+ w.autoBalance = 1
14
+
15
+ # Define fields for shapefile
16
+ w.field('gebnutzbez', 'C') # Gebaeude Nutzung Bezeichnung
17
+ w.field('funktion', 'C') # Funktion value (mapped to text)
18
+ w.field('fktkurz', 'C') # Kurz Funktion (<null>)
19
+ w.field('name', 'C') # Name value
20
+ w.field('anzahlgs', 'C') # Anzahl der Oberirdischen Geschosse
21
+ w.field('lagebeztxt', 'C') # Lagebezeichnung text
22
+
23
+ # Parse the XML file
24
+ tree = ET.parse(input_xml)
25
+ root = tree.getroot()
26
+
27
+ # Namespace map
28
+ ns = {'gml': 'http://www.opengis.net/gml/3.2',
29
+ 'adv': 'http://www.adv-online.de/namespaces/adv/gid/6.0'}
30
+
31
+ # Building function mapping
32
+ funktion_mapping = {
33
+ '1000': 'Wohngebäude',
34
+ '2000': 'Gebäude für Wirtschaft oder Gewerbe',
35
+ '3000': 'Gebäude für öffentliche Zwecke',
36
+ '3020': 'Gebäude für Bildung und Forschung',
37
+ '2463': 'Garage',
38
+ '1610': 'Überdachung',
39
+ '2523': 'Umformer',
40
+ '1620': 'Treppe',
41
+ '9999': 'Sonstiges',
42
+ '1700': 'Mauer',
43
+ '3041': 'Kirche',
44
+ '3065': 'Kinderkrippe, Kindergarten, Kindertagesstätte',
45
+ '3043': 'Kapelle',
46
+ '3072': 'Feuerwehr'
47
+ }
48
+
49
+ # Helper function to extract polygon coordinates
50
+ def extract_polygon(coords_text):
51
+ try:
52
+ coords = list(map(float, coords_text.split()))
53
+ return [(coords[i], coords[i+1]) for i in range(0, len(coords), 2)]
54
+ except Exception as e:
55
+ print(f"Error parsing coordinates: {e}")
56
+ return None
57
+
58
+ # Cache frequently accessed elements
59
+ lagebezeichnung_cache = {}
60
+ for lage_elem in root.findall('.//adv:AX_LagebezeichnungMitHausnummer', ns):
61
+ gml_id = lage_elem.attrib.get('{http://www.opengis.net/gml/3.2}id')
62
+ if gml_id:
63
+ unverschluesselt_elem = lage_elem.find('.//adv:lagebezeichnung/adv:AX_Lagebezeichnung/adv:unverschluesselt', ns)
64
+ hausnummer_elem = lage_elem.find('.//adv:hausnummer', ns)
65
+ unverschluesselt = unverschluesselt_elem.text if unverschluesselt_elem is not None else ''
66
+ hausnummer = hausnummer_elem.text if hausnummer_elem is not None else ''
67
+ lagebezeichnung_cache[gml_id] = f"{unverschluesselt} {hausnummer}".strip()
68
+
69
+ # Process AX_Gebaeude and AX_SonstigesBauwerkOderSonstigeEinrichtung
70
+ for gebaeude in root.findall('.//adv:AX_Gebaeude', ns) + root.findall('.//adv:AX_SonstigesBauwerkOderSonstigeEinrichtung', ns):
71
+ # Create 'gebnutzbez' value
72
+ gebnutzbez = 'Gebaeude' if gebaeude.tag == '{http://www.adv-online.de/namespaces/adv/gid/6.0}AX_Gebaeude' else 'Sonstiges Bauwerk Oder Sonstige Einrichtung'
73
+
74
+ # Extract and map 'funktion' value
75
+ funktion_elem = gebaeude.find('.//adv:gebaeudefunktion', ns)
76
+ if funktion_elem is None:
77
+ funktion_elem = gebaeude.find('.//adv:bauwerksfunktion', ns)
78
+ funktion = funktion_mapping.get(funktion_elem.text, 'Unbekannt') if funktion_elem is not None and funktion_elem.text else '<null>'
79
+
80
+ # Set 'fktkurz' to '<null>'
81
+ fktkurz = '<null>'
82
+
83
+ # Extract 'name' value
84
+ name_elem = gebaeude.find('.//adv:name', ns)
85
+ name = name_elem.text if name_elem is not None else '<null>'
86
+
87
+ # Extract 'anzahlDerOberirdischenGeschosse' value
88
+ anzahlgs_elem = gebaeude.find('.//adv:anzahlDerOberirdischenGeschosse', ns)
89
+ anzahlgs = anzahlgs_elem.text if anzahlgs_elem is not None else '<null>'
90
+
91
+ # Extract 'lagebeztxt' based on the 'zeigtAuf' reference
92
+ zeigtauf_elem = gebaeude.find('.//adv:zeigtAuf', ns)
93
+ lagebeztxt = '<null>'
94
+ if zeigtauf_elem is not None:
95
+ xlink_href = zeigtauf_elem.attrib.get('{http://www.w3.org/1999/xlink}href')
96
+ if xlink_href:
97
+ gml_id = xlink_href.split(':')[-1]
98
+ lagebeztxt = lagebezeichnung_cache.get(gml_id, '<null>')
99
+
100
+ # Extract coordinates for the polygon
101
+ pos_list = gebaeude.findall('.//gml:posList', ns)
102
+ polygon_coords = []
103
+ if pos_list:
104
+ for pos in pos_list:
105
+ coords = extract_polygon(pos.text)
106
+ if coords:
107
+ polygon_coords.extend(coords)
108
+
109
+ if polygon_coords:
110
+ # Add polygon and record to shapefile
111
+ w.poly([polygon_coords])
112
+ w.record(gebnutzbez, funktion, fktkurz, name, anzahlgs, lagebeztxt)
113
+
114
+ # Save shapefile
115
+ w.close()
116
+
117
+ # Define spatial reference (projection file)
118
+ with open(output_shapefile.replace('.shp', '.prj'), 'w') as prj_file:
119
+ prj_file.write('PROJCS["ETRS89 / UTM zone 32N",'
120
+ 'GEOGCS["ETRS89",'
121
+ 'DATUM["European_Terrestrial_Reference_System_1989",'
122
+ 'SPHEROID["GRS 1980",6378137,298.257222101]],'
123
+ 'PRIMEM["Greenwich",0],'
124
+ 'UNIT["degree",0.0174532925199433]],'
125
+ 'PROJECTION["Transverse_Mercator"],'
126
+ 'PARAMETER["latitude_of_origin",0],'
127
+ 'PARAMETER["central_meridian",9],'
128
+ 'PARAMETER["scale_factor",0.9996],'
129
+ 'PARAMETER["false_easting",500000],'
130
+ 'PARAMETER["false_northing",0],'
131
+ 'UNIT["metre",1]]')
kat.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import geopandas as gpd
2
+ from shapely.ops import unary_union
3
+ import shapefile
4
+ from shapely.geometry import Polygon, MultiPolygon
5
+ import sys
6
+
7
+ # Input shapefile
8
+ input_shapefile = sys.argv[1]
9
+
10
+ # Output shapefile
11
+ output_shapefile = sys.argv[2]
12
+
13
+ # Step 1: Load the shapefile
14
+ gdf = gpd.read_file(input_shapefile)
15
+
16
+ # Step 2: Fix invalid geometries
17
+ gdf['geometry'] = gdf['geometry'].buffer(0)
18
+
19
+ # Step 3: Group by gemarkung and create exterior boundaries
20
+ gemarkung_boundaries = {}
21
+ gemarkung_data = {}
22
+ for gemarkung, group in gdf.groupby('gemarkung'):
23
+ merged_polygon = unary_union(group.geometry)
24
+ if isinstance(merged_polygon, Polygon):
25
+ exterior_boundary = Polygon(merged_polygon.exterior)
26
+ elif isinstance(merged_polygon, MultiPolygon):
27
+ exterior_boundary = MultiPolygon([Polygon(poly.exterior) for poly in merged_polygon.geoms])
28
+ else:
29
+ print(f"Skipping invalid geometry for gemarkung: {gemarkung}")
30
+ continue
31
+ gemarkung_boundaries[gemarkung] = exterior_boundary
32
+
33
+ # Store additional data for each gemarkung
34
+ sample_row = group.iloc[0]
35
+ gemarkung_data[gemarkung] = {
36
+ 'gemeinde': sample_row['gemeinde'],
37
+ 'schluessel': sample_row['flstkennz'].split('___')[0]
38
+ }
39
+
40
+ # Step 4: Create a new shapefile with the exterior boundaries
41
+ w = shapefile.Writer(output_shapefile)
42
+ w.autoBalance = 1
43
+
44
+ # Define fields for shapefile
45
+ w.field('oid_1', 'C')
46
+ w.field('art', 'C')
47
+ w.field('name', 'C')
48
+ w.field('schluessel', 'C')
49
+ w.field('gemeinde', 'C')
50
+
51
+ # Add geometries and attribute values to the shapefile
52
+ for gemarkung, boundary in gemarkung_boundaries.items():
53
+ data = gemarkung_data[gemarkung]
54
+
55
+ # Original record
56
+ if isinstance(boundary, Polygon):
57
+ w.poly([list(boundary.exterior.coords)])
58
+ w.record(f"DE{data['schluessel']}", 'Gemarkung', gemarkung, data['schluessel'], data['gemeinde'])
59
+ elif isinstance(boundary, MultiPolygon):
60
+ for poly in boundary.geoms:
61
+ w.poly([list(poly.exterior.coords)])
62
+ w.record(f"DE{data['schluessel']}", 'Gemarkung', gemarkung, data['schluessel'], data['gemeinde'])
63
+
64
+ # Additional record
65
+ if isinstance(boundary, Polygon):
66
+ w.poly([list(boundary.exterior.coords)])
67
+ w.record(f"DE{data['schluessel']}000", 'Gemarkungsteil / Flur', 'Flur', f"{data['schluessel']}00", data['gemeinde'])
68
+ elif isinstance(boundary, MultiPolygon):
69
+ for poly in boundary.geoms:
70
+ w.poly([list(poly.exterior.coords)])
71
+ w.record(f"DE{data['schluessel']}000", 'Gemarkungsteil / Flur', 'Flur', f"{data['schluessel']}00", data['gemeinde'])
72
+
73
+ # Define spatial reference (projection file)
74
+ with open(output_shapefile.replace('.shp', '.prj'), 'w') as prj_file:
75
+ prj_file.write('PROJCS["ETRS89 / UTM zone 32N",'
76
+ 'GEOGCS["ETRS89",'
77
+ 'DATUM["European_Terrestrial_Reference_System_1989",'
78
+ 'SPHEROID["GRS 1980",6378137,298.257222101]],'
79
+ 'PRIMEM["Greenwich",0],'
80
+ 'UNIT["degree",0.0174532925199433]],'
81
+ 'PROJECTION["Transverse_Mercator"],'
82
+ 'PARAMETER["latitude_of_origin",0],'
83
+ 'PARAMETER["central_meridian",9],'
84
+ 'PARAMETER["scale_factor",0.9996],'
85
+ 'PARAMETER["false_easting",500000],'
86
+ 'PARAMETER["false_northing",0],'
87
+ 'UNIT["metre",1]]')
88
+
89
+ # Save the shapefile
90
+ w.close()
91
+
92
+ print(f"Shapefile '{output_shapefile}' created successfully with exterior boundaries and additional fields.")
main.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess
2
+ import time
3
+
4
+ def run_script(script_name, *args):
5
+ command = ['python', script_name] + list(args)
6
+ start_time = time.time()
7
+ result = subprocess.run(command, capture_output=True, text=True)
8
+ end_time = time.time()
9
+ elapsed_time = end_time - start_time
10
+ if result.returncode != 0:
11
+ print(f"Error running {script_name}: {result.stderr}")
12
+ else:
13
+ print(f"Successfully ran {script_name} in {elapsed_time:.2f} seconds")
14
+ return elapsed_time
15
+
16
+ if __name__ == "__main__":
17
+ # Define file paths
18
+ xml_file = "1546621_0.xml"
19
+ bez_dict_file = "bez_dict.json"
20
+ flurstueck_shapefile = "flurstueck.shp"
21
+ nutzung_shapefile = "nutzung.shp"
22
+ nutzung_flurstueck_shapefile = "nutzungFlurstueck.shp"
23
+ gebauede_bauwerk_shapefile = "gebauedeBauwerk.shp"
24
+ verwaltungs_einheit_shapefile = "verwaltungsEinheit.shp"
25
+ kataster_bezirk_shapefile = "katasterBezirk.shp"
26
+
27
+ # Track total execution time
28
+ total_start_time = time.time()
29
+
30
+ # Run scripts in the correct order
31
+ total_time = 0
32
+ total_time += run_script('flurstueck.py', xml_file, flurstueck_shapefile)
33
+ total_time += run_script('nutzung.py', xml_file, bez_dict_file, nutzung_shapefile)
34
+ total_time += run_script('nutflu.py', flurstueck_shapefile, nutzung_shapefile, nutzung_flurstueck_shapefile)
35
+ total_time += run_script('guby.py', xml_file, gebauede_bauwerk_shapefile)
36
+ total_time += run_script('ver.py', flurstueck_shapefile, xml_file, verwaltungs_einheit_shapefile)
37
+ total_time += run_script('kat.py', flurstueck_shapefile, kataster_bezirk_shapefile)
38
+
39
+ total_end_time = time.time()
40
+ total_elapsed_time = total_end_time - total_start_time
41
+
42
+ print(f"Total execution time: {total_elapsed_time:.2f} seconds")
nutflu.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import geopandas as gpd
2
+ import sys
3
+
4
+ def clean_geometries(gdf):
5
+ # Check and fix invalid geometries
6
+ gdf['geometry'] = gdf['geometry'].buffer(0) # This can help fix some topology issues
7
+ gdf = gdf[gdf.is_valid] # Remove invalid geometries
8
+ return gdf
9
+
10
+ def union_shapefiles(shapefile1, shapefile2, output_shapefile):
11
+ gdf1 = gpd.read_file(shapefile1)
12
+ gdf2 = gpd.read_file(shapefile2)
13
+
14
+ # Clean geometries
15
+ gdf1 = clean_geometries(gdf1)
16
+ gdf2 = clean_geometries(gdf2)
17
+
18
+ # Perform the union
19
+ union_gdf = gpd.overlay(gdf1, gdf2, how='union')
20
+
21
+ # Save the result to a new shapefile
22
+ union_gdf.to_file(output_shapefile)
23
+
24
+ # Example usage
25
+ if __name__ == "__main__":
26
+ shapefile1 = sys.argv[1]
27
+ shapefile2 = sys.argv[2]
28
+ output_shapefile = sys.argv[3]
29
+ union_shapefiles(shapefile1, shapefile2, output_shapefile)
nutzung.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import xml.etree.ElementTree as ET
2
+ import shapefile
3
+ import json
4
+ import re
5
+ import codecs
6
+ from shapely.geometry import Polygon, MultiPolygon
7
+ import sys
8
+
9
+ # Input XML file
10
+ input_xml = sys.argv[1]
11
+
12
+ # Input JSON file for bez_dict
13
+ bez_dict_file = sys.argv[2]
14
+
15
+ # Output shapefile
16
+ output_shapefile = sys.argv[3]
17
+
18
+ # Load bez_dict from JSON file
19
+ with codecs.open(bez_dict_file, 'r', encoding='utf-8') as f:
20
+ bez_dict = json.load(f)
21
+
22
+ # Create shapefile writer
23
+ w = shapefile.Writer(output_shapefile)
24
+ w.autoBalance = 1
25
+
26
+ # Define fields for shapefile
27
+ w.field('nutzart', 'C') # Nutzart as string
28
+ w.field('bez', 'C') # BEZ as string
29
+ w.field('name', 'C') # NAME as string
30
+
31
+ # Parse the XML file
32
+ tree = ET.parse(input_xml)
33
+ root = tree.getroot()
34
+
35
+ # List of tag names to process
36
+ tags_to_process = [
37
+ "AX_Gehoelz", "AX_Wohnbauflaeche", "AX_UnlandVegetationsloseFlaeche",
38
+ "AX_Strassenverkehr", "AX_StehendesGewaesser", "AX_SportFreizeitUndErholungsflaeche",
39
+ "AX_Platz", "AX_Landwirtschaft", "AX_IndustrieUndGewerbeflaeche",
40
+ "AX_Fliessgewaesser", "AX_FlaecheGemischterNutzung", "AX_Wald", "AX_Weg", "AX_Friedhof",
41
+ "AX_FlaecheBesondererFunktionalerPraegung", "AX_Bahnverkehr"
42
+ ]
43
+
44
+ # Helper function to extract coordinates and create Polygon
45
+ def extract_polygon(coords_text):
46
+ coords = list(map(float, coords_text.split()))
47
+ return [(coords[i], coords[i+1]) for i in range(0, len(coords), 2)]
48
+
49
+ # Helper function to format nutzart
50
+ def format_nutzart(tag):
51
+ # Remove 'AX_' prefix and add spaces before capital letters
52
+ return ' '.join(re.findall('[A-Z][^A-Z]*', tag[3:]))
53
+
54
+ # Helper function to extract bez value
55
+ def extract_bez(elem):
56
+ funktion_elem = elem.find('.//{http://www.adv-online.de/namespaces/adv/gid/6.0}funktion')
57
+ vegetationsmerkmal_elem = elem.find('.//{http://www.adv-online.de/namespaces/adv/gid/6.0}vegetationsmerkmal')
58
+
59
+ if funktion_elem is not None:
60
+ return bez_dict.get(funktion_elem.text, "<null>")
61
+ elif vegetationsmerkmal_elem is not None:
62
+ return bez_dict.get(vegetationsmerkmal_elem.text, "<null>")
63
+ else:
64
+ return "<null>"
65
+
66
+ # Process the elements
67
+ for tag_name in tags_to_process:
68
+ for elem in root.findall(f".//{{http://www.adv-online.de/namespaces/adv/gid/6.0}}{tag_name}"):
69
+
70
+ # Format nutzart
71
+ nutzart = format_nutzart(tag_name)
72
+
73
+ # Extract bez
74
+ bez = extract_bez(elem)
75
+
76
+ # Extract name
77
+ name_elem = elem.find('.//{http://www.adv-online.de/namespaces/adv/gid/6.0}name')
78
+ name = name_elem.text if name_elem is not None else "<null>"
79
+
80
+ # Extract coordinates for polygon
81
+ coordinates = elem.findall('.//{http://www.opengis.net/gml/3.2}posList')
82
+ if coordinates:
83
+ polygon_coords = []
84
+ for coord_elem in coordinates:
85
+ polygon_coords.extend(extract_polygon(coord_elem.text))
86
+
87
+ # Create a Shapely polygon and fix invalid geometries
88
+ try:
89
+ poly = Polygon(polygon_coords)
90
+ if not poly.is_valid:
91
+ poly = poly.buffer(0)
92
+
93
+ if isinstance(poly, Polygon):
94
+ w.poly([list(poly.exterior.coords)])
95
+ elif isinstance(poly, MultiPolygon):
96
+ for p in poly.geoms:
97
+ w.poly([list(p.exterior.coords)])
98
+
99
+ # Add record to shapefile
100
+ w.record(nutzart, bez, name)
101
+ except Exception as e:
102
+ print(f"Error processing polygon: {e}")
103
+
104
+ # Save shapefile
105
+ w.close()
106
+
107
+ print("Shapefile created successfully.")
108
+
109
+ # Create .prj file
110
+ prj = open(output_shapefile.replace('.shp', '.prj'), "w")
111
+ epsg = 'PROJCS["ETRS89 / UTM zone 32N",GEOGCS["ETRS89",DATUM["European_Terrestrial_Reference_System_1989",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6258"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4258"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",9],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","25832"]]'
112
+ prj.write(epsg)
113
+ prj.close()
114
+
115
+ print("Shapefile and .prj file created successfully.")
requirements.txt ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==23.2.1
2
+ altgraph==0.17.4
3
+ annotated-types==0.7.0
4
+ anyio==4.6.0
5
+ attrs==24.2.0
6
+ certifi==2024.8.30
7
+ charset-normalizer==3.3.2
8
+ click==8.1.7
9
+ click-plugins==1.1.1
10
+ cligj==0.7.2
11
+ colorama==0.4.6
12
+ contourpy==1.3.0
13
+ cycler==0.12.1
14
+ fastapi==0.115.0
15
+ ffmpy==0.4.0
16
+ filelock==3.16.1
17
+ fiona==1.10.0
18
+ fonttools==4.53.1
19
+ fsspec==2024.9.0
20
+ GDAL==3.9.2
21
+ geopandas==1.0.1
22
+ gradio==4.44.0
23
+ gradio_client==1.3.0
24
+ h11==0.14.0
25
+ httpcore==1.0.5
26
+ httpx==0.27.2
27
+ huggingface-hub==0.25.0
28
+ idna==3.10
29
+ importlib_resources==6.4.5
30
+ Jinja2==3.1.4
31
+ kiwisolver==1.4.7
32
+ lxml==5.3.0
33
+ markdown-it-py==3.0.0
34
+ MarkupSafe==2.1.5
35
+ matplotlib==3.9.2
36
+ mdurl==0.1.2
37
+ numpy @ file:///D:/bld/numpy_1725411960638/work/dist/numpy-2.1.1-cp312-cp312-win_amd64.whl#sha256=e94e5df6c5700d841731b7e98583918f6096aee8c7f282eddef410fb039b3879
38
+ orjson==3.10.7
39
+ packaging==24.1
40
+ pandas==2.2.2
41
+ pefile==2024.8.26
42
+ pillow==10.4.0
43
+ psutil==6.0.0
44
+ pydantic==2.9.2
45
+ pydantic_core==2.23.4
46
+ pydub==0.25.1
47
+ Pygments==2.18.0
48
+ pyinstaller==6.10.0
49
+ pyinstaller-hooks-contrib==2024.8
50
+ pyogrio==0.9.0
51
+ pyparsing==3.1.4
52
+ pyproj==3.6.1
53
+ pyshp==2.3.1
54
+ python-dateutil==2.9.0.post0
55
+ python-multipart==0.0.10
56
+ pytz==2024.2
57
+ pywin32-ctypes==0.2.3
58
+ PyYAML==6.0.2
59
+ requests==2.32.3
60
+ rich==13.8.1
61
+ ruff==0.6.7
62
+ semantic-version==2.10.0
63
+ setuptools==72.1.0
64
+ shapely==2.0.6
65
+ shellingham==1.5.4
66
+ six==1.16.0
67
+ sniffio==1.3.1
68
+ starlette==0.38.6
69
+ tomlkit==0.12.0
70
+ tqdm==4.66.5
71
+ typer==0.12.5
72
+ typing_extensions==4.12.2
73
+ tzdata==2024.1
74
+ urllib3==2.2.3
75
+ uvicorn==0.30.6
76
+ websockets==12.0
77
+ wheel==0.43.0
ver.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import geopandas as gpd
2
+ from shapely.ops import unary_union
3
+ import xml.etree.ElementTree as ET
4
+ import shapefile
5
+ from shapely.geometry import Polygon, MultiPolygon
6
+ import sys
7
+
8
+ # Input shapefile
9
+ input_shapefile = sys.argv[1]
10
+
11
+ # Input XML file
12
+ input_xml = sys.argv[2]
13
+
14
+ # Output shapefile
15
+ output_shapefile = sys.argv[3]
16
+
17
+ # Create shapefile writer for the output
18
+ w = shapefile.Writer(output_shapefile)
19
+ w.autoBalance = 1
20
+
21
+ # Step 1: Load the shapefile and get the merged polygon with exterior boundary
22
+ gdf = gpd.read_file(input_shapefile)
23
+
24
+ # Step 1.1: Identify and fix invalid geometries
25
+ gdf['valid'] = gdf.is_valid
26
+
27
+ # Print invalid geometries
28
+ invalid_geometries = gdf[~gdf['valid']]
29
+ if not invalid_geometries.empty:
30
+ print(f"Invalid geometries found: {len(invalid_geometries)}. Attempting to fix them.")
31
+
32
+ # Fix invalid geometries using buffer(0)
33
+ gdf['geometry'] = gdf['geometry'].buffer(0)
34
+
35
+ # Combine all polygons into one using unary_union
36
+ merged_polygon = unary_union(gdf.geometry)
37
+
38
+ # Step 1.2: Check if merged_polygon is a MultiPolygon or a single Polygon
39
+ if isinstance(merged_polygon, Polygon):
40
+ exterior_boundaries = [merged_polygon.exterior]
41
+ elif isinstance(merged_polygon, MultiPolygon):
42
+ exterior_boundaries = [poly.exterior for poly in merged_polygon.geoms]
43
+ else:
44
+ raise TypeError("Resulting geometry is neither a Polygon nor a MultiPolygon.")
45
+
46
+ # Define fields for shapefile
47
+ w.field('art', 'C') # Type of tag (Gemeinde, Bundesland, etc.)
48
+ w.field('name', 'C') # Name value
49
+ w.field('schluessel', 'C') # Schlüssel value
50
+ w.field('uebaname', 'C') # Uebaname value
51
+ w.field('ueobjekt', 'C') # Ueobjekt value
52
+
53
+ # Parse the XML file
54
+ tree = ET.parse(input_xml)
55
+ root = tree.getroot()
56
+
57
+ # Namespace map
58
+ ns = {'gml': 'http://www.opengis.net/gml/3.2',
59
+ 'adv': 'http://www.adv-online.de/namespaces/adv/gid/6.0'}
60
+
61
+ # Store the tag names
62
+ tag_names = {
63
+ 'AX_Gemeinde': 'Gemeinde',
64
+ 'AX_Bundesland': 'Bundesland',
65
+ 'AX_Regierungsbezirk': 'Regierungsbezirk',
66
+ 'AX_KreisRegion': 'Kreis / kreisfreie Stadt'
67
+ }
68
+
69
+ # Track if "Gemeinde" and "Kreis / kreisfreie Stadt" have already been added
70
+ first_gemeinde_added = False
71
+ first_kreis_added = False
72
+
73
+ # Helper function to extract polygon coordinates
74
+ def extract_polygon(coords_text):
75
+ try:
76
+ coords = list(map(float, coords_text.split()))
77
+ return [(coords[i], coords[i+1]) for i in range(0, len(coords), 2)]
78
+ except Exception as e:
79
+ print(f"Error parsing coordinates: {e}")
80
+ return None
81
+
82
+ # Step 3: Add the extracted XML data to the shapefile along with the exterior boundary from the polygon
83
+ tags = ['AX_Gemeinde', 'AX_Bundesland', 'AX_Regierungsbezirk', 'AX_KreisRegion']
84
+ data = {}
85
+
86
+ for tag in tags:
87
+ for element in root.findall(f'.//adv:{tag}', ns):
88
+ tag_name = tag_names.get(tag, '<null>')
89
+ name_elem = element.find('.//adv:bezeichnung', ns)
90
+ name = name_elem.text if name_elem is not None else '<null>'
91
+
92
+ schluessel_elem = element.find('.//adv:schluesselGesamt', ns)
93
+ schluessel = schluessel_elem.text if schluessel_elem is not None else '<null>'
94
+
95
+ # Define uebaname based on tag
96
+ if tag == 'AX_Gemeinde':
97
+ uebaname = data.get('AX_KreisRegion', {}).get('name', '<null>')
98
+ elif tag == 'AX_Bundesland':
99
+ uebaname = '<null>'
100
+ elif tag == 'AX_Regierungsbezirk':
101
+ uebaname = data.get('AX_Bundesland', {}).get('name', '<null>')
102
+ elif tag == 'AX_KreisRegion':
103
+ uebaname = data.get('AX_Regierungsbezirk', {}).get('name', '<null>')
104
+
105
+ # Define ueobjekt based on schluessel
106
+ if tag == 'AX_Gemeinde':
107
+ ueobjekt = f"DE{schluessel[:5]}"
108
+ elif tag == 'AX_Bundesland':
109
+ ueobjekt = '<null>'
110
+ elif tag == 'AX_Regierungsbezirk':
111
+ ueobjekt = '<null>'
112
+ elif tag == 'AX_KreisRegion':
113
+ ueobjekt = f"DE{schluessel[:3]}"
114
+
115
+ data[tag] = {'name': name, 'schluessel': schluessel}
116
+
117
+ # Skip if first Gemeinde or Kreis / kreisfreie Stadt has already been added
118
+ if (tag == 'AX_Gemeinde' and first_gemeinde_added) or (tag == 'AX_KreisRegion' and first_kreis_added):
119
+ continue
120
+
121
+ # Set flags after first Gemeinde or Kreis / kreisfreie Stadt is added
122
+ if tag == 'AX_Gemeinde':
123
+ first_gemeinde_added = True
124
+ elif tag == 'AX_KreisRegion':
125
+ first_kreis_added = True
126
+
127
+ print("="*50)
128
+ print(tag_name)
129
+ print(name)
130
+ print(schluessel)
131
+ print(uebaname)
132
+ print(ueobjekt)
133
+ print("="*50)
134
+
135
+ # Add record to shapefile (with the tag data)
136
+ w.record(tag_name, name, schluessel, uebaname, ueobjekt)
137
+
138
+ # Step 4: Add the exterior boundaries to the shapefile
139
+ for boundary in exterior_boundaries:
140
+ w.poly([list(boundary.coords)])
141
+
142
+ # Define spatial reference (projection file)
143
+ with open(output_shapefile.replace('.shp', '.prj'), 'w') as prj_file:
144
+ prj_file.write('PROJCS["ETRS89 / UTM zone 32N",'
145
+ 'GEOGCS["ETRS89",'
146
+ 'DATUM["European_Terrestrial_Reference_System_1989",'
147
+ 'SPHEROID["GRS 1980",6378137,298.257222101]],'
148
+ 'PRIMEM["Greenwich",0],'
149
+ 'UNIT["degree",0.0174532925199433]],'
150
+ 'PROJECTION["Transverse_Mercator"],'
151
+ 'PARAMETER["latitude_of_origin",0],'
152
+ 'PARAMETER["central_meridian",9],'
153
+ 'PARAMETER["scale_factor",0.9996],'
154
+ 'PARAMETER["false_easting",500000],'
155
+ 'PARAMETER["false_northing",0],'
156
+ 'UNIT["metre",1]]')
157
+
158
+ # Save the shapefile
159
+ w.close()