3

big fan of xpath on .net, and sax in python, but first time using xpath in python.

I have a small script, that uses xpath to select some nodes from a doc, iterates through them, and then ideally uses xpath again to get the relevant data from them. However I can't get that last bit, once I have the xmlNode I cannot get a context from it.

import libxml2
import urllib

doc = libxml2.parseDoc(
        urllib.urlopen('http://somemagicwebservice.com/').read())
ctxt = doc.xpathNewContext()
listitems = ctxt.xpathEval('//List/ListItem')
for item in listitems:
    itemctxt = item.xpathNewContext()
    title = itemctxt.xpathEval('//ItemAttributes/Title')
    asin = itemctxt.xpathEval('//Item/ASIN')
    itemctxc.xpathFreeContext()
ctxt.xpathFreeContext()
doc.freeDoc()

However the itemctxt = item.xpathNewContext() bit fails with

itemctxt = item.xpathNewContext()
AttributeError: xmlNode instance has no attribute 'xpathNewContext'

Any ideas how to use xpath on a xmlNode? I can't find any good online info. Thanks

2 Answers 2

2

I don't think an XPathContext makes sense on an element? Try creating a new XPathContext, and setting it's node to the current element.

That said, I haven't used libxml2 directly, so it's a bit of a wild guess. I typically uses lxml, that exposes an ElementTree API around libxml2 and libxslt. It's much easier to use, and does indeed allow xpath() on elements. Of course, if you already have a lot of code using libxml2 you probably don't want to switch, but in that case you might want to take a look at lxmls source to see how it does it.

http://codespeak.net/svn/lxml/trunk/src/lxml/xpath.pxi

http://codespeak.net/svn/lxml/trunk/src/lxml/_elementpath.py

Seems good starting places.

Sign up to request clarification or add additional context in comments.

2 Comments

Well I had similar problems with lxml, but it turns out the problem was actually related to how xpath deals with namespaces. lxml's ElementPath simplified things a bit. Thanks.
If anyone wants to see what I ended up with, check out bitbucket.org/kurthaeusler/getwishlist/src/tip/getwishlist.py
2

https://stackoverflow.com/a/3379708/288875 suggests to call setContextNode(..) on a newly created context:

itemctxt = doc.xpathNewContext()

for item in listitems:
    itemctxt.setContextNode(item)
    title = itemctxt.xpathEval('.//ItemAttributes/Title')

    ...

itemctxt.xpathFreeContext()

In the version of python libxml (2.9.1) which I'm currently using it turns out that one can even call:

item.xpathEval('.//ItemAttributes/Title')

Note that you'll have to add a dot at the beginning of the xpath expressions .// (instead of //), otherwise you'll get search results relative to the document root.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.