Not able get element using xpath following-sibling - xpath

I am not able select xpath using following sibling. It says element not found
tried below syntax,
//x/y[contains(text(),"Status"]/following-sibling::/x/y
//x/y[contains(text(),"Status"]/following-sibling::/x/y/text()
//x/y[contains(text(),"Status"]/../x/y
This is what my HTML code looks like,
<X>
<y> Status </y>
</x>
<x>
<y> ACTIVE</y>
</x>
None of above syntax gives ACTIVE as output. It throws element not found error. Can anyone help me to formulate proper syntax to get value.

This expression
(//y)[2]
Outputs:
ACTIVE
Is that what you're looking for?

I think you want this:
//x[contains(y,"Status")]/following-sibling::x/y/text()
Like mentioned in a comment, y doesn't have any siblings; only x does. Select the x that contains a y with "Status" and then select the following x sibling (and child y's text()).

Related

Select XML Node by position

I have the following XML structure
<Root>
<BundleItem>
<Item>1</Item>
<Item>2</Item>
<Item>3</Item>
</BundleItem>
<Item>4</Item>
<Item>5</Item>
<Item>6</Item>
<BundleItem>
<Item>7</Item>
<Item>8</Item>
<Item>9</Item>
</BundleItem>
</Root>
And by providing the following xPath
//Item[1]
I am selecting
<Item>1</Item>
<Item>4</Item>
<Item>7</Item>
My goal is to select only <Item>1</Item> or <Item>7</Item> regardless of the parent element where they are found and only depending on the position, which i am providing in the xPath.
Is it possible to do that only by using the position and without providing additional criterias in the xPath ?
//Item[1] selects the all the first child elements that are <Item/> regardless of their parent.
To get the two items you are looking for you could use //Item[text() = 1 or text() = 7].
A good tutorial can be found at w3schools.com and you can play with XPath expressions over your XML input here. (I am not affiliated with either of these resources but find them useful.)

What's wrong with this xpath statement?

Trying to get the color WHITE out of the line of code.
<a href="javascript:void(0)" class="itemAttr current" title="WHITE" data-
value="WHITE"><img src="https://gloimg.rglcdn.com/rosegal/pdm-product-
pic/Clothing/2019/06/05thumb-img/1559762268621192281.jpg"></a>
I've tried this:
color = driver.find_element_by_xpath("""//p[#id="select-attr-
0"]/a[#href="javascript:void(0)"]#title""").click()
I get this error message:
The string
'//p[#id="select-attr-0"]/a[#href="javascript:void(0)"]#title' is not
a valid XPath expression.
What I want is to get "WHITE".
It looks like you are missing a / before the #title attribute. Try this xpath instead:
//p[#id="select-attr-0"]/a[#href="javascript:void(0)"]/#title
In order to get an attribute value of an element, you need to put '/' before the '#title', so the following should work (provided the parent element p is correctly addressed):
//p[#id="select-attr-0"]/a[#href="javascript:void(0)"]/#title
When working with XPATHs, it is often useful to use one of free online testers to get instant path feedback, e.g. this one
Try using the below xpath snippet.
//p[#id='select-attr- 0']//child::a[#value='WHITE']

xpath: nested nodes with same name

Is it possible to write Xpath exression to find following nodes:
a/b/c
a/b/b/c
a/b/b/b/c
a/b/b/b/.../b/.../b/c
etc.
but not
a/b/b/e/b/c
?
Thanks for any advice
For the following input:
<root>
<a><b><c>1</c></b></a>
<a><b><b><c>2</c></b></b></a>
<a><b><b><b><c>3</c></b></b></b></a>
<a><b><b><e><b><c>4</c></b></e></b></b></a>
<a><b><b><e><b><b><c>5</c></b></b></e></b></b></a>
</root>
You can try the following expression:
//a[deep-equal(distinct-values(descendant::*[position()<last()]/name()), ('b'))]//c
How it works:
For any a the names of all but the last descendant are calculated and it is checked if the distinct list of that names matches the list containing just b. And for such an a the descendant c is one you want to select.
I tested it with the 2010 version of XMLSpy, which returns the c elements containing 1, 2 and 3. I think more modern tools will also work. But you need at least XPath 2.0 for this.
Question is not totally clear, but you can try to use below expression:
//a[.//b and not(.//e)]//c[not(.//*)]
This should allow to match cthat has no own child and is descendant of a, that has b descendant, but not e
UPDATE
You can try
//a[count(.//b)=count(.//*)-count(.//c)]//c[not(.//*)]
or
//a[not(.//*[not(self::b)]//c)]//c[not(.//*)]

