Verwerken van XML response vanuit SOAP request

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 volgende »

Johnny Cash

Johnny Cash

17/01/2019 17:44:54
Quote Anchor link
Beste programmeurs,

Als basic programmeur ben ik al 2 dagen bezig om een groot probleem op te lossen die waarschijnlijk heel simpel is voor de programmeur experts onder ons. Het volgende is er aan de hand.

Via onderstaand stukje script roep ik de status op van een bepaalde zending:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
$WebserviceClient = new SoapClient("http://xxx/App_Services/xxx.asmx?wsdl");
 $parameters= array("Username"=>$username, "Password"=>$password, "Zending"=>$zending, "Postcode"=>$postocde, "Referentie"=>$referentie);
 $WebmethodResult = $WebserviceClient->GetShipmentStatus($parameters) or die('FOUT!');


Als ik vervolgens via PRINT_R het resultaat in $WebmethodResult op het scherm toon krijg ik een response terug die begint met stdClass Object en daarna alle informatie over die bepaalde zending.

mijn print_r ziet er als volgt uit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
echo "<pre>";
  print_r($WebmethodResult);
echo "</pre>";


Als ik de BRONCODE van de code op het scherm bekijk zie ik veel code staan zoals
<MovementID>225362222</MovementID><ShipmentID>18815421</ShipmentID><CompanyID>985</CompanyID><MovementType>Afgeleverd</MovementType>

Mijn vraag is hoe ik met PHP de response ($WebmethodResult) uit de SOAP request kan benaderen zodat ik het MovementType element kan declareren in een variable waarna ik een if/else constructie kan maken zoals:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
if(MovementType=="Afgeleverd"){
 #mail versturen#
}else{
 #niets doen#
}


Ik hoop dat ik het probleem goed geschetst heb. Alle feedback is welkom.
Gewijzigd op 17/01/2019 17:50:15 door Johnny Cash
 
PHP hulp

PHP hulp

24/04/2019 18:58:38
Honeypot
 
Adoptive Solution

Adoptive Solution

17/01/2019 18:20:04
 
Johnny Cash

Johnny Cash

17/01/2019 21:52:04
Quote Anchor link
Ik heb dat stuk inderdaad ook gezien. Ik heb hetgeen proberen na te bootsen echter kwam ik niet verder. Op dit miment heeft het stuk wat k hierboven gepost heb het enige resultaar zonder errors. Ik ben dus opzoek naar een fuctie om die lange array uit te lezen en daaruit die specifiek venoemde varabele te halen...

Heb je misschien nog een andere tip naast die link.?

Toevoeging op 18/01/2019 10:11:20:

Beste Adoptive Solutions,

Ik heb zowel de voorbeelden uit Example #11 DOM Interoperability en ook #10 geprobeerd.
Geen van beiden geeft het gewenste resultaat.

Ik kreeg steeds de melding dat SimpleXMLElement of loadXML een String verwacht maar dat ik of een array of een object geef. Hoe kan ik dit nu converteren? I"m lost in deze bewerking.
 
Adoptive Solution

Adoptive Solution

18/01/2019 10:48:42
Quote Anchor link
Heb nog wat nagezocht.

Gebaseerd op :

https://stackoverflow.com/questions/4194489/how-to-parse-soap-xml

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
$xml
= '<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <PaymentNotification xmlns="http://apilistener.envoyservices.com">
            <payment>
                <uniqueReference>ESDEUR11039872</uniqueReference>      
                <epacsReference>74348dc0-cbf0-df11-b725-001ec9e61285</epacsReference>
                <postingDate>2019-01-05T15:19:45</postingDate>
                <bankCurrency>EUR</bankCurrency>
                <bankAmount>16.00</bankAmount>
                <appliedCurrency>EUR</appliedCurrency>
                <appliedAmount>1.00</appliedAmount>
                <countryCode>NL</countryCode>
                <bankInformation>Sean Wood</bankInformation>
                <merchantReference>ESDEUR11039872</merchantReference>
            </payment>
        </PaymentNotification>
        <PaymentNotification xmlns="http://apilistener.envoyservices.com">
            <payment>
                <uniqueReference>ESDEUR11040226</uniqueReference>      
                <epacsReference>74348dc0-cbf0-df11-b725-001ec9e61285</epacsReference>
                <postingDate>2019-01-15T15:19:45</postingDate>
                <bankCurrency>EUR</bankCurrency>
                <bankAmount>441.00</bankAmount>
                <appliedCurrency>EUR</appliedCurrency>
                <appliedAmount>1.00</appliedAmount>
                <countryCode>ES</countryCode>
                <bankInformation>Paul Newman</bankInformation>
                <merchantReference>ESDEUR11040226</merchantReference>
            </payment>
        </PaymentNotification>
    </soap:Body>
