Append data dynamically to my xml SOAP message - python

I am calling an API by sending an xml request by doing a string formatting like this:
data = '''<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns2:MultiAvailabilityRequest xmlns:m="http://www.derbysoft.com/doorway" Password="CoolJoe" Token="{token}" UserName="CoolJoe">
<ns2:MultiAvailabilityCriteria NumberOfUnits="{units}">
<ns2:StayDateRange CheckIn="2016-05-02" CheckOut="2016-05-04"/>
<ns2:GuestCounts>
<ns2:GuestCount AdultCount="{adultcount}"/>
</ns2:GuestCounts>
<ns2:HotelCodes>
<ns2:HotelCode>{hotelcode}</ns2:HotelCode>
</ns2:HotelCodes>
</ns2:MultiAvailabilityCriteria>
</ns2::MultiAvailabilityRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'''.format(token=token, units=units, adultcount=adultcount, hotelcode=hotelcode)
The above code is working fine and getting the value of different hotelcodes, token etc and showing the results based on them.
But, I have one more different requirement where the hotelcodes could be more than 1 (either 2,3 or more). And, the required xml will look like this:
data = '''<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns2:MultiAvailabilityRequest xmlns:m="http://www.derbysoft.com/doorway" Password="CoolJoe" Token="{token}" UserName="CoolJoe">
<ns2:MultiAvailabilityCriteria NumberOfUnits="{units}">
<ns2:StayDateRange CheckIn="2016-05-02" CheckOut="2016-05-04"/>
<ns2:GuestCounts>
<ns2:GuestCount AdultCount="{adultcount}"/>
</ns2:GuestCounts>
<ns2:HotelCodes>
<ns2:HotelCode>{hotelcode1}</ns2:HotelCode>
<ns2:HotelCode>{hotelcode2}</ns2:HotelCode>
<ns2:HotelCode>{hotelcode3}</ns2:HotelCode>
</ns2:HotelCodes>
</ns2:MultiAvailabilityCriteria>
</ns2::MultiAvailabilityRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>'''.format(token=token, units=units, adultcount=adultcount)
So, my question is: how do I check whether two hotelcodes are present or more than two. As you can see from second xml for each hotel code, a new line like this adds up:
<ns2:HotelCode>{hotelcode1}</ns2:HotelCode>
Any help would be appreciated. Thanks.

Basically you should split the process in two parts:
fill in the hotel codes (doesn't really matter if it's one or more):
hotelcode_string =''.join(['<ns2:HotelCode>{hotelcode}</ns2:HotelCode>'.format(hotelcode=code) for code in set([item["hotelcode"] for item in hotelcode])])
put the hotel code section in the xml:
data = '''.... <ns2:HotelCodes>{hotelcode_string}</ns2:HotelCodes>
...'''.format(token=token, units=units, adultcount=adultcount,hotelcode_string=hotelcode_string)

Related

Get the http://tempuri.org/ node used in the latest SOAP request when using suds-py3

I am making a SOAP webcall using suds-py3. This issue here is that the namespace for http://tempuri.org/ keeps switching between 'ns0' to'ns1'.
So before I pass my xml parameters I want to know which abbrevation it is accepting at the moment 'ns0' or 'ns1'
What I plan is to create an exception deliberately and parse through the exception output to get the abbreviation it is expecting. Below is my code. This gives me proper exception but when I try to get it into a variable it is not helping, it just gives me the class.
from suds import WebFault
c = client.Client(wsdl_url)
try:
c.service.getcategorylist()
except WebFault:
x=repr(WebFault)
it prints out the below
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://tempuri.org/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns1:Body>
<ns0:getcategorylist/>
</ns1:Body>
</SOAP-ENV:Envelope>
but when i try to check what is in x, it give below
"<class 'suds.WebFault'>"
I need the SOAP request part into a variable, so that I can get out the namespace abbreviation for http://tempuri.org/ 'ns0'
Thanks for help.
Ok ,Have found a solution to this issue.
wsdl_url = 'https://..?wsdl'
c = client.Client(wsdl_url)
# call service without any parameters to get error
try:
c.service.getcategorylist()
except:
pass
# this will give the last call details
x = str(c.last_sent())
X will save the last call details as below
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://tempuri.org/" xmlns:SOAP-
NV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns1:Body>
<ns0:getcategorylist/>
</ns1:Body>
</SOAP-ENV:Envelope>
extract the currently used node abbreviation
ix = x.find('="http://tempuri.org/"')
node = x[ix - 3:ix]
Now node holds the latest node abbreviation 'ns0/ns1' and I use this throughout the other code to make real service requests

cant find specific node/element using python elementtree

