Questions about xPath structure with SoapUI and Property Transfer - some basics needed - xpath

I am now trying another xpath property transfer in SoapUI, and am struggling again.
Rather than specifics I thought I would ask some general questions.
If the response I am wanting to extract from has a line like this:
<ns2:getApprovedPortChangeRequestsResponse xmlns:ns2="http://transferobjects.abc.abc.org">
Oddly, when I click the ns: button in SoapUI it generates the following:
declare namespace soap='http://schemas.xmlsoap.org/soap/envelope/';
declare namespace ns1='http://transferobjects.abc.abc.org';
declare namespace ns2='http://abc.abc.org/api/serviceorder';
But the message response is pretty clear with the ns2 line above
Then I think that I can safely assume that I should do this:
declare namespace ns2='getApprovedPortChangeRequestsResponse';
Now, when I do the part describing what I want to capture, I am using the ns2 tag, following by the section names that follow as I go in to the message, in this case two layers:
//ns2:return/approvedPortChangeRequests/#version
The value I want is the value of the field called version, don't know if I want the # symbol this time, it's a numeric value, but I get null regardless of whether the # is there or not. I have thoroughly checked the response message and pretty certain I have it right. There are a couple of other sections in the response above the field, but they are at the same level as , from what I can see.
I have tried including the getApprovedPortChangeRequestsResponse as a parent layer in the last line, with no effect.
Only when I use getApprovedPortChangeRequestsResponse in the ns2 declaration can I get anything other than Null, and then only verbose errors like this:
[net.sf.saxon.trans.XPathException: XPath syntax error at char 7 on line 2 in {\n//ns2:/return}:
QName cannot end with colon: {ns2:}]
Basically, I am utterly ignorant and my googlefu hasn't shown me any resource where I can build any sort of understanding of what I am doing, so any suggestion on that front would be appreciated. I just need a couple of examples of doing this in SoapUI, and I should be sweet.
Thanks in advance.
EDIT- Full Response here:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getApprovedPortChangeRequestsResponse xmlns:ns2="http://transferobjects.abc.abc.org">
<return>
<success>true</success>
<approvedPortChangeRequests>
<lspOverride>false</lspOverride>
<numbers>
<complete>false</complete>
<gainingCompanyId>11667</gainingCompanyId>
<losingCompanyId>11657</losingCompanyId>
<notRequired>false</notRequired>
<phoneNumber>
<phoneNumber>098453509</phoneNumber>
</phoneNumber>
</numbers>
<DateTimeStart>2018-03-07T08:00:00+13:00</DateTimeStart>
<som>6001309</som>
<category>Simple</category>
<requestDateTime>2018-03-07T12:05:25+13:00</requestDateTime>
<requesterResellerId>21</requesterResellerId>
<responderResellerId>1</responderResellerId>
<responseDue>
<actualDays>0</actualDays>
<actualHours>1</actualHours>
<actualMinutes>47</actualMinutes>
<businessDays>0</businessDays>
<businessHours>1</businessHours>
<businessMinutes>47</businessMinutes>
<negative>false</negative>
</responseDue>
<status>
<status>Awaiting APC Approval</status>
</status>
<version>1</version>
</approvedPortChangeRequests>
</return>
</ns2:getApprovedPortChangeRequestsResponse>
</soap:Body>
</soap:Envelope>

In your payload, version is an element rather than an attribute, so you don't need the #.
soapUI tries to help you out by declaring namespaces, but you can go simpler. If version is all you need and there's only one, you can navigate directly to it regardless of namespaces by using //version. The // notation will select a node no matter where it is in the payload.

Related

Oracle Service Bus - Assign expression

I have this problem and I am not sure why it's happening and how to fix it. I have created an OSB peject. In the proxy service pipeline I am doing a Service Callout to a sync SOAP service in another application. The other service needs the request body as below:
<RequestSelectionValues xmlns="http://www.camstar.com/WebService/WSShopFloor">
<inputServiceData xmlns:q1="http://www.camstar.com/WebService/DataTypes" q1:type="OnlineQuery">
<OnlineQuerySetup>
<__CDOTypeName/>
<__name>xLot By FabLotNumber</__name>
</OnlineQuerySetup>
<Parameters>
<__listItem>
<Name>FabLotNumber</Name>
<DefaultValue>FAB_Lot_1</DefaultValue>
</__listItem>
<__listItem>
<Name>BLOCKOF200ROWS</Name>
<DefaultValue>1</DefaultValue>
</__listItem>
</Parameters>
</inputServiceData>
<queryOption xmlns:q2="http://www.camstar.com/WebService/DataTypes" q2:type="QueryOption">
<RowSetSize>1000</RowSetSize>
<StartRow>1</StartRow>
<QueryType>user</QueryType>
<ChangeCount>0</ChangeCount>
<RequestRecordCount>false</RequestRecordCount>
<RequestRecordSetAndCount>false</RequestRecordSetAndCount>
</queryOption>
<serviceInfo xmlns:q3="http://www.camstar.com/WebService/DataTypes" q3:type="OnlineQuery_Info">
<OnlineQuerySelection>
<RequestValue>false</RequestValue>
<RequestMetadata>false</RequestMetadata>
<RequestSubFieldValues>false</RequestSubFieldValues>
<RequestSelectionValues>true</RequestSelectionValues>
</OnlineQuerySelection>
</serviceInfo>
</RequestSelectionValues>
I am using an Assign to put the above expression in a variable.
Notice the line:
<serviceInfo xmlns:q3="http://www.camstar.com/WebService/DataTypes" q3:type="OnlineQuery_Info">
xmlns:q3="http://www.camstar.com/WebService/DataTypes" needs to be before q3:type="OnlineQuery_Info" for the other service to be called successfully otherwise the service call fails.
In the development it looks fine. I can test the assign of expression as well.
When I go to the OSB console to test the service I notice that in the Assign variable the namespace place switches and it becomes like this:
<serviceInfo q3:type="OnlineQuery_Info" xmlns:q3="http://www.camstar.com/WebService/DataTypes">
This makes the service calls to fail. I have tried putting the body payload in an xslt. Result is the same. I am not sure why it switches the type before namespace. The end result is that the service is not working as expected.
Any idea what I can do to fix this issue. How can I prevent the switching?
Thanks
I haven't found any settings in OSB that can prevent reordering of attributes for you. However, the above OSB behavior is completely XML standard compliant. In fact, the target service side should be XML compliant and treat the two variants mentioned above as the same, because according to XML standard, tow XML documents with only difference in attribute ordering should be treated as the same.
EDIT:
Please go here to download a modified config. My thoughts are:
Specify the business service to invoke in 'Text as Request' mode, as "CamstarLotQuery/business/CSWSShopFloor_Txt" shown below:
Manipulate messages as text, not XML, in your proxy service, as specified in "CamstarLotQuery/proxy/CamstarLotQueryTxt_Txt":
You might need to specify a SOAP Action in http header when calling a business service, depending on the target service.
One solution i can think of is to assign all the namespaces at the Parent Tag Level, and keep the attributes where they are applicable.
Example:
<RequestSelectionValues xmlns:q1="http://www.camstar.com/WebService/DataTypes" xmlns="http://www.camstar.com/WebService/WSShopFloor" xmlns:q2="http://www.camstar.com/WebService/DataTypes" xmlns:q3="http://www.camstar.com/WebService/DataTypes">
But the problem with this implementation is that since the namespace declaration is now Global, you have to declare your namespace prefixes (q1, q2, q3) to the blocks where the namespaces were previously defined.
Example:
<q3:serviceInfo q3:type="OnlineQuery_Info">
<q3:OnlineQuerySelection>
<q3:RequestValue>false</q3:RequestValue>
<q3:RequestMetadata>false</q3:RequestMetadata>
<q3:RequestSubFieldValues>false</q3:RequestSubFieldValues>
<q3:RequestSelectionValues>true</q3:RequestSelectionValues>
</q3:OnlineQuerySelection>
</q3:serviceInfo>
if this namespace prefix is not declared, then as per XML standards, the tag assume the 'default' namespace value - which will be the namespace of the parent.
However, even though this solution has a round-about way of implementation, this solution will definitely work.

How to Use Query_Match for Soap UI

I am having trouble using the MockOperation Editor in Soap UI.
I have got this request:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<methodName xmlns="http://tempuri.org/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<dataAreaId>error</dataAreaId>
<pInvoiceList>
<dataAreaId>NOTTHESAME</dataAreaId>
...
</pInvoiceList>
</methodName>
</s:Body>
</s:Envelope>
I tried almost every XPATH expression but I always get "Missing match in request"
What to fill in the Xpath box?
I tried:
//dataAreaId/text()
//dataAreaId/
//dataAreaId
/dataAreaId/text()
/dataAreaId
/methodName/dataAreaId/text()
/methodName/dataAreaId/
/methodName/dataAreaId
I finally managed to get it based on the answer from user1740631
Seems I it had to do with namespaces afterall.
The correct syntax:
declare namespace tem='http://tempuri.org/';
//tem:methodName/tem:dataAreaId[1]
If you don't care about namespaces you can use the following syntax:
XPath1.0
//*[local-name() = 'methodName']/*[local-name() = 'dataAreaId'][1]
XPath2.0
//*:methodName/*:dataAreaId[1]
Write like this
For First One
//methodName[1]/dataAreaId[1]
For Second one
//methodName[1]/pInvoiceList[1]/dataAreaId[1]
*If you have multiple node with same name in Xml then you should use numbers to locate that particular node.
There is a good hint: When defining an Assertion for a Testcase (or maybe also in the Mock-Window) there is a button "Declare" above the XPath-Expression-Field. It doesn't really look like a button, until you point with the mouse-pointer at it, so I didn't realize it at first.
Just click on the button an SoapUI (actually I use 5.2.1) will add the declare-statements for you, that you can use.
I found that feature coincidentally, as it is not really visible. Maybe this can help also...

SoapUI XPath assertion with wildcards

Is there a way to use a wildcard inside an assertion in a XPath test with SoapUI?
I took a look at SoapUI's documentation and they say you can do something like this
<path1>
<path2>*</path2>
</path1>
I checked the 'Allow Wildcards' checkbox.
My question is : I want to assert my date starts with 2012-08-22 but i dont care about the minutes and seconds. I guess my the expression should be something like 2012-08-22* but it doesn't work.
What you are doing sounds like it should work. Here is a quick example i cooked up using a rest service from http://www.geonames.org/export/web-services.html#timezone. I'm using the demo they have supplied
http://api.geonames.org/timezone?lat=47.01&lng=10.2&username=demo
output is
<geonames>
<timezone tzversion="tzdata2012c">
<countryCode>AT</countryCode>
<countryName>Austria</countryName>
<lat>47.01</lat>
<lng>10.2</lng>
<timezoneId>Europe/Vienna</timezoneId>
<dstOffset>2.0</dstOffset>
<gmtOffset>1.0</gmtOffset>
<rawOffset>1.0</rawOffset>
<time>2012-07-25 04:39</time>
<sunrise>2012-07-25 05:50</sunrise>
<sunset>2012-07-25 21:00</sunset>
</timezone>
</geonames>
If you do an xpath match on the result and use the select from current button you get
//geonames/timezone/time
2012-07-25 04:39
If you update this to
//geonames/timezone/time
2012-07-25*
this will work fine and when updating the rest request with a new lat and lng the assertion will still pass since it is not checking the time. If this doesn't help, please supply your full assertion and maybe i could help more.
*note: for soap requests, make sure to declare the namespace and then use the proper format
//ns1:message
It will be sort of a pain, but here is what you can do:
1) Figure out an Xpath 'base' using the assertion tab (sounds like you are here already). I used this public site to test against: http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl
I used the CornerPoints method with 'hawaii' as the single param.
I created this 'base' xpath:
declare namespace ns1='http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl';
declare namespace SOAP-ENC='http://schemas.xmlsoap.org/soap/encoding/';
declare namespace SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/';
/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:CornerPointsResponse/listLatLonOut
(it will write the declare statements for you if you click declare)
(which you can test out in the assertions window)
2) Create a Properties step
3) Create a Property transfer step
4) Create a groovy script
5) add a property... i called mine misc
6) add a transfer step
* transfer from the CornerPoints - Request 1 --- Response
* paste the Xpath stuff in the box under the 'transfer from'
* Transfer to your property
(You can test with the little play button)
7) Add something like this to your groovy script:
def x = context.expand( '${Properties#misc}' )
def parts = x.tokenize(',')
for (def part in parts)
{
log.info(part)
if (part.startsWith("-153"))
log.info("good")
}
In the groovy step you can do anything you need to get at your (partial) data. The sample code I added gets lat/lons out of a long line wrapped in CDATA and then checks for just the starting part of some of the data.. just an example.
Remember that you can use groovy and java string methods:
http://groovy.codehaus.org/groovy-jdk/java/lang/String.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html
More groovy tips:
http://www.soapui.org/Scripting-Properties/tips-a-tricks.html

