raheem.unr
raheem.unr

Reputation: 877

How to convert SOAP response to PHP Array?

I am unable to convert SOAP response to Array in php.

here is the code

 $response = $client->__doRequest($xmlRequest,$location,$action,1);

here is the SOAP response.

<soap:envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:body>
<searchflightavailability33response xmlns="http://FpwebBox.Fareportal.com/Gateway.asmx">
<searchflightavailability33result>
    &lt;Fareportal&gt;&lt;FpSearch_AirLowFaresRS&gt;&lt;CntKey&gt;1777f5a7-7824-46ce-a0f8-33d5e6e96816&lt;/CntKey&gt;&lt;Currency CurrencyCode="USD"/&gt;&lt;OriginDestinationOptions&gt;&lt;OutBoundOptions&gt;&lt;OutBoundOption segmentid="9W7008V21Feb14"&gt;&lt;FlightSegment etc....
    </searchflightavailability33result>
</searchflightavailability33response>
</soap:body>
</soap:envelope>;

i used the following ways to convert to Array,but i am getting empty output.

1.echo '<pre>';print_r($client__getLastResponse());
2.echo '<pre>';print_r($response->envelope->body->searchflightavailability33response);
3.echo '<pre>';print_r($client->SearchFlightAvailability33($response));
     4.simplexml_load_string($response,NULL,NULL,"http://schemas.xmlsoap.org/soap/envelope/");  

5.echo '<pre>';print_r($client->SearchFlightAvailability33($response));

please advice me.

Upvotes: 39

Views: 89678

Answers (10)

Lookson
Lookson

Reputation: 11

For anyone getting super angry and furious of making this soap xml import getting worked: I have done a solution making it as workarround and works with ALL kind xml files.

How it works:

  1. Import xml local file into a string.
  2. Cut all needed rows from string - for my purpose I needed all records starting as "ns25:Ntry" and ending as "</ns25:Ntry>" and saving it into array. So every ns56:Ntry record was in array as single row.
  3. Then when we have rows with ns25:Ntry data - we can cut from there any other needed data records (they are inside tags like for example <ns25:Amt Ccy="PLN">30</ns25:Amt>)

There is the code with needed instruction comments inside of it.

    #Provide XML file - $xmlfile is path to a file.
$xml_string = htmlspecialchars(file_get_contents($xmlFile));

#Function to cut whole xml into rows of data into array
function rozbierz_xml_pekao($od, $do, $string){
    $rekordy = array();
    $rozpoczecieTagu = $od;
    $rozpoczecieTagu = htmlspecialchars($rozpoczecieTagu);
    $zakonczenieTagu = $do;
    $zakonczenieTagu = htmlspecialchars($zakonczenieTagu);
    
    $rozpoczecieTaguDlugosc = strlen($rozpoczecieTagu);
    $zakonczenieTaguDlugosc = strlen($zakonczenieTagu);
    
    $poczatek = 0;
    
    while (($poczatek = strpos($string, $rozpoczecieTagu, $poczatek)) !== false) {
        $poczatek += $rozpoczecieTaguDlugosc;
        $koniec = strpos($string, $zakonczenieTagu, $poczatek);
    
        if ($koniec !== false) {
            $rekordy[] = substr($string, $poczatek, $koniec - $poczatek);
            $poczatek = $koniec + $zakonczenieTaguDlugosc;
        } else {
            break; 
        }
    }

    return $rekordy;
}

#Function to cut data from any single row
function wyciagnij_rekord_xml($od, $do, $string){
$rozpoczecieTagu = $od;
$rozpoczecieTagu = htmlspecialchars($rozpoczecieTagu);
$zakonczenieTagu = $do;
$zakonczenieTagu = htmlspecialchars($zakonczenieTagu);

$rozpoczecieTaguDlugosc = strlen($rozpoczecieTagu);
$zakonczenieTaguDlugosc = strlen($zakonczenieTagu);

$poczatek = 0;

$poczatek = strpos($string, $rozpoczecieTagu, $poczatek);

if ($poczatek !== false) {
    $poczatek += $rozpoczecieTaguDlugosc;
    $koniec = strpos($string, $zakonczenieTagu, $poczatek);

    if ($koniec !== false) {
        return substr($string, $poczatek, $koniec - $poczatek);
    } else {
        return null; 
    }
} else {
    return null; 
}
}

//Get all "Ntry" records into array.
$rekordy_raw = rozbierz_xml_pekao("<ns25:Ntry>", "</ns25:Ntry>", $xml_string);
$rekordy = array();

//For each record - cut any data from it closed into tags.
foreach($rekordy_raw as $single_rekord){
    //echo "Taking data from ROW: ".$single_rekord."<br><br>"; //Uncomment to see whole row
    $rekord_array['id'] = $id;
    $rekord_array['title'] = $title;
    $rekord_array['price'] = $price;

    echo "<pre>";
    print_r($rekord_array);
    echo "</pre>";
}

Thats all.

Upvotes: 1

falinhares
falinhares

