How Can I Convert a Multidimensional Array in Php to XML - php

I have an array like
$a = array(
'aaa' => "sample",
'bbb' => "sample2",
'ccc' => "adas",
'ddd' => "2",
'eee' => '2013-09-05',
'fff' => "false",
'ggg' => "893",
'qqq' => '2013-09-05',
'sss' => array(
"iii" => array(
'vvv' => "sample3",
'xxx' => 500,
)
),
'nnn' => '2013-09-05',
'mmm' => "Normal",
);
and I want to convert it to xml but witout using SimpleXMLElement or another function. That's why I have tried to do it with foreach. Here is my code ;
$data = '';
foreach ($a as $k => $v) {
if (is_array($k)) {
$data .= "<a:$k>" . $v . "</a:$k>";
foreach ($k as $j => $m) {
if (is_array($j)) {
foreach ($j as $s => $p) {
$data .= "<a:$s>" . $p . "</a:$s>";
}
} else {
$data .= "<a:$j>" . $m . "</a:$j>";
}
}
} else {
$data .= "<a:$k>" . $v . "</a:$k>";
}
}
but it's not working. I can make it work with hashmaps in another language but it must be in php. How can I do this.
Thanks.

You could try this:
function createXml($array, $level = 0)
{
$xml = ($level == 0) ? '<?xml version="1.0" encoding="ISO-8859-1"?>'.PHP_EOL : '';
$tab = str_pad('', $level, ' ', STR_PAD_LEFT);
foreach($array as $node => $value)
{
$xml .= "{$tab}<{$node}>";
if(!is_array($value))
{
$xml .= $value;
}
else
{
$level++;
$xml .= PHP_EOL.createXml($value, $level).$tab;
}
$xml .= "</{$node}>".PHP_EOL;
}
return $xml;
}
$xml = createXml($a);
echo $xml;

Related

How can I foreach this array object?

I want to foreach the game name and info and each game must filter as platform_name.
$list = (object)[];
$list->egame =
[
(object)['platform_name'=>'TT', 'game'=>(object)[(object)['game_name'=>'game1', 'info'=>'test1'],(object)['game_name'=>'game2', 'info'=>'test2'],(object)['game_name'=>'game3', 'info'=>'test3']]],
(object)['platform_name'=>'TG', 'game'=>(object)[(object)['game_name'=>'game4', 'info'=>'test4'],(object)['game_name'=>'game5', 'info'=>'test5']]],
(object)['platform_name'=>'TBIN', 'game'=>(object)[(object)['game_name'=>'game6', 'info'=>'test6']]]
];
?>
Try this
$list = (object)[];
$list->egame =
[
(object)['platform_name' => 'TT', 'game' => (object)[(object)['game_name' => 'game1', 'info' => 'test1'], (object)['game_name' => 'game2', 'info' => 'test2'], (object)['game_name' => 'game3', 'info' => 'test3']]],
(object)['platform_name' => 'TG', 'game' => (object)[(object)['game_name' => 'game4', 'info' => 'test4'], (object)['game_name' => 'game5', 'info' => 'test5']]],
(object)['platform_name' => 'TBIN', 'game' => (object)[(object)['game_name' => 'game6', 'info' => 'test6']]]
];
$arr = (array)$list->egame;
for ($i = 0; $i < count($arr); $i++) {
foreach ($arr[$i] as $key => $value) {
$aa = (array)$arr[$i]->game;
foreach ($aa as $k => $v) {
echo $aa[$k]->game_name." ".$aa[$k]->info."<br/>";
}
echo "<br/>";
}
}
Here You go:
<?php
$list = (object)[];
$list->egame =
[
(object)['platform_name'=>'TT', 'game'=>(object)[(object)['game_name'=>'game1', 'info'=>'test1'],(object)['game_name'=>'game2', 'info'=>'test2'],(object)['game_name'=>'game3', 'info'=>'test3']]],
(object)['platform_name'=>'TG', 'game'=>(object)[(object)['game_name'=>'game4', 'info'=>'test4'],(object)['game_name'=>'game5', 'info'=>'test5']]],
(object)['platform_name'=>'TBIN', 'game'=>(object)[(object)['game_name'=>'game6', 'info'=>'test6']]]
];
foreach ( $list->egame as $eg ) {
foreach ( $eg->game as $game ) {
echo "game: " . $game->game_name . " info: " . $game->info . "<br>";
}
}
?>
Edit #1
Includes platform:
foreach ( $list->egame as $eg ) {
foreach ( $eg->game as $game ) {
echo "platform: " . $eg->platform_name . " game: " . $game->game_name . " info: " . $game->info . "<br>";
}
}

how to convert std Object to simpleXMLelement Object in PHP [duplicate]

