[Python] Comparison op attribute value

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Niekleair
  • Registratie: Oktober 2006
  • Laatst online: 11-06-2024
Hallo, ik ben ben bezig met een Python scriptje dat met behulp van Xpath (Element tree) data uit een XML bestand haalt.

Onderstaand is een voorbeeld. Ik heb helaas geen invloed op hoe het XML bestand wordt aangeleverd. Het bestand kan evt. wel gewijzigd worden (b.v. parsen en zaken vervangen).

Mijn XML bestand ziet er ongeveer zo uit:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
<OBJECTS>
  <WINKEL vestiging="markt">
    <KAST id="001" verdieping="1" thema="spanning">
      <PLANK id="01" draagkracht="100000">
        <BOEK sku="9456101" titel="Zomaar Een boek" gewicht="400" prijs="30">2</BOEK>
        <BOEK sku="9674152" titel="Drukwerk" gewicht="750" prijs="45">3</BOEK>
      </PLANK>     
    </KAST>
  </WINKEL>
  <WINKEL vestiging="winkelcentrum">
  </WINKEL>
</OBJECTS>


De values van boek is het aantal boeken dat aanwezig is.

Hoe kan ik nu alle boeken met een prijs lager dan 40 euro selecteren?

Python:
1
for BOEK in root.findall("./WINKEL/KAST/PLANK/BOEK[@prijs<'40']"):

geeft TypeError: 'NoneType' object is not iterable

OF is het niet mogelijk om attributes met een waarde groter/kleiner dan te selecteren?

[img]error.jpg[/img]

Beste antwoord (via Niekleair op 09-12-2020 19:52)


  • pedorus
  • Registratie: Januari 2008
  • Niet online
Ben(V) schreef op woensdag 9 december 2020 @ 16:29:
Waarom gebruik je niet gewoon een regex?
Zoiets.

Python:
1
2
3
4
5
6
7
import re

fp = open('Test.xml', 'r')
Data = fp.read()
for Boek in re.findall(r'.*<BOEK sku="(.+?)" titel="(.+?)".*prijs="(.+?)">',Data):
    if int(Boek[2]) < 40:
        print(Boek[1])


Deze findall levert een list van drie tuples te weten sku, title en prijs.
Vergelijk het eens:
Python:
1
2
3
4
5
from lxml import etree

root = etree.parse("Test.xml")
for BOEK in root.xpath("//BOEK[@prijs<40]"):
    print(BOEK.attrib["titel"])
Welke vind je mooier en welke werkt beter als de xml ook maar ietsje veranderd (afgezien van de theoretische gevallen die al mis gaan)?
Niekleair schreef op woensdag 9 december 2020 @ 00:45:
geeft een SyntaxError: Invalid predicate.
Dan hielp het toch iets, want dat is een goede foutmelding om op te zoeken. Geeft direct terug dat je beter iets als lxml kan gebruiken ;)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten

Alle reacties


Acties:
  • +1 Henk 'm!

  • Daedalus
  • Registratie: Mei 2002
  • Niet online

Daedalus

Moderator Apple Talk

Keep tryin'

Kijk nog 'ns goed naar het pad in je XPath expressie en het pad van XML elementen in je voorbeeld :)

Afgezien daarvan heb je het complete pad niet nodig met de juiste pad expressie. Wat je wilt (naar ik aanneem), is alle BOEK elementen met een prijs attribuut kleiner dan 40.

[ Voor 53% gewijzigd door Daedalus op 09-12-2020 00:37 ]

“You know what I've noticed Hobbes? Things don't bug you if you don't think about them. So from now on, I simply won't think about anything I don't like, and I'll be happy all the time!” | 宇多田ヒカル \o/


Acties:
  • +1 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Niekleair schreef op woensdag 9 december 2020 @ 00:24:
OF is het niet mogelijk om attributes met een waarde groter/kleiner dan te selecteren?
Lijkt me een kwestie van testen. Dat lijkt te kunnen, dus dat is het niet. Ik zou eerst zorgen met een van de vele tools dat de xpath klopt (of de xml bij de xpath hoort zoals ik heb gedaan ;)). Overigens zou ik getallen niet tussen '' zetten, hoewel dat wel goed gaat.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Niekleair
  • Registratie: Oktober 2006
  • Laatst online: 11-06-2024