Passing a blank XSD::QName using soap4r

I have overridden the SimpleHandler to pass a username and password using soap4r. the problem is that I am forced to give a QName, and this is causing the result to fail because it's not in the right format.
What soap4r is adding is something like this (the "ns1" things are dummy values):
<env:Header>
<n1:ns1 env:mustUnderstand="0"
xmlns:n1="ns1">
<n1:Username>someuser</n1:Username>
<n1:Password>topsecret</n1:Password>
</n1:ns1>
</env:Header>
What it needs to be is this:
<env:Header>
<n1:Username>someuser</n1:Username>
<n1:Password>topsecret</n1:Password>
</env:Header>
How can I NOT pass in a containing name?
Looks like you need to make some changes to soap4r: http://dev.ctor.org/soap4r/browser/branches/1_5/lib/soap/header/handler.rb
If the service isn't all that complicated you could try Handsoap
https://github.com/unwire/handsoap/wiki/authentication#WS-Security
Soap4R is quite picky about overriding headers. In your situation, you'll need to add two "flat" handlers (one for Username, and another for Password) instead of a single one with both.

SOAP::RPC::Driver formatting problems. How can I change it?

I'm dealing with a SOAP webservice call from a server that is expecting to receive method calls with the paramaters in the format of:
<urn:offeringId> 354 </urn:offeringId>
But SOAP::RPC::Driver is generating messages in the form of:
<offeringId xsi:type = "xsd:int">354</offeringId>
The server keeps erroring when it gets these messages (especially since it's expecting offeringId to be a custom type internal to itself, not an int).
Is there anyway to configure the driver to format things the way the server is expecting it. Is the server even doing SOAP? I'm having trouble finding reference to that style of formating for SOAP (I know it DOES work though, because SOAPUI works just fine with that type of message).
-Jenny
Edit: I've got at least part of it solved. the RPC::Driver (obviously) uses the RPC standard, whereas apparently the server I'm trying to talk to is doing "document". Now, when I look at RPC::Driver's API, I'm seeing a method named "add_document_method". That SOUNDS to me like it might be what I want, but I can't figure out what paramaters to give it. The examples I've seen around the net don't make much sense to me, things like:
def GetNamePair(response)
response.account.each do |x|
class << x
attr :configuration, true
end
x.configuration = Hash[*x.a.map do |y|
[y.__xmlattr[XSD::QName.new(nil, 'n')], String.new(y)]
end.flatten]
end
end
mNS = 'urn:zimbraAdmin'
drv.add_document_method('GetAllAdminAccountsRequest', mNS, [XSD::QName.new(mNS, 'GetAllAdminAccountsRequest')],
[XSD::QName.new(mNS, 'GetAllAdminAccountsResponse')] )
puts YAML.dump(GetNamePair(drv.GetAllAdminAccountsRequest([]))
All I really know is that I have a method that takes in certain parameters.... I really don't get why, if this method does what I think it does, it has to be more complicated. Isn't this just a matter of taking the exact same data and formating it differently? I'm so confused....
Okay, what I ended up doing was using SOAP:RPC:Drivers add_document_method, which requires me to give it the wsdl, namespace, etc, and then give it the attributes later as a single input hash thingy (and gives me the output in a similar format). It worked, it just wasn't as clean as add_rpc_method (which is waht add_method defaults to)
-Jenny

Resources