Looking for n-th instance of x node in root node

Suppose I have following xml
<root>
<x>
<y />
<z>
<y />
</z>
<n>
<m>
<y />*
</m>
</n>
</x>
<x>
<y />
<z>
<y />
</z>
<y />*
</x>
</root>
I would like to retrieve those y nodes which are followed with *
So it is always third node in x ancestor node
I tried something like:
//x//y[3]
However it doesn't work I guess it would work only if y nodes are on the same level.
So I tried
(//x//y)[3] but it retrieves only one node (third one) in whole document
So I tried something like:
//x(//y)[3]
//x(//y[3])
//x//(y[3])
etc. but I get parse error
Is there any way to retrieve what I need using xpath?
Use:
//x/descendant::y[3]
This selects every third y descendant of each x in the document. It sometimes helps to write out an expanded expression to see what's really going on. In this case, the following:
//x//y[3]
is equivalent to:
/descendant-or-self::node()/child::x/descendant-or-self::node()/child::y[3]
Written this way it becomes obvious why it doesn't do what you wanted (i.e. it's looking for any y that is the third child of an x element and there isn't one). What you really wanted was every third y descendant. Here it is fully expanded:
/descendant-or-self::node()/child::x/descendant::y[3]
The important lesson here is that it pays to know what the XPath abbreviated syntax is really doing. The spec is actually quite readable. I recommend taking a look.
Update: both of these examples are XPath 2.0 only.
In XPath 1.0:
/row//y/(ancestor::x//y)[3]
In XPath 2.0:
for $x in /row//x
return ($x//y)[3]

Problem running xpath query with namespaces

I'm trying to use an xpath expression to select a node-set in an xml document with different namespaces defined.
The xml looks something like this:
<?POSTEN SND="SE00317644000" REC="5566420989" MSGTYPE="EPIX"?>
<ns:Msg xmlns:ns="http://www.noventus.se/epix1/genericheader.xsd">
<GenericHeader>
<SubsysId>1</SubsysId>
<SubsysType>30003</SubsysType>
<SendDateTime>2009-08-13T14:28:15</SendDateTime>
</GenericHeader>
<m:OrderStatus xmlns:m="http://www.noventus.se/epix1/orderstatus.xsd">
<Header>
<OrderSystemId>Soda SE</OrderSystemId>
<OrderNo>20090811</OrderNo>
<Status>0</Status>
</Header>
<Lines>...
I want to select only "Msg"-nodes that has the "OrderStatus" child and therefore I want to use the following xpath expression: /Msg[count('OrderStatus') > 0] but this won't work since I get an error message saying: "Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function".
So I think I want to use an expression that looks something like this: /*[local-name()='Msg'][count('OrderStatus') > 0] but that doesn't seem to work.. any ideas?
Br,
Andreas
I want to use the following xpath
expression:
/Msg[count('OrderStatus')[ 0]
but this won't work since I get an error message saying: "Namespace
Manager or XsltContext needed.
This is a FAQ.
In XPath a unprefixed name is always considered to belong in "no namespace".
However, the elements you want to select are in fact in the "http://www.noventus.se/epix1/genericheader.xsd"
namespace.
You have two possible ways to write your XPath expression:
Use the facilities of the hosting language to associate prefixes to all different namespaces to which names from the expression belong. You haven't indicated what is the hosting language in this concrete case, so I can't help you with this. A C# example can be found here.
If you have associated the prefix "xxx" to the namespace "http://www.noventus.se/epix1/genericheader.xsd" and the prefix "yyy" to the namespace "http://www.noventus.se/epix1/orderstatus.xsd", then your Expression can be written as:
/xxx:Msg[yyy:OrderStatus]
:2: If you don't want to use any prefixes at all, an XPath expression can still be constructed, however it will not be too readable:
/*[local-name() = 'Msg' and *[local-name() = 'OrderStatus']]
Finally, do note:
In order to test if an element x has a child y it isn't necessary to test for a positive count(y). Just use: x[y]
Xpath positions are 1-based. This means that NodeSetExpression[0] never selects a node. You want: NodeSetExpression[1]

Resources