</soap:Envelope>'
;

$response = strtr( $xml, ['</soap:' => '</', '<soap:' => '<'] );
$output = json_decode( json_encode( simplexml_load_string( $response ) ) );
//var_dump($output->Body->PaymentNotification->payment);
echo '<pre>' . print_r( $output, TRUE ) . '</pre>';
?>


En deze :

https://stackoverflow.com/questions/21777075/how-to-convert-soap-response-to-php-array

Met dezelfde xml, maar nu als bestand.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php
$response
= file_get_contents( 'soap.xml' );
$xml      = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $response );
$xml      = simplexml_load_string($xml);
$json     = json_encode($xml);
$responseArray = json_decode($json,true);
echo '<pre>' . print_r( $responseArray, TRUE ) . '</pre>';
?>
 
Johnny Cash

Johnny Cash

18/01/2019 11:28:42
Quote Anchor link
Hallo Adoptive Solution,

Thank voor het zoekwerk. Echter ben ik deze beiden ook al tegengekomen.
Het issue is en blijft bij mij dat wanneer ik de examples verwerk in mijn kleine stukje script dat ik nog steeds de foutmeldingen blijf behouden van "function expect a string, object is given" of "expect a string, array is given".

Ik moet dus op één of andere manier de response die ik terug krijg omzetten naar een werkbaar XML bestand om daar vervolgens iets me te kunnen doen m.b.v. PHP.

Als ik de print_r functie gebruik voor de variabele "$WebmethodResult" dan krijg ik dit te zien op m'n scherm:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
stdClass Object
(
    [GetShipmentStatusResult] => stdClass Object
        (
            [schema] =>
            [any] => 18237412Laadscan depotP78RayonAfgeleverdA47Rayon AfgeleverdA47Rayon
        )

)
 
Adoptive Solution

Adoptive Solution

18/01/2019 12:24:32
Quote Anchor link
Op basis van je summiere info heb ik dit gebakken

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$xml
= '<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <GetShipmentStatusResult>
            <schema></schema>
            <any>18237412Laadscan depotP78RayonAfgeleverdA47Rayon AfgeleverdA47Rayon</any>
        </GetShipmentStatusResult>
    </soap:Body>
</soap:Envelope>'
;

$response = strtr( $xml, ['</soap:' => '</', '<soap:' => '<'] );
$output = json_decode( json_encode( simplexml_load_string( $response ) ) );
//var_dump($output->Body->PaymentNotification->payment);
echo '<pre>' . print_r( $output, TRUE ) . '</pre>';
$output = $output->Body;
echo $output->GetShipmentStatusResult->any . '<br />';
?>


xml kan je laten zien met deze regel
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
echo '<pre>' . htmlentities($xml) . '</pre>';
?>
 
Johnny Cash

Johnny Cash

18/01/2019 13:00:21
Quote Anchor link
Bedankt voor je snelle reacties. Nou vraag ik me dan toch één ding wel af.
Hoe vul ik de $xml variabele?

In jouw voorbeeld gaat je er vanuit dat ik deze $xml gevuld heb.
Echter is alleen de variabele $WebmethodResult gevuld met de response. En deze response laat hetgeen zien ik gepost heb om 11:28

Moet ik dan zeggen: $xml = $WebmethodResult; ??
Want dat krijg ik wederom dezelfde melding "... expects parameter 1 to be string, object given"
Gewijzigd op 18/01/2019 13:01:16 door Johnny Cash
 
Thomas van den Heuvel

Thomas van den Heuvel

18/01/2019 13:18:55
Quote Anchor link
Weet je zeker dat je niet ergens de tweede parameter van json_decode() mist, deze zou true moeten zijn. Dit zorgt ervoor dat objecten worden omgezet naar associatieve arrays.
 
Johnny Cash

Johnny Cash

18/01/2019 13:43:55
Quote Anchor link
Ik heb in een ander voorbeeld inderdaad ook iets geprobeerd met json_decode() waarbij de tweede parameter true was, maar ook daarbij krijg ik een foutmelding dat er een string wordt verwacht en niet een object of array.
 
Johnny Cash

Johnny Cash

21/01/2019 10:19:23
Quote Anchor link
Afgelopen weekend heb ik hier nog eens goed naar gekeken, maar ik krijg elke keer het stdClass Object terug met gegevens. Hoe kan ik deze nou uitlezen?
 