How can I convert an array to a SimpleXML object in PHP?
Here is php 5.2 code which will convert array of any depth to xml document:
Array
(
['total_stud']=> 500
[0] => Array
(
[student] => Array
(
[id] => 1
[name] => abc
[address] => Array
(
[city]=>Pune
[zip]=>411006
)
)
)
[1] => Array
(
[student] => Array
(
[id] => 2
[name] => xyz
[address] => Array
(
[city]=>Mumbai
[zip]=>400906
)
)
)
)
generated XML would be as:
<?xml version="1.0"?>
<student_info>
<total_stud>500</total_stud>
<student>
<id>1</id>
<name>abc</name>
<address>
<city>Pune</city>
<zip>411006</zip>
</address>
</student>
<student>
<id>1</id>
<name>abc</name>
<address>
<city>Mumbai</city>
<zip>400906</zip>
</address>
</student>
</student_info>
PHP snippet
<?php
// function defination to convert array to xml
function array_to_xml( $data, &$xml_data ) {
foreach( $data as $key => $value ) {
if( is_array($value) ) {
if( is_numeric($key) ){
$key = 'item'.$key; //dealing with <0/>..<n/> issues
}
$subnode = $xml_data->addChild($key);
array_to_xml($value, $subnode);
} else {
$xml_data->addChild("$key",htmlspecialchars("$value"));
}
}
}
// initializing or creating array
$data = array('total_stud' => 500);
// creating object of SimpleXMLElement
$xml_data = new SimpleXMLElement('<?xml version="1.0"?><data></data>');
// function call to convert array to xml
array_to_xml($data,$xml_data);
//saving generated xml file;
$result = $xml_data->asXML('/file/path/name.xml');
?>
Documentation on SimpleXMLElement::asXML used in this snippet
a short one:
<?php
$test_array = array (
'bla' => 'blub',
'foo' => 'bar',
'another_array' => array (
'stack' => 'overflow',
),
);
$xml = new SimpleXMLElement('<root/>');
array_walk_recursive($test_array, array ($xml, 'addChild'));
print $xml->asXML();
results in
<?xml version="1.0"?>
<root>
<blub>bla</blub>
<bar>foo</bar>
<overflow>stack</overflow>
</root>
keys and values are swapped - you could fix that with array_flip() before the array_walk. array_walk_recursive requires PHP 5. you could use array_walk instead, but you won't get 'stack' => 'overflow' in the xml then.
The answers provided here only convert array to XML with nodes, you are not able to set attributes. I have written a php function that allows you to convert an array to php and also set attributes for particular nodes in the xml. The downside here is you have to construct an array in a particular way with few conventions (only if you want to use attributes)
The following example will allow you to set attributes in XML too.
The source can be found here:
https://github.com/digitickets/lalit/blob/master/src/Array2XML.php
<?php
$books = array(
'#attributes' => array(
'type' => 'fiction'
),
'book' => array(
array(
'#attributes' => array(
'author' => 'George Orwell'
),
'title' => '1984'
),
array(
'#attributes' => array(
'author' => 'Isaac Asimov'
),
'title' => 'Foundation',
'price' => '$15.61'
),
array(
'#attributes' => array(
'author' => 'Robert A Heinlein'
),
'title' => 'Stranger in a Strange Land',
'price' => array(
'#attributes' => array(
'discount' => '10%'
),
'#value' => '$18.00'
)
)
)
);
/* creates
<books type="fiction">
<book author="George Orwell">
<title>1984</title>
</book>
<book author="Isaac Asimov">
<title>Foundation</title>
<price>$15.61</price>
</book>
<book author="Robert A Heinlein">
<title>Stranger in a Strange Land</title>
<price discount="10%">$18.00</price>
</book>
</books>
*/
?>
I found all of the answers to use too much code. Here is an easy way to do it:
function to_xml(SimpleXMLElement $object, array $data)
{
foreach ($data as $key => $value) {
if (is_array($value)) {
$new_object = $object->addChild($key);
to_xml($new_object, $value);
} else {
// if the key is an integer, it needs text with it to actually work.
if ($key != 0 && $key == (int) $key) {
$key = "key_$key";
}
$object->addChild($key, $value);
}
}
}
Then it's a simple matter of sending the array into the function, which uses recursion, so it will handle a multi-dimensional array:
$xml = new SimpleXMLElement('<rootTag/>');
to_xml($xml, $my_array);
Now $xml contains a beautiful XML object based on your array exactly how you wrote it.
print $xml->asXML();
<?php
function array_to_xml(array $arr, SimpleXMLElement $xml)
{
foreach ($arr as $k => $v) {
is_array($v)
? array_to_xml($v, $xml->addChild($k))
: $xml->addChild($k, $v);
}
return $xml;
}
$test_array = array (
'bla' => 'blub',
'foo' => 'bar',
'another_array' => array (
'stack' => 'overflow',
),
);
echo array_to_xml($test_array, new SimpleXMLElement('<root/>'))->asXML();
From PHP 5.4
function array2xml($data, $root = null){
$xml = new SimpleXMLElement($root ? '<' . $root . '/>' : '<root/>');
array_walk_recursive($data, function($value, $key)use($xml){
$xml->addChild($key, $value);
});
return $xml->asXML();
}
Another improvement:
/**
* Converts an array to XML
*
* #param array $array
* #param SimpleXMLElement $xml
* #param string $child_name
*
* #return SimpleXMLElement $xml
*/
public function arrayToXML($array, SimpleXMLElement $xml, $child_name)
{
foreach ($array as $k => $v) {
if(is_array($v)) {
(is_int($k)) ? $this->arrayToXML($v, $xml->addChild($child_name), $v) : $this->arrayToXML($v, $xml->addChild(strtolower($k)), $child_name);
} else {
(is_int($k)) ? $xml->addChild($child_name, $v) : $xml->addChild(strtolower($k), $v);
}
}
return $xml->asXML();
}
Usage:
$this->arrayToXML($array, new SimpleXMLElement('<root/>'), 'child_name_to_replace_numeric_integers');
Here is my entry, simple and clean..
function array2xml($array, $xml = false){
if($xml === false){
$xml = new SimpleXMLElement('<root/>');
}
foreach($array as $key => $value){
if(is_array($value)){
array2xml($value, $xml->addChild($key));
}else{
$xml->addChild($key, $value);
}
}
return $xml->asXML();
}
header('Content-type: text/xml');
print array2xml($array);
So anyway... I took onokazu's code (thanks!) and added the ability to have repeated tags in XML, it also supports attributes, hope someone finds it useful!
<?php
function array_to_xml(array $arr, SimpleXMLElement $xml) {
foreach ($arr as $k => $v) {
$attrArr = array();
$kArray = explode(' ',$k);
$tag = array_shift($kArray);
if (count($kArray) > 0) {
foreach($kArray as $attrValue) {
$attrArr[] = explode('=',$attrValue);
}
}
if (is_array($v)) {
if (is_numeric($k)) {
array_to_xml($v, $xml);
} else {
$child = $xml->addChild($tag);
if (isset($attrArr)) {
foreach($attrArr as $attrArrV) {
$child->addAttribute($attrArrV[0],$attrArrV[1]);
}
}
array_to_xml($v, $child);
}
} else {
$child = $xml->addChild($tag, $v);
if (isset($attrArr)) {
foreach($attrArr as $attrArrV) {
$child->addAttribute($attrArrV[0],$attrArrV[1]);
}
}
}
}
return $xml;
}
$test_array = array (
'bla' => 'blub',
'foo' => 'bar',
'another_array' => array (
array('stack' => 'overflow'),
array('stack' => 'overflow'),
array('stack' => 'overflow'),
),
'foo attribute1=value1 attribute2=value2' => 'bar',
);
$xml = array_to_xml($test_array, new SimpleXMLElement('<root/>'))->asXML();
echo "$xml\n";
$dom = new DOMDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML($xml);
$dom->formatOutput = TRUE;
echo $dom->saveXml();
?>
I wanted a code that will take all the elements inside an array and treat them as attributes, and all arrays as sub elements.
So for something like
array (
'row1' => array ('head_element' =>array("prop1"=>"some value","prop2"=>array("empty"))),
"row2"=> array ("stack"=>"overflow","overflow"=>"overflow")
);
I would get something like this
<?xml version="1.0" encoding="utf-8"?>
<someRoot>
<row1>
<head_element prop1="some value">
<prop2 0="empty"/>
</head_element>
</row1>
<row2 stack="overflow" overflow="stack"/>
</someRoot>
To achive this the code is below, but be very careful, it is recursive and may actually cause a stackoverflow :)
function addElements(&$xml,$array)
{
$params=array();
foreach($array as $k=>$v)
{
if(is_array($v))
addElements($xml->addChild($k), $v);
else $xml->addAttribute($k,$v);
}
}
function xml_encode($array)
{
if(!is_array($array))
trigger_error("Type missmatch xml_encode",E_USER_ERROR);
$xml=new SimpleXMLElement('<?xml version=\'1.0\' encoding=\'utf-8\'?><'.key($array).'/>');
addElements($xml,$array[key($array)]);
return $xml->asXML();
}
You may want to add checks for length of the array so that some element get set inside the data part and not as an attribute.
I use a couple of functions that I wrote a while back to generate the xml to pass back and forth from PHP and jQuery etc...
Neither use any additional frameworks just purely generates a string that can then be used with SimpleXML (or other framework)...
If it's useful to anyone, please use it :)
function generateXML($tag_in,$value_in="",$attribute_in=""){
$return = "";
$attributes_out = "";
if (is_array($attribute_in)){
if (count($attribute_in) != 0){
foreach($attribute_in as $k=>$v):
$attributes_out .= " ".$k."=\"".$v."\"";
endforeach;
}
}
return "<".$tag_in."".$attributes_out.((trim($value_in) == "") ? "/>" : ">".$value_in."</".$tag_in.">" );
}
function arrayToXML($array_in){
$return = "";
$attributes = array();
foreach($array_in as $k=>$v):
if ($k[0] == "#"){
// attribute...
$attributes[str_replace("#","",$k)] = $v;
} else {
if (is_array($v)){
$return .= generateXML($k,arrayToXML($v),$attributes);
$attributes = array();
} else if (is_bool($v)) {
$return .= generateXML($k,(($v==true)? "true" : "false"),$attributes);
$attributes = array();
} else {
$return .= generateXML($k,$v,$attributes);
$attributes = array();
}
}
endforeach;
return $return;
}
Love to all :)
You could use the XMLParser that I have been working on.
$xml = XMLParser::encode(array(
'bla' => 'blub',
'foo' => 'bar',
'another_array' => array (
'stack' => 'overflow',
)
));
// #$xml instanceof SimpleXMLElement
echo $xml->asXML();
Would result in:
<?xml version="1.0"?>
<root>
<bla>blub</bla>
<foo>bar</foo>
<another_array>
<stack>overflow</stack>
</another_array>
</root>
Based on everything else here, handles numerical indices + attributes via prefixing with #, and could inject xml to existing nodes:
Code
function simple_xmlify($arr, SimpleXMLElement $root = null, $el = 'x') {
// based on, among others http://stackoverflow.com/a/1397164/1037948
if(!isset($root) || null == $root) $root = new SimpleXMLElement('<' . $el . '/>');
if(is_array($arr)) {
foreach($arr as $k => $v) {
// special: attributes
if(is_string($k) && $k[0] == '#') $root->addAttribute(substr($k, 1),$v);
// normal: append
else simple_xmlify($v, $root->addChild(
// fix 'invalid xml name' by prefixing numeric keys
is_numeric($k) ? 'n' . $k : $k)
);
}
} else {
$root[0] = $arr;
}
return $root;
}//-- fn simple_xmlify
Usage
// lazy declaration via "queryparam"
$args = 'hello=4&var[]=first&var[]=second&foo=1234&var[5]=fifth&var[sub][]=sub1&var[sub][]=sub2&var[sub][]=sub3&var[#name]=the-name&var[#attr2]=something-else&var[sub][#x]=4.356&var[sub][#y]=-9.2252';
$q = array();
parse_str($val, $q);
$xml = simple_xmlify($q); // dump $xml, or...
$result = get_formatted_xml($xml); // see below
Result
<?xml version="1.0"?>
<x>
<hello>4</hello>
<var name="the-name" attr2="something-else">
<n0>first</n0>
<n1>second</n1>
<n5>fifth</n5>
<sub x="4.356" y="-9.2252">
<n0>sub1</n0>
<n1>sub2</n1>
<n2>sub3</n2>
</sub>
</var>
<foo>1234</foo>
</x>
Bonus: Formatting XML
function get_formatted_xml(SimpleXMLElement $xml, $domver = null, $preserveWhitespace = true, $formatOutput = true) {
// http://stackoverflow.com/questions/1191167/format-output-of-simplexml-asxml
// create new wrapper, so we can get formatting options
$dom = new DOMDocument($domver);
$dom->preserveWhiteSpace = $preserveWhitespace;
$dom->formatOutput = $formatOutput;
// now import the xml (converted to dom format)
/*
$ix = dom_import_simplexml($xml);
$ix = $dom->importNode($ix, true);
$dom->appendChild($ix);
*/
$dom->loadXML($xml->asXML());
// print
return $dom->saveXML();
}//-- fn get_formatted_xml
Here's a function that did the trick for me:
Just call it with something like
echo arrayToXml("response",$arrayIWantToConvert);
function arrayToXml($thisNodeName,$input){
if(is_numeric($thisNodeName))
throw new Exception("cannot parse into xml. remainder :".print_r($input,true));
if(!(is_array($input) || is_object($input))){
return "<$thisNodeName>$input</$thisNodeName>";
}
else{
$newNode="<$thisNodeName>";
foreach($input as $key=>$value){
if(is_numeric($key))
$key=substr($thisNodeName,0,strlen($thisNodeName)-1);
$newNode.=arrayToXml3($key,$value);
}
$newNode.="</$thisNodeName>";
return $newNode;
}
}
I found this solution similar to the original problem
<?php
$test_array = array (
'bla' => 'blub',
'foo' => 'bar',
'another_array' => array (
'stack' => 'overflow',
),
);
class NoSimpleXMLElement extends SimpleXMLElement {
public function addChild($name,$value) {
parent::addChild($value,$name);
}
}
$xml = new NoSimpleXMLElement('<root/>');
array_walk_recursive($test_array, array ($xml, 'addChild'));
print $xml->asXML();
Most of the above answers are correct. However, I came up with this answer which solves the array_walk_recursive compatibility issue and also the numerical keys problem. It also passed all the tests I made:
function arrayToXML(Array $array, SimpleXMLElement &$xml) {
foreach($array as $key => $value) {
// None array
if (!is_array($value)) {
(is_numeric($key)) ? $xml->addChild("item$key", $value) : $xml->addChild($key, $value);
continue;
}
// Array
$xmlChild = (is_numeric($key)) ? $xml->addChild("item$key") : $xml->addChild($key);
arrayToXML($value, $xmlChild);
}
}
I have also added a test class for this which you may find useful:
class ArrayToXmlTest extends PHPUnit_Framework_TestCase {
public function setUp(){ }
public function tearDown(){ }
public function testFuncExists() {
$this->assertTrue(function_exists('arrayToXML'));
}
public function testFuncReturnsXml() {
$array = array(
'name' => 'ardi',
'last_name' => 'eshghi',
'age' => 31,
'tel' => '0785323435'
);
$xmlEl = new SimpleXMLElement('<root/>');
arrayToXml($array, $xmlEl);
$this->assertTrue($xmlEl instanceOf SimpleXMLElement);
}
public function testAssocArrayToXml() {
$array = array(
'name' => 'ardi',
'last_name' => 'eshghi',
'age' => 31,
'tel' => '0785323435'
);
$expectedXmlEl = new SimpleXMLElement('<root/>');
$expectedXmlEl->addChild('name', $array['name']);
$expectedXmlEl->addChild('last_name', $array['last_name']);
$expectedXmlEl->addChild('age', $array['age']);
$expectedXmlEl->addChild('tel', $array['tel']);
$actualXmlEl = new SimpleXMLElement('<root/>');
arrayToXml($array, $actualXmlEl);
$this->assertEquals($expectedXmlEl->asXML(), $actualXmlEl->asXML());
}
public function testNoneAssocArrayToXml() {
$array = array(
'ardi',
'eshghi',
31,
'0785323435'
);
// Expected xml value
$expectedXmlEl = new SimpleXMLElement('<root/>');
foreach($array as $key => $value)
$expectedXmlEl->addChild("item$key", $value);
// What the function produces
$actualXmlEl = new SimpleXMLElement('<root/>');
arrayToXml($array, $actualXmlEl);
$this->assertEquals($expectedXmlEl->asXML(), $actualXmlEl->asXML());
}
public function testNestedMixArrayToXml() {
$testArray = array(
"goal",
"nice",
"funny" => array(
'name' => 'ardi',
'tel' =>'07415517499',
"vary",
"fields" => array(
'small',
'email' => 'ardi.eshghi#gmail.com'
),
'good old days'
),
"notes" => "come on lads lets enjoy this",
"cast" => array(
'Tom Cruise',
'Thomas Muller' => array('age' => 24)
)
);
// Expected xml value
$expectedXmlEl = new SimpleXMLElement('<root/>');
$expectedXmlEl->addChild('item0', $testArray[0]);
$expectedXmlEl->addChild('item1', $testArray[1]);
$childEl = $expectedXmlEl->addChild('funny');
$childEl->addChild("name", $testArray['funny']['name']);
$childEl->addChild("tel", $testArray['funny']['tel']);
$childEl->addChild("item0", "vary");
$childChildEl = $childEl->addChild("fields");
$childChildEl->addChild('item0', 'small');
$childChildEl->addChild('email', $testArray['funny']['fields']['email']);
$childEl->addChild("item1", 'good old days');
$expectedXmlEl->addChild('notes', $testArray['notes']);
$childEl2 = $expectedXmlEl->addChild('cast');
$childEl2->addChild('item0', 'Tom Cruise');
$childChildEl2 = $childEl2->addChild('Thomas Muller');
$childChildEl2->addChild('age', $testArray['cast']['Thomas Muller']['age']);
// What the function produces
$actualXmlEl = new SimpleXMLElement('<root/>');
arrayToXml($testArray, $actualXmlEl);
$this->assertEquals($expectedXmlEl->asXML(), $actualXmlEl->asXML());
}
}
other solution:
$marray=array(....);
$options = array(
"encoding" => "UTF-8",
"output_type" => "xml",
"version" => "simple",
"escaping" => array("non-ascii, on-print, markup")
);
$xmlres = xmlrpc_encode_request('root', $marray, $options);
print($xmlres);
IF the array is associative and keyed correctly, it would probably be easier to turn it into xml first. Something like:
function array2xml ($array_item) {
$xml = '';
foreach($array_item as $element => $value)
{
if (is_array($value))
{
$xml .= "<$element>".array2xml($value)."</$element>";
}
elseif($value == '')
{
$xml .= "<$element />";
}
else
{
$xml .= "<$element>".htmlentities($value)."</$element>";
}
}
return $xml;
}
$simple_xml = simplexml_load_string(array2xml($assoc_array));
The other route would be to create your basic xml first, like
$simple_xml = simplexml_load_string("<array></array>");
and then for each part of your array, use something similar to my text creating loop and instead use the simplexml functions "addChild" for each node of the array.
I'll try that out later and update this post with both versions.
Just a edit on a function above, when a key is numeric, add a prefix "key_"
// initializing or creating array
$student_info = array(your array data);
// creating object of SimpleXMLElement
$xml_student_info = new SimpleXMLElement("<?xml version=\"1.0\"?><student_info></student_info>");
// function call to convert array to xml
array_to_xml($student,$xml_student_info);
//saving generated xml file
$xml_student_info->asXML('file path and name');
function array_to_xml($student_info, &$xml_student_info) {
foreach($student_info as $key => $value) {
if(is_array($value)) {
if(!is_numeric($key)){
$subnode = $xml_student_info->addChild("$key");
array_to_xml($value, $subnode);
}
else{
$subnode = $xml_student_info->addChild("key_$key");
array_to_xml($value, $subnode);
}
}
else {
if(!is_numeric($key)){
$xml_student_info->addChild("$key","$value");
}else{
$xml_student_info->addChild("key_$key","$value");
}
}
}
}
You can Use the following function in you code directly,
function artoxml($arr, $i=1,$flag=false){
$sp = "";
for($j=0;$j<=$i;$j++){
$sp.=" ";
}
foreach($arr as $key=>$val){
echo "$sp<".$key.">";
if($i==1) echo "\n";
if(is_array($val)){
if(!$flag){echo"\n";}
artoxml($val,$i+5);
echo "$sp</".$key.">\n";
}else{
echo "$val"."</".$key.">\n";
}
}
}
Call the function with first argument as your array and the second argument must be 1, this will be increased for perfect indentation, and third must be true.
for example, if the array variable to be converted is $array1 then,
calling would be, the calling function should be encapsulated with <pre> tag.
artoxml($array1,1,true);
Please see the page source after executing the file, because the < and > symbols won't be displayed in a html page.
function toXML($data, $obj = false, $dom) {
$is_first_level = false;
if($obj === false) {
$dom = new DomDocument('1.0');
$obj = $dom;
$is_first_level = true;
}
if(is_array($data)) {
foreach($data as $key => $item) {
$this->toXML($item, $obj->appendChild($dom->createElement($key)), $dom);
}
}else {
$obj->appendChild($dom->createTextNode($data));
}
if($is_first_level) {
$obj->formatOutput = true;
return $obj->saveXML();
}
return $obj;
}
function array2xml(array $data, SimpleXMLElement $object = null, $oldNodeName = 'item')
{
if (is_null($object)) $object = new SimpleXMLElement('<root/>');
$isNumbered = true;
$idx = 0;
foreach ($data as $key => $x)
if (is_string($key) || ($idx++ != $key + 0))
$isNumbered = false;
foreach ($data as $key => $value)
{
$attribute = preg_match('/^[0-9]/', $key . '') ? $key : null;
$key = (is_string($key) && !preg_match('/^[0-9]/', $key . '')) ? $key : preg_replace('/s$/', '', $oldNodeName);
if (is_array($value))
{
$new_object = $object->addChild($key);
if (!$isNumbered && !is_null($attribute)) $new_object->addAttribute('id', $attribute);
array2xml($value, $new_object, $key);
}
else
{
if (is_bool($value)) $value = $value ? 'true' : 'false';
$node = $object->addChild($key, htmlspecialchars($value));
if (!$isNumbered && !is_null($attribute) && !isset($node->attributes()->id))
$node->addAttribute('id', $attribute);
}
}
return $object;
}
This function returns for example a list of <obj>...</obj><obj>...</obj> XML tags for numeric indexes.
Input:
array(
'people' => array(
'dog',
'cat',
'life' => array(
'gum',
'shoe',
),
'fish',
),
array('yeah'),
)
Output:
<root>
<people>
<people>dog</people>
<people>cat</people>
<life>
<life>gum</life>
<life>shoe</life>
</life>
<people>fish</people>
<people>
<people>yeah</people>
</people>
</people>
</root>
This should satisfy all common needs. Maybe you may change the 3rd line to:
$key = is_string($key) ? $key : $oldNodeName . '_' . $key;
or if you are working with plurals ending with s:
$key = is_string($key) ? $key : preg_replace('/s$/', '', $oldNodeName);
With FluidXML you can generate, starting from a PHP Array, an XML for SimpleXML with... just two lines of code.
$fluidxml = fluidxml($array);
$simplexml = simplexml_import_dom($fluidxml->dom());
An example array could be
$array = [ 'doc' => [
'fruit' => 'orange',
'cake' => [
'#id' => '123',
'#' => 'tiramisu' ],
[ 'pasta' => 'matriciana' ],
[ 'pasta' => 'boscaiola' ]
] ];
https://github.com/servo-php/fluidxml
You may use xmlrpc_encode to create a xml from array if a verbose xml is not a problem.
www.php.net/xmlrpc_encode
be careful the xml created differs in case you use associative and/or numeric keys
<?php
// /params/param/value/struct/member
// there is a tag "member" for each element
// "member" contains a tag "name". its value is the associative key
$xml1 = xmlrpc_encode(array('a'=>'b','c'=>'d'));
$simplexml1 = simplexml_load_string($xml1);
print_r($xml1);
print_r($simplexml1);
// /params/param/value/array/data
// there is a tag "data" for each element
// "data" doesn't contain the tag "name"
$xml2 = xmlrpc_encode(array('a','b'));
$simplexml2 = simplexml_load_string($xml2);
print_r($xml2);
print_r($simplexml2);
?>
function array2xml($array, $xml = false){
if($xml === false){
$xml = new SimpleXMLElement('<?xml version=\'1.0\' encoding=\'utf-8\'?><'.key($array).'/>');
$array = $array[key($array)];
}
foreach($array as $key => $value){
if(is_array($value)){
$this->array2xml($value, $xml->addChild($key));
}else{
$xml->addChild($key, $value);
}
}
return $xml->asXML();
}
My answer, cobbling together others' answers. This should correct for the failure to compensate for numeric keys:
function array_to_xml($array, $root, $element) {
$xml = new SimpleXMLElement("<{$root}/>");
foreach ($array as $value) {
$elem = $xml->addChild($element);
xml_recurse_child($elem, $value);
}
return $xml;
}
function xml_recurse_child(&$node, $child) {
foreach ($child as $key=>$value) {
if(is_array($value)) {
foreach ($value as $k => $v) {
if(is_numeric($k)){
xml_recurse_child($node, array($key => $v));
}
else {
$subnode = $node->addChild($key);
xml_recurse_child($subnode, $value);
}
}
}
else {
$node->addChild($key, $value);
}
}
}
The array_to_xml() function presumes that the array is made up of numeric keys first. If your array had an initial element, you would drop the foreach() and $elem statements from the array_to_xml() function and just pass $xml instead.
I would have commented the second most voted answer, because it doesn't preserve structure and generates bad xml if there is numerically indexed inner arrays.
I developed my own version based on it, because I needed simple converter between json and xml regardless of the structure of data. My version preserves numeric key information and structure of the original array. It creates elements for the numerically indexed values by wrapping values to value -named elements with key-attribute that contains numerical key.
For example
array('test' => array(0 => 'some value', 1 => 'other'))
converts to
<test><value key="0">some value</value><value key="1">other</value></test>
My version of array_to_xml -function (hope it helps somebody :)
function array_to_xml($arr, &$xml) {
foreach($arr as $key => $value) {
if(is_array($value)) {
if(!is_numeric($key)){
$subnode = $xml->addChild("$key");
} else {
$subnode = $xml->addChild("value");
$subnode->addAttribute('key', $key);
}
array_to_xml($value, $subnode);
}
else {
if (is_numeric($key)) {
$xml->addChild("value", $value)->addAttribute('key', $key);
} else {
$xml->addChild("$key",$value);
}
}
}
}
Whole XML structure is defined in $data Array:
function array2Xml($data, $xml = null)
{
if (is_null($xml)) {
$xml = simplexml_load_string('<' . key($data) . '/>');
$data = current($data);
$return = true;
}
if (is_array($data)) {
foreach ($data as $name => $value) {
array2Xml($value, is_numeric($name) ? $xml : $xml->addChild($name));
}
} else {
$xml->{0} = $data;
}
if (!empty($return)) {
return $xml->asXML();
}
}
If you work in magento and you have this type of associative array
$test_array = array (
'0' => array (
'category_id' => '582',
'name' => 'Surat',
'parent_id' => '565',
'child_id' => '567',
'active' => '1',
'level' => '6',
'position' => '17'
),
'1' => array (
'category_id' => '567',
'name' => 'test',
'parent_id' => '0',
'child_id' => '576',
'active' => '0',
'level' => '0',
'position' => '18'
),
);
then this is best to convert associative array to xml format.Use this code in controller file.
$this->loadLayout(false);
//header ("content-type: text/xml");
$this->getResponse()->setHeader('Content-Type','text/xml');
$this->renderLayout();
$clArr2xml = new arr2xml($test_array, 'utf-8', 'listdata');
$output = $clArr2xml->get_xml();
print $output;
class arr2xml
{
var $array = array();
var $xml = '';
var $root_name = '';
var $charset = '';
public function __construct($array, $charset = 'utf-8', $root_name = 'root')
{
header ("content-type: text/xml");
$this->array = $array;
$this->root_name = $root_name;
$this->charset = $charset;
if (is_array($array) && count($array) > 0) {
$this->struct_xml($array);
} else {
$this->xml .= "no data";
}
}
public function struct_xml($array)
{
foreach ($array as $k => $v) {
if (is_array($v)) {
$tag = ereg_replace('^[0-9]{1,}', 'item', $k); // replace numeric key in array to 'data'
$this->xml .= "<$tag>";
$this->struct_xml($v);
$this->xml .= "</$tag>";
} else {
$tag = ereg_replace('^[0-9]{1,}', 'item', $k); // replace numeric key in array to 'data'
$this->xml .= "<$tag><![CDATA[$v]]></$tag>";
}
}
}
public function get_xml()
{
$header = "<?xml version=\"1.0\" encoding=\"" . $this->charset . "\"?><" . $this->root_name . ">";
$footer = "</" . $this->root_name . ">";
return $header . $this->xml . $footer;
}
}
I hope it helps to all.
// Structered array for XML convertion.
$data_array = array(
array(
'#xml_tag' => 'a',
'#xml_value' => '',
'#tag_attributes' => array(
array(
'name' => 'a_attr_name',
'value' => 'a_attr_value',
),
),
'#subnode' => array(
array(
'#xml_tag' => 'aa',
'#xml_value' => 'aa_value',
'#tag_attributes' => array(
array(
'name' => 'aa_attr_name',
'value' => 'aa_attr_value',
),
),
'#subnode' => FALSE,
),
),
),
array(
'#xml_tag' => 'b',
'#xml_value' => 'b_value',
'#tag_attributes' => FALSE,
'#subnode' => FALSE,
),
array(
'#xml_tag' => 'c',
'#xml_value' => 'c_value',
'#tag_attributes' => array(
array(
'name' => 'c_attr_name',
'value' => 'c_attr_value',
),
array(
'name' => 'c_attr_name_1',
'value' => 'c_attr_value_1',
),
),
'#subnode' => array(
array(
'#xml_tag' => 'ca',
'#xml_value' => 'ca_value',
'#tag_attributes' => FALSE,
'#subnode' => array(
array(
'#xml_tag' => 'caa',
'#xml_value' => 'caa_value',
'#tag_attributes' => array(
array(
'name' => 'caa_attr_name',
'value' => 'caa_attr_value',
),
),
'#subnode' => FALSE,
),
),
),
),
),
);
// creating object of SimpleXMLElement
$xml_object = new SimpleXMLElement('<?xml version=\"1.0\"?><student_info></student_info>');
// function call to convert array to xml
array_to_xml($data_array, $xml_object);
// saving generated xml file
$xml_object->asXML('/tmp/test.xml');
/**
* Converts an structured PHP array to XML.
*
* #param Array $data_array
* The array data for converting into XML.
* #param Object $xml_object
* The SimpleXMLElement Object
*
* #see https://gist.github.com/drupalista-br/9230016
*
*/
function array_to_xml($data_array, &$xml_object) {
foreach($data_array as $node) {
$subnode = $xml_object->addChild($node['#xml_tag'], $node['#xml_value']);
if ($node['#tag_attributes']) {
foreach ($node['#tag_attributes'] as $tag_attributes) {
$subnode->addAttribute($tag_attributes['name'], $tag_attributes['value']);
}
}
if ($node['#subnode']) {
array_to_xml($node['#subnode'], $subnode);
}
}
}

