Getting Exception: String could not be parsed as XML when calling SimpleXMLElement - php

I am trying to parse this XML (http://numismatics.org/search/apis/getNuds?identifiers=1995.11.282) and pull out the elements under but when I call SimpleXMLElement I get: "Exception: String could not be parsed as XML" (the API is from http://numismatics.org/search/apis)
Here is what the XML basically looks like from the link above:
<nuds xmlns="http://nomisma.org/nuds" xmlns:mets="http://www.loc.gov/METS/" xmlns:tei="http://www.tei-c.org/ns/1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://nomisma.org/nuds http://nomisma.org/nuds.xsd" recordType="physical">
...deleted to shorten question
<digRep>
<mets:fileSec>
<mets:fileGrp USE="obverse">
<mets:file USE="iiif">
<mets:FLocat LOCYPE="URL" xlink:href="http://images.numismatics.org/collectionimages%2F19501999%2F1995%2F1995.11.282.obv.noscale.jpg"/>
</mets:file>
...deleted to shorten question
</mets:fileGrp>
</mets:fileSec>
</digRep>
</nuds>
Here is the test code I'm using from this example
$detail = simplexml_load_file("http://numismatics.org/search/apis/getNuds?identifiers=1995.11.282");
$digRep = new \SimpleXMLElement($detail->nuds->digRep); //the slash before the SimpleXMLElement is required for Laravel
$digRep->registerXPathNamespace('c', 'http://www.loc.gov/METS');
$result = $digRep->xpath('//c:mets:fileSec');
foreach ($result as $title) {
echo $title . "\n";
}
I am wondering if this has to do with "mets:fileSec" but I am not quite sure what "fileSec" is in this context.

mets is just the alias for the namespace http://www.loc.gov/METS/ (the xmlns:mets definition). This is perfectly fine XML and it parses in the browser if called directly. I suggest checking if you really can get the XML with PHP (with file_get_contents()) and not some error message. Services return sometimes different result for different user agents.

Related

Get Attribute value from Soap Response PHP

I am getting a soap response as expected and then converting to an array. Here is my code:
$response = $client->__getLastResponse();
$response = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $response);
$xml = new SimpleXMLElement($response);
$body = $xml->xpath('//soapBody')[0];
$array = json_decode( str_replace('#', '', json_encode((array)$body)), TRUE);
print_r($array);
here is the output:
Array (
[GetCompanyCodeResponse] => Array (
[GetCompanyCodeResult] => Array (
[Customers] => Array (
[Customer] => Array (
[attributes] => Array (
[CustomerNo] => 103987
[CustomerName] => epds api testers Inc
[ContactId] => 219196
)
)
)
)
)
How do i echo the ContactId? Ive tried the following:
$att = $array->attributes();
$array->attributes()->{'ContactId'};
print_r($array);
I get the following error:
Fatal error: Uncaught Error: Call to a member function attributes() on array
Also tried:
$array->Customer['CustomerId'];
I get following error:
Notice: Trying to get property 'Customer' of non-object
Expecting to get 219196
I found the solution to the above problem. Not sure if it is the most elegant way to do it, but it returns result as expected. If there is a more efficient way to get the ContactId, I am open to suggestions.
print_r($array['GetCompanyCodeResponse']['GetCompanyCodeResult']
['Customers']['Customer']['attributes']['ContactId']);
You have followed some very bad advice on how to parse the XML, and completely thrown away the functionality of SimpleXML.
Specifically, the reason you can't run the attributes() method is that you've converted the SimpleXML object to a plain array using this ugly hack:
$array = json_decode( str_replace('#', '', json_encode((array)$body)), TRUE);
To use SimpleXML as its authors intended, I suggest you read:
The examples in the PHP manual
This reference answer on handling XML namespaces
Since you didn't paste the actual XML in the question, I'm going to take a guess that it looks like this:
<?xml version = "1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope">
<soap:Body xmlns="http://www.example.org/companyInfo">
<GetCompanyCodeResponse>
<GetCompanyCodeResult>
<Customers>
<Customer CustomerNo="103987" CustomerName="epds api testers Inc" ContactId="219196" />
</Customers>
</GetCompanyCodeResult>
</GetCompanyCodeResponse>
</soap:Body>
</soap:Envelope>
If that is in $response, we don't need to do any weirdness with str_replace or json_encode, we can use the methods built into SimpleXML to navigate around the XML:
$xml = new SimpleXMLElement($response);
// The Body is in the SOAP Envelope namespace
$body = $xml->children('http://www.w3.org/2001/12/soap-envelope')->Body;
// The element inside that is in some other namespace
$innerResponse = $body->children('http://www.example.org/companyInfo')->GetCompanyCodeResponse;
// We need to traverse the XML to get to the node we're interested in
$customer = $innerResponse->GetCompanyCodeResult->Customers->Customer;
// Unprefixed attributes aren't technically in any namespace (an oddity in the XML namespace spec!)
$attributes = $customer->attributes(null);
// Here's the value you were looking for
echo $attributes['ContactId'];
Unlike your previous code, this won't break if:
The server starts using a different local prefix instead of soap:, or adding a prefix on the GetCompanyCodeResponse element
The response comes back with more than one Customer (the ->Customer always means the same as ->Customer[0], the first child element with that name)
The Customer element has child elements or text content as well as attributes
It also allows you to use other features of SimpleXML, like using an xpath expression to search the document or even switching to the full DOM API for more complex operations.

simplexml_load_string is stripping data out of soap response

So i am hitting a soap service, when i get the data and parse it through simplexml_load_string in order to access the data as an object (or just basically access the data) simplexml_load_string seems to strip it out.
A Raw response from soap service looks like:
A result parsed through simplexml_load_string
using the following code:
$result = simplexml_load_string((string)$result->DisplayCategoriesResult->any);
i get a result of:
this looks correct but at a closer look you will notice its just id's and the names of the categories are left behing simplexml_load_string
how can i manage to get the proper result? if there is another way of getting the raw data into a "usable" form or object that solution is also welcome
The text content of XML nodes doesn't show up when using print_r or var_dump, etc. They aren't "traditional" PHP objects, so you can't use the standard debugging options.
To access the text content (whether embedded as CDATA or otherwise), you need to step down into the child elements, and then cast them to strings:
<?php
$xml = <<<XML
<randgo xmlns="">
<status>0</status>
<message>Success</message>
<categories>
<category id="53"><![CDATA[go eat]]></category>
<category id="54"><![CDATA[go do]]></category>
<category id="55"><![CDATA[go out]]></category>
</categories>
</randgo>
XML;
$sxml = simplexml_load_string($xml);
foreach ($sxml->categories->category as $category)
{
echo $category['id'] . ": " . (string) $category, PHP_EOL;
}
=
$ php simplexml_categories.php
53: go eat
54: go do
55: go out
See: https://eval.in/590975
(Sorry if there are any typos in the XML, I think I copied from the screenshot correctly...)
The category names are CDATA. Try something like this to read it.
$doc = new DOMDocument();
$doc->load((string)$result->DisplayCategoriesResult->any);
$categories = $doc->getElementsByTagName("categories");
foreach ($categories as $categorie) {
foreach($categorie->childNodes as $child) {
if ($child->nodeType == XML_CDATA_SECTION_NODE) {
echo $child->textContent . "<br/>";
}
}
}

PHP SOAPCall null result

I have deployed a SOAP WS with AXIS. I use SOAPClient library and PHP 5.5.9 on Ubuntu 14.04 to call the exposed operations, but when I make the "__SoapCall" it returns nothing. I have also tried with "NuSOAP" library, but I obtain the same result.
But when I call "__getLastResponse", It returns the good response (although duplicated), as you can see:
<?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>
<idXMLReturn xmlns="http://aemetproyecto">PD94bWwgdm...</idXMLReturn>
</soapenv:Body>
</soapenv:Envelope>
<?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>
<idXMLReturn xmlns="http://aemetproyecto">PD94bWwgdm...</idXMLReturn>
</soapenv:Body>
</soapenv:Envelope>
Here is the WSDL
My PHP code:
<?php
function generarTabla($id, $formato){
try{
// Create the SoapClient instance
$url = "http://localhost:8080/axis/services/AemetProyect?wsdl";
$client = new SoapClient($url, array("trace" => 1, "exception" => 1));
// Creo XML
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
$xml .= "<!DOCTYPE id [\n";
$xml .= "<!ELEMENT id (#PCDATA)>\n";
$xml .= "]>\n";
$xml .= "<id>".$id."</id>";
// Codifico XML en Base64
$Base64xml = base64_encode($xml);
// Llamada SOAP a DescargarInfoTiempo
$resultado = $client -> __soapCall("DescargarInfoTiempo",
array($Base64xml));
//$resultado = $client -> __getLastResponse();
//echo $resultado;
//$resultado = $client -> __getLastRequest();
//echo $resultado;
echo $resultado;
} catch (SoapFault $ex){
$error = "SOAP Fault: (faultcode: {$ex->faultcode}\n"
."faultstring: {$ex->faultstring})";
echo $error;
} catch (Exception $e){
$error = "Exception: {$e->faultstring}";
echo $error;
}
}
?>
I've noticed that the name of return element ("idXMLReturn") is not the same that the name described in WSDL ("DescargarInfoTiempoReturn").
Can this be the problem?
Update
I've tried to do:
$argumens['idXML'] = $Base64xml;
$resultado = $client -> __soapCall("DescargarInfoTiempo",
array($arguments));
and
$arguments['idXML'] = $Base64xml;
$resultado = $client ->DescargarInfoTiempo($arguments);
But then I get "Notice: Array to string conversion" when I do the call.
Your error is in a little detail.
For a call using the SoapClient, you must send the arguments in a array of arguments, instead to send a xml (why you need to do a codification base64? Is some rule of your WebService?). See the PHP docs for get the right way
arguments
An array of the arguments to pass to the function. This can be either an ordered or an associative array. Note that most SOAP servers require parameter names to be provided, in which case this must be an associative array.
So, your array arguments* must to be something like this:
$arguments['id'] = $id// if you need base 64, use base64_encode($id) or something
$resultado = $client -> __soapCall("DescargarInfoTiempo",array($arguments));
Other option to do the same thing, is call the function directly:
$arguments['id'] = $id// if you need base 64, use base64_encode($id) or something
$resultado = $client ->DescargarInfoTiempo($arguments);// note that we don't need array($arguments), just $arguments
See other examples in the comments on the doc page.
Finally, if you still want to create your XML to send, I advise you to do it with other methos like file_get_contents or CURL and don't forget to create your XML with a soap envelop, is needed for the Soap Protocol
*Some old WebServices needs a array with name "parameters"
UPDATE
Look, you're trying to send your $arguments in a array that contains only one element: The XML in your $Base64xml var. I think that The problem still here.
According to PHP manual, you can't send XML in your SoapCall. The var must be a associative array with your vars, so try to do something like this:
$arguments['id'] = $id// this $id var is your function argument(int, string or somenthing else), forget the created XML
$resultado = $client -> __soapCall("DescargarInfoTiempo",array($arguments));
About the base64 that you need, I never needed it before, but see the marcovtwout comment in this page of PHP manual
If your WSDL file containts a parameter with a base64Binary type, you should not use base64_encode() when passing along your soap vars. When doing the request, the SOAP library automatically base64 encodes your data, so otherwise you'll be encoding it twice.
So, I belive that you don't need to encode your vars.
In short, forget the XML and send only your vars. The PHP SoapClient create the Soap envelop with the corrected encodes and all these things.
If you still with problems doing this, try to enclose your var with some SoapVars. Maybe your WSDL configuration needs this treatment.
I hope this helps
The solution is to specify the document literal style as it is explained in
Creating a SOAP call using PHP with an XML body
As I said above, "I've noticed that the name of return element ("idXMLReturn") is not the same that the name described in WSDL ("DescargarInfoTiempoReturn")"
So, that's the problem: AXIS doesn't generate a Envelope that fits to the WSDL schema. It seems java:RPC provider doesn't worry about the return names of operations.
For now, I've solved it by renaming the parameter from "idXML" to "DescargarInfoTiempo", so SOAP response will be "DescargarInfoTiempoReturn" and it will fit with the WSDL schema and PHP will map the response correctly.

SaveXml in php returning empty string

I have the following xml :
<assumption_list>
<assumption name="test" id="23" description="test1" is_shared="no">
<watchlists>
<watchlist globalissuer="koolwater" prepayrate="5" prepaytype="CPR" defaultrate="5" defaulttype="CDR" lossrate="7" lagmonths="2"/>
</watchlists>
</assumption>
</assumption_list>
I load the following received from a jsp call in php as DOMDocument
I am trying the get the <watchlists> node as a string by using the following code :
$result = $xmlDoc->getElementsByTagName('watchlists');
$strxml='';
foreach($result as $element)
{
print_r(simplexml_import_dom($element));
$strxml = $xmlDoc->saveXML($element);
var_dump($strxml);
}
I do see my print_r(simplexml_import_dom($element)); this getting populated but for some reasons i see the empty string after the saveXml operation. Is there something wrong with the current implementation.
I am trying to get the xml string representation so that i can pass the xml string to c# dll used by php application
If you want to output the xml string representation, you can use a simple htmlentities() on this one. Consider this example: Sample Output
$xmlDoc = '<assumption_list> <assumption name="test" id="23" description="test1" is_shared="no"> <watchlists> <watchlist globalissuer="koolwater" prepayrate="5" prepaytype="CPR" defaultrate="5" defaulttype="CDR" lossrate="7" lagmonths="2"/> </watchlists> </assumption></assumption_list>';
$xmlDoc = simplexml_load_string($xmlDoc);
$result = $xmlDoc->assumption->watchlists->watchlist;
// echo $result->asXML(); // output as xml
echo htmlentities($result->asXML()); // output as xml string

Parsing XML using JSON PHP and outputting data

I am trying to parse some xml in PHP and can build the correct url to fetch the data, but I am stuck on the process of determining how to look at the structure so I can avoid errors like this
Notice: Trying to get property of non-object in C:\wamp\www\sportchecker\soccer.php on line 39
Call Stack
# Time Memory Function Location
1 0.0020 252360 {main}( ) ..\sports.php:0
Here is an example URL http://api.pinnaclesports.com/v1/leagues?sportid=29, are their any tools that can tell me how to navigate through the tree in php code? The call I make with the API key has lots of data returned. Here is my code below
$url = "http://api.pinnaclesports.com/v1/feed?sportid=$sport_id&leagueid=$league_id&clientid=$client_id&apikey=$api_key&oddsformat=$oddsformat";
$json_string = file_get_contents($url);
$parsed_json = json_decode($json_string);
// output the xml data
$wSports = $parsed_json->sports->sport->id;
echo "Status : ${wSports} ";
// test if url is correct
echo $url;
Edit: here is a sample of the data, I am trying to get the teams and time back.
<rsp status="ok">
<fd>
<fdTime>1385326075704</fdTime>
<sports>
<sport>
<id>29</id>
<leagues>
<league>
<id>1739</id>
<events>
<event>
<startDateTime>2013-11-25T22:59:00Z</startDateTime>
<id>334321824</id>
<IsLive>No</IsLive>
<status>I</status>
<drawRotNum>2056</drawRotNum>
<homeTeam type="Team1">
<name>Atletico Huracan</name>
<rotNum>2054</rotNum>
</homeTeam>
<awayTeam type="Team2">
<name>Talleres Cordoba</name>
<rotNum>2055</rotNum>
</awayTeam>
<periods>
<period lineId="117000156">
<number>0</number>
<description>Game</description>
<cutoffDateTime>2013-11-25T22:59:00Z</cutoffDateTime>
<spreads>
<spread>
<awaySpread>0.25</awaySpread>
<awayPrice>1.869</awayPrice>
<homeSpread>-0.25</homeSpread>
<homePrice>1.97</homePrice>
</spread>
</spreads>
Use simplexml.
$sports = new SimpleXMLElement($parsedJson);
$sports->sport[0]->id

Categories