Reputation: 11

Did a small change on one of the answers because my SOAP response has a s:Body and not a S:Body:

$response1 = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $response);
$xml = new SimpleXMLElement($response1);
$body = $xml->xpath('//sBody')[0];
$array = json_decode(json_encode((array)$body), TRUE); 
p_debug($array);

$myfile = fopen("req_resposta.xml", "w") or die("Unable to open file!");
fwrite($myfile, $response1);
fclose($myfile);

Upvotes: 0

Zain Ali
Zain Ali

Reputation: 11

in my case i used $body = $xml->xpath('//soapBody')[0];

$response = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $response);
$xml = new SimpleXMLElement($response);
$body = $xml->xpath('//SBody')[0];
$array = json_decode(json_encode((array)$body), TRUE);
print_r($array);

Upvotes: 1

Irshad Khan
Irshad Khan

Reputation: 6046

I found a perfect solution to parse SOAP response to an Array:

$plainXML = mungXML( trim($soapXML) );
$arrayResult = json_decode(json_encode(SimpleXML_Load_String($plainXML, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

print_r($arrayResult);


// FUNCTION TO MUNG THE XML SO WE DO NOT HAVE TO DEAL WITH NAMESPACE
function mungXML($xml)
{
    $obj = SimpleXML_Load_String($xml);
    if ($obj === FALSE) return $xml;

    // GET NAMESPACES, IF ANY
    $nss = $obj->getNamespaces(TRUE);
    if (empty($nss)) return $xml;

    // CHANGE ns: INTO ns_
    $nsm = array_keys($nss);
    foreach ($nsm as $key)
    {
        // A REGULAR EXPRESSION TO MUNG THE XML
        $rgx
        = '#'               // REGEX DELIMITER
        . '('               // GROUP PATTERN 1
        . '\<'              // LOCATE A LEFT WICKET
        . '/?'              // MAYBE FOLLOWED BY A SLASH
        . preg_quote($key)  // THE NAMESPACE
        . ')'               // END GROUP PATTERN
        . '('               // GROUP PATTERN 2
        . ':{1}'            // A COLON (EXACTLY ONE)
        . ')'               // END GROUP PATTERN
        . '#'               // REGEX DELIMITER
        ;
        // INSERT THE UNDERSCORE INTO THE TAG NAME
        $rep
        = '$1'          // BACKREFERENCE TO GROUP 1
        . '_'           // LITERAL UNDERSCORE IN PLACE OF GROUP 2
        ;
        // PERFORM THE REPLACEMENT
        $xml =  preg_replace($rgx, $rep, $xml);
    }

    return $xml;

} // End :: mungXML()

It will give you a perfect array of SOAP XML Data.

Upvotes: 53

ThW
ThW

Reputation: 19512

SOAP can be read as just XML but you should take the namespaces into consideration. This is not difficult with PHPs DOM. In your example the SOAP uses a namespace for the inner nodes and the {http://FpwebBox.Fareportal.com/Gateway.asmx}searchflightavailability33result element contains another XML document as text content.

$xml = <<<'XML'
<soap:envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:body>
<searchflightavailability33response xmlns="http://FpwebBox.Fareportal.com/Gateway.asmx">
<searchflightavailability33result>
    &lt;Fareportal&gt;&lt;FpSearch_AirLowFaresRS&gt;&lt;CntKey&gt;1777f5a7-7824-46ce-a0f8-33d5e6e96816&lt;/CntKey&gt;&lt;Currency CurrencyCode="USD"/&gt;&lt;/FpSearch_AirLowFaresRS&gt;&lt;/Fareportal&gt;
    </searchflightavailability33result>
</searchflightavailability33response>
</soap:body>
</soap:envelope>
XML;

// define a constant for the namespace URI
const XMLNS_FPW = 'http://FpwebBox.Fareportal.com/Gateway.asmx';

$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
// register a prefix for the namespace
$xpath->registerNamespace('fpw', XMLNS_FPW);

// read the result element text content
$result = $xpath->evaluate('string(//fpw:searchflightavailability33result)');
var_dump($result);

// load the result string as XML
$innerDocument = new DOMDocument();
$innerDocument->loadXML($result);
$innerXpath = new DOMXpath($innerDocument);

// read data from it
var_dump($innerXpath->evaluate('string(//CntKey)'));

Upvotes: 0

neurona.dev
neurona.dev

Reputation: 1407

The following SOAP response structure can be easily converted in an array using a combination of the previous methods. Using only the the function "simplexml_load_string" removing the colon ":" it returned null in some cases.

SOAP Response

<S:Envelope
    xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:transaccionResponse
            xmlns:ns2="http://ws.iatai.com/">
            <respuestaTransaccion>
                <idTransaccion>94567</idTransaccion>
                <referencia>3958</referencia>
                <idEstado>3</idEstado>
                <nombreEstado>Declinada</nombreEstado>
                <codigoRespuesta>202</codigoRespuesta>
                <valor>93815.0</valor>
                <iva>86815.0</iva>
                <baseDevolucion>0.0</baseDevolucion>
                <isoMoneda>COP</isoMoneda>
                <fechaProcesamiento>24-07-2015 12:18:40 PM</fechaProcesamiento>
                <mensaje>REJECT</mensaje>
                <tarjetaRespuesta>
                    <idFranquicia>1</idFranquicia>
                    <nombreFranquicia>VISA</nombreFranquicia>
                    <numeroBin>411111</numeroBin>
                    <numeroProducto>1111</numeroProducto>
                </tarjetaRespuesta>
                <procesadorRespuesta>
                    <idProcesador>3</idProcesador>
                </procesadorRespuesta>
            </respuestaTransaccion>
        </ns2:transaccionResponse>
    </S:Body>
</S:Envelope>

PHP conversion:

$response = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $response);
$xml = new SimpleXMLElement($response);
$body = $xml->xpath('//SBody')[0];
$array = json_decode(json_encode((array)$body), TRUE); 
print_r($array);

Result:

Array
(
    [ns2transaccionResponse] => Array
        (
            [respuestaTransaccion] => Array
                (
                    [idTransaccion] => 94567
                    [referencia] => 3958
                    [idEstado] => 3
                    [nombreEstado] => Declinada
                    [codigoRespuesta] => 202
                    [valor] => 93815.0
                    [iva] => 86815.0
                    [baseDevolucion] => 0.0
                    [isoMoneda] => COP
                    [fechaProcesamiento] => 24-07-2015 12:18:40 PM
                    [mensaje] => REJECT
                    [tarjetaRespuesta] => Array
                        (
                            [idFranquicia] => 1
                            [nombreFranquicia] => VISA
                            [numeroBin] => 411111
                            [numeroProducto] => 1111
                        )

                    [procesadorRespuesta] => Array
                        (
                            [idProcesador] => 3
                        )

                )

        )

)

Upvotes: 63

Aleli Sanchez Mendez
Aleli Sanchez Mendez

Reputation: 81

The second answer from @gtrujillos worked for me but with some changes, because the json string needs more formatting code in my case and the xPath needs to be in this way "//S:Body". This is the code that finally solve my problem. I toke the same SOAP Response example and the code for getting and returning a Soap response I found it here:

PHP convertion

//getting the Soap Response
header("Content-Type: text/xml\r\n");
ob_start();

$capturedData = fopen('php://input', 'rb');
$content = fread($capturedData, 5000);
fclose($capturedData);
ob_end_clean();

//getting the SimpleXMLElement object
$xml = new SimpleXMLElement($content);
$body = $xml->xpath('//S:Body')[0];

//transform to json
$json = json_encode((array)$body);

//Formatting the JSON
$json = str_replace(array("\n","\r","?"),"",$Json);
$json = preg_replace('/([{,]+)(\s*)([^"]+?)\s*:/','$1"$3":',$json);
$Json = preg_replace('/(,)\s*}$/','}',$json);

//Getting the array
$array=json_decode($Json,true);

//whatever yo need to do with the array ...

//Return a Soap Response
$returnedMsg=true;//this will depend of what do you need to return
print '<?xml version="1.0" encoding="UTF-8"?>
     <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>
     <notifications xmlns="http://soap.sforce.com/2005/09/outbound">
     <Ack>' . $returnedMsg . '</Ack>
     </notifications>
     </soapenv:Body>
     </soapenv:Envelope>';

Upvotes: 2

user2977753
user2977753

Reputation: 61

I got a single value using DOMDocument.

    $soap_response = $client->__getLastResponse();

    $dom_result = new DOMDocument;
    if (!$dom_result->loadXML($soap_response))
        throw new Exception(_('Error parsing response'), 11);

    $my_val = $dom_result->getElementsByTagName('my_node')->item(0)->nodeValue;

Upvotes: 4

Amuk Saxena
Amuk Saxena

Reputation: 1571

Php parse SOAP response to an array

 $xml = file_get_contents($response);

// SimpleXML seems to have problems with the colon ":" in the <xxx:yyy> response tags, so take them out
$xml = preg_replace(“/(<\/?)(\w+):([^>]*>)/”, “$1$2$3″, $xml);
$xml = simplexml_load_string($xml);
$json = json_encode($xml);
$responseArray = json_decode($json,true);

Upvotes: 9

raheem.unr
raheem.unr

Reputation: 877

finally i found the solution is

we can get body of the response from SOAP the following ways

example1:

$xml = new SimpleXMLElement($soapResponse);
foreach($xml->xpath('//soap:body') as $header) {
    $output = $header->registerXPathNamespace('default', 'http://FpwebBox.Fareportal.com/Gateway.asmx');    
}

example2:

$doc = new DOMDocument('1.0', 'utf-8');
    $doc->loadXML( $soapResponse );
    $XMLresults     = $doc->getElementsByTagName("SearchFlightAvailability33Response");
    $output = $XMLresults->item(0)->nodeValue;

Upvotes: 18

Related Questions