How to convert array to string in PHP?

Hi i am using CakePHP version 2.x
I am print my array using
pr($this->request->params['named']);
//Output
Array
(
[street_name] => Bhubaneswar
[house_number] => 1247
[phone] => xxxxxxxx
[zip] => xxxxx
)
In above array i want to view looks like
/street_name:Bhubaneswar/house_number:1247/phone:xxxxxxxx/zip:xxxxx
How to convert above array in string format?
Try this:
$strResult = "";
foreach ($this->request->params['named'] as $key=>$value){
$strResult .= "/{$key}:{$value}";
}
The most easy and speedy solution.
$result = '';
foreach ($this->request->params['name'] as $k => $v) {
$result .= sprintf('/%s:%s', $k, $v);
}
As a one-liner:
echo '/' . str_replace('=', ':', http_build_query($array, '', '/'));
Would output:
/street_name:Bhubaneswar/house_number:1247/phone:xxx/zip:xxx
foreach (array_expression as $key => $value){
echo "/". $key . ":" . $value;
}
Try following code:
$ar = array('street_name' => 'Bhubaneswar',
'house_number' => 1247,
'phone' => 'xxxxxxxx',
'zip' => 'xxxxx');
echo convert($ar);
function convert($ar)
{
$str = '';
foreach($ar as $i=>$k)
{
$str .= '/'.$i.':'.$k;
}
return $str;
}
Output
/street_name:Bhubaneswar/house_number:1247/phone:xxxxxxxx/zip:xxxxx
function implode_with_keys($glue, $separator, $pieces)
{
$string = '';
foreach ($pieces as $key => $value) {
$string .= $glue . $key . $separator . $value;
}
return $string;
}
In your case you'd use it like this:
implode_with_keys('/', ':', $this->request->params['named']);
This will return the desired string /street_name:Bhubaneswar/house_number:1247/phone:xxxxxxxx/zip:xxxxx.
<?php
$array = array(
'street_name' => 'Bhubaneswar',
'house_number' => '1247',
'phone' => 'xxxxxxxx',
'zip' => 'xxxxx',
);
while (current($array)) {
echo '/'.key($array).':'.$array[key($array)];
next($array);
}
?>
this will return
/street_name:Bhubaneswar/house_number:1247/phone:xxxxxxxx/zip:xxxxx

