#!/usr/bin/python3 import sys import gzip import time import datetime from lxml import etree # Knihovna lxml je Python binding na C knihovnu lxml, takže většina zpracování XMLka # je implementovaná rychle v C. # Lze ji získat pomocí `pip3 install lxml` def die(exit_code, message): print(message, file=sys.stderr) sys.exit(exit_code) def hasTagValue(el, name, value): """Kontroluje jestli má element daný tag s danou hodnotou. Arguments: el {etree.Element} -- Naparsovaný XML element name {str} -- Název tagu value {str} -- Hodnota ke kontrole Returns: bool """ for tag in el.findall("tag"): if tag.get('k') == name: return tag.get('v') == value return False ################## nodes, ways, libNodes, libWays = 0, 0, 0, 0 start = time.time() # Funkce na vypisování statistiky def printStat(readed): megabytes = readed / 1024 / 1024 elapsed = time.time() - start elapsedString = str(datetime.timedelta(seconds=elapsed)) speed = megabytes/elapsed if elapsed > 0 else 0 print( f"Elapsed: {elapsedString:20s} Read: {megabytes:10.2f}MB ({speed:5.2f}MB/s)" + f"\tLibraries in nodes: {libNodes:6d}/{nodes:<10d}\tLibraries in ways: {libWays:6d}/{ways:<10d}", file=sys.stderr, end="\r", flush=True ) ################## if len(sys.argv) != 2: die(1, f"Usage: {sys.argv[0]} \n") # 1. Otevřeme gzip soubor printStat(0) with gzip.open(sys.argv[1], 'rb') as gzippedFile: # Budeme streamově parsovat pomocí iterparse(). Ten se může "chytat" na více # typů eventů - nám bude stačit defaultní "end", který nastává vždy po načtení # celého tagu (tedy třeba po načtení ). Je potřeba vyjmenovat elementy, # které nás zajímají, abychom nebyli voláni například pro vnořené elementy # a nemuseli to speciálně ošetřovat. for event, elem in etree.iterparse(gzippedFile, tag=('node', 'way', 'relation')): if elem.tag == 'node': nodes += 1 if hasTagValue(elem, "amenity", "library"): libNodes += 1 print(f"Library: {etree.tostring(elem)}\n") elif elem.tag == 'way': ways += 1 if hasTagValue(elem, "amenity", "library"): libWays += 1 print(f"Library area: {etree.tostring(elem)}\n") # Vypíšeme statistiku každých 10000 načtených elementů if (nodes+ways) % 10000 == 0: printStat(gzippedFile.tell()) # Odstraníme zpracovaný element z paměti (musíme udělat explicitně, jinak by tam zůstal). # Musíme smazat i všechny rodiče současného elementu, kteří byli vytvořeni při parsování # (jinak by nám elementy zůstaly a postupně užíraly paměť, souvisí to s interním fungováním # knihovny lxml) elem.clear() while elem.getprevious() is not None: del elem.getparent()[0] del elem printStat(gzippedFile.tell()) elapsedString = str(datetime.timedelta(seconds=time.time() - start)) print(f"\n\nTotal time: {elapsedString}\n", file=sys.stderr)