PHP parse xml to array - php

i need to convert an xml to array.
I get the xml from an online api.
My code so far:
function download_page($path){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$path);
curl_setopt($ch, CURLOPT_FAILONERROR,1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
$retValue = curl_exec($ch);
curl_close($ch);
return $retValue;
}
$sXML = download_page('https://url/api/user/distgroup/domain/user?t=ticketofuser');
echo "xml start: ". htmlentities($sXML);
$oXML = new SimpleXMLElement($sXML);
echo "xml: ". $oXML;
foreach($oXML["distributionGroups"] as $key=>$value)
{
$groups[$key]["group"]["id"]=$value["id"];
$groups[$key]["group"]["domain"]=$value["domain"];
$groups[$key]["group"]["name"]=$value["name"];
$groups[$key]["group"]["type"]=$value["type"];
$groups[$key]["group"]["loggedIn"]=$value["loggedIn"];
$groups[$key]["group"]["nightMode"]=$value["nightMode"];
$groups[$key]["group"]["loggedInAgents"]=$value["loggedInAgents"];
$groups[$key]["group"]["freeAgents"]=$value["freeAgents"];
$groups[$key]["group"]["callsWaiting"]=$value["callsWaiting"];
}
$temp=array();
foreach ($groups as $key => $row) {
$temp[$key] = $row["id"];
}
array_multisort($temp, SORT_ASC, $groups);
$_SESSION["groups"]=$groups;
echo "groups: ". $groups;
Afterdownloaded the xml it looks like this when i echo it with htmlentities($sXML);
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<distributionGroups>
<group>
<id>33247</id>
<domain>soluno.se</domain>
<name>Kamoda Support</name>
<type>ATTENDANT</type>
<loggedIn>true</loggedIn>
<nightMode>false</nightMode>
<loggedInAgents>1</loggedInAgents>
<freeAgents>1</freeAgents>
<callsWaiting>0</callsWaiting>
</group>
<group>
<id>33257</id>
<domain>soluno.se</domain>
<name>Test 5</name>
<type>ATTENDANT</type>
<loggedIn>false</loggedIn>
<nightMode>false</nightMode>
<loggedInAgents>0</loggedInAgents>
<freeAgents>0</freeAgents>
<callsWaiting>0</callsWaiting>
</group>
</distributionGroups>
My problem is that my array is empty after my try to foreach fill the array.
What am i doing wrong?

In your second foreach, you are missing the key group. Also, you could use $oXML->group to iterator over the XML elements:
$oXML = new SimpleXMLElement($sXML);
$groups = [] ;
foreach($oXML->group as $group)
{
$groups[]["group"] = [
'id' => (string)$group->id,
'domain' => (string) $group->domain,
'name' => (string) $group->name,
'type' => (string) $group->type,
'loggedIn' => (string) $group->loggedIn,
'nightMode' => (string) $group->nightMode,
'loggedInAgents' => (string) $group->loggedInAgents,
'freeAgents' => (string) $group->freeAgents,
'callsWaiting' => (string) $group->callsWaiting,
];
}
$temp=array();
foreach ($groups as $key => $row) {
$temp[$key] = $row['group']["id"]; // missing 'group' in $row['group']
}
array_multisort($temp, SORT_ASC, $groups);
print_r($temp);
print_r($groups);
Output of $temp:
Array
(
[0] => 33247
[1] => 33257
)
Output of $groups:
Array
(
[0] => Array
(
[group] => Array
(
[id] => 33247
[domain] => soluno.se
[name] => Kamoda Support
[type] => ATTENDANT
[loggedIn] => true
[nightMode] => false
[loggedInAgents] => 1
[freeAgents] => 1
[callsWaiting] => 0
)
)
[1] => Array
(
[group] => Array
(
[id] => 33257
[domain] => soluno.se
[name] => Test 5
[type] => ATTENDANT
[loggedIn] => false
[nightMode] => false
[loggedInAgents] => 0
[freeAgents] => 0
[callsWaiting] => 0
)
)
)
Or you could remove "group" in your first array :
$oXML = new SimpleXMLElement($sXML);
$groups = [] ;
foreach($oXML->group as $group)
{
$groups[] = [
'id' => (string)$group->id,
'domain' => (string) $group->domain,
'name' => (string) $group->name,
'type' => (string) $group->type,
'loggedIn' => (string) $group->loggedIn,
'nightMode' => (string) $group->nightMode,
'loggedInAgents' => (string) $group->loggedInAgents,
'freeAgents' => (string) $group->freeAgents,
'callsWaiting' => (string) $group->callsWaiting,
];
}
$temp=array();
foreach ($groups as $key => $row) {
$temp[$key] = $row["id"];
}
array_multisort($temp, SORT_ASC, $groups);

