PHP XML not parsing with SimpleXml [duplicate] - php

This question already has answers here:
Reference - How do I handle Namespaces (Tags and Attributes with a Colon in their Name) in SimpleXML?
(2 answers)
Closed 2 years ago.
my xml not parsing, i have no idea why
First line of xml not parsing, but second line parsing good
I know about im missings whatever in code, but searched in google and not find correct answer for it
// this xml not work, with <soap:Envelope> tags
$string = '<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetBrandsListResponse xmlns="http://tempuri.org/">
<GetBrandsListResult>
<DocumentElement>
<BrandLst>
<ID>1</ID>
<Name>Audi</Name>
</BrandLst>
<BrandLst>
<ID>350</ID>
<Name>BMW</Name>
</BrandLst>
</DocumentElement>
</GetBrandsListResult>
</GetBrandsListResponse>
</soap:Body>
</soap:Envelope>';
// but this xml works, without soap envelope tags
$string = '
<BrandLst>
<ID>1</ID>
<Name>Audi</Name>
</BrandLst>
';
$xml = simplexml_load_string($string);
var_dump($xml);

Fixed with adding xpath and registerXPathNamespace
$xml = simplexml_load_string($string);
$xml->registerXPathNamespace('default', 'http://tempuri.org/');
$auto = $xml->xpath("//default:BrandLst");

Related

simplexml_load_string always fails if there are special characters inside tags

