xpath expression to read value based on value of sibling - xpath

I've below xml and would like to read the value of 'Value' tag whose Name matches 'test2'. I'm using the below xpath , but did not work. Can someone help.
/*[ local-name()='OutputData']/*[ local-name()='OutputDataItem']/*[ local-name()='Name'][normalize-space(.) = 'test2']//*[local-name()='Value']/text()
<get:OutputData>
<get:OutputDataItem>
<get:Name>test1</get:Name>
<get:Value/>
</get:OutputDataItem>
<get:OutputDataItem>
<get:Name>test2</get:Name>
<get:Value>B5B4</get:Value>
</get:OutputDataItem>
<get:OutputDataItem>
<get:Name>test3</get:Name>
<get:Value/>
</get:OutputDataItem>
<get:OutputDataItem>
<get:Name>OP_VCscEncrptCd_VAR</get:Name>
<get:Value/>
</get:OutputDataItem>
</get:OutputData>
Thanks

You were close, but because the get:name and get:value are siblings, you need to adjust your XPath a little.
Your XPath was attempting to address get:value elements that were descendants of get:name, rather than as siblings. Move the criteria that is filtering the get:name into a predicate, then step down into the get:value:
/*[ local-name()='OutputData']/*[ local-name()='OutputDataItem']
[*[ local-name()='Name'][normalize-space(.) = 'test2']]/*[local-name()='Value']/text()
You could also combine the criteria of the predicate filter on the get:name and use an and:
/*[ local-name()='OutputData']/*[ local-name()='OutputDataItem']
[*[ local-name()='Name' and normalize-space(.) = 'test2']]/*[local-name()='Value']/text()

This should work I think:
//*[local-name()="get:Name" and text()="test2"]/following-sibling::*[local-name()="get:Value"]/text()

Related

Conditional XPath on multiple elements

I am trying to use xpath to set an exchange property from the value of one element, depending on what the value is in another element...
So in my case i want an xpath to identify the PartyID where the RoleCode = 60. And another xpath expression to find the PartyID for where the RoleCode = Z60.
I would have used [1] etc but the send cannot guarantee the order the segments will be in.
Help is much appreciated!
<RegisteredProductCollection>
<RegisteredProduct>
<Status>1</Status>
<AddressLine2>test</AddressLine2>
<AddressLine1>37</AddressLine1>
<RegisteredProductPartyInformation>
<RegisteredProductPartyInformation>
<PartyID>9000028253</PartyID>
<RoleCode>60</RoleCode>
</RegisteredProductPartyInformation>
<RegisteredProductPartyInformation>
<PartyID>1288219</PartyID>
<RoleCode>Z60</RoleCode>
</RegisteredProductPartyInformation>
</RegisteredProductPartyInformation>
<PostalCode>3200</PostalCode>
<Country>NZ</Country>
<ProductID>G02411</ProductID>
<SerialID>1234124124</SerialID>
<City>test</City>
<ReferenceDate>20200514000000</ReferenceDate>
<District>wai</District>
</RegisteredProduct>
</RegisteredProductCollection>
You can use these XPath-1.0 expressions:
//RegisteredProductPartyInformation[RoleCode='60']/PartyID
and
//RegisteredProductPartyInformation[RoleCode='Z60']/PartyID
Change the ' to " if necessary.

How to select a specific category value in this Xpath expression

I have a feed here. I'm trying to create an XPath expression that returns items that have a category equal to Bananas. Due to the limitations in my XML parser, I can't use namespaces directly to select items.
The expression /rss/channel/item//*[name()='itunes:category'] returns this:
Element='<itunes:category
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
text="Apples"/>'
Element='<itunes:category
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
text="Bananas"/>'
...
And /rss/channel/item//*[name()='itunes:category']/#text returns this:
Attribute='text=Apples'
Attribute='text=Bananas'
...
But I can't figure out how to limit the response to just a single category (e.g., Bananas)?
I want some kind of expression like this:
/rss/channel/item//*[name()='itunes:category' and contains(., 'Bananas')]
But this doesn't work. It's not syntactically valid. What would be the right XPath expression syntax to just return Bananas?
Do you just mean to filter by attributes of item child, but still return item node?
/rss/channel/item/*[name()='itunes:category' and contains(#text,'Apples')]/parent::item
or simplier
/rss/channel/item[*[name()='itunes:category' and #text='Apples']]
I used Apples in example because using your example xml file there is 0 results for Bananas.

How to construct an xpath returning all of a set of elements

Considering theses xpath expressions :
//*[#id="searchResults"]/div[1]/div[1]/h2/span
//*[#id="searchResults"]/div[3]/div[1]/h2/span
//*[#id="searchResults"]/div[5]/div[1]/h2/span
For your info the div inside search result's class is article searchResult and the one inside article searchResult is header.
I am not sure how to construct an xpath matching all three of the above elements. Is there a tool or a how to guide for that?
Thanks
Use position function
//*[#id="searchResults"]/div[position()=1 or position()=3 or position()=5]/div[1]/h2/span
If, by 'all', you mean all div in even position index, then you can use mod operator to check :
//*[#id="searchResults"]/div[position() mod 2 = 1]/div[1]/h2/span
but if 'all' literally means all, then you don't need index to return all matched elements :
//*[#id="searchResults"]/div/div[1]/h2/span

Selenium Webdriver + Ruby regex: Can I use regex with find_element?

I am trying to click an element that changes per each order like so
edit_div_123
edit_div_124
edit_div_xxx
xxx = any three numbers
I have tried using regex like so:
#driver.find_element(:css, "#edit_order_#{\d*} > div.submit > button[name=\"commit\"]").click
#driver.find_element(:xpath, "//*[(#id = "edit_order_#{\d*}")]//button").click
Is this possible? Any other ways of doing this?
You cannot use Regexp, like the other answers have indicated.
Instead, you can use a nifty CSS Selector trick:
#driver.find_element(:css, "[id^=\"edit_order_\"] > div.submit > button[name=\"commit\"]").click
Using:
^= indicates to find the element with the value beginning with your criteria.
*= says the criteria should be found anywhere within the element's value
$= indicates to find the element with with your criteria at the end of the value.
~= allows you to find the element based on a single criteria when the actual value has multiple space-seperated list of values.
Take a look at http://net.tutsplus.com/tutorials/html-css-techniques/the-30-css-selectors-you-must-memorize/ for some more info on other neat CSS tricks you should add to your utility belt!
You have no provided any html fragment that you are working on. Hence my answer is just based on the limited inputs provided your question.
I don't think WebDriver APIs support regex for locating elements. However, you can achieve what you want using just plain XPath as follows:
//*[starts-with(#id, 'edit_div_')]//button
Explanation: Above xpath will try to search all <button> nodes present under all elements whose id attribute starts with string edit_div_
In short, you can use starts-with() xpath function in order to match element with id format as edit_div_ followed by any number of characters
No, you can not.
But you should do something like this:
function hasClass(element, className) {
var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
return re.test(element.className);
}
This worked for me
#driver.find_element(:xpath, "//a[contains(#href, 'person')]").click

How to get H1,H2,H3,... using a single xpath expression

How can I get H1,H2,H3 contents in one single xpath expression?
I know I could do this.
//html/body/h1/text()
//html/body/h2/text()
//html/body/h3/text()
and so on.
Use:
/html/body/*[self::h1 or self::h2 or self::h3]/text()
The following expression is incorrect:
//html/body/*[local-name() = "h1"
or local-name() = "h2"
or local-name() = "h3"]/text()
because it may select text nodes that are children of unwanted:h1, different:h2, someWeirdNamespace:h3.
Another recommendation: Always avoid using // when the structure of the XML document is statically known. Using // most often results in significant inefficiencies because it causes the complete document (sub)tree roted in the context node to be traversed.

Resources