You could make it more flexible by getting the code to copy across each element within the group, adding an element to the array with the element name. This means that as the XML changes (or if) then the code will still retain all of the data being passed over.
I've also merged the two loops, so that $temp is set in the same loop as the main data.
$oXML = new SimpleXMLElement($sXML);
$groups = array();
$temp=array();
foreach ( $oXML->group as $group ) {
$data = array();
foreach ( $group as $element ) {
$data[ $element->getName() ] = (string)$element;
}
$groups[]["group"] = $data;
$temp[] = $data["id"];
}
print_r($temp);
print_r($groups);

new SimpleXMLElement($sXML) creates an object (not an array) of an XML element. So in your case, this $oXML = new SimpleXMLElement($sXML); gives you the distributionGroups element. From there you can access its child elements like foreach($oXML->group as $group), but remember that $group would also be an instance of SimpleXMLElement(). To access the content of the element you actually need to cast the object, i.e. (int) $group->loggedInAgents, to get an integer value. Otherwise $group-> loggedInAgents will actually give you another SimpleXMLElement() object, rather than a variable.
read more in the docs

Related

Better way to dynamically access values in nested array

I need a way to dynamically access values in a nested array using an index map. What i want to achieve is looping over an array with data and extract some values that can be in any level of the nesting and save it to a bi-dimensional array.
So far I've come up with the following code, which works quite well, but I was wondering if there is a more efficient way to do this.
<?php
// Sample data
$array = array();
$array[0]['code'] = "ABC123";
$array[0]['ship'] = array("name" => "Fortune", "code" => 'FA');
$array[0]['departure'] = array("port" => "Amsterdam", "code" => "AMS");
$array[0]['document'] = array("type" => "Passport", "data" => array("valid" => '2022-03-18', 'number' => 'AX123456') );
$array[1]['code'] = "QWERT67";
$array[1]['ship'] = array("name" => "Dream", "code" => 'DR');
$array[1]['departure'] = array("port" => "Barcelona", "code" => "BRC");
$array[1]['document'] = array("type" => "Passport", "data" => array("valid" => '2024-12-09', 'number' => 'DF908978') );
// map of indexes of $array I need in my final result array. The levels of the nested indexes is subdivided by ":"
$map = array("code", "ship:name", "departure:port", "document:type", "document:data:number");
$result = array();
// loop array for rows of data
foreach($array as $i => $row){
// loop map for indexes
foreach($map as $index){
// extract specific nested values from $row and save them in 2-dim array $result
$result[$i][$index] = xpath_array($index, $row);
}
}
// print out result
print_r($result);
// takes path to value in $array and returns given value
function xpath_array($xpath, $array){
$tmp = array();
// path is subdivded by ":"
$elems = explode(":", $xpath);
foreach($elems as $i => $elem){
// if first (or ony) iteration take root value from array and put it in $tmp
if($i == 0){
$tmp = $array[$elem];
}else{
// other iterations (if any) dig in deeper into the nested array until last item is reached
$tmp = $tmp[$elem];
}
}
// return found item (can be value or array)
return $tmp;
}
Any suggestion?
This was quite tricky for me, i used Recursive function, first we normalize array keys to obtain key as you want like this document:type, then we normalize array to obtain all at same level :
/**
* #param array $array
* #param string|null $key
*
* #return array
*/
function normalizeKey(array $array, ?string $key = ''): array
{
$result = [];
foreach ($array as $k => $v) {
$index = !empty($key) && !\is_numeric($key) ? $key.':'.$k : $k;
if (true === \is_array($v)) {
$result[$k] = normalizeKey($v, $index);
continue;
}
$result[$index] = $v;
}
return $result;
}
/**
* #param array $item
* #param int $level
*
* #return array
*/
function normalizeStructure(array $item, int $level = 0): array
{
foreach ($item as $k => $v) {
$level = isset($v['code']) ? 0 : $level;
if (true === \is_array($v) && 0 === $level) {
$item[$k] = normalizeStructure($v, ++$level);
continue;
}
if (true === \is_array($v) && 0 < $level) {
$item = \array_merge($item, normalizeStructure($v, ++$level));
unset($item[$k]);
continue;
}
}
return $item;
}
$data = normalizeStructure(normalizeKey($array));
I edited your data set to add more nests:
// Sample data
$array = array();
$array[0]['code'] = "ABC123";
$array[0]['ship'] = array("name" => "Fortune", "code" => 'FA');
$array[0]['departure'] = array("port" => "Amsterdam", "code" => "AMS");
$array[0]['document'] = array("type" => "Passport", "data" => array("valid" => '2022-03-18', 'number' => 'AX123456'));
$array[1]['code'] = "QWERT67";
$array[1]['ship'] = array("name" => "Dream", "code" => 'DR');
$array[1]['departure'] = array("port" => "Barcelona", "code" => "BRC");
$array[1]['document'] = array("type" => "Passport", "data" => array("valid" => '2024-12-09', 'number' => 'DF908978', 'check' => ['number' => '998', 'code' => 'itsWell', 'inception' => ['border' => 'finalInception']]));
With these data, you should finally receive this result:
/*
Array
(
[0] => Array
(
[code] => ABC123
[ship:name] => Fortune
[ship:code] => FA
[departure:port] => Amsterdam
[departure:code] => AMS
[document:type] => Passport
[document:data:valid] => 2022-03-18
[document:data:number] => AX123456
)
[1] => Array
(
[code] => QWERT67
[ship:name] => Dream
[ship:code] => DR
[departure:port] => Barcelona
[departure:code] => BRC
[document:type] => Passport
[document:data:valid] => 2024-12-09
[document:data:number] => DF908978
[document:data:check:number] => 998
[document:data:check:code] => itsWell
[document:data:check:inception:border] => finalInception
)
)
*/
Recursivity seems to be like Inception, everything is nested and you can lose your mind in 😆, mine was already lost in.

