Reputation: 3
I have this XML:
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>For input string: ""</faultstring>
<detail />
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
I want to get the content of Body > Fault > faultcode, faultstring
But I'm not getting the expected output with this code:
$xml = "\<?xml version='1.0' encoding='UTF-8'?\>\<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'\>\<soapenv:Body\>\<soapenv:Fault\>\<faultcode\>soapenv:Server\</faultcode\>\<faultstring\>For input string: '\</faultstring\>\<detail /\>\</soapenv:Fault\>\</soapenv:Body\>\</soapenv:Envelope\>";
$xmlObject = simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA);
$namespaces = $xmlObject->getNamespaces(true);
$body = $xmlObject->children($namespaces['soapenv'])->Body->Fault->faultcode;
dd($body);
output :
SimpleXMLElement {#1890}
Upvotes: 0
Views: 58
Reputation: 146588
There is no <faultcode>
in the soapenv
namespace so you need to switch namespaces:
$xmlObject->children($namespaces['soapenv'])->Body->Fault->children()->faultcode
Full working example (with damaged XML corrected):
$xml = "<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'>
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>For input string: '</faultstring>
<detail/>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>";
$xmlObject = simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA);
$namespaces = $xmlObject->getNamespaces(true);
$faultcode = $xmlObject->children($namespaces['soapenv'])->Body->Fault->children()->faultcode;
var_dump((string)$faultcode);
string(14) "soapenv:Server"
Demo.
To be fully correct, though, it's important to be aware that what really defines a namespace is the URI (http://schemas.xmlsoap.org/soap/envelope/
here). The prefix (soapenv
) can be changed locally, which is the whole point of having namespaces in the first place: to avoid name collisions. Having that into account, the namespace becomes hard-coded data:
$xml = "<?xml version='1.0' encoding='UTF-8'?>
<changedToIllustrateHowNamespacesWork:Envelope xmlns:changedToIllustrateHowNamespacesWork='http://schemas.xmlsoap.org/soap/envelope/'>
<changedToIllustrateHowNamespacesWork:Body>
<changedToIllustrateHowNamespacesWork:Fault>
<faultcode>changedToIllustrateHowNamespacesWork:Server</faultcode>
<faultstring>For input string: '</faultstring>
<detail/>
</changedToIllustrateHowNamespacesWork:Fault>
</changedToIllustrateHowNamespacesWork:Body>
</changedToIllustrateHowNamespacesWork:Envelope>";
const SOAPENV_NAMESPACE_URI = 'http://schemas.xmlsoap.org/soap/envelope/';
$xmlObject = simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA);
$faultcode = $xmlObject->children(SOAPENV_NAMESPACE_URI)->Body->Fault->children()->faultcode;
var_dump((string)$faultcode);
string(43) "changedToIllustrateHowNamespacesWork:Server"
Demo.
On a side note, there is a dedicated SOAP extension though, admittedly, it isn't as intuitive as it could. You use that extension to do the whole request and map results to PHP classes, and that way you don't need to parse responses manually.
Upvotes: 1
Reputation: 26
I think your mistake is how you get the "faultstring" property. Remember that you are setting the "soapenv" namespace and the "faultcode" property does not have this namespace. This is the example I was trying:
<?php
$xml = <<<XML
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'>
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>For input string</faultstring>
<detail />
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
XML;
$xmlObject = simplexml_load_string($xml);
$namespaces = $xmlObject->getNamespaces(true);
$body = $xmlObject->children($namespaces['soapenv'])->Body->Fault;
print_r($body->xpath('faultstring'));
This is the result: Screenshot of result
I also leave you an example of how I think it would be easier to obtain the value you need from the "faultstring" property:
<?php
try {
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
// Execute XPath query to get "faultstring" property value
$faultString = $xpath->evaluate('//soapenv:Fault/faultstring');
var_dump($faultString->item(0)->nodeValue);
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
This is the result: Screenshot of result
Upvotes: 1