How to get full classname with xpathquery? - xpath

I'm parsing through a HTML document and I need a class name of a div. I know a part of the class name (that never changes) but I need the full class name.
Here's the code I use:
$doc = new DOMDocument;
$doc->loadHTMLFile('http://some_website.com');
$xpath = new DOMXPath($doc);
$classname_of_the_div=$xpath->query('//div[#class="part_of_the_class_name_that_never_changes"]');
When I var_dump() the $classname_of_the_div and $classname_of_the_div->item(0) the result is:
object(DOMNodeList)#3 (1) { ["length"]=> int(0) }
NULL
I know that $classname_of_the_div=$xpath->evaluate('string(//div[#class="part_of_the_class_name_that_never_changes"])'); gives me the content of the div but how do I get the full class name?
P.S.: The part of the classname is separated from the rest of the class name by white spaces, so it's not really a part of the class. The div has just several classes.

I mean the div has several class names like - I want to select it by "class2" for example and receive the
full class string including "class1 class2 class3"
Then, an XPath expression like
//div[#class="part_of_the_class_name_that_never_changes"]
will never yield a result, save for the situation that a particular div element only has one class, that is, the one "that never changes". That's because the XPath expression above means:
Select div elements that have a class attribute whose string value
exactly corresponds to "part_of_the_class_name_that_never_changes".
But imagine the following situation:
<div class="part_of_the_class_name_that_never_changes other_class1 other_class2"/>
Then, you would need to change the expression to:
//div[contains(#class,'part_of_the_class_name_that_never_changes')]/#class
The expression means:
Look for div elements that have a class attribute whose string
value contains the string
"part_of_the_class_name_that_never_changes" and return the attribute
value.

Related

Is it possible in XPATH to find an element by attribute value, not by name?