Save array to XML file using SimpleXML

I'm using the code below to sort the content of my XML file by "WebCategory". My question is how do I save the newly sorted $products array back to the XML file?
<?php
$products = array();
$xml = simplexml_load_file('nwgalaxy-edited.xml');
foreach($xml->Product as $item) {
$products[] = array(
'ProductID' => (string)$item->attributes()->ProductID,
'Description' => (string)$item->Description,
'WebCategory' => (string)$item->WebCategory,
'WebSubCategory' => (string)$item->WebSubCategory,
'WebSubCat2' => (string)$item->WebSubCat2,
'QtyOnHand' => intval($item->QtyOnHand),
'SellingPrice' => intval($item->SellingPrice),
'ListPrice' => intval($item->ListPrice),
'NWGalaxy' => intval($item->NWGalaxy),
'UPC' => intval($item->UPC),
'VendorProductID' => (string)$item->VendorProductID,
'ImageSmall' => (string)$item->ImageSmall,
'ImageLarge' => (string)$item->ImageLarge
);
}
array_sort_by_column($products, 'WebCategory');
function array_sort_by_column(&$array, $column, $direction = SORT_ASC) {
$reference_array = array();
foreach($array as $key => $row) {
$reference_array[$key] = $row[$column];
}
array_multisort($reference_array, $direction, $array);
}
?>
This may work, not tested but should give general idea.
// Create tag products
$xml = new SimpleXMLElement('<products/>');
// Walk the array with callback to method $xml->addChild($this)
array_walk_recursive($products, array($xml, 'addChild'));
// Save generated content to file.
file_put_contents('nwgalaxy-edited.xml', $xml->asXML());

Php array and json

help me to convert the following array in to json.
I tried to convert the array.
Array
(
[0] => Array
(
[c_code] => 200001
[itemname] => 303 10CAP
[c_pack_code] => PK0075
[c_web_img_link] =>
)
[1] => Array
(
[c_code] => 200005
[itemname] => 3P 4TAB
[c_pack_code] =>
[c_web_img_link] =>
)
)
current result for the following code is
public function searchOrder($idx, $data) {
if (!empty($data)) {
$result = OrderbukModel::func_get_searchlist($idx,$data);
if (!empty($result)) {
$resultArray[] = $result;
print_r(json_encode($result));
} else {
$resultArray[$idx] = ["Mysql returns empty result !"];
print_r(json_encode($resultArray));
exit;
}
}
}
now i got the result is like
[{"c_code":"200001","itemname":"303 10CAP","c_pack_code":"PK0075","c_web_img_link":""},{"c_code":"200005","itemname":"3P 4TAB","c_pack_code":"","c_web_img_link":""}]
But I need the result as follows
[{"c_code":"2000001","c_code":"200005"},
{"itemname":"303 10CAP","itemname":"3P 4TAB"},
{"c_pack_code":"PK0075","c_pack_code":""},
{"c_web_img_link":"","c_web_img_link":""}]
Example of how you can you make the json from array. Collect the data in two different array and after loop marge them and store the result in another array after that encode them.
Note: Your desired JSON is not a valid format, you can't use same index
for two data.
Online Example: https://3v4l.org/kdPDI
$arr = array(
array(
'c_code' => '200001',
'itemname' => '303 10CAP',
'c_pack_code' => 'PK0075',
'c_web_img_link' => ''
),
array(
'c_code' => '200005',
'itemname' => '3P 4TAB',
'c_pack_code' => '',
'c_web_img_link' => ''
)
);
$res1 = array();
$res2 = array();
foreach($arr as $val){
$res1['c_code'][] = $val['c_code'];
$res1['itemname'][] = $val['itemname'];
$res2['c_pack_code'][] = $val['c_pack_code'];
$res2['c_web_img_link'][] = $val['c_web_img_link'];
}
$out = array(array_merge($res1, $res2));
echo json_encode($out);