Ah, KAST vergeten in het voorbeeld.

Als ik dat toevoeg en het volgende script in python draai:

Python:
1
2
3
4
5
6
import xml.etree.ElementTree as ET
tree = ET.parse('boekwinkel.xml')
root = tree.getroot()

for BOEK in root.findall("./WINKEL/KAST/PLANK/BOEK[@prijs<'40']"):
    print(BOEK.attrib)


wordt niets geselecteerd. ; dat wil zeggen ik krijg niet de verwachte output

@Daedalus Inderdaad wil ik de BOEK elementen selecteren met een prijs attribuut kleiner dan 40.
Afgezien daarvan heb je het complete pad niet nodig met de juiste pad expressie
bedoel je iets in de trant van
code:
1
//BOEK[@prijs<40]



@pedorus Bedankt, die link gaat zeker helpen met testen.

De XPath expressie gaat nu goed, echter voor Python zijn de ' ' bij het attribuut nodig.
B.v.

Python:
1
2
for BOEK in root.findall(".//BOEK[@prijs='45']"):
  print(BOEK.attrib)


Geeft het verwachte resultaat:
code:
1
{'sku': '9674152', 'titel': 'Drukwerk', 'gewicht': '750', 'prijs': '45'}


Python:
1
2
for BOEK in root.findall(".//BOEK[@prijs=45]"):
  print(BOEK.attrib)

geeft een SyntaxError: Invalid predicate.

[ Voor 78% gewijzigd door Niekleair op 09-12-2020 02:00 ]

[img]error.jpg[/img]


Acties:
  • +1 Henk 'm!

  • Daedalus
  • Registratie: Mei 2002
  • Niet online

Daedalus

Moderator Apple Talk

Keep tryin'

Ah, je XPath expressie is nu goed, maar het probleem zit 'm in de XPath ondersteuning in Python. Zie Supported XPath syntax. Je zou lxml kunnen proberen, aangezien dit doorgaans de betere XML lib voor Python is, maar het is niet duidelijk uit de documentatie hoeveel XPath deze ondersteund (alhoewel het werkt op basis van libxml2, dus het zou standards compliant moeten zijn).

“You know what I've noticed Hobbes? Things don't bug you if you don't think about them. So from now on, I simply won't think about anything I don't like, and I'll be happy all the time!” | 宇多田ヒカル \o/


Acties:
  • 0 Henk 'm!

  • Ben(V)
  • Registratie: December 2013
  • Laatst online: 17:37
Waarom gebruik je niet gewoon een regex?
Zoiets.

Python:
1
2
3
4
5
6
7
import re

fp = open('Test.xml', 'r')
Data = fp.read()
for Boek in re.findall(r'.*<BOEK sku="(.+?)" titel="(.+?)".*prijs="(.+?)">',Data):
    if int(Boek[2]) < 40:
        print(Boek[1])


Deze findall levert een list van drie tuples te weten sku, title en prijs.

[ Voor 12% gewijzigd door Ben(V) op 09-12-2020 16:34 ]

All truth passes through three stages: First it is ridiculed, second it is violently opposed and third it is accepted as being self-evident.


Acties:
  • +2 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 23-09 14:00
Ben(V) schreef op woensdag 9 december 2020 @ 16:29:
Waarom gebruik je niet gewoon een regex?
Zoiets.

Python:
1
2
3
4
5
6
7
import re

fp = open('Test.xml', 'r')
Data = fp.read()
for Boek in re.findall(r'.*<BOEK sku="(.+?)" titel="(.+?)".*prijs="(.+?)">',Data):
    if int(Boek[2]) < 40:
        print(Boek[1])


Deze findall levert een list van drie tuples te weten sku, title en prijs.
Dit is natuurlijk een gewoon cowboy oplossing. Het werkt (in dit geval), maar je wilt dit soort code absoluut niet hebben; zeker niet in productiecode.

Acties:
  • +1 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Ben(V) schreef op woensdag 9 december 2020 @ 16:29:
Waarom gebruik je niet gewoon een regex?
Zoiets.

Python:
1
2
3
4
5
6
7
import re

