Projektierungshinweisea
Die Antwort von @tdelaney grundsätzlich richtig ist, aber ich möchte eine Nuance von Python Elementstruktur API zeigen. Hier ist ein Zitat aus the lxml
tutorial:
Elemente Text enthalten:
<root>TEXT</root>
In vielen XML-Dokumente (datenzentrierte Dokumente), das ist der einzige Ort, an dem Text zu finden ist. Es wird von einem Blatt-Tag ganz unten in der Baumhierarchie eingekapselt.
Wenn jedoch XML für getaggten Textdokumente wie (X) HTML verwendet wird, Text kann auch zwischen verschiedenen Elementen, direkt in der Mitte des Baumes erscheinen:
<html><body>Hello<br/>World</body></html>
Hier ist der <br/>
-Tag umgeben von Text. Dies wird oft als XML im Document-Stil oder Mixed-Content bezeichnet. Elemente unterstützen dies durch ihre tail
Eigenschaft. Es enthält den Text, der direkt auf das Element folgt, bis zum nächsten Element in der XML-Struktur.
Die beiden Eigenschaften text
und tail
reichen aus, um beliebigen Textinhalt in einem XML-Dokument darzustellen. Auf diese Weise benötigt die ElementTree-API keine speziellen Textknoten zusätzlich zur Element-Klasse, die dazu neigen, ziemlich oft im Weg zu sein (wie Sie vielleicht von klassischen DOM-APIs wissen).
Implementierung
Wenn man diese Eigenschaften berücksichtigt es möglich ist, Dokumenttext abzurufen, ohne den Baum zu Ausgangstextknoten zu zwingen.
#!/usr/bin/env python3.3
import itertools
from pprint import pprint
try:
from lxml import etree
except ImportError:
from xml.etree import cElementTree as etree
def textAndElement(node):
'''In py33+ recursive generators are easy'''
yield node
text = node.text.strip() if node.text else None
if text:
yield text
for child in node:
yield from textAndElement(child)
tail = node.tail.strip() if node.tail else None
if tail:
yield tail
if __name__ == '__main__':
xml = '''
<species>
Mammals: <dog/> <cat/>
Reptiles: <snake/> <turtle/>
Birds: <seagull/> <owl/>
</species>
'''
doc = etree.fromstring(xml)
pprint(list(textAndElement(doc)))
#[<Element species at 0x7f2c538727d0>,
#'Mammals:',
#<Element dog at 0x7f2c538728c0>,
#<Element cat at 0x7f2c53872910>,
#'Reptiles:',
#<Element snake at 0x7f2c53872960>,
#<Element turtle at 0x7f2c538729b0>,
#'Birds:',
#<Element seagull at 0x7f2c53872a00>,
#<Element owl at 0x7f2c53872a50>]
gen = textAndElement(doc)
next(gen) # skip root
groups = []
for _, g in itertools.groupby(gen, type):
groups.append(tuple(g))
pprint(dict(zip(*[iter(groups)] * 2)))
#{('Birds:',): (<Element seagull at 0x7fc37f38aaa0>,
# <Element owl at 0x7fc37f38a820>),
#('Mammals:',): (<Element dog at 0x7fc37f38a960>,
# <Element cat at 0x7fc37f38a9b0>),
#('Reptiles:',): (<Element snake at 0x7fc37f38aa00>,
# <Element turtle at 0x7fc37f38aa50>)}
, wenn Sie auf der rechten Seite durchsehen ... es sieht aus wie der 4. ein unter ähnlichen sollten Sie in die richtige Richtung ... –
haben Sie die Kontrolle über das XML-Format haben?Normalerweise werden Klassifizierer wie Säugetiere usw. als xml-Elementnamen oder -attribute (z. B.) ausgedrückt, so dass xpath-Selektoren leicht geschrieben werden können. –
tdelaney
Nein, ich kann das XML nicht ändern. – Alicia