Xpath with Python

14

I have the following XML (simplified):

<produto refid="cat01" idprod="tv01">
    <marca>xxx</marca>
    <modelo>xxxx</modelo>
    <genero>xxx</genero>
</produto>
<v:utilizador iduser="U00000" comercial="12344" loja="xxxxx">
    <nome>xxxxx</nome>
    <contacto>94xxxxxx</contacto>
    <email>loja@xxxxxxx</email>
    <morada>xxxxxx</morada>
    <localidade>xxxxxx</localidade>
    <cesto>
        <encomenda refidprod="rlg04" estado="enviado"/>
        <encomenda refidprod="tv04" estado="enviado"/>
    </cesto>
</v:utilizador>
<u:utilizador iduser="U00003" comercial="" loja="">
    <nome>xxxxx</nome>
    <contacto>93xxxxxx</contacto>
    <email>xxxxxxxx</email>
    <morada>xxxxxx</morada>
    <localidade>xxxxx</localidade>
    <cesto>
        <encomenda refidprod="tlf04" estado="em processo"/>
    </cesto>
</u:utilizador>

And I have to work out a Python code that shows all products purchased by a particular user. I've done the following:

from lxml import etree

u={'u':'Utilizador'} ##Declaração do namespace

file = "marketplace.xml"
treeDoc = etree.parse(file)

nome=str(raw_input('Insira o nome: '))
print("Cesto de " + nome)

elemList = treeDoc.xpath("//produto[./@idprod=//utilizadores/u:utilizador[./nome='"+ nome +"']/cesto/encomenda/@refidprod]/marca", namespaces=u)

for elem in elemList:
    print("Item: ", elem.get("idprod"))
    nameList = elem.xpath("produto")
    print(nameList[0].tag, ": ", nameList[0].text)

It just does not return anything to me. Can someone tell me what the problem is? Another question: How do I get the xpath to return the two namespaces without having to do different querys?     

asked by anonymous 28.02.2015 / 13:00

2 answers

1

I know you do not answer your question exactly, but have you tried using xmltodict?

Module link: link

'''python
>>> doc = xmltodict.parse("""
... <mydocument has="an attribute">
... <and>
... <many>elements</many>
... <many>more elements</many>
... </and>
... <plus a="complex">
... element as well
... </plus>
... </mydocument>
... """)
>>>
>>> doc['mydocument']['@has']
u'an attribute'
>>> doc['mydocument']['and']['many']
[u'elements', u'more elements']
>>> doc['mydocument']['plus']['@a']
u'complex'
>>> doc['mydocument']['plus']['#text']
u'element as well'
'''
    
28.05.2015 / 00:12
0

This can solve your problem here:

import xml.etree.ElementTree as ET

#dicionario de namespaces
ns_dic = {'v' : 'http://exemplo.org',
          'u' : 'http://exemplo2.org'}

tree = ET.parse('marketplace.xml')
root = tree.getroot()

#usuario entra com nome
nome = "'%s'"%input() #python 2.7 use raw_input()

utilizadores = [] #declaro lista de utilizadores
#busco todos os utilizadores com o nome dado independente do namespace
for ns in ns_dic: 
    utilizadores.append(root.findall("./%s:utilizador[nome=%s]"%(ns, nome), ns_dic))

utilizadores = sum(utilizadores, []) #planifico a lista

cestos = {} #crio um dicionario do tipo {user_id : lista_de_encomendas}
for utilizador in utilizadores:
    user_id = utilizador.get('iduser')
    cesto = utilizador.findall("cesto/encomenda")
    cestos[user_id] = cesto
    for encomenda in cesto:
        print("id: %s, estado:%s"%(encomenda.get("refidprod"), encomenda.get("estado")))

In your example, if I look for the first user, the code returns this:

>>>
id: rlg04, estado:enviado
id: tv04, estado:enviado
>>> utilizadores
[<Element '{http://exemplo.org}utilizador' at 0x00000000035B1958>]
>>> cestos
{'U00000': [<Element 'encomenda' at 0x00000000035B1B88>, <Element 'encomenda' at 0x00000000035B1BD8>]}

Notice that I'd rather use% w_th of% than% w_%, because for me, the code becomes clearer.

    
04.07.2015 / 17:44