Xml: zu bestimten Knoten hüpfen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
kimx
User
Beiträge: 7
Registriert: Sonntag 18. Oktober 2009, 14:41

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:

Code: Alles auswählen

print(root.findall(".//a[@x]")[0].tag)
Aber in diesem Beispiel kann man den Wert des Arguments nicht mitgeben.
Gibt es da eine Methode?

Danke im voraus
kim
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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:

Code: Alles auswählen

print(root.findall(".//a[@x=3]")[0].tag)
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.
kimx
User
Beiträge: 7
Registriert: Sonntag 18. Oktober 2009, 14:41

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 ([)
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ß
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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>]
kimx
User
Beiträge: 7
Registriert: Sonntag 18. Oktober 2009, 14:41

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"
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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?
kimx
User
Beiträge: 7
Registriert: Sonntag 18. Oktober 2009, 14:41

Ich habs von dieser Seite:
http://www.video.mediaset.it/category/categories.sxml

Bei mir gings.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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?
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>]
kimx
User
Beiträge: 7
Registriert: Sonntag 18. Oktober 2009, 14:41

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"]')
kimx
User
Beiträge: 7
Registriert: Sonntag 18. Oktober 2009, 14:41

Jetzt gehts. Habe leider den Post mit der korrekten Methode nicht gesehen.
Sehr gutes Forum, danke nochmal

kimx
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 :roll:.

Gruß
Antworten