Python XpathEvaluator without namespace
Asked Answered
D

1

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)?

Dichogamy answered 26/10, 2012 at 17:36 Comment(0)
H
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
Harwood answered 26/10, 2012 at 18:12 Comment(9)
I don't see how that helps solving the issue.Dichogamy
@puntofisso, The simplest way to see, is to try it.Harwood
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-novachevDichogamy
@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.Harwood
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.Dichogamy
@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.Harwood
Yep, exactly. I'm missing that "whateverEvaluateMethod" :) I guess I'm using a library without much convenience functions for Xpath.Dichogamy
@puntofisso, Almost every programming language has such function/method -- I believe that one nees just to search the appropriate documentation.Harwood
@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: 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)"Harwood

© 2022 - 2024 — McMap. All rights reserved.