I have the below XML document I am trying to parse. I just need to grab one node from the document. I need to get the serviceProfile text. I'm banging my head against the desk here... I am new to Python.
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getUserResponse
xmlns:ns="http://www.cisco.com/AXL/API/11.5">
<return>
<user uuid="{blbhbl-bhblb-kbhb}">
<firstName>fname</firstName>
<displayName>fname lname</displayName>
<middleName/>
<lastName>lname</lastName>
<userid>wooty</userid>
<password/>
<pin/>
<mailid>wooty#woot.com</mailid>
<department/>
<manager/>
<userLocale />
<associatedDevices/>
<primaryExtension/>
<associatedPc/>
<enableCti>false</enableCti>
<digestCredentials/>
<phoneProfiles/>
<defaultProfile/>
<presenceGroupName uuid="{sdsds-sdsds-sdsdsd-sdsdsd-sdsd}">Standard Presence group</presenceGroupName>
<subscribeCallingSearchSpaceName/>
<enableMobility>false</enableMobility>
<enableMobileVoiceAccess>false</enableMobileVoiceAccess>
<maxDeskPickupWaitTime>10000</maxDeskPickupWaitTime>
<remoteDestinationLimit>4</remoteDestinationLimit>
<associatedRemoteDestinationProfiles/>
<associatedTodAccess/>
<status>1</status>
<enableEmcc>false</enableEmcc>
<associatedCapfProfiles/>
<ctiControlledDeviceProfiles/>
<patternPrecedence />
<numericUserId />
<mlppPassword />
<customUserFields/>
<homeCluster>true</homeCluster>
<imAndPresenceEnable>true</imAndPresenceEnable>
<serviceProfile uuid="{dsdsdsd-sdsdsd-sdsd-sdsds-sdsds}">1 IM Presence Only</serviceProfile>
<lineAppearanceAssociationForPresences/>
<directoryUri>blah#wooty.com</directoryUri>
<telephoneNumber>555-555-5555</telephoneNumber>
<title/>
<mobileNumber/>
<homeNumber/>
<pagerNumber/>
<extensionsInfo/>
<selfService />
<userProfile/>
<calendarPresence>false</calendarPresence>
<ldapDirectoryName uuid="{sdsd-sdsdsd-sdsds-sdsds}">someinfo</ldapDirectoryName>
<userIdentity>blah#woot.com</userIdentity>
<nameDialing>blehWoot</nameDialing>
<ipccExtension/>
<convertUserAccount uuid="{sdsd-sdsdsd-sdsds-sdsds}">someinfo</convertUserAccount>
<enableUserToHostConferenceNow>false</enableUserToHostConferenceNow>
<attendeesAccessCode/>
</user>
</return>
</ns:getUserResponse>
</soapenv:Body>
</soapenv:Envelope>
Based on #danielHaley suggestions i created the following code to retrieve the node.
#read XML response and get service profile
tree = ET.ElementTree(ET.fromstring(response.content))
root = tree.getroot()
serviceprofile = root.find(".//serviceProfile").text
Worked great. thank you so much for your help.

Python Spyne custom output parameters

I need an output like this in Spyne:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<getActiveServicesResponse xmlns="http://mci.tajmi.ir/">
<getActiveServicesReturn>12345:2030:hafez poem:hafez </getActiveServicesReturn>
<getActiveServicesReturn>12346:2031:شعر طنز:tanz </getActiveServicesReturn>
<getActiveServicesReturn>bardari123:203861:سرویس بارداري :bar
</getActiveServicesReturn>
</getActiveServicesResponse>
</soapenv:Body>
</soapenv:Envelope>
What I can generate is
<?xml version='1.0' encoding='UTF-8'?>
<soap11env:Envelope xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://mci.tajmi.ir/">
<soap11env:Body>
<tns:getActiveServicesResponse>
<tns:getActiveServicesReturn>
<tns:string>12345:2030:hafez poem:hafez</tns:string>
<tns:string>12346:2031:شعر طنز:tanz </tns:string>
....
</tns:getActiveServicesReturn>
</tns:getActiveServicesResponse>
</soap11env:Body>
</soap11env:Envelope>
How can I customize the output? I tried complex methods without success.
have a look at my code at https://github.com/timi-ro/simulator. you can find how to make it. Also read it:
Spyne - how to duplicate one elements of wsdl file created by spyne?

Python suds XML element from nested complex type is not created in SOAP envelope