- Ariën -
Beheerder

- Ariën -

21/01/2019 12:50:20
Quote Anchor link
Maak er een array van door true mee te geven:

json_decode($json, true);
 
Johnny Cash

Johnny Cash

21/01/2019 13:09:00
Quote Anchor link
En dan bevat $json de waarden uit $WebmethodResult als ik het goed begrijp?
 
- Ariën -
Beheerder

- Ariën -

21/01/2019 13:42:12
Quote Anchor link
Ja
 
Johnny Cash

Johnny Cash

21/01/2019 14:06:15
Quote Anchor link
Hoe is het dan mogelijk dat ik de volgende foutmelding krijg bij deze functie:
Warning: json_decode() expects parameter 1 to be string, object given

$defarray = json_decode($WebmethodResult, true);

$WebmethodResult bestaat dus uit objecten welke ik niet kan decoden met json_decode($WebmethodResult, true);
 
- Ariën -
Beheerder

- Ariën -

21/01/2019 15:42:00
Quote Anchor link
$defarray = json_decode((array) $WebmethodResult, true);

Typecasting wilt soms wel eens een handje helpen.

Ik kwam ook dit tegen tijdens een zoektocht op internet:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
function object_to_array($data)
{
    if (is_array($data) || is_object($data))
    {
        $result = array();
        foreach ($data as $key => $value)
        {
            $result[$key] = object_to_array($value);
        }
        return $result;
    }
    return $data;
}
Gewijzigd op 21/01/2019 15:43:17 door - Ariën -
 
Johnny Cash

Johnny Cash

21/01/2019 16:08:08
Quote Anchor link
Thnx voor je reactie. Ik heb de code gebruikt zoals je hebt aangegeven. Maar zoals ik al verwachtte nu de volgende foutmelding:

Warning: json_decode() expects parameter 1 to be string, array given in....

Er wordt dus een string verwacht en niet een array of object.
De gedefinieerde functie object_to_array had ik inderdaad ook al geprobeerd.
Gewijzigd op 21/01/2019 16:09:21 door Johnny Cash
 
Thomas van den Heuvel

Thomas van den Heuvel

21/01/2019 17:18:00
Quote Anchor link
Laten we eens bij het begin beginnen.

In wezen doe je met $client->getShipmentStatus($parameters) een aanroep van __soapCall().

Hier staat (onder Return Values):
Quote:
On error, if the SoapClient object was constructed with the exceptions option set to FALSE, a SoapFault object will be returned.

Ik weet niet of dit de default is, maar ik denk wel dat je er verstandig aan doet om ofwel een try-catch mechanisme te gebruiken, ofwel te controleren of er fouten optreden middels is_soap_fault(), afhankelijk van wat je instelt via de exceptions optie. Ook lijkt het mij handig en verstandig zoveel mogelijk expliciet te configureren, zodat je ook zeker weet dat de code ook op een voorgeschreven manier werkt want defaults zijn immers niet altijd de default.

Vervolgens geeft getShipmentStatus() iets terug. De documentatie van soapCall zegt hierover:
Quote:
SOAP functions may return one, or multiple values. If only one value is returned by the SOAP function, the return value of __soapCall will be a simple value (e.g. an integer, a string, etc). If multiple values are returned, __soapCall will return an associative array of named output parameters.

Dus ik zou in eerste instantie een array verwachten. Maar jij zegt dat het een object is of zelfs XML. Wat is het nu? :p Heeft deze webservice ook een documentatie, staat daar in beschreven wat je terug kunt verwachten?

Maar het lijkt er dus op dat alles min of meer goed verloopt (foutafhandeling en configuratie daar gelaten) en je dus enkel een waarde ergens uit moet peuteren (een object? een lap XML? iets anders?), maar dat staat verder los van dit hele SOAP gebeuren lijkt mij.
Gewijzigd op 21/01/2019 17:19:00 door Thomas van den Heuvel
 
Johnny Cash

Johnny Cash

21/01/2019 17:42:52
Quote Anchor link
Bedankt Thomas voor het diepgaande antwoord.

De aanroep die ik doe geeft inderdaad een response terug.
Via onderstaande code toon ik op m'n scherm wat er terugkomt, namelijk:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
echo "<pre>";
  print_r($WebmethodResult);
echo "</pre>";


Op het scherm ziet dat er uit zoals:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
stdClass Object
(
    [GetShipmentStatusResult] => stdClass Object
        (
            [schema] =>
            [any] => 18237421 2019-01-15AfgeleverdA47Rayon
        )

)


