I have a xml parser that returns an associative array. Here's the structure:
<addresses id="123">
<anonymous-address> <test>data 1 </test>
</anonymous-address>
</addresses>
print_r($this->params) will return
Array
(
[addresses] => Array
(
[id] => 123
[anonymous-address] => Array
(
[0] => Array
(
[test] => Array
(
[VALUE] => data 1
)))))
This array then gets passed through list() as:
list($root, $data) = $parsedXML;
Then I attempt to get an id attribute from root and read to do it this way:
$id = $data[$root]['id'];
Edit: This works for all but one $root value which it 400's for. This case of the switch ($root) has the same code as the others, so I have no idea why it errs only there.
var_dump($root, $data) outputs
string (9) "addresses"
array(1) {
["addresses"]=>
array(2) {
["id"]=>
string(3) "123"
["anonymous-address"]=>
array(1) {
["VALUE"]=>
string(7) "data 1 "
}
}
}
$a = list($root, $data);
now $a will be:
array(0 => $root, 1 => $data);
so you can get them like this:
$a[0], $a[1]
so probably
$id = $a[1][$a[0]]['id'];
Related
I have a very big array, I will try to explain the issue in small examples:
Input:
Array (
[alert:accountDisabled:heading] => XYZ
[alert:accountDisabled:message] => XYZ
[alert:accountExpired:heading] => XYZ
[alert:accountExpired:message] => XYZ
[alert:errorResponse:heading] => XYZ
[button:back] => XYZ
)
What I need to get is:
array() {
["alert"]=> array(7) {
["accountDisabled"]=> array(2) {
["heading"]=> string(3) "XYZ"
["message"]=> string(3) "XYZ" }
["accountExpired"]=> array(2) {
["heading"]=> string(3) "XYZ"
["message"]=> string(3) "XYZ" }
["clientError"]=> array(2) {
["heading"]=> string(3) "XYZ"
["message"]=> string(3) "XYZ" }
["errorResponse"]=> array(1) {
["heading"]=> string(3) "XYZ" }
}
["button"]=> array(1) {
["back"]=> string(3) "XYZ"
}
As I said this is a very small example, but the point is to get hierarchy from keys from array number one, hierarchy is divided by this character in key :
I checked for those questions that look similar to this one but they are not helpful lat all
How to access and manipulate multi-dimensional array by key names / path?
Using a string path to set nested array data
SO please read carefully the description of my issue.
I tried to use it for each loop, and I succeed to divide elements from the key, for one element, but I'm not sure where I need to store those hierarchy values for the next elements, any ideas?
$input = [
'alert:accountDisabled:heading' => 'XYZ_1',
'alert:accountDisabled:message' => 'XYZ_2',
'alert:accountExpired:heading' => 'XYZ_3',
'alert:accountExpired:message' => 'XYZ_4',
'alert:errorResponse:heading' => 'XYZ_5',
'button:back' => 'XYZ_6'
];
$results = [];
foreach ($input as $key => $value) {
$arr = explode(':', $key);
$result = $value;
for ($i = count($arr) - 1; $i >= 0; $i--) {
$result = [ $arr[$i] => $result ];
}
$results[] = $result;
}
$result = array_merge_recursive(...$results);
print_r($result);
Output:
Array
(
[alert] => Array
(
[accountDisabled] => Array
(
[heading] => XYZ_1
[message] => XYZ_2
)
[accountExpired] => Array
(
[heading] => XYZ_3
[message] => XYZ_4
)
[errorResponse] => Array
(
[heading] => XYZ_5
)
)
[button] => Array
(
[back] => XYZ_6
)
)
Based on Lukas.j answer, you can use this function:
function parsePath($array, $separator = ':'){
$result = [];
foreach($array as $key => $value){
if(strpos($key, $separator) !== FALSE){
$keys = explode($separator, $key);
$inner_result = $value;
foreach (array_reverse($keys) as $valueAsKey) $inner_result = [$valueAsKey => $inner_result];
$result[] = $inner_result;
}
}
return array_merge_recursive(...$result);
}
For example
[Nationality_1] string(8)=>Indian [Nationality_5] string(12)=>American [Nationality_12] string(17)=>Japanese
I got these array values by foreach loop but I want to put these value to single array by index on strings
Desired output
[Nationality] [0] string(8)=>Indian [1] string(12)=>American[2]string(17)=>Japanese
I have tried array_values but output Null
I tried this but creates duplicate array in loop for multiple orders Please help me on it . Thanks
$Nationality[] = $value;
One solution is below code:
$nationality = array(
'Nationality_1' => 'Indian',
'Nationality_2' => 'American',
'Nationality_3' => 'Japanese'
);
$temp = array();
foreach ($nationality as $val) {
$temp[] = $val;
}
$nationality = $temp;
print_r($nationality);
unset($temp);
// Array ( [0] => Indian [1] => American [2] => Japanese )
It sounds like you may want to use array_values to pull all the nationalities from your input list.
array_values
Return all the values of an array
http://php.net/array_values
What you do with that is then up to you but from your desired output it seems you want them under another array with a "Nationality" key?
Here is an example...
$input = array(
'Nationality_1' => 'Indian',
'Nationality_5' => 'American',
'Nationality_12' => 'Japanese'
);
$output = array('Nationality' => array_values($input));
var_dump($output);
/*
array(1) {
["Nationality"]=>
array(3) {
[0]=>
string(6) "Indian"
[1]=>
string(8) "American"
[2]=>
string(8) "Japanese"
}
}
*/
See the code in action: https://eval.in/869938
I have an array like this:
$arr = array(
'home.js' => new File(),
'view/index.html' => new File(),
'src/index.js' => new File(),
'src/libs/jquery.js' => new File()
);
Now I want to convert in a structure like this:
Array
(
[0] => Array
(
[text] => home.js
)
[1] => Array
(
[text] => view
[children] => Array
(
[0] => Array
(
[text] => index.html
)
)
)
[2] => Array
(
[text] => src
[children] => Array
(
[0] => Array
(
[text] => index.js
)
[1] => Array
(
[text] => libs
[children] => Array
(
[0] => Array
(
[text] => jquery.js
)
)
)
)
)
)
I tried for hours, with help of StackOverfow answers but I couldn't come up with a solution as all other questions have a different setup.
Edit:
What I got so far with the help of SO is (can't remember the exact answer though):
$out = array();
foreach($arr as $path => $file) {
$parts = explode('/', trim($path, '/'));
applyChain($out, $parts, $file);
}
function applyChain(&$arr, $parts, $value)
{
if (!is_array($parts)) {
return;
}
if (count($parts) == 0) {
$arr = $value;
} else {
array_shift($parts);
applyChain($arr[], $parts, $value);
}
}
print_r($out);
I don't know how exactly it works, especially the part applyChain($arr[] ...). It kinda works with the depth, but not with the file names. I get following output:
Array
(
[0] => File Object
(
)
[1] => Array
(
[0] => File Object
(
)
)
[2] => Array
(
[0] => File Object
(
)
)
[3] => Array
(
[0] => Array
(
[0] => File Object
(
)
)
)
)
There would be a solution in a few lines using explode() and eval(). But eval() is not considered clean, so lets try recursion:
<?php
class File {
}
$arr = array(
'home.js' => new File(),
'view/index.html' => new File(),
'src/index.js' => new File(),
'src/libs/jquery.js' => new File()
);
function sub($path) {
$rv = array();
$parts = explode('/', $path, 2); // strip off one level
$rv['text'] = $parts[0]; // put it into 'text' element
if (count($parts)>1) // is there anything left?
$rv['children'] = sub($parts[1]); // do the same for the rest of the path
return $rv;
}
$new = array();
foreach (array_keys($arr) as $file) {
$new[] = sub($file);
}
var_dump($new);
?>
But, as Peter commented, this creates seperate substructures even if the pathes have some part in common (like src/libs/jquery.js and src/libs/melon.js).
With the use of ugly eval() (which can be replaced later) I got the following code:
<?php
class File {
}
$arr = array(
'home.js' => new File(),
'view/index.html' => new File(),
'src/index.js' => new File(),
'src/libs/jquery.js' => new File(),
'src/libs/melon.js' => new File(),
);
// conversion
function sub($element) {
$rv = array();
foreach (array_keys($element) as $sub) {
$part['text'] = $sub;
if (is_array($element[$sub])) {
$part['children'] = sub($element[$sub]);
}
$rv[] = $part;
}
return $rv;
}
// create array with path file/folder names as keys
$new = array();
foreach (array_keys($arr) as $row) {
$def = '$new["'.preg_replace('&/&', '"]["', $row).'"] = 1;';
eval($def);
}
// run
$new2 = sub($new);
var_dump($new2);
?>
This outputs
array(3) {
[0]=>
array(1) {
["text"]=>
string(7) "home.js"
}
[1]=>
array(2) {
["text"]=>
string(4) "view"
["children"]=>
array(1) {
[0]=>
array(1) {
["text"]=>
string(10) "index.html"
}
}
}
[2]=>
array(2) {
["text"]=>
string(3) "src"
["children"]=>
array(2) {
[0]=>
array(1) {
["text"]=>
string(8) "index.js"
}
[1]=>
array(2) {
["text"]=>
string(4) "libs"
["children"]=>
array(2) {
[0]=>
array(1) {
["text"]=>
string(9) "jquery.js"
}
[1]=>
array(1) {
["text"]=>
string(8) "melon.js"
}
}
}
}
}
}
I'm trying to find a way to sort my array from SimpleXMLElement. I'd like to sort by start time which I can get from event_start_dt. I'd also like to sort by room ID as a separate process. Currently the array is in order by object(SimpleXMLElement) #. Here is the var_dump($array):
object(SimpleXMLElement)#275 (1) {
["reservation"]=> array(3)
{
[0]=> object(SimpleXMLElement)#287 (28) {
["reservation_id"]=> string(7) "8644894"
["event_start_dt"]=> string(25) "2013-12-02T12:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T13:00:00-08:00"
["event_id"]=> string(6) "314147"
["event_name"]=> string(24) "Practice"
["room_id"]=> string(3) "202"
}
[1]=> object(SimpleXMLElement)#288 (28) {
["reservation_id"]=> string(7) "8595185"
["event_start_dt"]=> string(25) "2013-12-02T08:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T09:00:00-08:00"
["event_id"]=> string(6) "314005"
["event_name"]=> string(24) "Meeting"
["room_id"]=> string(3) "207"
}
[2]=> object(SimpleXMLElement)#289 (28) {
["reservation_id"]=> string(7) "8718654"
["event_start_dt"]=> string(25) "2013-12-02T10:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T11:00:00-08:00"
["event_id"]=> string(6) "315811"
["event_name"]=> string(20) "Maintenance"
["room_id"]=> string(3) "202"
}
} }
I've tried usort and asort but haven't gotten it to work with either method.
usort method:
function sortByTime($a, $b){
$a = strtotime($array->event_start_dt);
$b = strtotime($array->event_start_dt);
if ($a==$b) return 0;
return ($a < $b) ?-1 : 1;
}
usort($arrTimes, 'sortByTime');
var_dump($arrTimes);
Trying the code below gives me warning: usort() expects parameter 1 to be array, object given.
foreach ($rez->reservation as $value){
$var1 = $value->space_reservation->space_name;
$var2 = substr($value->event_start_dt,11,5);
}
sort_obj_arr($value,$var1,SORT_DESC);
echo "<pre>SORTED ";
print_r($value);
echo "</pre>";
function sort_obj_arr(& $arr, $sort_field, $sort_direction)
{
$sort_func = function($obj_1, $obj_2) use ($sort_field, &$sort_direction)
{
if ($sort_direction == SORT_ASC) {
return strnatcasecmp($obj_1->$sort_field, $obj_2->$sort_field);
} else {
return strnatcasecmp($obj_2->$sort_field, $obj_1->$sort_field);
}
};
usort($arr, $sort_func);
}
I have an array from my controler but cannot get usort working:
I get either: usort() expects parameter 1 to be array, object given or null.
$array = array($this->data);
print_r($array);
array(1) {
[0]=> object(SimpleXMLElement)#280 (1) { ["reservation"]=> array(3) {
[0]=> object(SimpleXMLElement)#287 (28) {
["reservation_id"]=> string(7) "8644894"
["event_start_dt"]=> string(25) "2013-12-02T12:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T13:00:00-08:00"
["event_id"]=> string(6) "314147"
["event_name"]=> string(24) "Practice"
["room_id"]=> string(3) "202"
}
[1]=> object(SimpleXMLElement)#288 (28) {
["reservation_id"]=> string(7) "8595185"
["event_start_dt"]=> string(25) "2013-12-02T08:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T09:00:00-08:00"
["event_id"]=> string(6) "314005"
["event_name"]=> string(24) "Meeting"
["room_id"]=> string(3) "207"
}
[2]=> object(SimpleXMLElement)#289 (28) {
["reservation_id"]=> string(7) "8718654"
["event_start_dt"]=> string(25) "2013-12-02T10:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T11:00:00-08:00"
["event_id"]=> string(6) "315811"
["event_name"]=> string(20) "Maintenance"
["room_id"]=> string(3) "202"
}
} }
Request for print_r:
SimpleXMLElement Object
(
[reservation] => Array(3)
(
[0] => SimpleXMLElement Object
(
[reservation_id] => 8604174
[event_start_dt] => 2013-12-31T06:00:00-08:00
[event_end_dt] => 2013-12-31T08:00:00-08:00
[event_id] => 314147
[event_name] => Practice
[room_id] => 202
)
[1] => SimpleXMLElement Object
(
[reservation_id] => 8604177
[event_start_dt] => 2013-12-31T05:00:00-08:00
[event_end_dt] => 2013-12-31T06:00:00-08:00
[event_id] => 314150
[event_name] => Meeting
[room_id] => 216
)
[2] => SimpleXMLElement Object
(
[reservation_id] => 8604189
[event_start_dt] => 2013-12-31T10:00:00-08:00
[event_end_dt] => 2013-12-31T11:00:00-08:00
[event_id] => 314150
[event_name] => Maintenance
[room_id] => 220
)
)
)
$arrTimes = xml2array($array->reservation);
var_dump($arrTimes)
array(5) {
["reservation_id"]=> string(7) "8604175"
["event_start_dt"]=> string(25) "2014-01-02T06:00:00-08:00"
["event_end_dt"]=> string(25) "2014-01-02T08:00:00-08:00"
["event_id"]=> string(6) "314147"
["event_name"]=> string(24) "Practice"
}
Use array_multisort
foreach ($rez->reservation as $value)
{
$dateTime[] = $value->event_start_dt;
}
array_multisort($dateTime,SORT_ASC,SORT_STRING,$rez->reservation);
echo "<pre>";
print_r($rez->reservation);
Check it. this is my code
<?php
$myarray=array(
0 => array
(
'dateTime' => '2013-12-02T10:00:00-08:00',
'chanl1' => '20.10',
'chanl2' => '45.4',
'chanl3' => '',
),
1 => array
(
'dateTime' => '2013-12-02T11:00:00-08:00',
'chanl1' => '20.11',
'chanl2' => '45.4',
'chanl3' => '',
),
2 => array
(
'dateTime' => '2013-12-02T12:00:00-08:00',
'chanl1' => '20.12',
'chanl2' => '33.8',
'chanl3' => '',
),
3 => array
(
'dateTime' => '2013-12-02T09:00:00-08:00',
'chanl1' => '20.9',
'chanl2' => '33.9',
'chanl3' => ''
));
foreach($myarray as $c=>$key) {
$dateTime[] = $key['dateTime'];
}
array_multisort($dateTime,SORT_ASC,SORT_STRING,$myarray);
echo "<pre>";
print_r($myarray);
?>
Output is :
Array
(
[0] => Array
(
[dateTime] => 2013-12-02T09:00:00-08:00
[chanl1] => 20.9
[chanl2] => 33.9
[chanl3] =>
)
[1] => Array
(
[dateTime] => 2013-12-02T10:00:00-08:00
[chanl1] => 20.10
[chanl2] => 45.4
[chanl3] =>
)
[2] => Array
(
[dateTime] => 2013-12-02T11:00:00-08:00
[chanl1] => 20.11
[chanl2] => 45.4
[chanl3] =>
)
[3] => Array
(
[dateTime] => 2013-12-02T12:00:00-08:00
[chanl1] => 20.12
[chanl2] => 33.8
[chanl3] =>
)
)
FIDDLE
Before you can sort the data, you need to create an array which contains as its values the separate items you want to sort. From your debug outputs, these are multiple <reservation> nodes in the input XML, which are children of the element represented by $array/$this->data in those samples (it doesn't matter if it's the root of the document or not, SimpleXML has no Document object).
Your print_r and var_dump output shows that you do not currently have such an array, only a SimpleXML object:
Your first example shows var_dump($array) giving output beginning object(SimpleXMLElement)#275 (1) { - ignore the word array further in, that's just how var_dump is rendering the insides of the object.
Later, you have a print_r($array); beginning array(1) { - but this is only because you've wrapped the real data in a single-element array on the line above ($array = array($this->data);) and that one element ($array[0]) shows as object(SimpleXMLElement)#280 (1) { ....
Note that there's no need to go further and convert all the inner SimpleXML objects into arrays - you just need a list that is sortable, containing the items you are interested in. I would personally use a simple and explicit foreach loop, for maximum code readability, although "cleverer" solutions are available.
Once you have a sortable list, you need a callback function for usort which compares its two parameters. The attempt you've made is along the right lines, but refers to the non-existent (in that function) variable $array; the values you need to compare are the function's arguments, which you've called $a and $b - specifically, you want to compare strtotime($a->event_start_dt) with strtotime($b->event_start_dt).
You can also make the function much simpler, because it follows the common misconception that the return value of the callback should be -1, 0, or 1. In fact, it can be any integer, and only its sign matters - returning -42 will have the same effect as returning -999, namely placing item $a before $b in the resulting array.
I can't easily give a tested example, because you haven't provided the underlying XML to reproduce your input (e.g. echo $this->data->asXML();), but the basic approach I would take would be this:
// Start with an empty array, and add all the items we're interested in to it
$sortable_array = array();
// Loop over all <reservation> children of the SimpleXML object $this->data
// See http://php.net/manual/en/simplexml.examples-basic.php
foreach ( $this->data->reservation as $reservation_node )
{
// Add the individual node to our array
$sortable_array[] = $reservation_node;
}
// Now let's sort out the callback function for the sorting
// This could also be an anonymous function passed directly to usort
function sort_callback_event_start($a, $b)
{
// $a and $b are both items in our $sortable_array, and therefore
// <reservation> nodes which we expect to each have a child
// called <event_start_dt>
// If we convert both dates to Unix timestamps, we have two integers
// to compare, and a simple subtraction gives the desired result
// of <0, 0, or >0 as documented at http://php.net/usort
return
strtotime((string)$a->event_start_dt)
-
strtotime((string)$b->event_start_dt);
}
// Now, we have everything we need to do the actual sorting
usort($sortable_array, 'sort_callback_event_start');
// $sortable_array is now sorted as desired! :D
// Note that the items within it are still SimpleXML objects,
// so you still need to access their properties to do something useful
// e.g. some HTML output with the names listed in order of their start date:
echo '<ol>';
foreach ( $sortable_array as $reservation_node )
{
echo '<li>', (string)$reservation_node->event_name, '</li>';
}
echo '</ol>';
I would just cast it as an array using this function (example function from php.net). But note that this will not sort the XML, rather sort the new array
/**
* function xml2array
*
* This function is part of the PHP manual.
*
* The PHP manual text and comments are covered by the Creative Commons
* Attribution 3.0 License, copyright (c) the PHP Documentation Group
*
* #author k dot antczak at livedata dot pl
* #date 2011-04-22 06:08 UTC
* #link http://www.php.net/manual/en/ref.simplexml.php#103617
* #license http://www.php.net/license/index.php#doc-lic
* #license http://creativecommons.org/licenses/by/3.0/
* #license CC-BY-3.0 <http://spdx.org/licenses/CC-BY-3.0>
*/
function xml2array ( $xmlObject, $out = array () )
{
foreach ( (array) $xmlObject as $index => $node )
$out[$index] = ( is_object ( $node ) ) ? xml2array ( $node ) : $node;
return $out;
}
and pass it the XMLObject
$arrTimes = xml2array(YourSimpleXMLElement);
and then use your original usort function on the new array
function sortByTime($a, $b){
$a = strtotime($a['event_start_dt']);
$b = strtotime($b['event_start_dt']);
if ($a==$b)
return 0;
return ($a < $b) ? -1 : 1;
}
Finally
usort($arrTimes, 'sortByTime');
You have to convert frist in to xml to array using json encode decode
$xml_array = json_decode(json_encode((array)$xml), TRUE);
u will get list of array....than u can sory according to date using strtotime function.
I have an array that looks like this:
array(3) {
[0]=>
array(2) {
[0]=>
string(10) "2012-11-14"
[1]=>
string(5) "3238"
}
[1]=>
array(2) {
[0]=>
string(10) "2012-11-13"
[1]=>
string(5) "3231"
}
[2]=>
array(2) {
[0]=>
string(10) "2012-11-13"
[1]=>
string(5) "3231"
}
I would like to write a foreach loop that would turn this array into:
array(2) {
[0]=>
array(1) {
"2012-11-14" => "3238"
}
[1]=>
array(1) {
"2012-11-13" => "3231"
}
So, basically, I would like to use the array element formatted as Y-M-D date as key to the second element in the array.
Given the following array...
$array = array(
0 => array(0 => "2012-11-14", 1 => "3238"),
1 => array(0 => "2012-11-13", 1 => "3231"),
2 => array(0 => "2012-11-13", 1 => "3231"),
);
putting it into a new array like this:
$new_array = array();
foreach ($array as $key => $item)
{
$new_array[$key][$item[0]] = $item[1];
}
print_r($new_array);
produces this output:
Array
(
[0] => Array
(
[2012-11-14] => 3238
)
[1] => Array
(
[2012-11-13] => 3231
)
[2] => Array
(
[2012-11-13] => 3231
)
)
My answer doesn't get rid of the duplicates, but the added dimension as specified in the original question means that duplicate dates as keys aren't an issue.
<?php
$data = array(
array("2012-11-14", "3238"),
array("2012-11-13", "3231"),
array("2012-11-13", "3231") // warning! when there are two record with same date, the second's count will be display
);
$result = array();
foreach ($data as $value) {
$result[$value[0]] = $value[1];
}
echo '<pre>';
print_r($result);
<?php
$newArray = array();
for($i=0;$i<count($arrayVariable);$i++)
{
$newArray[$arrayVariable[$i][0]] = $arrayVariable[$i][1];
}
echo '<pre>';print_r($newArray);echo '</pre>';
?>
Didn't test it but something like this should work in concept. Of course change arrayVariable to your variable.. but that aside.
You can use this code to get what you want:
$dates = array(
array("2012-11-01", "3238"),
array("2012-11-03", "4321")
);
print_r($dates);
$result = array();
foreach($dates as $value) {
$result[][$value[0]] = $value[1];
}
print_r($result);
The output will look like the requested form:
Array
(
[0] => Array
(
[2012-11-01] => 3238
)
[1] => Array
(
[2012-11-03] => 4321
)
)
Codepad demo: http://codepad.org/XAmUEdYh
However, I would personally prefer Aykut's solution. You would of course have a problem when you've got two records with the same date, but the overall array layout is a bit nicer ;).
Here is what I came up with:
<?php
$original = array(
array(
"2012-11-14",
"3238"
),
array(
"2012-11-13",
"3231"
),
array(
"2012-11-13",
"3231"
)
);
$newArray = array();
foreach($original as $subArray){
$newArray[] = array($subArray[0] => $subArray[1]);
}
var_dump($newArray);