2

I'm having difficulty understanding the proper syntax to use to get at single elements when parsing XML in Python with lxml.

when I do this:

print self.root.xpath("descendant::*[@Name='GevCCP']/*",namespaces=self.nsmap)

I get a list of subordinate nodes:

[<Element {http://www.genicam.org/GenApi/Version_1_0}ToolTip at 0x1175830>, <Element {http://www.genicam.org/GenApi/Version_1_0}Description at 0x117b6c8>, <Element {http://www.genicam.org/GenApi/Version_1_0}DisplayName at 0x117bb48>, <Element {http://www.genicam.org/GenApi/Version_1_0}Visibility at 0x117bb90>, <Element {http://www.genicam.org/GenApi/Version_1_0}Streamable at 0x117bd88>, <Element {http://www.genicam.org/GenApi/Version_1_0}EnumEntry at 0x117b8c0>, <Element {http://www.genicam.org/GenApi/Version_1_0}EnumEntry at 0x1214878>, <Element {http://www.genicam.org/GenApi/Version_1_0}EnumEntry at 0x1214560>, <Element {http://www.genicam.org/GenApi/Version_1_0}pValue at 0x1214a70>]

So how then do I access, say the first subelement of that list directly with the xpath syntax?

I've tried:

print self.root.xpath("descendant::*[@Name='GevCCP']/ToolTip",namespaces=self.nsmap)

which gives me an empty set:

[]

I've also tried specifying namespaces in the xpath which invariably leads to a lxml.etree.XPathEvalError: Invalid expression error.

Ultimately, I'd like to do this on all sorts of elements such as:

self.root.xpath("descendant::*[@Name='GevCCP']/pValue")
self.root.xpath("descendant::*[@Name='GevCCP']/EnumEntry[@Name='Group']/Value")
self.root.xpath("descendant::*[@Name='GevHeartbeatTimeoutReg']/Address")

The lxml documentation does not seem to cover my use case and anything else I have found about xpath and namespaces seems incomplete.

Octopus
  • 8,075
  • 5
  • 46
  • 66
  • You have a namespace `http://www.genicam.org/GenApi/Version_1_0` which you have to register. You can't select elements using their local names as selectors (e.g. `/ToolTip`, `pValue`, etc.) without having the namespace mapped either to a prefix or (if your api supports it) as default. Try `"descendant::*[@Name='GevCCP']/*[local-name()='ToolTip']"`. If that works, you need to register namespaces (or ignore it in all your expressions like this). – helderdarocha Jul 03 '14 at 22:21

1 Answers1

3

The best solution is to register a namespace that is used in your XML source. Usually that is done by assigning it to a prefix that you can use in your expressions. Is your nsmap variable mapping the namespaces correctly? Choose a prefix (such as g, for example):

self.nsmap = {'g': 'http://www.genicam.org/GenApi/Version_1_0'}

And then use the prefix to qualify your XPath selectors:

self.root.xpath("descendant::*[@Name='GevCCP']/g:ToolTip", namespaces=self.nsmap)
helderdarocha
  • 23,209
  • 4
  • 50
  • 65