Read nested array dynamicly in php

I need to read nested arrays without knowing how the array will look.
For example;
$data = array(
'Data1_lvl1' => array(
'Data1_lvl2' => "value",
'Data2_lvl2' => array(
'Data1_lvl3' => "value"
)
),
'Data2_lvl1' => 'value'
);
Needs to be formatted to strings like:
Data1_lvl1/Data1_lvl2/
Data1_lvl1/Data2_lvl2/Data1_lvl3/
Data2_lvl1/
But the array can be of any size with any number of nested arrays inside it.
$data = array(
'Data1_lvl1' => array(
'Data1_lvl2' => "value",
'Data2_lvl2' => array(
'Data1_lvl3' => "value"
)
),
'Data2_lvl1' => 'value'
);
function printArray($array)
{
foreach ($array as $key=>$value)
{
echo $key.'/';
if (is_array($value))
{
printArray($value);
} else {
echo '<br>';
}
}
}
printArray($data);
If you want to output only the name of array elements then this recursive function will do the trick.
Your data:
$data = array(
'Data1_lvl1' => array(
'Data1_lvl2' => "value",
'Data2_lvl2' => array(
'Data1_lvl3' => "value"
)
),
'Data2_lvl1' => 'value'
);
Function:
function array2str($array, $str) {
foreach($array as $key => $val) {
if (is_array($val) ) {
$str .= $key . '/';
array2str($val, $str);
}
}
echo $str.'<br />';
return $str;
}
array2str($data);
As you can see the script does ECHO in itself with <br /> to break the line when viewing results in a browser.
One way would to walk recursively through array with function similar to this:
<?php
function f($d, $str = '') {
foreach ($d as $key => $val) {
if (is_array($val)) f($val, $str . '/' . $key); // If this element is array parse next level
else print_r($str . '/' . $key . '/'); // Output current string or do what you need to do with it..
}
}
$data = array(
'Data1_lvl1' => array(
'Data1_lvl2' => "value",
'Data2_lvl2' => array(
'Data1_lvl3' => "value"
)
),
'Data2_lvl1' => 'value'
);
f($data);
with that function:
<?php
function print_tree ($data, $prefix = '', &$index = 1) {
foreach($data as $key => $datum) {
echo $index++ . '. ' . ($new_prefix = $prefix . $key . '/') . PHP_EOL;
if (is_array($datum)) {
print_tree ($datum, $new_prefix, $index);
}
}
}
I get
Data1_lvl1/
Data1_lvl1/Data1_lvl2/
Data1_lvl1/Data2_lvl2/
Data1_lvl1/Data2_lvl2/Data1_lvl3/
Data2_lvl1/

