framing xpath expression with Dynamic Id clarification - webdriver with java - java

below are the xpath the id parameter is dynamic
sampels:
//*[#id="00e46000000UZ8a_RelatedCustomPermissionsSecurityList_page"]/div[1]/div"
//*[#id='00e6F000001ffnh_RelatedCustomPermissionsSecurityList_page']/div[1]/div
so the begining 15 digits dynamically generated, so i try to find the element with below xpath
//[ends-with(#id,'_RelatedCustomPermissionsSecurityList_page')]/div[1]/div
while executing i'm getting the below error
invalid selector: Unable to locate an element with the xpath expression //[ends-with(#id,'_RelatedCustomPermissionsSecurityList_page')]/div[1]/div because of the following error:
SyntaxError: Failed to execute 'evaluate' on 'Document': The string '//[ends-with(#id,'_RelatedCustomPermissionsSecurityList_page')]/div[1]/div' is not a valid XPath expression.

Selenium doesn't support ends-with() syntax. You might need to use contains() instead
//*[contains(#id,'_RelatedCustomPermissionsSecurityList_page')]/div[1]/div
or you also might use substring() to match value after 15 starting characters
//*[substring(#id, 16) = '_RelatedCustomPermissionsSecurityList_page']/div[1]/div

ends-with is xpath 2.0 function. Browsers support only xpath 1.0. See reference.
Use contains instead
//[contains(#id, '_RelatedCustomPermissionsSecurityList_page')]/div[1]/div

The alternative way to deal with dynamic element you can use CSSSelector as well
For this :
//*[#id="00e46000000UZ8a_RelatedCustomPermissionsSecurityList_page"]/div[1]/div
use CSSselector like this :
[id$='_RelatedCustomPermissionsSecurityList_page']>div>div
Also look into this :
css=a[id^='id_prefix_']
css=a[id$='_id_suffix']
css=a[id*='id_pattern']

Related

Appium NOT locating element when java variable is used in xpath

I'm trying to locate elements dynamically usign the xpath. However, when I use variable in the xpath, elements are NOT located. However, if I use hardcoded value, elements are located properly.
What am I missing here?
Below xpath locates the elements perfectly:
driver.findElements(By.xpath("//XCUIElementTypeStaticText[contains(#value, 'hp')]"));
whereas, below xpath doesn't locate the elements:
driver.findElements(By.xpath("//XCUIElementTypeStaticText[contains(#value, '" + device + "')]"));
Please note that , there are multiple elements matching the above xpath.
I even tried below code but of no use:
driver.findElements(By.XPath(String.Format("//XCUIElementTypeStaticText[contains(#value, '{0}')]", device)));
Any help would be appreciated.
Try do debug this issue as following:
Define the XPath string before calling driver.findElements method, format the string to have the proper value and then pass it into Selenium method, as following:
String xpathLocator = "//XCUIElementTypeStaticText[contains(#value, '%s')]";
xpathLocator = String.format(xpathLocator, device);
driver.findElements(By.xpath(xpathLocator));
As about your existing code.
Here driver.findElements(By.xpath("//XCUIElementTypeStaticText[contains(#value, '" + device + "')]"));
I can't see the formatting action.
And here driver.FindElements(By.XPath(string.Format("//XCUIElementTypeStaticText[contains(#value, '{0}')]", device)));
it seems to be a wrong syntax.
It should be String.format while you wrote string.Format
Try trimming the spaces as:
driver.findElements(By.xpath("//XCUIElementTypeStaticText[contains(#value, '"+device+"')]"));
Or using String.format() as:
String device = "hp";
driver.findElements(By.xpath(String.format("//XCUIElementTypeStaticText[contains(#value, '%s')]", device)));
Note:
Instead of FindElements() it should be findElements()
Instead of String.Format() it should be String.format()
The issue was with the case mismatch in the value returned by variable. i.e; device variable was returning 'hP' instead of 'hp'.
Corrected the code and it works fine now.

Jsoup match any element with a namespace

I would like to return all element with a particular namespace for example <server:cpu> <server:memory> using Jsoup css selector.
Document doc = Jsoup.parse("<server:cpu> <server:memory>");
Elements el = doc.select("sever|*");
But that return a Could not parse query exception
This documentation https://jsoup.org/apidocs/org/jsoup/select/Selector.html says you can use :
*|E elements of type E in any namespace ns
but I want to do the opposite: get element in namespace ns of any type. Is this possible?
EDIT:
I am not getting the exception anymore, however I am getting an empty Elements object after executing doc.select("sever|*");
I wrote something in Scala to accomplish namespace matching with wildcard () i.e ("namespace|") since it is not supported in JSoup version 1.10.2
def getElementsByNamespace(element: org.jsoup.nodes.Element, namespace: String): org.jsoup.select.Elements = {
import collection.JavaConverters._
val elements = element.select("*").asScala.filter(_.tagName().startsWith(s"$namespace:"))
new Elements(elements.asJava)
}
For java version please refer the link https://stackoverflow.com/a/23766900 suggested by #Pshemo
Thanks to #NaderHadjiGhanbari for help me understand and convert from Java collection to Scala collection

XPath- Getting Element from a table having dynamic ID

