XPath search for existing value - xpath

I am having an issue where when I create a condition where a value could be present but doesn't exist, im unable to pull the data
For Example I would be wanting to pull all location numbers with valid location names
<bookstores>
<location>
<name>ABCBooks</name>
<locationtotals>100</locationtotals>
</location>
<location>
<name>GrandBooks</name>
<locationtotals>200</locationtotals>
</location>
<location>
<name/>
<locationtotals>150</locationtotals>
</location>
</bookstores>
This is the logic I have been attempting to use but it does not pull any content
sum(location[name != '']/locationtotals) where i would be expecting a value of 300 but it gets returned as 0, the level I have set to loop through is bookstores.
is there any logic to check if a value exists that i can put in my conditions rather than the [name != '']?
Thank you very much

From the question
"the level I have set to loop through is bookstores"
How are you setting the context and is bookstores really the context of the expression during your execution?
Modifying your expression slightly to account for the context such as:
sum(bookstores/location[name != '']/locationtotals)
or
sum(//location[name != '']/locationtotals)
gives the result you are looking for.

Thank you for all the help!
We were able to solve the issue because in my actual xml file I was calling the condition at the incorrect level, the levels had almost identical names and the level i was calling was the incorrect one.
This issue is cleared even thought this problem was false positive.

Related

Choosing specific element in XPath

I got 2 elements under the same name "reason". When i'm using //*:reason/text() it gives me both of the elements, but i need the first one. (not the one inside "details"). please help..
<xml xmlns:gob="http://osb.yes.co.il/GoblinAudit">
<fault>
<ctx:fault xmlns:ctx="http://www.bea.com/wli/sb/context">
<ctx:errorCode>BEA-382500</ctx:errorCode>
<ctx:reason>OSB Service Callout action received SOAP Fault response</ctx:reason>
<ctx:details>
<ns0:ReceivedFaultDetail xmlns:ns0="http://www.bea.com/wli/sb/stages/transform/config">
<ns0:faultcode xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">soapenv:Server</ns0:faultcode>
<ns0:faultstring>BEA-380001: Internal Server Error</ns0:faultstring>
<ns0:detail>
<con:fault xmlns:con="http://www.bea.com/wli/sb/context">
<con:errorCode>BEA-380001</con:errorCode>
<con:reason>Internal Server Error</con:reason>
<con:location>
<con:node>RouteTo_FinancialControllerBS</con:node>
<con:path>response-pipeline</con:path>
</con:location>
</con:fault>
</ns0:detail>
</ns0:ReceivedFaultDetail>
</ctx:details>
<ctx:location>
<ctx:node>PipelinePairNode2</ctx:node>
<ctx:pipeline>PipelinePairNode2_request</ctx:pipeline>
<ctx:stage>set maintain offer</ctx:stage>
<ctx:path>request-pipeline</ctx:path>
</ctx:location>
</ctx:fault>
</fault>
</xml>
You are using the // qualifier which will descend into any subtree and find all occurences of reason. You can try to be more specific about the subpath:
//fault/*:fault/*:reason/text()
This will only match the outer reason but not the inner reason..
"...but i need the first one"
You can use position index to get the first matched reason element :
(//*:reason)[1]/text()
" (not the one inside "details")"
The above can be expressed as finding reason element which doesn't have ancestor details :
//*:reason[not(ancestor::*:details)]/text()
For a large XML document, using more specific path i.e avoid // at the beginning, would results in a more efficient XPath :
/xml/fault/*:fault/*:reason/text()
But for a small XML, it's just a matter of personal preference, since the improvement is likely to be negligible.

JMeter does not replace ${SUBPANEL_RELATE_MODULE_g1} with its value

It's a long story, but I will try make it simple:
I generated MeterMaid XML files with SugarMMM; I chose only the Accounts module:
I converted above files to JMeter format with MeterMaid (I consolidated the tests into one file and named it "filename.xml"):
ruby GenMeter.rb --inputfile=filename.xml --outputfile=filename.jmx
I did the necessary CSV setup. All the CSV file contains is the login details (usr,pwd) for testing concurrent user logins. This part works well indeed.
When I run the test, I can see that a whole bunch of ${} variables are converted into corresponding values. Sadly, ${SUBPANEL_RELATE_MODULE_g1} doesn't get resolved... here's what the GET url (from View Results Tree Listener component) looks like:
http://localhost/sugarcrm/index.php?module=${SUBPANEL_RELATE_MODULE_g1}&action=Popup&hide_clear_button=true&mode=MultiSelect&create=true&metadata=undefined
Note that it's not the only variable that isn't resolved. The following screenshot shows the other tests that fail, all also caused by other variables not replaced by their corresponding values:
Here's how this variable is set up (which is well before the time it's used):
Here's what Debug Sampler says:
JMeterVariables:
CAMPAIGN_ID=CAMPAIGN_ID_ERROR
CAMPAIGN_NAME=CAMPAIGN_NAME_ERROR
CONTACT_ID=997a3171-aa60-b2d6-a457-4e0ba8b0052b
CONTACT_ID_g=4
CONTACT_ID_g0=onclick="send_back('Contacts','997a3171-aa60-b2d6-a457-4e0ba8b0052b');">Prof
CONTACT_ID_g1=onclick="send_back('Contacts','
CONTACT_ID_g2=997a3171-aa60-b2d6-a457-4e0ba8b0052b
CONTACT_ID_g3=');">
CONTACT_ID_g4=Prof
CONTACT_NAME=Prof
CONTACT_NAME_g=4
CONTACT_NAME_g0=onclick="send_back('Contacts','997a3171-aa60-b2d6-a457-4e0ba8b0052b');">Prof
CONTACT_NAME_g1=onclick="send_back('Contacts','
CONTACT_NAME_g2=997a3171-aa60-b2d6-a457-4e0ba8b0052b
CONTACT_NAME_g3=');">
CONTACT_NAME_g4=Prof
FOUND_ID=1
JMeterThread.last_sample_ok=true
JMeterThread.pack=org.apache.jmeter.threads.SamplePackage#3c1635
MEMBER_OF_ID=d7c26344-cad8-0503-b02a-4e0cb4db3985
MEMBER_OF_ID_g=4
MEMBER_OF_ID_g0=onclick="send_back('Accounts','d7c26344-cad8-0503-b02a-4e0cb4db3985');">searchSearchForm
MEMBER_OF_ID_g1=onclick="send_back('Accounts','
MEMBER_OF_ID_g2=d7c26344-cad8-0503-b02a-4e0cb4db3985
MEMBER_OF_ID_g3=');">
MEMBER_OF_ID_g4=searchSearchForm
MEMBER_OF_NAME=searchSearchForm
MEMBER_OF_NAME_g=4
MEMBER_OF_NAME_g0=onclick="send_back('Accounts','d7c26344-cad8-0503-b02a-4e0cb4db3985');">searchSearchForm
MEMBER_OF_NAME_g1=onclick="send_back('Accounts','
MEMBER_OF_NAME_g2=d7c26344-cad8-0503-b02a-4e0cb4db3985
MEMBER_OF_NAME_g3=');">
MEMBER_OF_NAME_g4=searchSearchForm
OPPORTUNITY_ID=864e402f-0d76-ab6e-b54f-4e0cb42f0249
OPPORTUNITY_ID_g=4
OPPORTUNITY_ID_g0=onclick="send_back('Opportunities','864e402f-0d76-ab6e-b54f-4e0cb42f0249');">value
OPPORTUNITY_ID_g1=onclick="send_back('Opportunities','
OPPORTUNITY_ID_g2=864e402f-0d76-ab6e-b54f-4e0cb42f0249
OPPORTUNITY_ID_g3=');">
OPPORTUNITY_ID_g4=value
OPPORTUNITY_NAME=value
OPPORTUNITY_NAME_g=4
OPPORTUNITY_NAME_g0=onclick="send_back('Opportunities','864e402f-0d76-ab6e-b54f-4e0cb42f0249');">value
OPPORTUNITY_NAME_g1=onclick="send_back('Opportunities','
OPPORTUNITY_NAME_g2=864e402f-0d76-ab6e-b54f-4e0cb42f0249
OPPORTUNITY_NAME_g3=');">
OPPORTUNITY_NAME_g4=value
RANDOM_CHAR=o
RANDOM_CHAR_g=1
RANDOM_CHAR_g0=o
RANDOM_CHAR_g1=o
RANDOM_STRING=value
RANDOM_STRING_g=1
RANDOM_STRING_g0=value
RANDOM_STRING_g1=value
RECORD_NAME=NOT_FOUND
RECORD_NUMBER=3250317d-6c79-b20d-5e36-4e0cb4746e84
RECORD_NUMBER_g=2
RECORD_NUMBER_g0=javascript:lvg_nav('Accounts', '3250317d-6c79-b20d-5e36-4e0cb4746e84
RECORD_NUMBER_g1=javascript:lvg_nav('Accounts', '
RECORD_NUMBER_g2=3250317d-6c79-b20d-5e36-4e0cb4746e84
SEARCH_FIELD=SEARCH_FIELD_ERROR
START.HMS=190308
START.MS=1309453388621
START.YMD=20110630
SUBPANEL_RELATE_MODULE=Accounts
TEAM_ID=seed-Teams8
TEAM_ID_g=4
TEAM_ID_g0=onclick="send_team_to_form('Teams','seed-Teams8');">Ball
TEAM_ID_g1=onclick="send_team_to_form('Teams','
TEAM_ID_g2=seed-Teams8
TEAM_ID_g3=');">
TEAM_ID_g4=Ball
TEAM_NAME=Ball
TEAM_NAME_g=4
TEAM_NAME_g0=onclick="send_team_to_form('Teams','seed-Teams8');">Ball
TEAM_NAME_g1=onclick="send_team_to_form('Teams','
TEAM_NAME_g2=seed-Teams8
TEAM_NAME_g3=');">
TEAM_NAME_g4=Ball
TESTSTART.MS=1309455500088
pwd=user1
usr=user1
UPDATE:
Here's after changing Template to $1$$2$$3$$4$:
And here's the Debug output (the Sampler is put just after regex Controller):
JMeterVariables:
JMeterThread.last_sample_ok=true
JMeterThread.pack=org.apache.jmeter.threads.SamplePackage#18fde89
RANDOM_CHAR=t
RANDOM_CHAR_g=1
RANDOM_CHAR_g0=t
RANDOM_CHAR_g1=t
RANDOM_STRING=Tanzania
RANDOM_STRING_g=1
RANDOM_STRING_g0=Tanzania
RANDOM_STRING_g1=Tanzania
RECORD_NAME=NOT_FOUND
RECORD_NUMBER=DOCTYPE
RECORD_NUMBER_g=1
RECORD_NUMBER_g0=DOCTYPE
RECORD_NUMBER_g1=DOCTYPE
START.HMS=100932
START.MS=1312531772599
START.YMD=20110805
SUBPANEL_RELATE_MODULE=Accounts
TESTSTART.MS=1312542237235
pwd=user1
usr=user1
Verify in your CSV dataset config, all variables are declared correctly (no typos, no omissions, no spaces before variable names, etc.)
I would also suggest putting a debug sampler high in your tree, as it will show you every variable and its value and can save a lot of time.
Edit:
It looks like your regex is setup incorrectly for creating multiple groups. If you look in your Debug sampler, you have SUBPANEL_RELATE_MODULE=Accounts but not SUBPANEL_RELATE_MODULE_g1= . This implies you don't have GROUPS setup.
In looking at your regex, the line template: $0$ is saying "only give me one group", whereas it looks like you want 4. Thus, you should try template: $1$$2$$3$$4$ the first match should be _g1 the second _g2 and so on. Check out the manual for details.
make judicious use of the ${SUBPANEL_RELATE_MODULE_g1} variable throughout the script after it gets defined by the Regular Expression Extractor. Verify it exists. Use it in Controller titles, test headings, at the beginning of tests, and at the end of tests.
That will help narrow it down
This way you can follow it along in the script to make sure it exists just before the moment it is used, and find where it's breaking down. Basically print statement debugging.
I don't know about sugar CRM or metermaid but for jmeter I had a similar problem with variable that were not resolve.
Check if this variable is declared somewhere or maybe you need to write a reg ex to extract that value from the previous request.
The problem I got It was that I extracted the variable from a CSV files
the variable name was CONTRACTNO, CLIENTNO
my URL : /SomeURL/bla?eventId=contractSelected&contractNoSelected=${CONTRACTNO}&applicationID=BLa
And it wasn't working so I changed the variable name in the csv file to :
CONTRACTNO,CLIENTNO (look that I removed a space)
Jmeter tend to be very picky with space in name and variable definition.
You are expecting the following values
${SUBPANEL_RELATE_MODULE_g1}
but you have configured the Regular Expression Extractor reference name as
"SUBPANEL_RELATE_MODULE"
There two options you can get the values
You have to change the ${SUBPANEL_RELATE_MODULE_g1} into ${SUBPANEL_RELATE_MODULE}
You have to change the Regular Expression Extractor reference name as "SUBPANEL_RELATE_MODULE _g1" to "SUBPANEL_RELATE_MODULE"
After this your values will be replaced properly.
It looks like your regular expression isn't picking up a match, your default value is set to "Accounts" and in your debug output that's the value of the variable. You'll only get match groups if the regular expression matches.
The View Results Tree listener now has a RegExp tester, so you can go to the request that you're trying to extract the variable SUBPANEL_RELATE_MODULE from the result in the results tree and choose RegExp Tester from the dropdown where it says "Text".
You can then run your regular expression on the response data in the RegExp tester and probably find that it doesn't match and then hone your regular expression so that it matches and update it in your Regular Expression Extractor.

bpws:getVariableData() causes fault if no xpath match is found

I wanted to use "bpws:getVariableData()" to assign a value only if the xpath expression find a match. If not, nothing should happen. Unfortunately the bpel processing stops with a fault, if the xpath expression finds no match. Is there a way to achieve this behavior?
Thanks for your help.
I found that the oracle BPEL engine provides a feature to ignore missing from data. This Flag can be added to the copy element as follows:
<copy bpelx:ignoreMissingFromData="yes|no"/>
More info on how to set it in the JDeveloper: http://download.oracle.com/docs/cd/E17904_01/integration.1111/e10224/bp_manipdoc.htm#SOASE87087
This solves the problem with the fault message that is thrown. However it still does not show the wanted behavior. My intension was that no assignment is done, if the xpath expression cannot be evaluated. Using the bpelx:ignoreMissingFromData flag however assigns the empty string "" to the target.
In my use case I want to merge tow XML documents. I want to assign a new value to an element in document1 only if the element shows up in document2. If not, leave the element in document1 unchanged.
I solved the problem using a transformation instead of a BPEL assign. In the xsl I use the following statement. The transformation gets two XML documents a input. Document1 is referenced via the parameter $parameter_referenceDocument1.
<elementName>
<xsl:if test="xpathInDocument2">
<xsl:value-of select="xpathInDocument2"/>
</xsl:if>
<xsl:if test="not(xpathInDocument2)">
<xsl:value-of select="$parameter_referenceDocument1.xpathInDocument1"/>
</xsl:if>
</elementName>
I know its ugly, but solves the problem. If anyone has a better solution, please let me know.
No, the BPEL standard requires the engine to throw a selectionFailure in this case. To avoid such situations, make sure you have properly initialized variables and/or validate variable against a schema. Also you may guard an assign activity with an if/switch activity to check for the presence of the element before accessing it. You may also consider writing an custom XPath function that returns a default value in case the demanded element does not exist in the variable. However, I'm not sure if the Oracle BPEL engine supports that.
You can create a scope around the assign activity and using an exception handler on the scope catch the selectionFailure, the item which will then carry on processing.
In the exception handler you could then assign a default value if required.
To clarify Vanto's statement, the Oracle BPEL engine does support custom XPath functions which would allow you to do that.

XPath check for non-existing node

Im having a bit of trouble finding the right XPath syntax to check if a particular node in my XML exists. I'm only allowed to use XPath (so no XSL or something else like that, it has to be a pure XPath expression syntax).
I have an XML and it has a node Filename but it doesn't exist in every case. When the filename isn't specified, my LiveCycle proces will use a different route to fill in the filename. But how do I check if the Filename node exists?
Similar to count but maybe more direct depending of what you want is the function boolean
boolean(//Filename)
This returns true if "Filename" node exist and false if not.
You can use the count function - passing in the path of the nodes you are checking.
If they do not exist, then the value of count will be 0:
count(//Filename) = 0
Suppose you have the following XML document:
<top>
<function>
<filenamex>c:\a\y\z\myFile.xml</filenamex>
<default>Default.xml</default>
</function>
</top>
then this XPath expression selects either the filename element when it's present or the default element when no filename element is specified:
(/*/function/filename
|
/*/function/default
)
[1]
The shortest way to check if the filename element exists is:
/*/function/filename
So the first XPath expression could be re-written in the equivalent (but somewhat longer):
/*/function/filename
|
/*/function/default[not(/*/function/filename)]
Given the example Xml from another answer
<top>
<function>
<filenamex>c:\a\y\z\myFile.xml</filenamex>
<default>Default.xml</default>
</function>
</top>
To get nodes WITH node "filenamex" use /top/function[filenamex]
To get nodes WITHOUT node "filenamex" use /top/function[not(filenamex)]
I felt it necessary to answer here as the other answers did not work as advertised in XmlSpy

Spark engine conditional test

We use spark to generate HTML-mails. When merging our data into the template I noticed a difference between
<if condition="Equals(#context.UserAccount.Country,'BE')">
<p>You live in Belgium</p>
</if>
<else>
<p>You don't live in Belgium</p>
</else>
and
<if condition="#context.UserAccount.Country == 'BE'">
<p>You live in Belgium</p>
</if>
<else>
<p>You don't live in Belgium</p>
</else>
When I pass in a UserAccount with country set to 'BE' the first one prints correctly 'You live in Belgium', the second one produces the incorrect result.
Can someone tell me why? Can you test on equality of strings without using Equals()?
So the code you posted throws a compiler error when I try to run it. However, the error I get explains why you're seeing different behavior. The error I get his this:
CS0252: Warning as Error: Possible unintended reference comparison;
to get a value comparison, cast the left hand side to type 'string'
Looking at the code that Spark generates, the error and behavior you're seeing makes a lot more sense. First piece of code generates the following comparison:
if (Equals(Eval("context.UserAccount.Country"),"BE"))
I'm pretty sure Eval returns something of type object (regardless of what the actual type of the variable is). Then the call to Equals is probably equivalent to doing this:
Eval("context.UserAccount.Country").Equals("BE")
which then uses the overloaded equals method on the string class (thank you polymorphism) which would return true. Where as the second case:
if (Eval("context.UserAccount.Country") == "BE")
probably just does a reference comparison between two objects, which returns false.
If you don't use the # before context.UserAccount.Country, Spark will generate the following code (notice the lack of call to Eval):
if (context.UserAccount.Country == "BE")
Assuming context has a UserAccount property, that has a Country property of type string then the expression should correctly evaluate to true when Country has the value of "BE".

Resources