Solved

Reading XML embedded within SOAP response


Badge +1

Hi all,

Whilst I'm relatively familiar with the basic functionality of FME a recent project has required me to get involved with SOAP web services. Having read some of the online documentation I've managed to setup a work space to contact the web service and receive a response (using a Creator, XML Templater, HTTP Caller and XML Formatter).

I've successfully setup a work space to read in NHS local services and using the XML Fragmenter have exposed the attributes from the SOAP response under the ServiceTransferObject element.

The NHS the response was cleanly structured (example below):

...but the response from a 3rd party web service appears to be structured very differently. There are the expected Envelope and Body elements but the attributes I need to expose appear to be encoded within a single element, iData (example below):

Is anybody able to assist with being able to access the attributes held within the highlighted area of the above example (basically everything under the report element, about 40 attributes in total).

Many thanks

icon

Best answer by david_r 8 June 2017, 14:28

View original

7 replies

Userlevel 4

Just a tip: it's much easier for people here to help you out if you post code samples as text rather than as an image. That way it's possible to copy/paste the text into a workspace to experiment before answering.

That said, you can use the TextDecoder set to "XML" to decode the contents of the ax21:iData block back to proper XML, which you can then process further using e.g. the XMLFlattener etc.

Badge +1

Hi David, many thanks for the response.

Finally worked out that you have to use the 'code' option to insert XML text into a post!

Using the TextDecoder has been a step in the right direction but now I'm left with a file with two XML declarations (as shown in the example below);

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getReportsResponse xmlns:ns="http://client.abc">
<ns:return xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ax21="http://client.abc/xsd" xsi:type="ax21:Data">
<ax21:iData><?xml version="1.0" encoding="ISO-8859-1"?><reports anon_queue="abc_default_que"><report anon_report="N"><report_id>1274643</report_id><user_id>334263</user_id><cz_title></cz_title><cz_first_name>Darren</cz_first_name><cz_last_name>Fennell</cz_last_name><cz_email>darren.fennell@mydomain.co.uk</cz_email><cz_address><user_address1>Bodlondeb</user_address1><user_address2>Bangor Road</user_address2><user_city>Conwy</user_city><user_postcode>LL32 1DU</user_postcode><user_state>Wales</user_state><user_country>United Kingdom</user_country></cz_address></report></reports></ax21:iData>
<ax21:iDataLength>19774</ax21:iDataLength>
<ax21:iErrorMessage xsi:nil="true"></ax21:iErrorMessage>
<ax21:iWSCallId>7889149</ax21:iWSCallId>
</ns:return>
</ns:getReportsResponse>
</soapenv:Body>
</soapenv:Envelope>

I've tried passing this output into XMLFlattener and XMLFragmenter but both complain about the duplicate XML declarations.  I've also tried using XMLXQueryExtractor to try to ignore everything except those elements within the reports element but this also complains about the duplicate XML declarations.

Do you think that I could I carry out some manipulation on the original XML before I pass it through the TextDecoder (and before the second XML declaration was created) to isolate the contents of the iData element and then pass the response through the TextDecoder?

Many thanks

Userlevel 4

Maybe I should've been more clear, but I think you first have to extract the contents of ax21:iData into a separate attribute before decoding and then passing it on to the XMLFlattener etc. Otherwise you'll just end up with an invalid XML block, like the one you just posted.

Badge +1

Hi David,

Definitely getting somewhere now, I used the following XQuery expression to extract the contents of the iData element;

 

(: Query #1 :) declare namespace ax21="http://client.abc/xsd";

 

string(//ax21:iData)

Then used the TextDecoder to convert the encoded characters back into <, >, etc.

The result is passed into an XMLFragmenter and this appears to work well, exposing the XML elements as attributes until I get to child elements.  In the belowexample there is an element called <cz_address> and there are 6 child elements to this;

<cz_address>
<user_address1></user_address1>
<user_address2></user_address2>
<user_city></user_city>
<user_postcode></user_postcode>
<user_state></user_state>
<user_country></user_country>
</cz_address>

Do you know how I would expose these child elements as attributes?  I've tried the following as values for attributes to expose in the XMLFragmenter but none seem to work;

  • user_address1
  • cz_address_user_address1
  • cz_address/user_address1

Is this a matter of syntax or do I need to carry out an additional operation to flatten the child elements first?

Many thanks

Userlevel 4

I suspect that the attribute will be called something like

cz_address.user_address1

But I think the easiest way to check is send a representative feature to either the Data Inspector or the Logger, where the un-exposed attributes also will be visible. That way you'll see exactly what needs to be manually exposed in the workspace.

Badge +1

Hi David, cz_address.user_address1 was the syntax I needed, it's all working as I'd hoped now, many thanks for the help.

Userlevel 4

Hi David, cz_address.user_address1 was the syntax I needed, it's all working as I'd hoped now, many thanks for the help.

Great! Glad to hear it.

Reply