fp = open('Test.xml', 'r')
Data = fp.read()
for Boek in re.findall(r'.*<BOEK sku="(.+?)" titel="(.+?)".*prijs="(.+?)">',Data):
    if int(Boek[2]) < 40:
        print(Boek[1])


Deze findall levert een list van drie tuples te weten sku, title en prijs.
Omdat dit ook boeken vindt binnen ./MAGAZIJN/WEGGOOISTAPEL, en boeken die uitgecomment zijn, en, en, en, en je XML gewoon niet met een RegEx wil parsen. Nooit.

[ Voor 3% gewijzigd door CodeCaster op 09-12-2020 17:15 ]

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • DataGhost
  • Registratie: Augustus 2003
  • Laatst online: 17:31

DataGhost

iPL dev

Ben(V) schreef op woensdag 9 december 2020 @ 16:29:
Waarom gebruik je niet gewoon een regex?
Korte antwoord: XML is niet regulier
Lange antwoord: https://stackoverflow.com...xhtml-self-contained-tags

Acties:
  • 0 Henk 'm!

  • Niekleair
  • Registratie: Oktober 2006
  • Laatst online: 11-06-2024
Ik heb het gevonden; de python plugin xml.etree ondersteunt een beperkt aantal XPath expressies:

https://docs.python.org/3/library/xml.etree.elementtree.html#xpath-support

Met de xml.etree is het alleen mogelijk om op een specifieke waarde van een attribuut te zoeken.
Daar had ik overheen gelezen.

[img]error.jpg[/img]


Acties:
  • 0 Henk 'm!

  • Daedalus
  • Registratie: Mei 2002
  • Niet online

Daedalus

Moderator Apple Talk

Keep tryin'

Niekleair schreef op woensdag 9 december 2020 @ 18:51:
Ik heb het gevonden; de python plugin xml.etree ondersteunt een beperkt aantal XPath expressies:

https://docs.python.org/3/library/xml.etree.elementtree.html#xpath-support

Met de xml.etree is het alleen mogelijk om op een specifieke waarde van een attribuut te zoeken.
Daar had ik overheen gelezen.
Daedalus in "[Python] Comparison op attribute value" O-)

“You know what I've noticed Hobbes? Things don't bug you if you don't think about them. So from now on, I simply won't think about anything I don't like, and I'll be happy all the time!” | 宇多田ヒカル \o/


Acties:
  • 0 Henk 'm!

  • Niekleair
  • Registratie: Oktober 2006
  • Laatst online: 11-06-2024
Goed lezen blijft moeilijk. 8)7 8)7

Zat zelf inderdaad ook al naar lxml te kijken.

[img]error.jpg[/img]


Acties:
  • Beste antwoord
  • +1 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Ben(V) schreef op woensdag 9 december 2020 @ 16:29:
Waarom gebruik je niet gewoon een regex?
Zoiets.

Python:
1
2
3
4
5
6
7
import re

fp = open('Test.xml', 'r')
Data = fp.read()
for Boek in re.findall(r'.*<BOEK sku="(.+?)" titel="(.+?)".*prijs="(.+?)">',Data):
    if int(Boek[2]) < 40:
        print(Boek[1])


Deze findall levert een list van drie tuples te weten sku, title en prijs.
Vergelijk het eens:
Python:
1
2
3
4
5
from lxml import etree

root = etree.parse("Test.xml")
for BOEK in root.xpath("//BOEK[@prijs<40]"):
    print(BOEK.attrib["titel"])
Welke vind je mooier en welke werkt beter als de xml ook maar ietsje veranderd (afgezien van de theoretische gevallen die al mis gaan)?
Niekleair schreef op woensdag 9 december 2020 @ 00:45:
geeft een SyntaxError: Invalid predicate.
Dan hielp het toch iets, want dat is een goede foutmelding om op te zoeken. Geeft direct terug dat je beter iets als lxml kan gebruiken ;)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • Niekleair
  • Registratie: Oktober 2006
  • Laatst online: 11-06-2024
@Daedalus en @pedorus

Hartelijk bedankt voor jullie hulp. In mijn testbestand (de boekwinkel) werkt e.e.a. zoals verwacht.
Met LXML moet ik een heel eind komen.

[ Voor 13% gewijzigd door Niekleair op 09-12-2020 19:52 ]

[img]error.jpg[/img]

Pagina: 1