Implementing Condition in Xpath

Implementing condition in XPath

Specify the date in the xpath expression,

i.e.

$nodes = $xml->xpath('//xml/events[@date="14/12/2011"]');

would select only the last events-node in the example

XPath with multiple conditions

Try:

//category[@name='Sport' and ./author/text()='James Small']

Using an OR condition in Xpath to identify the same element

If the element has two xpath, then you can write two xpaths like below

xpath1 | xpath2

Eg: //input[@name="username"] | //input[@id="wm_login-username"]

It will choose any one xpath

Multiple conditions (and operator) in XPath

It depends on the version of XPath.

You can't do this in a single XPath 1.0 expression because it would require a structure like

/bookstore/myBooks/book[/bookstore/books/book[
@title = _outer-predicate_/@title and
@author = _outer-predicate_/@author]]/@name

i.e. you'd need to capture the book being tested by the outer predicate so you can compare it to the inner one. Pure XPath 1.0 doesn't support this, you'd have to iterate over the content of myBooks yourself (e.g. with an xsl:for-each, as you've tagged your question "xslt").

In XPath 2.0 you can do it in one expression with an explicit quantifier

/bookstore/myBooks/book[not(some $book in /bookstore/books/book satisfies
($book/@author = @author and $book/@title = @title))]/@name

How to apply condition on child xpath from parent xpath

It would be something like:

//p[contains(text(), 'Pending')]/parent::td/following-sibling::*/descendant::*/button[contains(text(),'Waved off')]

Going forward please include the whole <table> tag contents into your question, the chance of getting more accurate advice will be much higher

Sample Image

References:

  • XPath Tutorial
  • XPath Axes
  • XPath Operators & Functions

Implement if condition for xpath that does not exist Karate

The karate.get() API will gracefully return null if an XPath does not exist. So this works:

* def xml1 = <root><one>1</one></root>
* def temp = karate.get('$xml1/root/one')
* def result = temp ? 'yes' : 'no'
* match result == 'yes'

* def xml2 = <root><two>2</two></root>
* def temp = karate.get('$xml2/root/one')
* def result = temp ? 'yes' : 'no'
* match result == 'no'

Now just use the techniques in the docs on conditional logic and you should be able to do what you want. One more thing, there is nothing wrong with calling a second (re-usable) feature file, it can make things simpler in some cases.

Nested conditional if else statements in xpath

I. In XPath 2.0 one simply translates this to:

   if(/*/propertyTypes/propertyType = 'RESIDENTIAL')
then
(if(/*/leasehold='Yes')
then 'Rent'
else 'Buy'
)
else
if(/*/leasehold='Yes')
then 'Leasehold'
else 'Freehold'

XSLT 2.0 - based verification:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:template match="/">
<xsl:sequence select=
"if(/*/propertyTypes/propertyType = 'RESIDENTIAL')
then
(if(/*/leasehold='Yes')
then 'Rent'
else 'Buy'
)
else
if(/*/leasehold='Yes')
then 'Leasehold'
else 'Freehold'
"/>
</xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<property id="1011">
<leasehold>No</leasehold>
<freehold>Yes</freehold>
<propertyTypes>
<propertyType>RESIDENTIAL</propertyType>
</propertyTypes>
</property>

the XPath expression is evaluated and the result of this evaluation is copied to the output:

Buy

II. XPath 1.0 solution

In XPath 1.0 there isn't an if operator.

A conditional statement can still be implemented with a single XPath 1.0 expression, but this is more tricky and the expression may not be too readable and understandable.

Here is a generic way (first proposed by Jeni Tennison) to produce $stringA when a condition $cond is true() and otherwise produce $stringB:

concat(substring($stringA, 1 div $cond), substring($stringB, 1 div not($cond)))

One of the main achivements of this formula is that it works for strings of any length and no lengths need to be specified.

Explanation:

Here we use the fact that by definition:

number(true()) = 1

and

number(false()) = 0

and that

1 div 0 = Infinity

So, if $cond is false, the first argument of concat() above is:

 substring($stringA, Infinity)

and this is the empty string, because $stringA has a finite length.

On the other side, if $cond is true() then the first argument of concat() above is:

sibstring($stringA, 1) 

that is just $stringA.

So, depending on the value of $cond only one of the two arguments of concat() above is a nonempty string (respectively $stringA or $stringB).

Applying this generic formula to the specific question, we can translate the first half of the big conditional expression into:

concat(
substring('rent',
1 div boolean(/*[leasehold='Yes'
and
propertyTypes/propertyType = 'RESIDENTIAL'
]
)
),
substring('buy',
1 div not(/*[leasehold='Yes'
and
propertyTypes/propertyType = 'RESIDENTIAL'
]
)
)
)

This should give you an idea how to translate the whole conditional expression into a single XPath 1.0 expression.

XSLT 1.0 - based verification:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:template match="/">
<xsl:copy-of select=
"concat(
substring('rent',
1 div boolean(/*[leasehold='Yes'
and
propertyTypes/propertyType = 'RESIDENTIAL'
]
)
),
substring('buy',
1 div not(/*[leasehold='Yes'
and
propertyTypes/propertyType = 'RESIDENTIAL'
]
)
)
)
"/>
</xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document (above), the XPath expression is evaluated and the result of this evaluation is copied to the output:

buy

Do note:

If you decide to replace the specific strings with other strings that have different lengths than the original, you simply replace these strings in the above XPath 1.0 expression and you don't have to worry about specifying any lengths.

xpath multiple condition and return root

If you want to get the foo elements, start the [] just after foo:

//foo[bar/test/@val='hello' and bar/new/@val='world']

If you want the children of foo, put the brackets there:

//foo/bar[test/@val='hello' and new/@val="world"]


Related Topics



Leave a reply



Submit