* HINWEI Zu einem einzelnen Öffnungs- oder Schlussetikett eines einzelnen Elements ist es denkbar, dass einige Stückgrößen in Bezug auf die Anzahl der Zeilen gemessen werden können. Parsers, die die Größen in der Anzahl von Zeichen messen, ist möglicherweise plausibler. BoilerPlate -Code. Xml.etree.elementtree ) wird diskutiert, es klingt oft so, als ob es XML-Dateien "iterativ" analysiert, wie in Element-by-Element/Tag-by-Tag (siehe Anmerkung oben). < BR /> Aber es scheint, dass in der Praxis ein Datei-ähnliches Objekt als Eingabe angegeben hat und beide Parser die Ausgabe der .read < /code> -Methode dieses Datei-ähnlichen Objekts suchen und analysieren. (Im Gegensatz zur Ausgabe von .readline wie ich erwartet hatte.) Wenn dieses Datei-ähnliche Objekt ein Dateianschluss für eine 8-GB-Datei ist und dies auf einem Clusterknoten mit 2 GB Speicher ausgeführt wird, wird dies natürlich auch sein einen OOM -Fehler verursachen. < /p>
Code: Select all
.read
Code: Select all
import io
from lxml import etree
import xml.etree.ElementTree as etree2
xml_string = """
Manager
Star Team Member
"""
#### lxml output
for event, element in etree.iterparse(io.BytesIO(xml_string.encode("UTF-8")), recover=True, remove_blank_text=True,
events=("start", "end",)):
print(str((event, element, element.tag,
element.text.strip() if element.text is not None else element.text,
element.tail.strip() if element.tail is not None else element.tail)) + "\n")
print(f"{etree.tostring(element)}\n")
### xml.etree.ElementTree output is the same
for event, element in etree2.iterparse(io.BytesIO(xml_string.encode("UTF-8")),
events=("start", "end",)):
print(str((event, element, element.tag,
element.text.strip() if element.text is not None else element.text,
element.tail.strip() if element.tail is not None else element.tail)) + "\n")
print(f"{etree2.tostring(element)}\n")
class StreamString(object):
def __init__(self, string):
self._io = io.StringIO(string)
def read(self, len=None):
return self._io.readline().encode("UTF-8")
def close(self):
self._io.close()
### closer to what would be used in practice
class StreamFile(object):
def __init__(self, path):
self._file = open(path, "r")
def read(self, len=None):
return self._file.readline().encode("UTF-8")
def close(self):
self._file.close()
### demonstrating the expected line-by-line parsing behavior
iterator = etree.iterparse(StreamString(xml_string), recover=True, remove_blank_text=True,
events=("start", "end",))
event, root = next(iterator)
print(str((event, root, root.tag,
root.text.strip() if root.text is not None else root.text,
root.tail.strip() if root.tail is not None else root.tail)) + "\n")
print(f"{etree.tostring(root)}\n")
for event, element in iterator:
print(str((event, element, element.tag,
element.text.strip() if element.text is not None else element.text,
element.tail.strip() if element.tail is not None else element.tail)) + "\n")
print(f"{etree.tostring(root)}\n")
< /code>
Dies zeigt das erwartete Verhalten, wobei der Parsen -Baum, der dem Stammelement entspricht, mit jeder Iteration nacheinander wächst, wenn neue Zeilen hinzugefügt werden. Dieses Verhalten ist auch leichter zu verstehen und mit den zahlreichen Vorschlägen auf dieser Seite zu verhindern, wie die Speicher Fußabdrücke, die Knoten und ihren Vorfahren (und all ihren "älteren" Tiefen-First-Suchgeschwistern) entsprechen, nach der Analyse entsprechen. Mir ist unklar, warum dies nicht das Standardverhalten ist. < /P>
Hinweis: Obwohl die für die MWE verwendete XML Für XML-Dateien, die potenziell Gigabyte auf Größe auf Clusterknoten mit 1-2 GB Speicher sind. (Ich habe keine Kontrolle über die Rechenumgebung, ja, ich bin damit einverstanden, dass es sinnvoller ist, einfach vertikal auf einen einzelnen Knoten mit ~ 64 GB Speicher zu skalieren.)