PHP / Extract navigation from Array - php

I have an XML document and i'm using SimpleXMLElement to parse it with PHP like :
<Document>
<Hello>
<Name>Jason</Name>
</Hello>
</Document>
Example to access to the name loading my XML and then i do :
$xml->Document->Hello->Name
I would like to store all this routes in associative array like
$array = [
"Document->Hello->Name" => "name"
];
The problem is when i loop on this array my field is empty
I do this :
foreach($array as $key => $v)
{
$hereIsempty = $xml->$key
}
Is someone have a solution to get the value i want from my array mapping plz

Storing full route path in one key is a bad idea.
if you know in advance the meaning of the path: set the tags name to const value and then use it.
But if you realy need to save path as key in array, you can separate all tags in first sub-array and set needs value as second element of array; something like this:
$needs = [];
$routes = [
[
'tags' => ['Document', 'Hello'],
'need' => 'Name'
]
];
foreach ($routes as $route) {
tempXml = $xml;
foreach ($route['tags'] as $tag) {
$tempXml = $tempXml->{$tag};
}
$need[] = (string)$tempXml->{$route['need']};
}

Related

Create Dynamic Array Key Structure in PHP

I have documents stored on my server, and their information like title, filepath, date, category, etc., stored in a database. My goal is to be able to group the documents together by their categories. The document's category is stored in the database as a string like "COVID-19 | Guidance | Mortuary Affairs", and I want to convert it to an array like the following:
[
"COVID-19" => [
"Guidance"=> [
"Mortuary Affairs" => [
// Where the document info will be
]
]
]
]
The first step would be looping through the documents and exploding each category by the | delimiter:
foreach($all_documents as $document)
{
$categories = array_map('trim', explode('|', $document['category']));
}
Doing so results in the following:
[
"COVID-19",
"Guidance",
"Mortuary Affairs"
]
How would I then take this array and turn it into the nested array displayed at the top?
After the creation of the array with categories, you could iterate those categories and "drill" down a result object with a node-reference -- creating any missing properties, and then referencing them. Finally append the document to the deepest node's array (so multiple documents can end up at the same place):
$result = [];
foreach ($all_documents as $document) {
$categories = array_map('trim', explode('|', $document['category']));
$node =& $result; // reference the "root"
$last = array_pop($categories);
foreach ($categories as $category) {
if (!isset($node[$category])) $node[$category] = []; // create child
$node =& $node[$category]; // change the reference to the child
}
$node[$last][] = $document; // append document to this list
}
At the end $result will have the desired hierarchical structure.

adding object elements to array when they don't have keys=>values