Get array's key recursively and create underscore separated string

Right now i got an array which has some sort of information and i need to create a table from it. e.g.
Student{
[Address]{
[StreetAddress] =>"Some Street"
[StreetName] => "Some Name"
}
[Marks1] => 100
[Marks2] => 50
}
Now I want to create database table like which contain the fields name as :
Student_Address_StreetAddress
Student_Address_StreetName
Student_Marks1
Student_Marks2
It should be recursive so from any depth of array it can create the string in my format.
You can use the RecursiveArrayIterator and the RecursiveIteratorIterator (to iterate over the array recursively) from the Standard PHP Library (SPL) to make this job relatively painless.
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
$keys = array();
foreach ($iterator as $key => $value) {
// Build long key name based on parent keys
for ($i = $iterator->getDepth() - 1; $i >= 0; $i--) {
$key = $iterator->getSubIterator($i)->key() . '_' . $key;
}
$keys[] = $key;
}
var_export($keys);
The above example outputs something like:
array (
0 => 'Student_Address_StreetAddress',
1 => 'Student_Address_StreetName',
2 => 'Student_Marks1',
3 => 'Student_Marks2',
)
(Working on it, here is the array to save the trouble):
$arr = array
(
'Student' => array
(
'Address' => array
(
'StreetAddress' => 'Some Street',
'StreetName' => 'Some Name',
),
'Marks1' => '100',
'Marks2' => '50',
),
);
Here it is, using a modified version of #polygenelubricants code:
function dfs($array, $parent = null)
{
static $result = array();
if (is_array($array) * count($array) > 0)
{
foreach ($array as $key => $value)
{
dfs($value, $parent . '_' . $key);
}
}
else
{
$result[] = ltrim($parent, '_');
}
return $result;
}
echo '<pre>';
print_r(dfs($arr));
echo '</pre>';
Outputs:
Array
(
[0] => Student_Address_StreetAddress
[1] => Student_Address_StreetName
[2] => Student_Marks1
[3] => Student_Marks2
)
Something like this maybe?
$schema = array(
'Student' => array(
'Address' => array(
'StreetAddresss' => "Some Street",
'StreetName' => "Some Name",
),
'Marks1' => 100,
'Marks2' => 50,
),
);
$result = array();
function walk($value, $key, $memo = "") {
global $result;
if(is_array($value)) {
$memo .= $key . '_';
array_walk($value, 'walk', $memo);
} else {
$result[] = $memo . $key;
}
}
array_walk($schema, 'walk');
var_dump($result);
I know globals are bad, but can't think of anything better now.
Something like this works:
<?php
$arr = array (
'Student' => array (
'Address' => array (
'StreetAddress' => 'Some Street',
'StreetName' => 'Some Name',
),
'Marks1' => array(),
'Marks2' => '50',
),
);
$result = array();
function dfs($data, $prefix = "") {
global $result;
if (is_array($data) && !empty($data)) {
foreach ($data as $key => $value) {
dfs($value, "{$prefix}_{$key}");
}
} else {
$result[substr($prefix, 1)] = $data;
}
}
dfs($arr);
var_dump($result);
?>
This prints:
array(4) {
["Student_Address_StreetAddress"] => string(11) "Some Street"
["Student_Address_StreetName"] => string(9) "Some Name"
["Student_Marks1"] => array(0) {}
["Student_Marks2"] => string(2) "50"
}
function getValues($dataArray,$strKey="")
{
global $arrFinalValues;
if(is_array($dataArray))
{
$currentKey = $strKey;
foreach($dataArray as $key => $val)
{
if(is_array($val) && !empty($val))
{
getValues($val,$currentKey.$key."_");
}
else if(!empty($val))
{
if(!empty($strKey))
$strTmpKey = $strKey.$key;
else
$strTmpKey = $key;
$arrFinalValues[$strTmpKey]=$val;
}
}
}
}

Categories