I'm having issues using suds-jurko (a fork of suds) to handle SOAP services and am running in some issues which seem related to the presence of nested complex types in the wsdl.
Here's the offending service as defined in the wsdl:
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="FormHandler" targetNamespace="http://grid.agnis.net/FormHandler">
<import namespace="http://security.introduce.cagrid.nci.nih.gov/ServiceSecurity" location="FormHandler?wsdl=ServiceSecurity.wsdl">
</import>
<types>
<schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://grid.agnis.net/FormHandler">
<import namespace="gme://forms.AGNIS/2.0/net.agnis.forms" schemaLocation="FormHandler?xsd=net.agnis.forms.xsd"/>
<element name="SubmitFormRevisionRequest">
<complexType>
<sequence>
<element name="formRevision">
<complexType>
<sequence>
<element maxOccurs="1" minOccurs="1" ref="ns0:FormRevision"/>
So there is basically a <ns0:FormRevision> element nested inside a <formRevision> (which is taken from the current namespace)
I should be getting this:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="gme://forms.AGNIS/2.0/net.agnis.forms" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://grid.agnis.net/FormHandler" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns1:Body>
<ns2:SubmitFormRevisionRequest>
<ns2:formRevision>
<ns0:FormRevision>
<ns0:form publicId="4637831" version="1.0">
<ns0:originator uniqueName="cibmtr_center_number:XXX"/>
</ns0:form>
But when I print out the envelope, I get the following output:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="gme://forms.AGNIS/2.0/net.agnis.forms" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://grid.agnis.net/FormHandler" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns1:Body>
<ns2:SubmitFormRevisionRequest>
<ns2:formRevision>
<form publicId="4637831" version="1.0">
<originator uniqueName="cibmtr_center_number:XXX"/>
</form>
Notice the missing <ns0:FormRevision> element ? (along with the namespaces :ns0 for the other elements)
Can anyone assist me in fixing this issue ?
Thanks !!
JP

How to extract xml from log file to parse in python

I have a log file containing xml envelopes (2 types of xml structures: request and response). What i need to do is to parse this file, extract xml-s and put them into 2 arrays as strings (1st array for requests and 2nd array for responses), so i can parse them later.
Any ideas how can i achieve this in python ?
Snippet of log file to be parsed (log contains ):
2014-10-31 12:27:33,600 INFO Recharger_MTelemedia2Channel [mbpa.module.mgw.mtelemedia.mtbilling.MTSender][] Sending BILL request
2014-10-31 12:27:33,601 INFO Recharger_MTelemedia2Channel [mbpa.module.mgw.mtelemedia.mtbilling.MTSender][] <?xml version="1.0" encoding="UTF-8"?>
<request xmlns="XXX" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<transactionheader>
<username>XXX</username>
<password>XXX</password>
<time>31/10/2014 12:27:33</time>
<clientreferencenumber>123</clientreferencenumber>
<numberrequests>3</numberrequests>
<information>Description</information>
<postbackurl>http://localhost/status</postbackurl>
</transactionheader>
<transactiondetails>
<items>
<item id="1" client="XXX1" keyword="test"/>
<item id="2" client="XXX2" keyword="test"/>
<item id="3" client="XXX3" keyword="test"/>
</items>
</transactiondetails>
</request>
2014-10-31 12:27:34,487 INFO Recharger_MTelemedia2Channel [mbpa.module.mgw.mtelemedia.mtbilling.MTSender][] Response code 200 for bill request
2014-10-31 12:27:34,489 INFO Recharger_MTelemedia2Channel [mbpa.module.mgw.mtelemedia.mtbilling.MTSender][] <?xml version="1.0" encoding="UTF-8"?>
<response xmlns="XXX" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<serverreferencenumber>XXX123XXX</serverreferencenumber>
<clientreferencenumber>123</clientreferencenumber>
<information>Queued for Processing</information>
<status>OK</status>
</response>
Many thanks for reply!
Regards,
Robert
As both #Paco and #Lord_Gestalter suggested, you can use xml.etree and replace the non-XML elements from your file, something like this:
# I use re to substitute non-XML elements
import re
# then use xml module as a parser
import xml.etree.ElementTree as ET
# read your file and store in string 's'
with open('yourfilehere','r') as f:
s = f.read()
# then remove non-XML element with re
# I also remove <?xml ...?> part as your file consists of multiple xml logs
s = re.sub(r'<\?xml.*?>', '', ''.join(re.findall(r'<.*>', s)))
# wrap your s with a root element
s = '<root>'+s+'</root>'
# parse s with ElementTree
tree = ET.fromstring(s)
tree
<Element 'root' at 0x7f2ab877e190>
if you don't care about xml parser and just want 'request' & 'response' string, use re.search
with open('yourfilehere','r') as f:
s = f.read()
# put the string of both request and response into 'req' and 'res'
# or you need to construct a better re.search if you have multiple requests, responses
req = [re.search(r'<request.*\/request>', s).group()]
res = [re.search(r'<response.*\/response>', s).group()]
req
['<request xmlns="XXX" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><transactionheader><username>XXX</username><password>XXX</password><time>31/10/2014 12:27:33</time><clientreferencenumber>123</clientreferencenumber><numberrequests>3</numberrequests><information>Description</information><postbackurl>http://localhost/status</postbackurl></transactionheader><transactiondetails><items><item id="1" client="XXX1" keyword="test"/><item id="2" client="XXX2" keyword="test"/><item id="3" client="XXX3" keyword="test"/></items></transactiondetails></request>']
res
['<response xmlns="XXX" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><serverreferencenumber>XXX123XXX</serverreferencenumber><clientreferencenumber>123</clientreferencenumber><information>Queued for Processing</information><status>OK</status></response>']

Categories

Resources