Forum Discussion
How to get data from a SOAP WS with Power BI
Hello,
I have an application with a SOAP wb and I want to create Dashboards using Power BI Desktop.
How do I get data using the SOAP wb ?
I know that Power BI has a REST API and it says that it helps you push data into power bi resource but in my case I have an external resource I have to connect to.
Thank you for your help.
Best regards.
Manal
61 Replies
- JasonL
Advocate II
Hi,
I think we found somehting :
we created an XML file (poste.xml) with the info for the SOAP web service :
then in the advanced editor of the query editor we add the path to the file :
let
Source = Xml.Tables(Web.Contents("URLofthewebservice",[Content=File.Contents("C:\Users\username\Desktop\XX\post.xml"),Headers=[#"Accept-Encoding"="gzip,deflate", SOAPAction="", #"Content-Type"="text/xml;charset=UTF-8"]])),previously we used "get data" --"web"---- URLofthewebservice. you drill down untill you get a table, you can either load or modify the query.
- dataloreous
Advocate III
Were you able to make this approach work? We are also trying to call and load the a SOAP response from PowerBI without sucess. I read through the other messages stating that SOAP is a dying technology - however we do not have control over the software providing the data.
- JasonL
Advocate II
Hello dataloreous,
Yes we got it to work. Yes soapy SOAP is old and we are also stuck in the past... the joys of working for the governement...
This being said :
- Our SOAP web service return an XML file and need a user and a PW and some other info to get the data we want.
- You need to start somewhere and get data : either with an XML file or with the web service's URL. (its doesnt has any importance because we just want to get to the query editor (Power Query)
- So we started to get data from an XML file because we already tested our web service with an other app and we got the XML it returns, so we loaded it. And drilled down till we get something to load/modify :
- As I said, you can simply load the web service URL and use "WEB" to get data. The goal is to load something then access the query editor and advanced editor.
- In the query editor, you accesse the advanced editor (sorry for my french):
- in the advanced editor you change your source to :
let
Source = Xml.Tables(Web.Contents("URLofTheWebService",[Content=File.Contents("D:\download\post.xml"),Headers=[#"Accept-Encoding"="gzip,deflate", SOAPAction="", #"Content-Type"="text/xml;charset=UTF-8"]])), - We use Xml.Tables because as I said our web service return an Xml and web.contents because we connect to a web service
- "D:\download\post.xml" is the path to the XML file where we have the credentials to connect to the web service, you have to call it in your query, here's an example of the file (made with SOAP UI open source) :
- The rest of the query code depends on the structur of your XML, here's what we have :
- Table = Source{0}[Table],
Table1 = Table{0}[Table],
Table2 = Table1{0}[Table],
Table3 = Table2{0}[Table],
Table4 = Table3{0}[Table],
#"Changed Type" = Table.TransformColumnTypes(Table4,{{"chaineXml", type text}, {"codeRetour", Int64.Type}, {"codeSysteme", type text}, {"messageRetour", type text}, {"nbrErreurs", Int64.Type}, {"noFormulaire", Int64.Type}, {"nomSysteme", type text}, {"version", Int64.Type}}),
chaineXml1 = #"Changed Type"{0}[chaineXml],
#"Parsed XML" = Xml.Tables(chaineXml1),
Table5 = #"Parsed XML"{0}[Table],
Table6 = Table5{0}[Table],
#"Expanded Namespace:" = Table.ExpandTableColumn(Table6, "Namespace:", {"column1", "column2", "columnXX"}, {"Namespace:.column1", "Namespace:.column2", "Namespace:.columnXX"}),
#"Expanded Namespace:.column1" = Table.ExpandTableColumn(#"Expanded Namespace:", "Namespace:.column1", {"column2", "column3", "columnXX""}, {"Namespace:.column1.column2", "Namespace:.column1.column3", "Namespace:.column1.columnXX"})
in
#"Expanded Namespace:.column1" - Our code is structured like that because the XML file we get has all the data as XML text in one feild so we have to parse de data and transform the XML string in a table
Hope this help!
Jason
- AnonymousNot applicable
Hi all,
I am getting the following error.
DataFormat.Error: Xml processing failed. Either the input is invalid or it isn't supported. (Internal error: The 'link' start tag on line 31 position 6 does not match the end tag of 'head'. Line 80, position 3.)
Details:
BinaryHere is my Advanced Editor code:
let Source = Xml.Tables(Web.Contents("https://sandbox......./", [Content=File.Contents("C:\Users\....\get_default.xml"),Headers=[Authorization="Bearer 34653fdsgfdsffd", #"Content-Type"="text/xml", SOAPAction="http://....../get.........Details"]])) in SourceHere is my Xml code:
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ins='http://beans....._v3'> <soapenv:Header/> <soapenv:Body> <ins:removedforprivacy> <startDate>2012-10-17</startDate> <endDate>2012-10-22</endDate> <pagingInfo> <pageNumber>0</pageNumber> <pageSize>5</pageSize> </pagingInfo> </ins:removedforprivacy>
</soapenv:Body>
</soapenv:Envelope>This code works in R using RCurl, I have also tried it with the addition of <?xml version="1.0"?> at the start. I also tried it using the Content=Text.ToBinary(".....").
Could the issue be with the file being returned?
Thank you
:)
Edit 1: grammar etc.
Edit 2: The issue was the the main url - the inititial url used to set up the web access and a secondary used in the advanced editor. This was followed up by another issue where the data would not be loaded out of the query editor... This was solved by making sure the page size fit the data limit.
- juliovidigal
Advocate I
Apparently it's a problem with the return, even by the mention of lines 31 and 80, and your call does not have that size.
- Greg_Deckler
Community Champion
Well, the world has kind of moved on from SOAP and to my knowledge there is not any SOAP accessor function in Power Query:
https://msdn.microsoft.com/en-us/library/mt296615.aspx
A couple thoughts I had, use an ODBC driver for SOAP such as here:
http://www.drdobbs.com/windows/odbc-driver-development/184416434
The other thought that I had was a SOAP to OData proxy but I really can't find one out there, all I could find was how to convert from SOAP to OData:
http://www.codeproject.com/Articles/590627/Converting-SOAP-based-WCF-Service-to-RESTful-Desig
On a personal note, I am not sorry to see SOAP go away, it was seemed like a terribly costly data protocol in terms of overhead and I always stuck with RESTful services. I have a general idea that my feelings were shared by the majority of people out there and hence why SOAP has largely gone away.
- ManalRegular Visitor
Thank you!
After some more researches I found this : https://www.dreamfactory.com/content/turn-soap-rest
It seems like DreamFactory can turn a SOAP into REST WS. I will test it and see if it does work for me.
- AnonymousNot applicable
Hi Manal,
I'am wondering if the DreamFactory approach worked? Cloud you share your experiences?
Greetings,
Ronald
- TahaSolutionsRegular Visitor
Any recommendation to parse XML query from a server? in my use case I should send date time range to the server and request back the data from the server.
- erickfranz
Advocate I
I use this query:
let
Source = Xml.Tables(Web.Contents("xxxxxxxxxxxx"
,[Content=File.Contents("xxxxxxx\post.xml"),Headers=[Authorization="Basic xxxxxxxxxxx" ,#"Accept-Encoding"="gzip,deflate", #"Content-Type"="text/xml;charset=UTF-8"]]))
in
SourceThe Authorization is OK. My post.xml is:
<soap:Envelope xmlns:urn="urn:sap-com:document:xxxxxxxx" xmlns:soap-envelope="http://www.w3.org/2003/05/soap-envelope" >
<soap:Header/>
<soap:Body>
<urn:ZimStockProl>
<IAlmacen>xx</IAlmacen>
<ICentro>xx</ICentro>
</urn:ZimStockProl>
</soap:Body>
</soap:Envelope>I try it in SOAPUI and is OK, but the result in Power BI is different:
I think It must be the dirección "urn"
- erickfranz
Advocate I
I use this query:
let
Source = Xml.Tables(Web.Contents("xxxxxxxxxxxx"
,[Content=File.Contents("xxxxxxx\post.xml"),Headers=[Authorization="Basic xxxxxxxxxxx" ,#"Accept-Encoding"="gzip,deflate", #"Content-Type"="text/xml;charset=UTF-8"]]))
in
SourceThe Authorization is OK. My post.xml is:
<soap:Envelope xmlns:urn="urn:sap-com:document:xxxxxxxx" xmlns:soap-envelope="http://www.w3.org/2003/05/soap-envelope" >
<soap:Header/>
<soap:Body>
<urn:ZimStockProl>
<IAlmacen>xx</IAlmacen>
<ICentro>xx</ICentro>
</urn:ZimStockProl>
</soap:Body>
</soap:Envelope>I try it in SOAPUI and is OK, but the result in Power BI is different:
I think It must be the dirección "urn"
- erickfranz
Advocate I
I use this query:
let
Source = Xml.Tables(Web.Contents("xxxxxxxxxxxx"
,[Content=File.Contents("xxxxxxx\post.xml"),Headers=[Authorization="Basic xxxxxxxxxxx" ,#"Accept-Encoding"="gzip,deflate", #"Content-Type"="text/xml;charset=UTF-8"]]))
in
SourceThe Authorization is OK. My post.xml is:
<soap:Envelope xmlns:urn="urn:sap-com:document:xxxxxxxx" xmlns:soap-envelope="http://www.w3.org/2003/05/soap-envelope" >
<soap:Header/>
<soap:Body>
<urn:ZimStockProl>
<IAlmacen>xx</IAlmacen>
<ICentro>xx</ICentro>
</urn:ZimStockProl>
</soap:Body>
</soap:Envelope>I try it in SOAPUI and is OK, but the result in Power BI is different:
I think It must be the dirección "urn"
- erickfranz
Advocate I
I use this query:
let
Source = Xml.Tables(Web.Contents("xxxxxxxxxxxx"
,[Content=File.Contents("xxxxxxx\post.xml"),Headers=[Authorization="Basic xxxxxxxxxxx" ,#"Accept-Encoding"="gzip,deflate", #"Content-Type"="text/xml;charset=UTF-8"]]))
in
SourceThe Authorization is OK. My post.xml is:
<soap:Envelope xmlns:urn="urn:sap-com:document:xxxxxxxx" xmlns:soap-envelope="http://www.w3.org/2003/05/soap-envelope" >
<soap:Header/>
<soap:Body>
<urn:ZimStockProl>
<IAlmacen>xx</IAlmacen>
<ICentro>xx</ICentro>
</urn:ZimStockProl>
</soap:Body>
</soap:Envelope>I try it in SOAPUI and is OK, but the result in Power BI is different:
I think It must be the dirección "urn"
- gregcdFrequent Visitor
Hi Eric, I think you need to expand the "table" in the results in order to see the results you are expecting.
- AnonymousNot applicable
I ve got the same issue
with the query:
let body="<soapenv:Envelope xmlns:soapenv=#(0022)http://schemas.xmlsoap.org/soap/envelope/#(0022) xmlns:csv=#(0022)http://www.csv.org#(0022)> <soapenv:Header/> <soapenv:Body> <csv:ReportTransactions> <csv:DateFrom>2020-01-01</csv:DateFrom> <csv:DateBy>2020-01-04</csv:DateBy> <csv:UNP>691759953</csv:UNP> </csv:ReportTransactions> </soapenv:Body> </soapenv:Envelope>", Source = Xml.Tables(Web.Contents("http://XXXXX.1cws?wsdl", [Content=Text.ToBinary(body), Headers =[ #"Authorization" = "basic XXXX", #"Accept-Encoding"= "gzip,deflate", #"User-Agent"= "Apache-HttpClient/4.1.1 (java 1.5)", //#"Content-Length"="360", //SOAPAction="#(0022)http://www.csv.org#JI_WScsv:ReportTransactions_DD#(0022)", #"Content-Type"="application/soap+xml;charset=UTF-8;action=#(0022)http://www.csv.org#JI_WScsv:ReportTransactions_DD#(0022)", #"Connection"="Keep-Alive"]])) in Sourceit works in SOAP UI
but it returns result like no parameters are posted to service. Expanding of these tables does not give needed result
fiddler's header after SOAP UI (when SOAP gives needed result)
Can anybody help whith it?
- AnonymousNot applicable
I have solved the problem
I needed in URL of WSDL - remove in the end "?wsdl"
let body="<soapenv:Envelope xmlns:soapenv=#(0022)http://schemas.xmlsoap.org/soap/envelope/#(0022) xmlns:csv=#(0022)http://www.csv.org#(0022)> <soapenv:Header/> <soapenv:Body> <csv:ReportTransactions> <csv:DateFrom>2020-01-01</csv:DateFrom> <csv:DateBy>2020-01-04</csv:DateBy> <csv:UNP>691759953</csv:UNP> </csv:ReportTransactions> </soapenv:Body> </soapenv:Envelope>", Source = Xml.Tables(Web.Contents("http://XXXXXXXXXXX/ws/ws_csv.1cws", // NOT http://XXXXXXXXXXX/ws/ws_csv.1cws?wsdl - // this ending ?WSDL stopped the recieving of the response! [Content=Text.ToBinary(body), Headers =[ #"Authorization" = "basic XXXXXXXXXX", #"Accept-Encoding"= "gzip,deflate", #"Content-Type"="text/xml;charset=UTF-8" ]])), Table = Source{1}[Table], Table1 = Table{0}[Table], Table2 = Table1{0}[Table] in
- AnonymousNot applicable
I gave up on extracting SOAP trough Power BI directly. I now use Python scripts and load the output of those into Power BI. The problem I ran into was pagination.
The main transaction table in my soap source is 1 million rows. But I can only request 5000 records of either a month or a week of a certain year at the same time. In Python it is very easy to make the request variable just by using SOAP wrappers available in the python repository. I couldn't figure out how to do it in Power BI.
In the Netherlands we have a some really popular webservices used by many small to medium companies but unfortunately some of the largest use the legacy SOAP.
- AnonymousNot applicable
Hi, It is possible to work around the pagenation issue with in power bi. However, I would suggest using R/python instead unless you have to do it only in Power BI.
- AnonymousNot applicable
I created an Idea in the Ideas section to add a fully featured webservice connector.
I think this is an area where Power BI can improve. It should be easier to connect to webservices and use common features used within them.
If you agree, please vote for the idea :)
- AnonymousNot applicable
After getting into it more and more I have to say its getting easier. I have been able to build functioning connectors on several SOAP webservices now thanks to the people in this thread, other threads and some hard trial and error.
Today I had a service that in a response gives only 100 records. You need to input:
- Mark (timestamp value from which timestamp onwards you want to receive)
The response gives:
- Data (100 records)
- Mark (Timestamp value)
- More (Whether more data is available)
The service will send the first 100 records that have never been seen before by me first if you use the correct mark. The correct mark is the mark used in the last response of the server. If you use the incorrect mark it will start sending all data never seen by me up untill the mark and all data after the mark regardless whether I have seen it or not.
I have been struggling all day to figure out a way to use the mark sent by the server in my next request and eval the more value in the response,
In below example, GetTraces(mark as text, customer as text, creds as text) is a function that collects a response from the server with a mark of a specific customer number, creds contains the basis authentication base encoded value,
This is what I came up with in the end to keep generating requests with the correct mark untill the more value is false:, may it help someone
a = List.Generate( () => [Page = GetTraces(mark, customer, creds)], each [Page]{0}[more] <> "false", each [Page = GetTraces([Page]{0}[mark], customer, creds)]I process the resulting list further into the correct table in the Power BI GUI and past the resulting code in my connector code.
- Yggdrasill
Responsive Resident
This thread is very useful.
My datasource requires my IP and gives me user and password in return.This is my code and it returns data and works.
let SourceURL = "url of wsdl", options = [ #"Authorization" ="Basic XXXX", #"Accept-Encoding"= "gzip,deflate", // SOAPAction="", #"Content-Type"="text/xml;charset=UTF-8", #"Connection"="Keep-Alive" ], WebContent = Web.Contents(SourceURL, [Content=Text.ToBinary(" <soapenv:Envelope xmlns:soapenv=#(0022)http://schemas.xmlsoap.org/soap/envelope/#(0022)
xmlns:v1=#(0022)Host URL#(0022)> <soapenv:Header/> <soapenv:Body> <v1:getAll> <!--Optional:--> <from>2018-10-10T00:00:00Z</from> <!--Optional:--> <to>2018-10-10T00:00:00Z</to> </v1:getAll> </soapenv:Body> </soapenv:Envelope> "), Headers=options]) , XmlContent = Xml.Tables(WebContent), Table = XmlContent{0}[Table], Table1 = Table{0}[Table], Table2 = Table1{0}[Table], Table3 = Table2{0}[Table], Table4 = Table3{0}[Table], in Table4I'm trying to pass a parameter to the date filters in the xml text.
Anyone having any luck with that ?
- Yggdrasill
Responsive Resident
I've edited my previous code so I can pass parameters to the xml
The SOAP service allows me to get maximum of 31 days of data. So I created a date parameter which I call StartingDate. Then I created a list of decimal parameter which I call Days
The date format is strictly put as YYYY-MM-DD
Then I add this code before I call the servicelet
//parameters Date2 = Date.AddDays(Date.From(#"StartingDate"), #"Days"), Year = Text.From(Date.Year(#"StartingDate")), Month= Text.From( if Text.Length(Number.ToText(Date.Month(#"StartingDate"))) = 1 then Text.Combine({"0",Number.ToText(Date.Month(#"StartingDate"))}, "") else Date.Month(#"StartingDate") ), Day = Text.From( if Text.Length(Number.ToText(Date.Day(#"StartingDate"))) = 1 then Text.Combine({"0",Number.ToText(Date.Day(#"StartingDate"))}, "") else Date.Day(#"StartingDate") ), Year2 = Text.From(Date.Year(Date2)), Month2= Text.From( if Text.Length(Number.ToText(Date.Month(Date2))) = 1 then Text.Combine({"0",Number.ToText(Date.Month(Date2))}, "") else Date.Month(Date.AddDays(Date.From(Date2))) ), Day2 = Text.From( if Text.Length(Number.ToText(Date.Day(Date2))) = 1 then Text.Combine({"0",Number.ToText(Date.Day(Date2))}, "") else Date.Day(Date2) ), //Create Date filters DateFrom = Text.Combine({Year,Month,Day}, "-") , DateTo = Text.Combine({Year2,Month2,Day2}, "-") ,And then when it gets to the XML i simply do this
WebContent = Web.Contents(SourceURL, [Content=Text.ToBinary(" <soapenv:Envelope xmlns:soapenv=#(0022)http://schemas.xmlsoap.org/soap/envelope/#(0022) xmlns:v1=#(0022)XXXXXXXXXX#(0022)> <soapenv:Header/> <soapenv:Body> <v1:getAllLandings> <!--Optional:--> <from>"&DateFrom&"</from> <!--Optional:--> <to>"&DateTo&"</to> </v1:getAllLandings> </soapenv:Body> </soapenv:Envelope> "),Hope this helps
- Jonas1
Helper I
Been trying what you recommend in this thread for quite osme time now, but I am getting "Can not approve with the given credentials. Try again" when I am trying to retrieve my session token. My credentials are given in the xml-file while the connection type has been set to anonymous, so this should not make sense right?
I use the following code in the query:
let Source = Xml.Tables(Web.Contents("https://xxx.xxxxx.com/wsapi/services/authentication?WSDL",[Content=File.Contents("xxxx\xxxxx\xxxxx.xml"), Headers=[#"Accept-Encoding"="gzip,deflate", #"Content-Type"="text/xml;charset=UTF-8"]])) in SourceWhile the xml-file is the login-request for the api, only returning my username and password when I import the file to Power Bi independently:
Can you see anything wrong I am doing? Could JasonL or juliovidigal have a quick look for instance?
- juliovidigal
Advocate I
Good afternoon.
Can not do everything inside the M? To test, instead of using the XML file?EX..
let
Source = Xml.Tables(Web.Contents("https://advertising.criteo.com/API/v201305/AdvertiserService.asmx?WSDL"
,[Content=Text.ToBinary("<soapenv:Envelope xmlns="&Character.FromNumber(34)&"https://advertising.criteo.com/API/v201305"&Character.FromNumber(34)&" xmlns:soapenv="&Character.FromNumber(34)&"http://schemas.xmlsoap.org/soap/envelope/"&Character.FromNumber(34)&">
<soapenv:Body>
<clientLogin>
<username>[email protected]</username>
<password>aaaaaaaa</password>
</clientLogin>
</soapenv:Body>
</soapenv:Envelope>"),Headers=[#"Accept-Encoding"="gzip,deflate", #"Content-Type"="text/xml;charset=UTF-8"]]))
in
Source
- Jonas1
Helper I
Thanks for replying juliovidigal .
Yes, I can try to do that. What is the logic behind Character.FromNumber(34)? Is this something from your XML-file, or do you havew to use this in your M in order to make the urls work?