For example I have an XML element:
<input id="optSmsCode" type="tel" name="otp" placeholder="SMS-code">
Suppose I know that somewhere there must be an attribute with otp value, but I don’t know in what attribute it can be, respectively, is it possible to have an XPath expression of type like this:
.//input[(contains(*, "otp")) or (contains(*, "ode"))]
Try it like this and see if it works:
one = '//input/#*[(contains(.,"otp") or contains(.,"ode"))]/..'
print(driver.find_elements_by_xpath(one))
Edit:
The contains() function has a required cardinality of first argument of either one or zero. In plain(ish) English, it means you can check only one element at a time to see if it contains the target string.
So, the expression above goes through each attribute of input separately (/#*), checks if the attribute value of that specific attribute contains within it the target string and - if target is found - goes up to the parent of that attribute (/..) which, in the case of an attribute, is the node itself (input).
This XPath expression selects all <input> elements that have some attribute, whose string value contains "otp" or "ode". Notice that there is no need to "go up to the parent ..."
//input[#*[contains(., 'otp') or contains(., 'ode')]]
If we know that "otp" or "ode" must be the whole value of the attribute (not just a substring of the value), then this expression is stricter and more efficient to evaluate:
//input[#*[. ='otp' or . = 'ode']]
In this latter case ("otp" or "ode" are the whole value of the attribute), if we have to compare against many values then an XPath expression of the above form will quickly become too long. There is a way to simplify such long expression and do just a single comparison:
//input[#*[contains('|s1|s2|s3|s4|s5|', concat('|', ., '|'))]]
The above expression selects all input elements in the document, that have at least one attribute whose value is one of the strings "s1", "s2", "s3", "s4" or "s5".

Syntax error in xpath expression having contains

List <WebElement> elt2=driver.findElements(By.xpath("//*[contains#className,'textInputContainers']"));
Also tried the version below:
List< WebElement > elt2 = driver.findElements(By.xpath("//*[contains#id,'txt']"));
contains() is a function and so must have () around its arguments.
So change
//*[contains#className,'textInputContainers']
to
//*[contains(#className,'textInputContainers')]
Note: A more robust way to test for a class name within a #class attribute can be found here: Xpath: Find element with class that contains spaces

Use Datasource Properties in XPath Expression of SoapUI

I need to know whether it is possible to use a datasource property in XPath Expression panel of XPath Match Configuration. For instance, if we have the following XML document:
<ns1:Ions>
<ns1:Ion>UI</ns1:Ion>
<ns1:IonType>X</ns1:IonType>
<ns1:StartDate>2010-05-10</ns1:StartDate>
</ns1:Ions>
<ns1:Ions>
<ns1:Ion>HH</ns1:Ion>
<ns1:IonType>RI</ns1:IonType>
<ns1:StartDate>1998-11-23</ns1:StartDate>
</ns1:Ions>
<ns1:Ions>
<ns1:Ion>CF</ns1:Ion>
<ns1:IonType>A</ns1:IonType>
<ns1:StartDate>2000-06-10</ns1:StartDate>
</ns1:Ions>
I need to evaluate to see whether a content of IonType is 'A' only if its sibling node, Ion, has a value of 'CF'. I was hoping to accomplish this by setting XPath Match Configuration as following:
XPath Expression (DataSourceInput#ION is 'CF')
declare namespace ns1='http://my.namespace.com';
//ns1:Ions[ns1:Ion[text()=${DataSourceInput#ION}]]/ns1:IonType/text()
Expected Results (DataSourceInput#ION_TYPE is 'A')
${DataSourceInput#ION_TYPE}
Running the test would result in SoapUI [Pro] to error the following, Missing content for xpath declare. If I replace ${DataSourceInput#ION} with an actual value, i.e. 'CF', the test works accordingly (I even tried place single quotes around ${DataSourceInput#ION}, but it didn't work).
Is there another way of accomplish this in SoapUI?
I try what you do and it works for me if I put single quotes around the property:
declare namespace ns1='http://my.namespace.com';
//ns1:Ions[ns1:Ion[text()='${DataSourceInput#ION}']]/ns1:IonType/text()
Did you check that testStep name is exactly DataSourceInput? If there are spaces in the TestStep name (i.e your testStep name is Data Source Input you have to put ${Data Source Input#ION}).
Anyway I give you another way to do so, you can add a testStep of type groovy script after the testStep where you are getting the <Ions>response, and check the assert here like follows:
// get xml holder
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context);
def ionsHolder = groovyUtils.getXmlHolder("IonsTestStepName#response");
// generate xpath expression
def xpathExpression = "//*:Ions[*:Ion[text()='" + context.expand('${DataSourceInput#ION}') + "']]/*:IonType/text()";
log.info xpathExpression;
// get the node value
def nodeValue = ionsHolder.getNodeValue(xpathExpression);
// check expected value
assert nodeValue == context.expand('${DataSourceInput#ION_TYPE}'),'ERROR IONS VALUE';
Hope this helps,

Check if the node value exist

I want to check in a xml if there is a node with the value "Hotel Hafen Hamburg".
But I get the error.
SimpleXMLElement::xpath(): Invalid predicate on line 25
You can view the xml here.
http://de.sourcepod.com/dkdtrb22-19748
Until now I have written the following code.
$apiUmgebungUrl = "xml.xml";
$xml_umgebung = simplexml_load_file($apiUmgebungUrl);
echo $nameexist = $xml_umgebung->xpath('boolean(//result/name[#Hotel Hafen Hamburg');
It seems that your parantheses and brackets do not close properly at the end of your XPath expression - it should end on ]).
Also, what is Hotel Hafen Hamburg? If it is an attribute called value, your value check should look like this:
[#value="Hotel Hafen Hamburg"]
You cannot just write # and then a value, without specifying where that value is supposed to be.
EDIT: Looking at the Xml document, it seems that Hotel Hafen Hamburg is supposed to be the text content of the <name> element. Therefore, try looking for a text node with that value rather than an attribute:
boolean(//result/name[text() = "Hotel Hafen Hamburg"])

Xpath: find an element value from a match of id attribute to id anchor

I would like to find the value of an element matched on id attribute for which I only have the ref - the bit with #, the anchor.
I am looking for the value of partyId:
< party id="partyA" >
< partyId >THEID< /partyId >
but to get there I only have the href from the following
< MyData >
< MyReference href="#partyA" />
Strip the # sign does not look good to me.
Any hints?
Because you haven't provided complete XML documents, I have to use // -- a practice I strongly recommend to avoid.
Suppose that
$vDataRef
is defined as
//MyData/MyReference/#href
and its string value is "#partyA", then one possible XPath expression that selects the wanted node is:
//party[#id=substring($vDataRef,2)]
In case the XML document has a DTD in which the id attribute of party is defined to be of type ID, then it is more convenient and efficient to use the standard XPath function id():
id(substring($vDataRef,2))
Assuming you have your ID as a variable already (lets say $myId), then try using:
//party[contains($myId, #id)]
The contains() function will look to see on each matching node whether or not the partyId attibute is in the value that you pass in.
Alternatively (as that could be considered 'ropey'), you can try:
//party[#id=substring($myId, 2, 1 div 0)]
the substring() function should be a little more precise.

Resources