3

I need to write a dynamic function that finds elements on a subtree of an ATOM xml document.

To do so, I've written something like this:

    tree = etree.parse(xmlFileUrl)
    e = etree.XPathEvaluator(tree, namespaces={'def':'http://www.w3.org/2005/Atom'})
    entries = e('//def:entry')
    for entry in entries:
        mypath = tree.getpath(entry) + "/category"
        category = e(mypath)

The code above fails to find category.

The reason is that getpath returns an XPath without namespaces, whereas the XPathEvaluator e() requires namespaces.

Is there a way to either make getpath return namespaces in the path, or allow XPathEvaluator to accept the path without specifying the namespace (or, rather, specifying it some other way)?

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
puntofisso
  • 383
  • 1
  • 3
  • 17

1 Answers1

2

Use:

*[local-name() = 'category']

Or, if you want to be more precise:

*[local-name() = 'category' and namespace-uri() = 'http://www.w3.org/2005/Atom']

Or simply:

def:category
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • I don't see how that helps solving the issue. – puntofisso Oct 28 '12 at 20:58
  • @puntofisso, The simplest way to see, is to try it. – Dimitre Novatchev Oct 28 '12 at 21:21
  • Ok, sorry, my comment was a bit abrupt (and I thought I hadn't post it :P). The question is more: what if I want to build that path dynamically? Is there any chance to do it? Thanks for your help @dimitre-novachev – puntofisso Oct 29 '12 at 11:00
  • @puntofisso, There are many ways an XPath expression (which in itself is just a string) can be built dynamically. One needs to know if any information about the XML document is known in advance (static) and what are the pieces in the XPath expression "skeleton" that must be dynamically generated. As this is completely unmentioned in the current question, it would be good if you ask a new, separate SO question. – Dimitre Novatchev Oct 29 '12 at 11:49
  • Actually, @Dimitre, there's a problem in the answer. Let's say I do as you say and make a search for category = e('*[local-name() = "category"]') inside the for cycle. The problem with the evaluator is that it searches in the root. How can I make it search just on the current entry in the for cycle? That's why I needed to build the xpath automatically, basically, unless there's a way to invoke the e() on "entry" alone. – puntofisso Oct 30 '12 at 16:14
  • @puntofisso, This is a *relative* XPath expression, so it will "search in the root" only if the "root" is the current node off which the XPath expression is evaluated. So you need to do something like this (sorry, I don't know Python): `entry.whateverEvaluateMethod(*[local-name() = 'category'])` . Here `entry` should be the node off which you want the Xpath expression to be evaluated. – Dimitre Novatchev Oct 30 '12 at 16:19
  • Yep, exactly. I'm missing that "whateverEvaluateMethod" :) I guess I'm using a library without much convenience functions for Xpath. – puntofisso Oct 30 '12 at 16:58
  • @puntofisso, Almost every programming language has such function/method -- I believe that one nees just to search the appropriate documentation. – Dimitre Novatchev Oct 30 '12 at 18:08
  • @puntofisso, I don't know Python. I can tell you that in C# there is the XNode.XPathEvaluate() method, which returns `object` and the caller casts this to the expected object ype -- int, decimal, double, bool or XmlNodeList. A similar method is `XPathNavigator.Evaluate()` . I have seen at SO Java code examples, showing the use of similar method in Java. I made a quick search and found this: http://lxml.de/xpathxslt.html#xpath . It is said there: "When xpath() is used on an Element, the XPath expression is evaluated against the element (if relative) or against the root tree (if absolute)" – Dimitre Novatchev Nov 01 '12 at 12:04