Using SoapUI (great tool for WS by the way), I have the following xml result :
<code>c</code>
<code>b</code>
<code>a</code>
For this sample above, i would like to test the code value are order asc. Of course, for this sample the test will fail like excepted.
Any solution with xquery or xpath (i can use groovy inside the test if necessary)
Thanks in advance.
Use (XQuery or XPath 2.0):
not(code[. > following-sibling::code])
Two other ways:
empty(
for $x at $p in code
where ($x > code[$p + 1])
return $x
)
and
deep-equal(for $x in code order by $x return $x/data(.), code/data(.))
But Dimitre's answer seems the cleanest.
Related
I have a script where I have some if controllers. I'm attempting to add a 4th If controller that will trigger a script failure if none of the 3 expected values is returned. It's saying one of the 3 expected values is invalid.
1st, I have a user defined variable like this:
testTool= ${__P(testTool,APPLES)}
2nd, I have these 3 If controllers with these Expressions:
${__groovy(vars.get("testTool").toUpperCase().equals("APPLES"))}
${__groovy(vars.get("testTool").toUpperCase().equals("BANANAS"))}
${__groovy(vars.get("testTool").toUpperCase().equals("PEACHES"))}
The 4th If is supposed to be triggered if the value of testTool is not one of the 3 expected values. It's Expression looks like this:
> ${__groovy( (vars.get("testTool").toUpperCase().equals("APPLES") == false ||
> vars.get("testTool").toUpperCase().equals("BANANAS") == false ||
> vars.get("testTool").toUpperCase().equals("PEACHES") == false)) }
I have also tried it this way:
> ${__groovy((!vars.get("testTool").toUpperCase().equals("APPLES") ||
> !vars.get("testTool").toUpperCase().equals("BANANAS") ||
> !vars.get("testTool").toUpperCase().equals("PEACHES")),)}
It is somehow saying APPLES is an invalid testTool. What am I doing wrong? All if controllers have the 'Interpret Condition as Variable Expression' checked.
Use the following condition in if controller
${__groovy(!(vars.get("testTool").toUpperCase().equals("APPLES"))||!(vars.get("testTool").toUpperCase().equals("BANANAS"))||!(vars.get("testTool").toUpperCase().equals("PEACHES")))}
Please let me know if it helps
You should use && operator instead of ||, see Groovy Logical Operators for detailed explanation and more information.
Your 4th expression needs to be amended to look like:
${__groovy(!(vars.get("testTool").toUpperCase().equals("APPLES")) && !(vars.get("testTool").toUpperCase().equals("BANANAS")) && !(vars.get("testTool").toUpperCase().equals("PEACHES")))}
An easier option would be using Switch Controller, from implementation and especially performance perspectives it is the optimal solution.
Add Switch Controller to your Test Plan
Use ${testTool} as the "Switch Value"
Put 4 requests as the children of the Switch Controller and name them as:
APPLES
BANANAS
PEACHES
DEFAULT
So if ${testTool} variable value will be APPLES - the APPLES sampler will be executed, if ${testTool} variable value will be BANANAS - the BANANAS sampler will be executed, etc.
If ${testTool} will not match any other children - JMeter will run DEFAULT sampler
See Selection Statements in JMeter Made Easy guide for details.
I am new to XQuery. Can anyone explain how the debug process happens in XQuery?
For example, how to debug the below declaration:
declare
%rxq:produces('*/*')
%rxq:POST
%rxq:path('/sstatement/(Report)/([^/]+)')
function ReportSupplement(
$supplementType
, $submissionId
)
Please suggest any site for debugging XQuery.
Thanks in advance.
A typical way to debug queries in XQuery is to use the trace function around expressions of interest, like a call to the function above in your case.
For example:
for $i in trace(1 to 3, "s")
return <element>{$i * trace($i, "i") }</element>
and to read the output in a separate log, documented by your engine.
In this case, it will look like:
s[1]: 1
i[1]: 1
s[2]: 2
i[1]: 2
s[3]: 3
i[1]: 3
I'm trying to query an exist-db with xquery by taking parameters from the URL and building up seach parameters
xquery version "1.0";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace xs="http://www.w3.org/2001/XMLSchema";
declare option exist:serialize "method=xml media-type=text/xml omit-xml-declaration=no indent=yes";
let $param1:= request:get-parameter("param1",'0')
let $person :=
if($param1 = '0')
then "'*'"
else concat('contributions/person/#val="',$param1,'"')
return
<xml>
{
for $x in subsequence(//foo/bar[$person],1,3)
return $x
}
</xml>
The code above shows that I get the parameter from the url $param1.
variable $person checks to see if there was a parameter and based on that creates a query parameter. This variable works fine, from testing it prints out either '*' for no param or
contributions/person/#val='hello, world'
When I run the query it prints out as if the value is '*'. In the for $x part, can I pass a variable like that? I've tried putting concat($person,'') with the same results. Hardcoding the full path gives me the results I'm looking for, but I'm looking to create something more dynamic.
To note: there is only one variable, $person, but there will be others once I get it to work
I think ideally you would avoid dynamic string evaluation. In this example, some pretty simple reorganization would solve the problem without it:
<xml>
{
for $x in subsequence(//foo/bar[
if ($param1 = '0')
then *
else (contributions/person/#val = $param1)
],1,3)
return $x
}
</xml>
However, you can use eval(), but keep in mind there are security risks:
<xml>
{
for $x in subsequence(eval(
concat('//foo/bar[',$person,']')
),1,3)
return $x
}
</xml>
I have this property-transfer in SoapUI:
declare namespace soapEnv="http://schemas.xmlsoap.org/soap/envelope/";
//soapEnv:Body/LoginResponse/baseSequenceId
and lets say it returns 123456. But I want 123457 (what I get +1)
I tried this:
declare namespace soapEnv="http://schemas.xmlsoap.org/soap/envelope/";
//soapEnv:Body/LoginResponse/baseSequenceId + 1
but I get 123457.0 as a result. I tried some reformatting methods I found, but most possibly I did not use them in the correct way. I am quite new at this stuff.
I also tried this (with xquery):
declare namespace soapEnv="http://schemas.xmlsoap.org/soap/envelope/";
let $x := //soapEnv:Body/LoginResponse/baseSequenceId
return $x
and tried several things with $x but everything I tried ended up with null or InvocationTargetException.
Any help is appreciated !
Thanks a lot for your suggestions, although I couldn't make them work :(
Maybe there is something wrong with my SoapUI because all xpath functions return null..
I made it work with groovy:
groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
loginResponse = groovyUtils.getXmlHolder("Login#Response")
loginResponse.declareNamespace( "soapEnv", "http://schemas.xmlsoap.org/soap/envelope/" )
sessionIdStr = loginResponse.getNodeValue( "//soapEnv:Body/LoginResponse/sessionId" )
baseSequenceIdStr = loginResponse.getNodeValue( "//soapEnv:Body/LoginResponse/baseSequenceId" )
sequenceIdStr = (baseSequenceIdStr.toInteger() + 1).toString()
createRequest = groovyUtils.getXmlHolder("Create#Request")
createRequest.declareNamespace( "soapEnv", "http://schemas.xmlsoap.org/soap/envelope/" )
createRequest.setNodeValue( "//soapEnv:Header/SessionId", sessionIdStr )
createRequest.setNodeValue( "//soapEnv:Header/TransactionId", baseSequenceIdStr )
createRequest.setNodeValue( "//soapEnv:Header/SequenceId", sequenceIdStr )
createRequest.updateProperty()
Note that if the value of //soapEnv:Body/LoginResponse/baseSequenceId + 1 is an integer, XPath should not put in a decimal point when converting it to a string.
But maybe in this case XPath is returning a number, and it's SoapUI that's converting it to a string, and using a decimal point.
I would first try (updated):
string(//soapEnv:Body/LoginResponse/baseSequenceId + 1)
This is to force the conversion to string to happen within XPath, so that SoapUI won't have a chance to do anything funny with a numeric value.
Alternatively, you could try
floor(//soapEnv:Body/LoginResponse/baseSequenceId + 1)
or even
string(floor(...))
If that doesn't work, you could try
substring-before(//soapEnv:Body/LoginResponse/baseSequenceId + 1, '.')
It's not very elegant, but it might work.
Can I use an xpath query on a result already obtained using xpath?
In most hosting languages/environments (like XSLT, XQuery, DOM) you can. Don't know about PHP, but it would be strange if it doesn't allow this.
Of course, the result of the first query must be a node-set, in order for a future "/" operator to be possible/allowed/successful on it.
I have done it in PHP/SimpleXML. The thing that I didn't understand at first is that you're still dealing with the full SimpleXML object, so if you start with "/nodename", you're operating on root. If you start with "nodename" you are starting at the beginning of the result node. Here's my example:
$parsed=simplexml_load_string($XML);
$s = '/ItemSearchResponse/Items/Item';
$items = $parsed->xpath($s);
foreach($items as $item)
{
$s = 'ItemAttributes/Feature';
$features[]=$item->xpath($s);
$s = 'ASIN';
$asins[]=$item->xpath($s);
$s = 'ImageSets/ImageSet[#Category="primary"]';
$primary_img_set=$item->xpath($s);
$s = 'MediumImage/URL';
$medium_image_url[] = $primary_img_set[0]->xpath($s);
}
In PHP, for example, you can run a query with a context, i.e. a given node. So if you have got a DOMNodeList as a result of the first query you can do things like this:
$query1 = '//p';
$query2 = './a'; // do not forget the dot
$node = $xpath->query($query1)->item(0);
$result = $xpath->query($query2, $node);
Of course this is a silly example because it could have been done just in one shot with the correct XPath experssion but I believe it illustrates your question.