I'm trying to automate my Test Cases using Selenium for an OBIEE application. Now, I need to read a value from a tabular report generated. The problem is, the ID of the last cell where the total is, keeps on changing.
For example- Currently the id is: db_saw_9270_6_1610_0.
After refreshing, the ID becomes something else. The 4 numbers in between (9270) changes. The remaining bit are the same. I'm using the following logic to capture this element:
driver.findElement(By.xpath(".//*[contains(#id, '_6_1610_0')]")).getText();
But, it is returning org.openqa.selenium.NoSuchElementException: Unable to locate element:
Please tell me where did I go wrong and what should I do?
you can try starts-with and substring (as a substitute for xpath 2.0 methdod ends-with):
string xpath = "//*[starts-with(#id, 'db_saw_') and substring(#id, string-length(#id) - 8) = '_6_1610_0']"
driver.findElement(By.xpath(xpath)).getText();
You can try below xpath:-
driver.findElement(By.xpath("//*[starts-with(#id, 'db_saw')]")).getText();
driver.findElement(By.CSSselector("a[id*='_6_1610_0']")).getText();
Note: the a represents a html element. If your id is in a element then you have to replace a by table.
Check this out for more examples with css selector

Using multiple criteria to find a WebElement in Selenium

I am using Selenium to test a website, does this work if I find and element by more than one criteria? for example :
driverChrome.findElements(By.tagName("input").id("id_Start"));
or
driverChrome.findElements(By.tagName("input").id("id_Start").className("blabla"));
No it does not. You cannot concatenate/add selectors like that. This is not valid anyway. However, you can write the selectors such a way that will cover all the scenarios and use that with findElements()
By byXpath = By.xpath("//input[(#id='id_Start') and (#class = 'blabla')]")
List<WebElement> elements = driver.findElements(byXpath);
This should return you a list of elements with input tags having class name blabla and having id id_Start
To combine By statements, use ByChained:
driverChrome.findElements(
new ByChained(
By.tagName("input"),
By.id("id_Start"),
By.className("blabla")
)
)
However if the criteria refer to the same element, see #Saifur's answer.
CSS Selectors would be perfect in this scenario.
Your example would
By.css("input#id_start.blabla")
There are lots of information if you search for CSS selectors. Also, when dealing with classes, CSS is easier than XPath because Xpath treats class as a literal string, where as CSS treats it as a space delimited collection
Based #George's repply, the same code for C# :
//reference
using OpenQA.Selenium.Support.PageObjects;
...
int allElements = _driver.FindElements(new ByChained(
By.CssSelector(".sc-pAyMl.cnszJw"),
By.Id("base-field")
)).Count();

Xpath transformation not working in java

This is my xml document. I want to sign only the userID part using xml signature. I am using xpath transformation to select that particular element.
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
Version="2.0" IssueInstant="2012-05-22T13:40:52:390" ProtocolBinding="urn:oasis:na
mes:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="localhos
t:8080/consumer.jsp">
<UserID>
xyz
</UserID>
<testing>
text
</testing>
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
http://localhost:8080/saml/SProvider.jsp
</saml:Issuer>
</samlp:AuthnRequest>
I am using the following code to add the transformations :
transformList.add(exc14nTransform);
transformList.add(fac.newTransform(Transform.XPATH, new XPathFilterParameterSpec("samlp:AuthnRequest/UserID xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"")));
But I get the following :
Original Exception was javax.xml.transform.TransformerException: Extra illegal t
okens: 'xmlns', ':', 'samlp', '=', '"urn:oasis:names:tc:SAML:2.0:protocol"'
So, I tried removing the xmlns part.
transformList.add(fac.newTransform(Transform.XPATH, new XPathFilterParameterSpec("samlp:AuthnRequest/UserID")));
But it signs the whole document and gives the following message :
com.sun.org.apache.xml.internal.security.utils.CachedXPa
thFuncHereAPI fixupFunctionTable
INFO: Registering Here function
What is the problem?
EDIT
As #Jörn Horstmann said the message is just a log or something like that. Now the problem is that even after giving the xpath query the whole document is signed instead of just the UserID. I confirmed this by changing the value of <testing>element after signing the document. The result is that the document does not get validated(If it signed only the UserID part, then any changes made to <testing> should result in a valid signature .)
This is not a valid xpath expression, there is no way to declare namespace prefixe inside the expression.
samlp:AuthnRequest/UserID xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
XPathFilterParameterSpec does have another constructor that allows to specify a mapping of namespace prefixes, you could try the following expression:
new XPathFilterParameterSpec("samlp:AuthnRequest/UserID",
Collections.singletonMap("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"))
Edit:
The message does not seem to be an error, see line 426 here, its log level should probably be lower than INFO though.
I also had a look at the description of xpath filtering:
The XPath expression appearing in the XPath parameter is evaluated once for each node in the input node-set. The result is converted to a boolean. If the boolean is true, then the node is included in the output node-set. If the boolean is false, then the node is omitted from the output node-set.
So the correct xpath expression to only include the UserID in the signature would be self::UserID. But don't ask me if this actually makes sense for a xml signature. The example in the specification seems to use a xpath expression to include everything except the signature element itself:
not(ancestor-or-self::dsig:Signature)
Edit 2:
The correct expression is actually ancestor-or-self::UserID since the filter also has to include the text child nodes of the UserID node.

Categories

Resources