Als ik naar de Broncode kijk van deze response die ik op het scherm krijg ziet dat er als volgt uit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<pre>stdClass Object
(
    [GetShipmentStatusResult] => stdClass Object
        (
            [schema] => <xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="NewDataSet"><xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true"> .....etc. etc..... </xs:schema>
            [any] => <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"><NewDataSet xmlns=""><Shipment diffgr:id="Shipment1" msdata:rowOrder="0"><ShipmentID>18237421</ShipmentID><Country>NL</Country><MovementType>Tijdvenster</MovementType><Code>00</Code>.....etc. etc.....</Shipment></NewDataSet></diffgr:diffgram>
        )

)
</pre>


Voor de toepassing die ik wil maken wil ik graag het element "MovementType" gaan uitlezen, omdat daarin een status wordt gegeven. Daarom moet ik dus op een correcte manier de variabele $WebmethodResult uitlezen in PHP.
 
Thomas van den Heuvel

Thomas van den Heuvel

21/01/2019 20:27:43
Quote Anchor link
Mja, maar daar zit dus blijkbaar geserialiseerde XML in, deze zou je dus apart moeten uitpakken. Dit ziet er een beetje onorthodox uit (misschien? heb hier verder weinig ervaring mee). Heb je documentatie die hier beweegredenen voor geeft of uitlegt hoe je hier data uit kunt peuteren?

Anyhow, het volgende lijkt ongeveer te doen wat jij wilt, bij wijze van proof of concept. Iets soortgelijks zou voor bovenstaande SOAP-response ook moeten werken:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
// zorg dat output goed geencodeerd is
header('Content-Type: text/html; charset=UTF-8');

// voor het melden+weergeven van foutmeldingen voor debugging
error_reporting(E_ALL);
ini_set('display_startup_errors', true);
ini_set('display_errors', 'stdout');

// hulpfunctie voor het (veilig) dumpen van data
function dump($in) {
    if (is_array($in)) {
        $in = print_r($in, true);
    }

    echo '<pre>'.escape($in).'</pre>';
}


// hulpfunctie voor het escapen van output
function escape($in) {
    return htmlspecialchars($in, ENT_QUOTES, 'UTF-8');
}


// Test case, bouw een soortgelijk genest object met hierin een XML-string
$wrapper = new StdClass();

$subObj = new StdClass();

$subObj->xml = '<root><data>hoi</data></root>';

$wrapper->sub = $subObj;

// zet objecten om naar (geneste) arrays
$response = json_decode(json_encode($wrapper), true);

// inspecteer output
dump($response);

// selecteer de XML-string
$xml = $response['sub']['xml'];

// creeer hiermee een SimpleXMLElement object
$data = simplexml_load_string($xml);

// converteer dit wederom naar (geneste) arrays
$dataArray = json_decode(json_encode($data), true);

// And Bob's your uncle
dump($dataArray);
?>
[end]

EDIT: als dat XML-ding onhandig in elkaar zit (met attributen enzo) dan zul je deze misschien wat verder uit elkaar moeten trekken m.b.v. SimpleXML, maar als je eenmaal het XML-deel bij zijn kladden hebt zou dat niet ingewikkeld moeten zijn.
Gewijzigd op 21/01/2019 22:46:24 door Thomas van den Heuvel
 
Johnny Cash

Johnny Cash

22/01/2019 10:49:27
Quote Anchor link
Bedankt Thomas, ik ben zeker wel een stukje verder op weg met dit concept.
Echter krijg ik wederom de volgende foutmelding:

simplexml_load_string() expects parameter 1 to be string, array given in

Op basis van jouw concept krijg ik het volgende op mijn scherm (output):

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Array
(
    [sub] => Array
        (
            [xml] => Array
                (
                    [GetShipmentStatusResult] => Array
                        (
                            [schema] => <xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="NewDataSet"> .... etc. etc. .... </xs:schema>
                            [any] => <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"><NewDataSet xmlns=""><Shipment diffgr:id="Shipment1" msdata:rowOrder="0"><ShipmentID>18237421</ShipmentID></Shipment></NewDataSet></diffgr:diffgram>
                        )

                )

        )

)


Echter krijg ik nog steeds geen echo van het element "ShipmentID" op m'n scherm op één of andere manier.
 
- Ariën -
Beheerder

- Ariën -

22/01/2019 11:00:44
Quote Anchor link
Dat moet je nog steeds extraheren uit je schema en any velden.
 

Pagina: 1 2 volgende »



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.