Convert XML file to an array - php

I try to convert XML file to an array in PHP. However, when reading the first array, it is not in form of key and value array.
Is there any way to convert the first data in form of Key and Value? Thanks in advance.
readXML.php
function convertXMLFileToArray()
{
$xml_file = 'customers.xml';
$array_name = 'customer';
//Check whether the file exist
if(file_exists($xml_file)){
//Read the data from xml file
$dt = simplexml_load_file($xml_file,null,LIBXML_NOCDATA);
$json = json_encode($dt);
$outer_array = json_decode($json,TRUE);
//Remove outer array
$array = $outer_array[$array_name];
}
else{
$array = null;
}
var_dump($array);
return $array;
}
Case1
customers.xml
<customers>
<customer>
<cid>1</cid>
<name>Adam</name>
<age>20</age>
</customer>
</customers>
Output
array(3) { ["cid"]=> string(1) "1" ["name"]=> string(4) "Adam" ["age"]=> string(2) "20"}
Case2
customers.xml
<customers>
<customer>
<cid>1</cid>
<name>Adam</name>
<age>20</age>
</customer>
<customer>
<cid>2</cid>
<name>David</name>
<age>23</age>
</customer>
</customers>
Output
array(2) {
[0]=> array(3) { ["cid"]=> string(1) "1" ["name"]=> string(4) "Adam"
["age"]=> string(2) "20" }
[1]=> array(3) { ["cid"]=> string(1) "2" ["name"]=> string(4) "David"
["age"]=> string(2) "23" }
}

Here's one option (using simplexml_load_string instead of file):
function getCustomersFromXml($xml, $key = 'customer')
{
$data = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$out = [];
foreach ($data->$key as $item) {
$out[] = (array) $item;
}
return $out;
}
So you load the XML data, loop the customers object and push each customer object cast as an array into your output.
https://eval.in/990764

Related

Empty key converts into array in multidimentional array in php?

I am uploading one xml and trying to convert that data into php array and have to store it in db. My problem is when i get empty key inside loop it automatically converts into array. but i want it as a string only. As i am getting array so its difficult me to store it in db.Please help me with the solution.
Current Output :
array(19) {
["EMP_NAME"]=>
string(12) "ABC"
["EMP_ADDRESS"]=>
string(1) "MUMBAI"
["DEPARTMENT"]=>
string(1) "IT"
["LOCATION"]=>
array(0) {
}
}
Expected Output :
array(19) {
["EMP_NAME"]=>
string(12) "ABC"
["EMP_ADDRESS"]=>
string(1) "MUMBAI"
["DEPARTMENT"]=>
string(1) "IT"
["LOCATION"]=>
string(1) ""
}
This is my php code to get data from xml and looping through array.
$xml = file_get_contents('uploads/data.xml');
$xml = simplexml_load_string($xml);
$xml_array = json_decode(json_encode((array) $xml), 1);
$data = ($xml_array);
foreach($data as $val){
//var_dump($val);
}
I tried to fix it after getting.
<?php
function fixContent(&$val, $key = null) {
if (is_array($val)) {
if (!$val) $val = '';
else fix($val);
}
}
function fix(&$arr) {
array_walk($arr, 'fixContent');
array_walk_recursive($arr, 'fixContent');
}
$xml = "<?xml version='1.0'?>
<document>
<title>Forty What?</title>
<from>Joe</from>
<to>Jane</to>
<body></body>
</document>";
$xml = simplexml_load_string($xml);
$xml_array = json_decode(json_encode((array) $xml), 1);
fix($xml_array);
$data = $xml_array;
var_dump($data);
?>
Output:
array(4) {
["title"]=>
string(11) "Forty What?"
["from"]=>
string(3) "Joe"
["to"]=>
string(4) "Jane"
["body"]=>
string(0) ""
}
Demo: https://paiza.io/projects/qQC5pfvhGz_FniCIK6S_9g
Generic conversions are often not the best solution. They allow the source to control the output - especially if you use debug features like serializing a SimpleXMLElement instance.
Read the data from XML and add it to a result. This puts your code in control of the output. You can change the keys, validate and convert values, add defaults, ...
$xml = <<<'XML'
<EMP>
<EMP_NAME>ABC</EMP_NAME>
<EMP_ADDRESS>MUMBAI</EMP_ADDRESS>
<DEPARTMENT>IT</DEPARTMENT>
<LOCATION></LOCATION>
</EMP>
XML;
$employee = new SimpleXMLElement($xml);
$result = [
'EMP_NAME' => (string)$employee->EMP_NAME,
'EMP_ADDRESS' => (string)$employee->EMP_ADDRESS,
'DEPARTMENT' => (string)$employee->DEPARTMENT,
'LOCATION' => (string)$employee->LOCATION
];
var_dump($result);
Output:
array(4) {
["EMP_NAME"]=>
string(3) "ABC"
["EMP_ADDRESS"]=>
string(6) "MUMBAI"
["DEPARTMENT"]=>
string(2) "IT"
["LOCATION"]=>
string(0) ""
}
Or with DOM:
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
$result = [
'EMP_NAME' => $xpath->evaluate('string(/EMP/EMP_NAME)'),
'EMP_ADDRESS' => $xpath->evaluate('string(/EMP/EMP_ADDRESS)'),
'DEPARTMENT' => $xpath->evaluate('string(/EMP/DEPARTMENT)'),
'LOCATION' => $xpath->evaluate('string(/EMP/LOCATION)')
];
var_dump($result);