Getting XML attribute from the inner node using PHP SimpleXML is failing

Chaps,
I am trying to get attributes of the 'file' node in the following XML with SimpleXml but every time is gives me back null. I have successfully got the attributes for the study node but fail to get the 'file' atts .
here is the xml :
<?xml version="1.0" encoding="UTF-8"?>
<studies>
<study uid="1.3.12.2" acc="181">
<date>20051218</date>
<time>2156</time>
<ref>CG</ref>
<desc>Abdomen</desc>
<id></id>
<path>S00001</path>
<modality>CR</modality>
<reports>
<file cat="UNK" date="20141124">Card_Cloud.txt</file>
</reports>
</study>
and here is my code :
$studyXML = new SimpleXMLElement($studyXML);
$studyXML_array = array();
foreach ($studyXML ->study as $study)
{
// Getting uid and accession from XML attributes
$uid = (!empty($study)) ? (String)$study->attributes()->uid : '';
$acc = (!empty($study)) ? (String)$study->attributes()->acc : '';
// Getting the reports and putting them in an array
$reports = array ();
foreach($study->reports as $rep)
{
$cat = (String)$rep->attributes()->cat;
$reports[] = (String)$rep->file;
}
// Constructing the xml as an array
$studyXML_array[] = array
(
'uid' => $uid,
'acc' => $acc,
'date' => (String)$study->date,
'reports' => $reports
);
}
I can get "uid" and "acc" but I can't get "cat" and "date" inside file node.
When I look at the array of the xml in my debug variables I can see uid and acc attributes but no sign of cat and date attributes.
I Would really appreciate any help.
I prefer to stick to SimpleXML as all my code is using that so far.
Cheers
This is how I did it based on Ghost answer.
$reports = array ();
foreach($study->reports->file as $rep)
{
$temp = array();
$temp['repName'] = (String)$rep;
// Getting cat and date attributes of the report
foreach($rep->attributes() as $key => $rep)
{
$temp[$key] = (string) $rep;
}
$reports[] = $temp;
}
If you're trying to use print_r()/var_dump() to check, then it will do no justice. But it is there, try to traverse to it along with using ->attributes() inside the foreach as well:
$studyXML = new SimpleXMLElement($studyXML);
$studyXML_array = array();
foreach ($studyXML ->study as $study)
{
// Getting uid and accession from XML attributes
$uid = (!empty($study)) ? (String)$study->attributes()->uid : '';
$acc = (!empty($study)) ? (String)$study->attributes()->acc : '';
// Getting the reports and putting them in an array
$reports = array();
// loop each attribute
foreach($study->reports->file->attributes() as $key => $rep)
{
$reports[$key] = (string) $rep;
}
// Constructing the xml as an array
$studyXML_array[] = array(
'uid' => $uid,
'acc' => $acc,
'date' => (String) $study->date,
'reports' => $reports
);
}
echo '<pre>';
print_r($studyXML_array);
Sample Output:
Array
(
[0] => Array
(
[uid] => 1.3.12.2
[acc] => 181
[date] => 20051218
[reports] => Array
(
[cat] => UNK
[date] => 20141124
)
)
)

PHP fetch the value from JSON

I have the customer details in the following format
How do i fetch the customer id is '5' from the output.
json_decode(array)
Result:
stdClass Object (
[5] => stdClass Object (
[email] => siddareddy.vishnuvardhanreddy#gmail.com
[firstname] => vishnu
[lastname] => siddareddy
)
)
You can cast it to an array and then get the first key:
$key = key( (array) $result_object );
$array = json_decode($json, true);
foreach ($array as $key => $value)
{
echo $key; //or use $value array to get the rest of its info
}
Please note that your first line cannot yield the second line as output. The first line should return an array, while the second code block is an object.
You can loop through all keys and values of your Array/Object and get the '5' that way:
foreach( $decodedjson as $key => $val ) {
#Key is: 5
echo "Key is: {$key}";
#Val['firstname'] is: vishnu
echo "Val['firstname'] is: {$val['firstname']}";
}
You can access the numeric property like this
<?php
$data = array(
"5" => array(
'email' => 'siddareddy.vishnuvardhanreddy#gmail.com',
'firstname' => 'vishnu',
'lastname' => 'siddareddy'
)
);
$json = json_encode($data);
$obj = json_decode($json);
var_dump($obj->{5}->email);
$obj->{5}->email, this the trick.
If you want to invert the array from id to that array from say, email to id:
$result = json_decode($array, true);
// Change email to something else if you want another key
$inversecopy = array_flip(array_map(function($val) { return $val['email']; }, $result));
Example in phpfiddle

Categories