Let’s say you have XML like:
And now you’d like to get pairs order_id-client_name. And you’d like to make it in an elegant way, using xPath, not using DOM navigation, or worse, SAX parser. Getting all “client” nodes is easy:
3 | doc = libxml2.parseFile( 'clients.xml' ) |
4 | ctxt = doc.xpathNewContext() |
5 | clients = ctxt.xpathEval( '/clients/client' ) |
But now, how to run an xPath query on every node you found to get client name and orders? You have to tell the context object to change the scope of context, so the next query would be relative to the node you chose:
2 | ctxt.setContextNode(client) |
3 | client_name = ctxt.xpathEval( 'name' )[ 0 ].getContent() |
5 | orders = ctxt.xpathEval( 'orders/order' ) |
7 | ctxt.setContextNode(order) |
8 | orderId = ctxt.xpathEval( 'id' )[ 0 ].getContent() |
9 | print orderId + " " + client_name |
And that’s it. I’m writing it because documentation for libxml2’s python bindings is scarce, and it took me a while to get to know about setContextNode method.
Complete script:
3 | doc = libxml2.parseFile( 'clients.xml' ) |
4 | ctxt = doc.xpathNewContext() |
5 | clients = ctxt.xpathEval( '//client' ) |
8 | ctxt.setContextNode(client) |
9 | client_name = ctxt.xpathEval( 'name' )[ 0 ].getContent() |
11 | orders = ctxt.xpathEval( 'orders/order' ) |
13 | ctxt.setContextNode(order) |
14 | orderId = ctxt.xpathEval( 'id' )[ 0 ].getContent() |
15 | print orderId + " " + client_name |
19 | ctxt.xpathFreeContext() |
Use XSLT, Luke ;)
6 years later: Thank you very much, I was lost looking into the poor Python documentation exactly for this! It looks like they didn’t make the docs any better in this whole time :)
Awesome! I’m very happy that the things I’m writing here are useful, especially after this long time. That’s why I’ve started this blog in the first place – to write how I resolved the problems I’ve encountered, so other people don’t have to dig deep to find the solution.