Getting data from XML

I am struggling with reading XML file using PHP.
The XML I want to use is here:
http://www.gdacs.org/xml/rss.xml
Now, the data I am interested are the "item" nodes.
I created the following function, which gets the data:
$rawData = simplexml_load_string($response_xml_data);
foreach($rawData->channel->item as $value) {
$title = $value->title;
....
this works fine.
The nodes with the "gdcs:xxxx" were slightly more problematic, but I used the following code, which also works:
$subject = $value->children('dc', true)->subject;
Now the problem I have is with the "resources" node,
Basically the stripped down version of it would look like this:
<channel>
<item>
<gdacs:resources>
<gdacs:resource id="xx" version="0" source="xx" url="xx" type="xx">
<gdacs:title>xxx</gdacs:title>
</gdacs:resource>
<gdacs:resource id="xx" version="0" source="xx" url="xx" type="xx">
<gdacs:title>xxx</gdacs:title>
</gdacs:resource>
<gdacs:resource id="xx" version="0" source="xx" url="xx" type="xx">
<gdacs:title>xxx</gdacs:title>
</gdacs:resource>
</gdacs:resources>
</item>
</channel>
How in this case would I get the resources? I was able to get always just the first resource and only the title of it. What I would like to do is get all the resources items, which have "type" of a particular value and get their URL.
Running through XML the regular path, is , from my experience, slow and excruciating.
Have a look into XPath -> it's a way to extract data from XML through selectors ( similar to CSS selectors )
http://php.net/manual/en/simplexmlelement.xpath.php
You can select elements by their attributes similar to CSS
<?php
$xmlStr = file_get_contents('some_xml.xml');
$xml = new SimpleXMLElement($xmlStr);
$items = $xml->xpath("//channel/item");
$urls_by_item = array();
foreach($items as $x) {
$urls_by_item [] = $x->xpath("//gdacs:resources/gdacs:resource[#type='image']/#url");
}
Consider using the node occurrence of xpath with square brackets [] to align urls with corresponding titles. A more involved modification of #Daniel Batkilin's answer, you can incorporate both data pieces in an associative multidimensional array, requiring nested for loops.
$xml = simplexml_load_file('http://www.gdacs.org/xml/rss.xml');
$xml->registerXPathNamespace('gdacs', 'http://www.gdacs.org');
$items = $xml->xpath("//channel/item");
$i = 1;
$out = array();
foreach($items as $x) {
$titles = $xml->xpath("//channel/item[".$i."]/gdacs:resources/gdacs:resource[#type='image']/gdacs:title");
$urls = $xml->xpath("//channel/item[".$i."]/gdacs:resources/gdacs:resource[#type='image']/#url");
for($j=0; $j<count($urls); $j++) {
$out[$j.$i]['title'] = (string)$titles[$j];
$out[$j.$i]['url'] = (string)$urls[$j];
}
$i++;
}
$out = array_values($out);
var_dump($out);
ARRAY DUMP
array(40) {
[0]=>
array(2) {
["title"]=>
string(21) "Storm surge animation"
["url"]=>
string(92) "http://webcritech.jrc.ec.europa.eu/ModellingCyclone/cyclonesurgeVM/1000226/final/outres1.gif"
}
[1]=>
array(2) {
["title"]=>
string(26) "Storm surge maximum height"
["url"]=>
string(101) "http://webcritech.jrc.ec.europa.eu/ModellingCyclone/cyclonesurgeVM/1000226/final/P1_MAXHEIGHT_END.jpg"
}
[2]=>
array(2) {
["title"]=>
string(12) "Overview map"
["url"]=>
string(64) "http://dma.gdacs.org/saved/gdacs/tc/1000226/clouds_1000226_2.png"
}
[3]=>
array(2) {
["title"]=>
string(41) "Map of rainfall accummulation in past 24h"
["url"]=>
string(70) "http://dma.gdacs.org/saved/gdacs/tc/1000226/current_rain_1000226_2.png"
}
[4]=>
array(2) {
["title"]=>
string(23) "Map of extreme rainfall"
["url"]=>
string(62) "http://dma.gdacs.org/saved/gdacs/tc/1000226/rain_1000226_2.png"
}
[5]=>
array(2) {
["title"]=>
string(34) "Map of extreme rainfall (original)"
["url"]=>
string(97) "http://www.ssd.noaa.gov/PS/TROP/DATA/ETRAP/2015/NorthIndian/THREE/2015THREE.pmqpf.10100000.00.GIF"
}
...

PHP XML losing attributes

i have a problem while I load xml string into SimpleXMLElement ( i tried also with DOCDocument but result is the same). In XML i have this :
<definedNames>
<definedName name="name1" Id="1" hidden="1">NAME_TEST</definedName>
<definedName name="name2" Id="4" hidden="1">NAME_TEST_2</definedName>
</definedNames>
Now i need access to specific tag using 'name' attribute. But always when i tried to print_r, var_dump or smth else i always see all other attributes, but when comes to i see only array with
[0] = > NAME_TEST,
[1] => NAME_TEST_2
I tried also xpath, but everytime when i refer to attributes inside i get empty array.
So for now i tried : xpath, SimpleXMLDom, DOCDocument but result is always the same - empty array. Any clue ?
#edit
$xl->LoadTemplate('#xl/workbook.xml');
if (isset($workbook) && is_array($workbook) && count($workbook > 0)) {
$dom = new DOMDocument();
$dom->loadXML($xl->Source);
$xpath = new DOMXpath($dom);
foreach ($xpath->evaluate('//definedName') as $definedName) {
echo $definedName->getAttribute('name');
}
} else {
$TBS->Source = preg_replace('~\<definedNames\>.*\<\/definedNames\>~', '', $TBS->Source);
}
#edit2 - xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x15" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main">
<definedNames>
<definedName name="name1" Id="1" hidden="1">NAME_TEST</definedName>
<definedName name="name2" Id="4" hidden="1">NAME_TEST_2</definedName>
</definedNames>
</workbook>
i know there is smth like , but i already tried :
$xpath->evaluate('//workbook/definedNames/definedName[#*]')
or
$xpath->evaluate('/workbook/definedNames/definedName[#name="name1"]')
still result is empty.
With DOMDocument, you use Xpath to fetch values or nodes.
Load the XML into a document and create an DOMXpath instance for it:
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
Fetch a node value as string:
var_dump($xpath->evaluate('string(//definedName[#name="name1"])'));
Output:
string(9) "NAME_TEST"
Fetch all definedName element data into an array:
$byName = [];
foreach ($xpath->evaluate('//definedName') as $definedName) {
$byName[] = [
'name' => $definedName->getAttribute('name'),
'id' => $definedName->getAttribute('Id'),
'hidden' => $definedName->getAttribute('hidden'),
'text' => $definedName->nodeValue
];
}
var_dump($byName);
Output:
array(2) {
[0]=>
array(4) {
["name"]=>
string(5) "name1"
["id"]=>
string(1) "1"
["hidden"]=>
string(1) "1"
["text"]=>
string(9) "NAME_TEST"
}
[1]=>
array(4) {
["name"]=>
string(5) "name2"
["id"]=>
string(1) "4"
["hidden"]=>
string(1) "1"
["text"]=>
string(11) "NAME_TEST_2"
}
}
You can use the attributes() method on each element of the SimpleXMLElement Object. You can then access them:
$xml = '<definedNames>
<definedName name="name1" Id="1" hidden="1">NAME_TEST</definedName>
<definedName name="name2" Id="4" hidden="1">NAME_TEST_2</definedName>
</definedNames>';
$x = new SimpleXMLElement($xml);
foreach ($x as $element) {
var_dump($element->attributes());
}
The above returns:
object(SimpleXMLElement)#4 (1) {
["#attributes"]=>
array(3) {
["name"]=>
string(5) "name1"
["Id"]=>
string(1) "1"
["hidden"]=>
string(1) "1"
}
}
object(SimpleXMLElement)#3 (1) {
["#attributes"]=>
array(3) {
["name"]=>
string(5) "name2"
["Id"]=>
string(1) "4"
["hidden"]=>
string(1) "1"
}
}
You can then access individual attributes by using in the loop:
foreach ($x as $element) {
$element->attributes()->hidden;
$element->attributes()->Id;
$element->attributes()->name;
}
try simplexml_load_string()
$p = '<definedNames>
<definedName name="name1" Id="1" hidden="1">NAME_TEST</definedName>
<definedName name="name2" Id="4" hidden="1">NAME_TEST_2</definedName>
</definedNames>';
$xml = simplexml_load_string($p);
echo $xml->definedName[0]->attributes()->name;
echo $xml->definedName[1]->attributes()->name;
or use foreach to get all attaributes