I'm currently building an array off of an object and I've got one element called images that has multiple sub elements called 'urls' structured like so
categories": [
{
"images": [
{
"urls": [
"path/test.jpg",
"path/test2.jpg",
"path/test3.jpg"
],
},
{
"urls": [
"path/test4.jpg",
"path/test5.jpg",
"path/test6.jpg"
],
},
{
"urls": [
"path/test7.jpg",
"path/test8.jpg",
"path/test9.jpg"
],
},
]
The values there don't have keys, it's just the url path but I'd like to add these to my $groupItem array and just have each url be it's own element on the same level as the group number (basically I'm exporting and need each url as it's own column)
The structure I want
0 =>"path/test.jpg",
1 =>"path/test2.jpg",
2 =>"path/test3.jpg"
3 =>"path/test4.jpg",
4 =>"path/test5.jpg",
5 =>"path/test6.jpg"
6 =>"path/test7.jpg",
7 =>"path/test8.jpg",
8 =>"path/test9.jpg"
The loop/array:
foreach($prices->groups as $group){
$groupItem = array();
$groupItem["number"] = $group->number;
foreach($group->images as $images){
$groupItem["urls"] = $images->urls;
}
}
How can I simply just add on any url to the groupItem level of that array?
Outside the outer loop, init the value to an empty array:
$groupItem["urls"] = [];
Then use the empty array reference operator to append new values to the end of an array:
foreach($group->images as $images){
$groupItem["urls"][] = $images->urls; // add this url to the end of the list
}
Alternatively, use array_push():
foreach($group->images as $images){
array_push($groupItem["urls"], $images->urls);
}
I think you can probably also skip the inner loop and just use the array explode operator like this:
array_push($groupItem["urls"], ...$images->urls);
You might also use array_column with (from php 5.6) a variable length argument list:
For example, for the images which contains an array of objects where each object has a property urls and contains an array of image urls:
foreach ($prices->groups as $group) {
$groupItem = array();
$groupItem["number"] = $group->number;
$groupItem= array_merge($groupItem, ...array_column($group->images, "urls"));
}
Demo

Remove certain keys and values from associative array

I have a array that looks like this:
[['title'= >'my title','time'=>'14:00','date'=>'feb 2'],['title'= >'another','time'=>'14:00','date'=>'feb 2']]
Now I wish to remove all time and date keys from the arrays and also rename the title to text so it looks like this:
[['text'= >'my title'],['text'= >'another title']]
I have tried to use
$tags = array_map(function($tag) {
return array(
'text' => $tag['title'],
);
}, $tags);
But I cant get it to work
Laravel solution:
collect($array)->transform(function($i) { return ['text' => $i['title']]; })->toArray();
You can transform your collections,
$mycollection = $myModel->get();
return $mycollection->map(function($row){
return [
'text' => $row->title,
];
});
Or you can use Fractal: http://fractal.thephpleague.com/transformers/
$newTags = [];
foreach($tags as $tag) {
$newTags[] = [['text'] => $tag['title']];
}
$tags = $newTags;
This question isn't specific to Laravel, but since you mention it:
Use the collect() helper and it's methods for convenience. You'll want to look at pull, map, and maybe transform in particular.
If you don't use it then unset will delete the index you want from the array.
Alternatively, just create a new array:
$a = []
foreach($tags as $tag) {
$a[] = ['text' => $tag['title']];
}
edit: fix

XML Attributes to arrays (PHP)

I have an XML which includes many thousands of nodes with information about them in attributes.
Each node is like :
<Class Option1="fiahfs;if" Option2="fiowfr0r0" ClassID="1">
<Class Option1="ro;ewaj;frwajro" Option2="afj;wh;fha" Option3="34014upkla" ClassID="2">
....
I need to parse that info into PHP arrays with array names being attribute names and the number of element in array equal to ClassID Attribute.
The problem is that some nodes have attributes that other nodes I dont have. I previously used ->attributes() for one selected element as
$a => $b,
$$a=array();
then
${$a}[(integer)$products['ClassID']]=$b
Where $products is simplexml element got from parsing XML with xpath. That basically gave me what i needed - i had a few arrays and i could address my requests like $Option1[1] , $Option2[1], Option1[2]...etc.
But the problem is that if I create that structure using only attribute list of one selected element -there`ll be elements that that one element do not have,but other have, and after a create arrays and then parse XML -there'll not be some arrays. Like if i create arrays from [0] of that example, that will give me $Option1, $Option2, but no $Option3.
When I rebuilt my code to :
foreach ($XML->xpath('/idspace/Class') as $products){
foreach($products->attributes() as $a => $b){
if(!isset($$a) $$a=array();
${$a}[(integer)$products['ClassID']]=$b;
}}
And after that I tried to foreach($ClassID) - I`ve got only one element in that array.
How can I parse every XML attribute to array while using attribute "ClassID" as element number in array?
I'm quite confused with your arrays. For me it sounds strange to have an extra array for each attribute. Why not make one array that contains each element and have the attributes as children. So that in the end you get an array like this:
$products = array(
[1] => array(
[Option1] => "fiahfs;if",
[Option2] => "fiowfr0r0",
),
[2] => array(
[Option1] => "ro;ewaj;frwajro",
[Option2] => "afj;wh;fha",
[Option3] => "34014upkla",
),
In this way you can easily access all the attributes for a given ChildId:
$products[$childId]['Option1'] - or better check if the Attribute-Name exists.
You can use simplexml->attributes()
$products = array(); // products will have the result!
foreach ($xml->products as $productXml) { // don't know your xml structure here,
// but you need to iterate over every product in the xml
$singleProduct = array();
$classId = 0;
foreach($productXml->attributes() as $a => $b) {
if ($a == 'ClassID') {
$classId = $b;
} else {
$singleProduct[$a] = $b;
}
}
$products[$classId] = $singleProduct;
}

Create nested hashes from an array of elements for JSON encoding

I have produced an array of fruits stored somewhere. Say it looks like this
$myFruits = array("apples"=>1, "oranges"=>3, "bananas"=>5);
This array is then passed into a function that will return json-encoded data for an API.
First, I wanted to be able to return a list of all the types of fruits I have
{"fruits":["apples", "oranges", "bananas"]}
I used this to accomplish it
echo json_encode(array("scripts" => array_keys($scripts)));
Now, I would like each type of fruit to be contained in its own hash, as such
{"fruits":
[
{name: "apples"
},
{name: "oranges"
},
{name: "bananas"
]
}
This way I can add additional fields to each fruit object without breaking existing code that may be using previous versions of this API (eg: if I decided to add the fruit counts in there as well).
Seeing how I can just create a new array and assign my list of fruits to a key called "fruits", I tried to do the same for each inner hash:
$myFruits = array("apples"=>1, "oranges"=>3, "bananas"=>5);
$data = array();
foreach ($myFruits as $key => $value) {
// initialize an associative array for each fruit
$val = array();
array_push($val, array("name" => $key));
// add it to the list of fruits
array_push($data, $val);
}
// assign list of fruits to "fruits" key
$outData = array("fruits" => $data);
echo json_encode($outData);
But I get this instead
{"fruits":[[{"name":"apples"}],[{"name":"oranges"}],[{"name":"bananas"}]]}
There are extra square braces around each fruit hash, which I assume is because I'm using an array to store each key-value pair.
How would I get my desired output?
You're close to knowing what you're doing wrong. You're creating an array, and then just using it to add one item (another array) to it.
// initialize an associative array for each fruit
$val = array(); // this guy here is unnecessary!!
array_push($val, array("name" => $key));
// add it to the list of fruits
array_push($data, $val);
Instead, just push each individual array onto $data directly like this:
array_push($data, array("name" => $key));
DEMO
You are creating an extra level in your array, simply push a new array onto $data in each iteration:
foreach ($myFruits as $key => $value) {
$data[]=array("name" => $key, "count" => $value);
}
*edited as per your comment

Categories