I'm receiving from an external web service an XML like this(notice the colons inside the tags)
XML
<?xml version='1.0' encoding='UTF-8'?>
<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns0="http://webservice/CrsWSApi.wsdl/types/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<ns0:callwsapiResponseElement>
<ns0:result>
<ns0:object>BTS</ns0:object>
<ns0:receiver>BTSV45_ANSF_PROD-AKITT</ns0:receiver>
<ns0:sender>ANSFP</ns0:sender>
<ns0:data>
{"name":"Paolo", "cognome": Rossi, "data":"18/11/1983"}
</ns0:data>
<ns0:errormess xsi:nil="true"/>
<ns0:errorcode xsi:nil="true"/>
<ns0:status>1</ns0:status>
<ns0:sessionid>akit1</ns0:sessionid>
</ns0:result>
</ns0:callwsapiResponseElement>
</env:Body>
</env:Envelope>
if I use this function to parse it
PHP
$xml = simplexml_load_string($xml) or die("Error: Cannot create object");
I'm always receiving Error. If I remove the colons it works as expected. Is there a way to make this works without manipulating the colons before the xml parsing?
I want to avoid this manipulation
PHP
$xml = preg_replace(['/env:/','/:env(?!=)/','/ns0:/','/:ns0(?!=)/'], '', $myXMLData);
UPDATE
I already accepted a good answer that is reporting usefull links on how namespases are working in an xml environment, but I want to share another way to obtain the same result without parsing an xpath expression. We can you use the children method of simple_xml_loadstring specifiying the second parameter as a namespace.
fot the above code you can obtain the ns0:data content with this code(before you have to change the if statement as the accepted answer)
PHP
$xml = simplexml_load_string($response);
echo $xml
->children("env", true)
->Body
->children("ns0", true)
->callwsapiResponseElement
->result
->data;
// This will print
{"name":"Paolo", "cognome": Rossi, "data":"18/11/1983"}
For me it is very curious the return of simplexml_load_string (https://www.php.net/manual/en/function.simplexml-load-string.php):
This function may return Boolean false, but may also return a non-Boolean value which evaluates to false. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
And indeed if you replace the or die:
<?php
$response = <<<XML
<?xml version='1.0' encoding='UTF-8'?>
<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns0="http://webservice/CrsWSApi.wsdl/types/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<ns0:callwsapiResponseElement>
<ns0:result>
<ns0:object>BTS</ns0:object>
<ns0:receiver>BTSV45_ANSF_PROD-AKITT</ns0:receiver>
<ns0:sender>ANSFP</ns0:sender>
<ns0:data>
{"name":"Paolo", "cognome": Rossi, "data":"18/11/1983"}
</ns0:data>
<ns0:errormess xsi:nil="true"/>
<ns0:errorcode xsi:nil="true"/>
<ns0:status>1</ns0:status>
<ns0:sessionid>akit1</ns0:sessionid>
</ns0:result>
</ns0:callwsapiResponseElement>
</env:Body>
</env:Envelope>
XML;
$xml = simplexml_load_string($response);
if($xml===false){
die();
}
echo $xml->xpath("//*[local-name() = 'receiver']")[0];
Results:
BTSV45_ANSF_PROD-AKITT
You can then use the namespaces to find your data. This is a nice post Reference - How do I handle Namespaces (Tags and Attributes with a Colon in their Name) in SimpleXML?

simplexml_load_string asXML not empty, but children() function returns empty? [duplicate]

This question already has answers here:
SimpleXMLElement Access elements with namespace?
(4 answers)
Closed 1 year ago.
echo $xml->asXML();
Prints the following, and I am tring to access to elements here like: InvoiceStateResult
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soap:Header>
<wsa:Action>http://tempuri.org/SendEArchiveDataResponse</wsa:Action>
<wsa:MessageID>urn:uuid:72e8aaf0-b36d-422f-ab0b-486c17c50c83</wsa:MessageID>
<wsa:RelatesTo>urn:uuid:fc0a3e9d-40c1-4f3b-9517-8002825b7217</wsa:RelatesTo>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsse:Security>
<wsu:Timestamp wsu:Id="Timestamp-3a82271a-a910-4062-81aa-984468387047">
<wsu:Created>2021-05-28T12:12:23Z</wsu:Created>
<wsu:Expires>2021-05-28T12:27:23Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soap:Header>
<soap:Body>
<SendEArchiveDataResponse
xmlns="http://tempuri.org/">
<SendEArchiveDataResult>
<Invoices>
<InvoiceStateResult>
<ServiceResult>Error</ServiceResult>
<UUID>11111111-2222-3333-4444-555555555555</UUID>
<InvoiceId>T612014000000053</InvoiceId>
<StatusDescription>INVOICE EXISTS</StatusDescription>
<StatusCode>29</StatusCode>
<ErrorCode>0</ErrorCode>
<ReferenceNo>T612014000000053</ReferenceNo>
</InvoiceStateResult>
</Invoices>
<ServiceResult>Error</ServiceResult>
<ServiceResultDescription>This invoice processed before InvoiceId : TRL2021000000019 , UUID : DB3642EB-7A5F-40FD-8DF8-A922CA113837 SenderTaxID : 3324502175 . </ServiceResultDescription>
<Source>IntegrationWebService</Source>
<ErrorCode>30</ErrorCode>
<invoiceCount>1</invoiceCount>
</SendEArchiveDataResult>
</SendEArchiveDataResponse>
</soap:Body>
</soap:Envelope>
However I couldn't reach any of the nodes. I tried this:
foreach($xml->children() as $child) {
echo "Child node: " . $child . "</br>";
}
and it returns empty.
How will I access the nodes ?
Thanks
Simple XML, is - as the name suggests, a very simple implementation and it looks for standard namespaces. You can use registerXPathNamespace to look for non custom ones. See example below that works for your code.
$xml = simplexml_load_string($string);
$xml->registerXPathNamespace("soap", "http://www.w3.org/2003/05/soap-envelope");
print_r($xml->xpath('//soap:Body')[0]->SendEArchiveDataResponse->SendEArchiveDataResult->Invoices->InvoiceStateResult);

Reading Xml Nodes with PHP [duplicate]

This question already has answers here:
How do you parse and process HTML/XML in PHP?
(31 answers)
Closed 6 years ago.
I have a problem with PHP. I cannot read xml with PHP, and with SimpleXml.
How can I do.
My Xml files is below.
I just want your CompanyList.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soap:Header>
<wsa:Action>http://www.temp/Response</wsa:Action>
<wsa:MessageID>urn:uuid:eac190a5-c833-4dee-b4ef-fa81b0bad5c1</wsa:MessageID>
<wsa:RelatesTo>urn:uuid:834ace07-1e96-49d9-b958-3b2b87169917</wsa:RelatesTo>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsse:Security>
<wsu:Timestamp wsu:Id="Timestamp-55f3bafa-087a-4971-975d-a314957b4282">
<wsu:Created>2016-11-17T15:12:46Z</wsu:Created>
<wsu:Expires>2016-11-17T15:17:46Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soap:Header>
<soap:Body>
<ListResponse xmlns="http://fatura.edoksis.net">
<CompanyResult>
<Success>1</Sonuc>
<CompanyList>
<Company>
<Identifier>8380436088</Identifier>
<RegisterTime>2016-10-21T00:00:00Z</RegisterTime>
</Company>
<Company>
<Identifier>8380436088</Identifier>
<RegisterTime>2016-10-21T00:00:00Z</RegisterTime>
</Company>
</CompanyList>
</CompanyResult>
</CompanyResult>
</soap:Body>
</soap:Envelope>
$dom = new DOMDocument;
$dom->loadXML($response);
$books = $dom->getElementsByTagName('Identifier');
foreach ($books as $book) {
echo $book->nodeValue ."</br>";
}

Retrieving Specific Element Value XML - PHP [duplicate]

This question already has answers here:
How do you parse and process HTML/XML in PHP?
(31 answers)
Closed 8 years ago.
I have the following xml file:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:doTransactionResponse xmlns:ns2="http://soap.api.controller.web.payjar.com/">
<return>
<displayMessage>An error occurred with this payment, please contact your merchant (ref: P022)</displayMessage>
<merchantReference>mercRef_1350047403</merchantReference>
<payUReference>11999149347</payUReference>
<pointOfFailure>PAYU</pointOfFailure>
<resultCode>P022</resultCode>
<resultMessage>Transaction is not in the correct state - last transaction: FINALIZE state: SUCCESSFUL</resultMessage>
<successful>false</successful>
</return>
</ns2:doTransactionResponse>
</soap:Body>
</soap:Envelope>
I need to test the result code in the xml file against a series of codes. How would I get the specific element value of <resultCode> using PHP?
DOMDocument in combination with getElementsByTagName would be a quick solution.
DOMDocument::getElementsByTagName
$xml_string = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:doTransactionResponse xmlns:ns2="http://soap.api.controller.web.payjar.com/">
<return>
<displayMessage>An error occurred with this payment, please contact your merchant (ref: P022)</displayMessage>
<merchantReference>mercRef_1350047403</merchantReference>
<payUReference>11999149347</payUReference>
<pointOfFailure>PAYU</pointOfFailure>
<resultCode>P022</resultCode>
<resultMessage>Transaction is not in the correct state - last transaction: FINALIZE state: SUCCESSFUL</resultMessage>
<successful>false</successful>
</return>
</ns2:doTransactionResponse>
</soap:Body>
</soap:Envelope>';
$dom = new DOMDocument;
$dom->loadXML($xml_string);
$nodes = $dom->getElementsByTagName('resultCode');
foreach ($nodes as $node) {
echo $node->nodeValue;
}
Result: P022
Of course there are several other ways to work with XMLs in PHP (xpath etc.)
Using xpath. Here's the code as mentioned by KURN,
<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:doTransactionResponse
xmlns:ns2="http://soap.api.controller.web.payjar.com/">
<return>
<displayMessage>An error occurred with this payment, please contact
your merchant (ref: P022)</displayMessage>
<merchantReference>mercRef_1350047403</merchantReference>
<payUReference>11999149347</payUReference>
<pointOfFailure>PAYU</pointOfFailure>
<resultCode>P022</resultCode>
<resultMessage>Transaction is not in the correct state - last
transaction: FINALIZE state: SUCCESSFUL</resultMessage>
<successful>false</successful>
</return>
</ns2:doTransactionResponse>
</soap:Body>
</soap:Envelope>
';
$xml = simplexml_load_string($xml, NULL, NULL, "http://schemas.xmlsoap.org/soap/envelope/");
$xml->registerXPathNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
foreach($xml->xpath('//soapenv:Body') as $header)
{
$arr = $header->xpath('//resultCode'); // Should output 'something'.
$resultCode = $arr[0];
echo $resultCode;// outputs P022
}
?>
Actually this is quite easy with PHP:
$resultCode = simplexml_load_string($xml_string)->xpath('//resultCode')[0];
var_dump((string) $resultCode); // string(4) "P022"
Note that this code has no error checking, it might fatal-error in case the XML can not be loaded and warnings/notices if the element you're looking for does not exist at least once.

SoapClient XML return string with simpleXML

So I'm getting an xml file back from a soap service (of which I have no control over). It's returning back an xmlns which is causing simpleXML issues. I'm running a str_replace to get rid of that issue, however now simpleXML just returns an empty object. XML structure appears to be fine, no errors just an empty object.
$xmlString = $client->__getLastResponse();
$feed = str_replace(' xmlns="LMSWebservice"', '', $xmlString);
$sData= simplexml_load_string($feed);
print_r($sData);
Returns: SimpleXMLElement Object()
XML source before str replace is:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice">
<GetUserInternalIDByPersonalIDResult>
<Response xmlns="">
<Timestamp date="24/10/2013" time="04:27:37" />
<User>
<UserInternalID>4907</UserInternalID>
</User>
</Response>
</GetUserInternalIDByPersonalIDResult>
</GetUserInternalIDByPersonalIDResponse>
</soap:Body>
</soap:Envelope>
After str replace:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUserInternalIDByPersonalIDResponse>
<GetUserInternalIDByPersonalIDResult>
<Response xmlns="">
<Timestamp date="24/10/2013" time="04:27:37" />
<User>
<UserInternalID>4907</UserInternalID>
</User>
</Response>
</GetUserInternalIDByPersonalIDResult>
</GetUserInternalIDByPersonalIDResponse>
</soap:Body>
</soap:Envelope>
Any help would be greatly appreciated, this is driving me crazy!
----So if I don't get rid of the namespace attribute I get this error message:
Warning: simplexml_load_string() [function.simplexml-load-string]: Entity: line 1: parser warning : xmlns: URI LMSWebservice is not absolute in serviceTest2.php on line 16
Warning: simplexml_load_string() [function.simplexml-load-string]: LSchema"><soap:Body><GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice" in serviceTest2.php on line 16
Warning: simplexml_load_string() [function.simplexml-load-string]: ^ in serviceTest2.php on line 16
If I try using xPath to get at UserInternalID it returns an empty array. If what you're saying is correct and this is going into simpleXML correctly, then how do I access the UserInternalID node? Sorry, this is the first time using simpleXML and this is just perplexing me.
So just tried changing the NS
$feed = str_replace('xmlns="LMSWebservice"', 'xmlns="ns:LMSWebservice"', $xmlString);
which goes in without errors.
I tried this for the xPath
$ID = $sData->xpath('UserInternalID');
I understand this is probably completely wrong, but I haven't tried much else with this as it didn't seem to be going into simpleXML correctly in the first place. :/
So I've used
$ID = $sData->xpath('//UserInternalID');
echo $ID[0];
Which works perfectly. Thank you for all your help!
Through the extensive comments and your last edit finally the actual cause of your problem could be revealed, the xpath expression is wrong:
$ID = $sData->xpath('UserInternalID');
Wrong with it is the path, this matches no elements. Instead you could use:
$ID = (string) $xml->xpath('//UserInternalID')[0];
Or more verbose:
$ID = (string) $xml->xpath('//Response/User/UserInternalID')[0];
Key point here is that you write the correct path to the element you would like to query for.
Complete usage example:
<?php
/**
* SoapClient xml return string with simpleXML
*
* #link http://stackoverflow.com/q/19556414/367456
*/
$response = <<<RESPONSE
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUserInternalIDByPersonalIDResponse xmlns="LMSWebservice">
<GetUserInternalIDByPersonalIDResult>
<Response xmlns="">
<Timestamp date="24/10/2013" time="04:27:37" />
<User>
<UserInternalID>4907</UserInternalID>
</User>
</Response>
</GetUserInternalIDByPersonalIDResult>
</GetUserInternalIDByPersonalIDResponse>
</soap:Body>
</soap:Envelope>
RESPONSE;
$restore = libxml_use_internal_errors(TRUE);
$xml = simplexml_load_string($response);
libxml_use_internal_errors($restore);
echo $xml->xpath('//Response/User/UserInternalID')[0];
Output:
4907
Online Demo: https://eval.in/57149
$doc = new DOMDocument();
libxml_use_internal_errors(true);
$doc->loadHTML($response);
libxml_clear_errors();
$xml = $doc->saveXML($doc->documentElement);
$xml = simplexml_load_string($xml);
Use this helped me in a big way.

Categories