Php simplexml loop is putting the simple element into array. How do I get rid of it?

This is how the array comes out
array(3) { [0]=> string(3) "174" [1]=> object(SimpleXMLElement)#5 (1) { [0]=> string(2) "41" } [2]=> object(SimpleXMLElement)#4 (1) { [0]=> string(2) "21" } }
I'm using this code here that generates the array.
while($row = mysql_fetch_assoc($results)){
$values[] = $row['id'];
$dom = simplexml_load_file('../data/'.$row['id'].'.xml');
foreach($dom->children() as $child)
{
$values[] = $child->views;
}
}
var_dump($values);
The xml file looks like this
<?xml version="1.0"?>
<website site_id="174" user_id="26">
<view day="23" month="10" year="11">
<views>31</views>
</view>
<view day="23" month="12" year="11">
<views>21</views>
</view>
</website>
I need to get the value of the Views into an array, but I keep getting these annoying
object(SimpleXMLElement)#5 things in the array. Also this string(3) . How do I get rid of those.
Thank you
Try to change
$values[] = $child->views;
with
$values[] = (string)$child->views;
How do I get rid of those
If you don't need to see the type of the variable - just don't use var_dump(), but print_r() instead
To explain (string): This is called 'typecasting'. Also works with other types such as (int), (bool), etc.

Why does is_array() return false?

I have this SimpleXML object:
object(SimpleXMLElement)#176 (1) {
["record"]=>
array(2) {
[0]=>
object(SimpleXMLElement)#39 (2) {
["f"]=>
array(2) {
[0]=>
string(13) "stuff"
[1]=>
string(1) "1"
}
}
[1]=>
object(SimpleXMLElement)#37 (2) {
["f"]=>
array(2) {
[0]=>
string(13) "more stuff"
[1]=>
string(3) "90"
}
}
}
Why does is_array($object->record) return false? It clearly says it's an array. Why can't I detect it using is_array?
Also, I am unable to cast it as an array using (array) $object->record. I get this error:
Warning: It is not yet possible to
assign complex types to properties
SimpleXML nodes are objects that can contain other SimpleXML nodes. Use iterator_to_array().
It's not an array. The var_dump output is misleading. Consider:
<?php
$string = <<<XML
<?xml version='1.0'?>
<foo>
<bar>a</bar>
<bar>b</bar>
</foo>
XML;
$xml = simplexml_load_string($string);
var_dump($xml);
var_dump($xml->bar);
?>
Output:
object(SimpleXMLElement)#1 (1) {
["bar"]=>
array(2) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
}
}
object(SimpleXMLElement)#2 (1) {
[0]=>
string(1) "a"
}
As you can see by the second var_dump, it is actually a SimpleXMLElement.
I solved the problem using count() function:
if( count( $xml ) > 1 ) {
// $xml is an array...
}

Categories