This question already has answers here:
PHP sorting issue with simpleXML
(3 answers)
Closed 9 years ago.
We are fetching data from a remote server via their API. Unfortunately, their API does not order the returned data by date.
I am trying, without much success, to figure out how to re-organize the data so that it is ordered by the next_bookable_date. We are using PHP and SimpleXMLElement to parse the data and create a string which is then inserted into a webpage. But the current result is in the same order as data appears in the returned XML.
The basic XML results are below. There is much more data, that I stripped out to save space.
SimpleXMLElement Object
(
[request] => GET search.xml?start_date=2013-05-03&end_date=2013-05-17
[error] => OK
[total_tour_count] => 4
[tour] => Array
(
[0] => SimpleXMLElement Object
(
[next_bookable_date] => 2013-05-13
[tour_name] => Thailand Tour
)
[1] => SimpleXMLElement Object
(
[next_bookable_date] => 2013-05-12
[tour_name] => Bali Tour
)
[2] => SimpleXMLElement Object
(
[next_bookable_date] => 2013-05-05
[tour_name] => Hawaii Tour
)
[3] => SimpleXMLElement Object
(
[next_bookable_date] => 2013-05-06
[tour_name] => Bhutan Tour
)
)
)
The PHP code we are using to generate the html string (again stripped of a bit of html code to save space):
foreach($result->tour as $tour) {
$tourname = $tour->tour_name;
$tourdate = $tour->next_bookable_date;
// create string for dpt-soon
$dpt_soon_list .= "<li> some html using the above values </li>\n";
}
Is there a way to re-order the XML data once we receive it from the remote server? Or is there a way to reorder the PHP output when running the foreach?
You can use usort() to sort multidimensional arrays or objects. I wrote this bit of code to explain how to use it with SimpleXML:
<?php
// Load the XML file
$xml = simplexml_load_file("xml.xml");
// Get all children into an array
$Tours = (array)$xml->children();
$Tours = $Tours["tour"];
// Call usort on the array
usort($Tours, "sorttours");
// Output results
echo "<pre>".print_r($Tours, true)."</pre>";
// The function that specifies when an entry is larger, equal or smaller than another
function sorttours($a, $b) {
// Parse strings into a date for comparison
$Date1 = strtotime($a->next_bookable_date);
$Date2 = strtotime($b->next_bookable_date);
// If equal, return 0
if ($Date1 == $Date2) {
return 0;
}
// If Date1 is larger, return 1, otherwise -1
return ($Date1 > $Date2) ? 1 : -1;
}
?>
This example assumes that the XML looks somewhat like this:
<?xml version="1.0"?>
<tours>
<tour>
<next_bookable_date>2013-05-13</next_bookable_date>
<tour_name>Thailand Tour</tour_name>
</tour>
<tour>
<next_bookable_date>2013-05-12</next_bookable_date>
<tour_name>Bali Tour</tour_name>
</tour>
<tour>
<next_bookable_date>2013-05-05</next_bookable_date>
<tour_name>Hawaii Tour</tour_name>
</tour>
<tour>
<next_bookable_date>2013-05-06</next_bookable_date>
<tour_name>Bhutan Tour</tour_name>
</tour>
</tours>
If that is not the case, then you need to rewrite the sorttours function to use e.g. attributes to determine the order.
Related
EDIT: The reason I used json_decode is to get it from XML to an array.
So here is my dilemma:
I access an API that returns xml, I then convert it to an array as follows:
public function convertXMLtoJSON($xml){
return json_decode(json_encode(simplexml_load_string($xml), true), true);
}
When I have a single item (for example:) [SINGLE ITEM XML]
<LineItem>
<field>hello</field>
</LineItem>
It gets displayed like: [SINGLE ITEM ARRAY]
[LineItem] => Array(
[field] => hello
)
now if I have: [MULTI ITEM XML]
<LineItem>
<field>hello</field>
</LineItem>
<LineItem>
<field>hello part 2</field>
</LineItem>
I get: [MULTI ITEM ARRAY]
[LineItem] => Array(
[0] => Array (
[field] => hello
)
[1] => Array (
[field] => hello part 2
)
)
I need the first example to be in an array, not just by itself because differentiating between the two is just going to be way too time consuming.
As I understand your specific question, you want everything to be formatted like the multi array, even if there is only a single result.
I would handle this by checking the array for a count of 1 after it is returned. Let us suppose that you have an array called $xmlArray that has a single result in the format you describe.
if (count($xmlArray) == 1) {
$multiArray['LineItem'][] = $xmlArray['LineItem'];
}
This will convert the $xmlArray with a single element into the multi-line array format you have described in your question.
I have a XML object result from my database containing settings.
I am trying to access the values for a particular settingName:
SimpleXMLElement Object
(
[settings] => Array
(
[0] => SimpleXMLElement Object
(
[settingName] => Test
[settingDescription] => Testing
[requireValue] => 1
[localeID] => 14
[status] => 1
[value] => 66
[settingID] => 5
)
[1] => SimpleXMLElement Object
(
[settingName] => Home Page Stats
[settingDescription] => Show the Top 5 Teammate / Teamleader stats?
[requireValue] => 0
[localeID] => 14
[status] => 0
[value] => SimpleXMLElement Object
(
)
[settingID] => 3
)
)
)
I tried using xPath and have this so far:
$value = $fetchSettings->xpath("//settingName[text()='Test']/../value");
which returns:
Array ( [0] => SimpleXMLElement Object ( [0] => 66 ) )
How can I get the actual value and not just another array/object?
The end result will just be 66 for the example above.
SimpleXMLElement::xpath() returns a plain PHP array of "search results"; the first result will always be index 0 if any results were found.
Each "search result" is a SimpleXMLElement object, which has a magic __toString() method for getting the direct text content of a node (including CDATA, but including text inside child nodes, etc). The simplest way to call it is with (string)$my_element; (int)$my_element will also invoke it, then convert the result to an integer.
So:
$xpath_results = $fetchSettings->xpath("//settingName[text()='Test']/../value");
if ( count($xpath_results) > 0 ) {
$value = (string)$xpath_results[0];
}
Alternatively, the DOMXPath class can return results other than element and attribute nodes, due to the DOM's richer object model. For instance, you can have an XPath expression ending //text() to refer to the text content of a node, rather than the node itself (SimpleXML will do the search, but give you an element object anyway).
The downside is it's rather more verbose to use, but luckily you can mix and match the two sets of functions (using dom_import_simplexml() and its counterpart) as they have the same underlying representation:
// WARNING: Untested code. Please comment or edit if you find a bug!
$fetchSettings_dom = dom_import_simplexml($fetchSettings);
$xpath = new DOMXPath($fetchSettings_dom->ownerDocument);
$value = $xpath->evaluate(
"//settingName[text()='Test']/../value/text()",
$fetchSettings_dom
);
Because every element in a XML-file can appear as multiple times the parser always returns an array. If you are sure, that it is only a single item you can use current()
echo (string) current($value);
Note, that I cast the SimpleXMLElement to a string (see http://php.net/manual/simplexmlelement.tostring.php ) to get the actual value.
Use DomXPath class instead.
http://php.net/manual/en/domxpath.evaluate.php
The sample from php.net is just equivalent what you'd like to achieve:
<?php
$doc = new DOMDocument;
$doc->load('book.xml');
$xpath = new DOMXPath($doc);
$tbody = $doc->getElementsByTagName('tbody')->item(0);
// our query is relative to the tbody node
$query = 'count(row/entry[. = "en"])';
$entries = $xpath->evaluate($query, $tbody);
echo "There are $entries english books\n";
In this way, you can get values straight from the XML.
This question already has answers here:
PHP get values from SimpleXMLElement array
(5 answers)
Closed 9 years ago.
I'm using XML for the use of different languages. First of all, I'm not used to work with XML so I want to ask if I'm doing it right. Here is my XML code:
<lang>
<one>
<ENG>Text1</ENG>
<NL>Text2</NL>
</one>
</lang>
When I load this in php I get this array:
SimpleXMLElement Object ( [one] => SimpleXMLElement Object ( [ENG] => Text1 [NL] => Text2 ) )
I'm now trying to get each single element out of the XML, I have this code:
$xml = simplexml_load_file($file);
$result = $xml['one']['ENG'];
But it doesn't return any result, please help.
Thanks.
Use object accessor syntax instead:
$result = $xml->one->ENG;
I am pretty new to PHP an XML and hope you can help me with this.
Searching the forum didn't help me yet to find an answer to my specific issue.
I have a PHP page with a simplexml array that looks like the following, just longer:
SimpleXMLElement Object
(
[textID] => Array
(
[0] => SimpleXMLElement Object
(
[textID] => 1
[content] => Text1
)
[1] => SimpleXMLElement Object
(
[textID] => 2
[content] => Text2
)
[2] => SimpleXMLElement Object
(
[textID] => 3
[content] => Text3
)
)
)
Now I am trying to echo out a specific value from this array by referring to its ID which is an integer.
The only way I get this working is the following but this just goes by the order within the array, not by the actual ID:
<?php echo $objTexts->textID[1]->content; ?>
Can someone tell me what I am missing here ?
Thanks, Tim
SimpleXML has no way of knowing that the textID identifies which node is which - it is just another element in the XML.
Based on your sample output, your XML is a little confusing as you have multiple elements called textID which each have a single child, also called textID, which has a different meaning. Nonetheless, what you want to do can be achieved either by looping through all the outer textID elements and testing the value of their inner textID element:
foreach ( $objTexts->textID as $item )
{
if ( $item->textID == '2' )
{
...
}
}
Or, you could use XPath, which is a fairly simple query language for XML, and is supported within SimpleXML in the form of the ->xpath() method. In your case, you want to find a textID node which contains a textID child with a particular value, so the code would look something like this:
// ->xpath always returns a plain PHP array - not a SimpleXML object
$xpath_results = $objTexts->xpath('//textID[textID=2]');
// If you're certain you only want the first result:
echo $xpath_results[0]->content;
// If you might want multiple matches
foreach ( $xpath_results as $item )
{
...
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Able to see a variable in print_r()'s output, but not sure how to access it in code
I am using SOAP to get data from the server and in response i am getting a php array like this
Array
(
[BookResult] => stdClass Object
(
[PNR] => 5WPODU
[BookingId] => 31149
[Status] => stdClass Object
(
[StatusCode] => 03
[Description] => Fare is not available at the time of booking
[Category] => BK
)
[SSRDenied] => N
[ProdType] => Flight
)
)
All i want to know is how can i extract "PNR" and "StatusCode" value in separate variables so that i can store them in database.
Tried this not working
$p = (object) $array;
echo $p->StatusCode;
Try this:
$PNR = $array["BookResult"]->PNR;
$StatusCode= $array["BookResult"]->Status->StatusCode;
$array is an array. So first dive is $array['BookResult'].
BookResult is stdClass instance so next goes $array['BookResult']->Status (get object's property).
Status is also stdClass instance so get it's property: $array['BookResult']->Status->StatusCode
var_dump($array['BookResult']->PNR);
var_dump($array['BookResult']->Status->StatusCode);
Assuming results are being stored in $array
echo $array['BookResult']->Status->StatusCode;
echo $array['BookResult']->PNR;