Reputation: 8284
I am dealing with elements that sometimes contain their own text, and sometimes contain a span with the text. I'm generating an xpath in my program to get the elements I need based on the title attribute, so I'm using a template like this:
//div[@class='grid-canvas']//*[@title='Row %d column %s']
This works perfectly for elements that have their own text. But if they keep their text inside a child span, then I have to change my xpath template:
//div[@class='grid-canvas']//*[@title='Row %d column %s']/span
I really just want to use one template for my xpath. Since I either want the parent if it has no children, or the child element (which is a span) if it exists, I figured something like .[not(node())] | span
should work, so I tried this:
//div[@class='grid-canvas']//*[@title='Row %d column %s']/.[not(node())] | span
But it didn't work. I can't figure out what I'm missing. What am I doing wrong?
Upvotes: 1
Views: 2088
Reputation: 38732
Your third query start searching at the current context again – if you didn't set that somewhere else, it will be scan for a <span/>
root element.
XPath 1.0 does not allow alternations "in the middle" or at the end of a path, only as prefixes, so you will have to repeat the whole path:
//div[@class='grid-canvas']//*[@title='Row %d column %s']/span |
//div[@class='grid-canvas']//*[@title='Row %d column %s'][not(span)]
This will select all "sub"spans and those parent elements not containing a span element.
In XPath 2.0, you'd be able to do this if only one (or none) span elements exist:
//div[@class='grid-canvas']//*[@title='Row %d column %s']/(span, .)[1]
or for arbitrary numbers:
//div[@class='grid-canvas']//*[@title='Row %d column %s']/(span, .[not(span)])
Upvotes: 1