Seite 1 von 1
Xml: zu bestimten Knoten hüpfen
Verfasst: Sonntag 18. Oktober 2009, 15:03
von kimx
Hallo erstmal. Habe folgendes Problem: ich muss in einer XML-Datei zu einem Knoten springen dessen Argument einen bestimmten Wert enthält. Hier ein Beispiel:
Code: Alles auswählen
<categories>
<category>
<a id=1 />
<a id=2 />
</category>
</categories>
Ich müsste zum Knoten mit der id=2. Habe mit lxml probiert. Auf dem Tutoriel auf der lxml Homepage ist ein solches Fallbeispiel angeführt:
Aber in diesem Beispiel kann man den Wert des Arguments nicht mitgeben.
Gibt es da eine Methode?
Danke im voraus
kim
Verfasst: Sonntag 18. Oktober 2009, 15:08
von Hyperion
Dazu solltest Du Dir mal etwas zu XPath durchlesen:
http://de.wikipedia.org/wiki/XPath
Dort findet man schnell, dass man bei Prädikaten durchaus auf einen Wert vergleichen kann:
Verfasst: Sonntag 18. Oktober 2009, 17:00
von BlackJack
Und in der Dokumentation zu `lxml` findet man dann auch wie man die "3" variabel gestalten kann, ohne da mit Zeichenkettenformatierung hantieren zu müssen.
Verfasst: Sonntag 18. Oktober 2009, 18:21
von kimx
habe es wie folgt schon probiert:
Code: Alles auswählen
print (root.findall('.//category[@id="altri_video"]')[0].tag)
aber bekomme folgende Fehlermeldung:
Code: Alles auswählen
Traceback (most recent call last):
File "test.py", line 31, in <module>
print root.findall('.//category[@id="altri_video"]')
File "etree.pyx", line 1085, in etree._Element.findall
File "/usr/lib/python2.5/site-packages/lxml/_elementpath.py", line 193, in fin dall
return _compile(path).findall(element)
File "/usr/lib/python2.5/site-packages/lxml/_elementpath.py", line 171, in _co mpile
p = Path(path)
File "/usr/lib/python2.5/site-packages/lxml/_elementpath.py", line 88, in __in it__
"expected path separator (%s)" % (op or tag)
SyntaxError: expected path separator ([)
Verfasst: Sonntag 18. Oktober 2009, 19:05
von problembär
Hallo,
Dein xml ist nicht wohlgeformt.
Hier mal auf die altmodische Art (die die einzige ist, die bei mir klappt (da alte Installation)):
Code: Alles auswählen
import xml.dom.minidom
stuff = """<categories>
<category>
<a id="1" />
<a id="2" />
<a id="3">Hallo</a>
</category>
</categories>"""
dommod = xml.dom.minidom.parseString(stuff)
nodelist = dommod.getElementsByTagName("a")
for node in nodelist:
if node.attributes["id"].nodeValue == "3":
print
print "Node found: " + node.localName
for c in node.childNodes:
if c.nodeType == node.TEXT_NODE:
print "Text-value: " + c.nodeValue
at = []
for i in node.attributes.keys():
at.append(i)
print "Attributes: " + ",".join(at)
print
Gruß
Verfasst: Sonntag 18. Oktober 2009, 19:07
von Hyperion
Also bei mir klappt's eben so auch mit lxml:
Code: Alles auswählen
In [42]: data = u'<categories><category><a id="1"/><a id="2"/></category></categories>'
In [43]: root = etree.fromstring(data)
In [46]: root.findall('.//category/a[@id="2"]')
Out[46]: [<Element a at 1b036f0>]
In [47]: root.findall('.//category/a[@id="1"]')
Out[47]: [<Element a at 1b030c0>]
Verfasst: Sonntag 18. Oktober 2009, 19:13
von kimx
Das XML ist nur ein Beispiel. Habe es dort gar nicht getestet. Mein Fehler. Dies wäre das richtige:
http://pastebin.com/m563f23bc
Ein Beispiel könnte sein id="altri_video"
Verfasst: Sonntag 18. Oktober 2009, 19:26
von Hyperion
Imho ist das Dokument kaputt:
Code: Alles auswählen
In [55]: root = etree.parse(f)
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (16963, 0))
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (18148, 0))
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (18118, 0))
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (18235, 0))
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (19036, 0))
---------------------------------------------------------------------------
XMLSyntaxError Traceback (most recent call last)
C:\Dokumente und Einstellungen\nelson\Eigene Dateien\Downloads\<ipython console>
in <module>()
C:\Programme\Python26\lib\site-packages\lxml-2.2.2-py2.6-win32.egg\lxml\etree.py
d in lxml.etree.parse (src/lxml/lxml.etree.c:49590)()
C:\Programme\Python26\lib\site-packages\lxml-2.2.2-py2.6-win32.egg\lxml\etree.py
d in lxml.etree._parseDocument (src/lxml/lxml.etree.c:71423)()
C:\Programme\Python26\lib\site-packages\lxml-2.2.2-py2.6-win32.egg\lxml\etree.py
d in lxml.etree._parseFilelikeDocument (src/lxml/lxml.etree.c:71733)()
C:\Programme\Python26\lib\site-packages\lxml-2.2.2-py2.6-win32.egg\lxml\etree.py
d in lxml.etree._parseDocFromFilelike (src/lxml/lxml.etree.c:70648)()
C:\Programme\Python26\lib\site-packages\lxml-2.2.2-py2.6-win32.egg\lxml\etree.py
d in lxml.etree._BaseParser._parseDocFromFilelike (src/lxml/lxml.etree.c:67944)(
)
C:\Programme\Python26\lib\site-packages\lxml-2.2.2-py2.6-win32.egg\lxml\etree.py
d in lxml.etree._ParserContext._handleParseResultDoc (src/lxml/lxml.etree.c:6382
0)()
C:\Programme\Python26\lib\site-packages\lxml-2.2.2-py2.6-win32.egg\lxml\etree.py
d in lxml.etree._handleParseResult (src/lxml/lxml.etree.c:64741)()
C:\Programme\Python26\lib\site-packages\lxml-2.2.2-py2.6-win32.egg\lxml\etree.py
d in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:64084)()
XMLSyntaxError: Document is empty, line 1, column 1
Hast Du das laden und parsen können?
Verfasst: Sonntag 18. Oktober 2009, 19:29
von kimx
Verfasst: Sonntag 18. Oktober 2009, 19:34
von Hyperion
Also damit klappt's bei mir:
Code: Alles auswählen
In [65]: f = open("categories.sxml.xml", "r")
In [66]: root = etree.parse(f)
In [67]: root.findall('.//category[@id="altri_video"]')
Out[67]: [<Element category at 19b92d0>]
Wo liegt jetzt das Problem?
Verfasst: Sonntag 18. Oktober 2009, 19:39
von BlackJack
@kimx: Die Methode für XPath heisst ja auch `xpath()` und nicht `findall()`. Hier auch gleichmal mit einem Beispiel, wie man das parametrisieren kann:
Code: Alles auswählen
In [29]: doc.xpath('.//category[@id=$id]', id='altri_video')
Out[29]: [<Element category at 848adec>]
Verfasst: Sonntag 18. Oktober 2009, 19:43
von kimx
Bei mir gehts leider nicht. Habe Python 2.5.2. Wieder folgender Fehler:
Code: Alles auswählen
Traceback (most recent call last):
File "tt.py", line 7, in <module>
root.findall('.//category[@id="altri_video"]')
File "etree.pyx", line 1378, in etree._ElementTree.findall
File "etree.pyx", line 1085, in etree._Element.findall
File "/usr/lib/python2.5/site-packages/lxml/_elementpath.py", line 193, in findall
return _compile(path).findall(element)
File "/usr/lib/python2.5/site-packages/lxml/_elementpath.py", line 171, in _compile
p = Path(path)
File "/usr/lib/python2.5/site-packages/lxml/_elementpath.py", line 88, in __init__
"expected path separator (%s)" % (op or tag)
SyntaxError: expected path separator ([)
Mit folgendem Code:
Code: Alles auswählen
from lxml import etree
f = open("categories.sxml", "r")
root = etree.parse(f)
root.findall('.//category[@id="altri_video"]')
Verfasst: Sonntag 18. Oktober 2009, 19:55
von kimx
Jetzt gehts. Habe leider den Post mit der korrekten Methode nicht gesehen.
Sehr gutes Forum, danke nochmal
kimx
Verfasst: Sonntag 18. Oktober 2009, 23:46
von problembär
Nur der Vollständigkeit halber:
Code: Alles auswählen
import xml.dom.minidom
dommod = xml.dom.minidom.parse("m563f23bc.txt")
def getAbsPath(node):
a = [node.nodeName]
p = node.parentNode
while p.nodeName != "#document":
a.append(p.nodeName)
p = p.parentNode
a.reverse()
return "/".join(a)
def dokument(parent):
for node in parent.childNodes:
if node.attributes and node.attributes.has_key("id") and node.attributes["id"].nodeValue == "altri_video":
print getAbsPath(node)
dokument(node)
dokument(dommod)
Schon etwas umständlich

.
Gruß