Up until now, I've been using the snippet below to convert an XML tree to an array:
$a = json_decode(json_encode((array) simplexml_load_string($xml)),1);
..however, I'm now working with an XML that has duplicate key values, so the array is breaking when it loops through the XML. For example:
<users>
<user>x</user>
<user>y</user>
<user>z</user>
</users>
Is there a better method to do this that allows for duplicate Keys, or perhaps a way to add an incremented value to each key when it spits out the array, like this:
$array = array(
users => array(
user_1 => x,
user_2 => y,
user_3 => z
)
)
I'm stumped, so any help would be very appreciated.
Here is a complete universal recursive solution.
This class will parse any XML under any structure, with or without tags, from the simplest to the most complex ones.
It retains all proper values and convert them (bool, txt or int), generates adequate array keys for all elements groups including tags, keep duplicates elements etc etc...
Please forgive the statics, it s part of a large XML tools set I used, before rewriting them all for HHVM or pthreads, I havent got time to properly construct this one, but it will work like a charm for straightforward PHP.
For tags, the declared value is '#attr' in this case but can be whatever your needs are.
$xml = "<body>
<users id='group 1'>
<user>x</user>
<user>y</user>
<user>z</user>
</users>
<users id='group 2'>
<user>x</user>
<user>y</user>
<user>z</user>
</users>
</body>";
$result = xml_utils::xml_to_array($xml);
result:
Array ( [users] => Array ( [0] => Array ( [user] => Array ( [0] => x [1] => y [2] => z ) [#attr] => Array ( [id] => group 1 ) ) [1] => Array ( [user] => Array ( [0] => x [1] => y [2] => z ) [#attr] => Array ( [id] => group 2 ) ) ) )
Class:
class xml_utils {
/*object to array mapper */
public static function objectToArray($object) {
if (!is_object($object) && !is_array($object)) {
return $object;
}
if (is_object($object)) {
$object = get_object_vars($object);
}
return array_map('objectToArray', $object);
}
/* xml DOM loader*/
public static function xml_to_array($xmlstr) {
$doc = new DOMDocument();
$doc->loadXML($xmlstr);
return xml_utils::dom_to_array($doc->documentElement);
}
/* recursive XMl to array parser */
public static function dom_to_array($node) {
$output = array();
switch ($node->nodeType) {
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
$child = $node->childNodes->item($i);
$v = xml_utils::dom_to_array($child);
if (isset($child->tagName)) {
$t = xml_utils::ConvertTypes($child->tagName);
if (!isset($output[$t])) {
$output[$t] = array();
}
$output[$t][] = $v;
} elseif ($v) {
$output = (string) $v;
}
}
if (is_array($output)) {
if ($node->attributes->length) {
$a = array();
foreach ($node->attributes as $attrName => $attrNode) {
$a[$attrName] = xml_utils::ConvertTypes($attrNode->value);
}
$output['#attr'] = $a;
}
foreach ($output as $t => $v) {
if (is_array($v) && count($v) == 1 && $t != '#attr') {
$output[$t] = $v[0];
}
}
}
break;
}
return $output;
}
/* elements converter */
public static function ConvertTypes($org) {
if (is_numeric($org)) {
$val = floatval($org);
} else {
if ($org === 'true') {
$val = true;
} else if ($org === 'false') {
$val = false;
} else {
if ($org === '') {
$val = null;
} else {
$val = $org;
}
}
}
return $val;
}
}
You can loop through each key in your result and if the value is an array (as it is for user that has 3 elements in your example) then you can add each individual value in that array to the parent array and unset the value:
foreach($a as $user_key => $user_values) {
if(!is_array($user_values))
continue; //not an array nothing to do
unset($a[$user_key]); //it's an array so remove it from parent array
$i = 1; //counter for new key
//add each value to the parent array with numbered keys
foreach($user_values as $user_value) {
$new_key = $user_key . '_' . $i++; //create new key i.e 'user_1'
$a[$new_key] = $user_value; //add it to the parent array
}
}
var_dump($a);
First of all this line of code contains a superfluous cast to array:
$a = json_decode(json_encode((array) simplexml_load_string($xml)),1);
^^^^^^^
When you JSON-encode a SimpleXMLElement (which is returned by simplexml_load_string when the parameter could be parsed as XML) this already behaves as-if there would have been an array cast. So it's better to remove it:
$sxml = simplexml_load_string($xml);
$array = json_decode(json_encode($sxml), 1);
Even the result is still the same, this now allows you to create a subtype of SimpleXMLElement implementing the JsonSerialize interface changing the array creation to your needs.
The overall method (as well as the default behaviour) is outlined in a blog-series of mine, on Stackoverflow I have left some more examples already as well:
PHP convert XML to JSON group when there is one child (Jun 2013)
Resolve namespaces with SimpleXML regardless of structure or namespace (Oct 2014)
XML to JSON conversion in PHP SimpleXML (Dec 2014)
Your case I think is similar to what has been asked in the first of those three links.
Related
Have a question about mtownsend/request-xml (XML to array) plugin.
So, plugin makes XML file to array.
I use it in my Laravel projects and there is several reason, because I need exact it, but here is one problem.
Have two simple XML files
first file oneitem.xml with one item <flat> into <post>
<?xml version="1.0" encoding="UTF-8"?>
<data>
<post>
<flat>
<roms>4</roms>
<baths>2</baths>
</flat>
</post>
</data>
second file severalitems.xml one with several items <flat> into <post>:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<post>
<flat>
<roms>4</roms>
<baths>2</baths>
</flat>
<flat>
<roms>5</roms>
<baths>1</baths>
</flat>
<flat>
<roms>7</roms>
<baths>3</baths>
</flat>
</post>
</data>
Then, I use a simple code to make an array from this files, and show the result array for each:
$xmlone = XmlToArray::convert(file_get_contents('public/xml/test/oneitem.xml'));
$oneflat = $xmlone['post'];
print_r($oneflat);
$xmlseveral = XmlToArray::convert(file_get_contents('public/xml/test/severalitems.xml'));
$severalflats = $xmlseveral['post'];
print_r($severalflats);
If we try to make an array from first file (with one flat), and find all we have in posts we have this result:
Array ( [flat] => Array ( [roms] => 4 [baths] => 2 ) )
If we do the same in second file (with several `flat), we have this result
Array ( [flat] => Array ( [0] => Array ( [roms] => 4 [baths] => 2 ) [1] => Array ( [roms] => 5 [baths] => 1 ) [2] => Array ( [roms] => 7 [baths] => 3 ) )
So, if we have several items, plugin adds a additional arrays with keys, [0], [1], [2]....
I need to do it the same, even there is just one item flat into posts. So the results have same formats.
I know, that it makes plugin. If plugin see, that there is just one flat in post, he makes result array simple.
The code of main file of plugin is here, but I cant understand, which lines do it...
Thanks for your help
public static function convert($xml, $outputRoot = false)
{
$array = self::xmlStringToArray($xml);
if (!$outputRoot && array_key_exists('#root', $array)) {
unset($array['#root']);
}
return $array;
}
protected static function xmlStringToArray($xmlstr)
{
$doc = new DOMDocument();
$doc->loadXML($xmlstr);
$root = $doc->documentElement;
$output = self::domNodeToArray($root);
$output['#root'] = $root->tagName;
return $output;
}
protected static function domNodeToArray($node)
{
$output = [];
switch ($node->nodeType) {
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
$child = $node->childNodes->item($i);
$v = self::domNodeToArray($child);
if (isset($child->tagName)) {
$t = $child->tagName;
if (!isset($output[$t])) {
$output[$t] = [];
}
$output[$t][] = $v;
} elseif ($v || $v === '0') {
$output = (string) $v;
}
}
if ($node->attributes->length && !is_array($output)) { // Has attributes but isn't an array
$output = ['#content' => $output]; // Change output into an array.
}
if (is_array($output)) {
if ($node->attributes->length) {
$a = [];
foreach ($node->attributes as $attrName => $attrNode) {
$a[$attrName] = (string) $attrNode->value;
}
$output['#attributes'] = $a;
}
foreach ($output as $t => $v) {
if (is_array($v) && count($v) == 1 && $t != '#attributes') {
$output[$t] = $v[0];
}
}
}
break;
}
return $output;
}
}
** Thanks for your help!**
Looks like its not posstible. As I understood, standart PHP tools to XML to array convertation makes it so. The plugin based on them.
Anyway, I think there is a way to solve it throught changing source code of this plugin, but I soleved in my situation, by workung with results of XML to array convertation, and check if result array have one flat or several.
Here is the data structure I have (it's simplified for clearlier understanding):
• USA
• Alabama
• Montgomery
• Birmingham
• Arizona
• Phoenix
• Mesa
• Gilbert
• Germany
• West Germany
• Bonn
• Cologne
I need to return all path for given node – i.e.: if user enter Arizona, I need to return USA → Arizona. If enter Birmingham, I need to return USA → Alabama → Birmingham.
Is there in PHP simple way to search in such structures?
If you haven't huge data structure, you can use XML parsing. It's well known and easy to implement. It has desired ability to access parent element.
Here is an simple example:
$xml = <<<XML
<list>
<state name="USA">
<region name="Alabama">
<city name="Montgomery" />
<city name="Birmingham" />
</region>
<region name="Arizona">
<city name="Phoenix" />
<city name="Mesa" />
<city name="Gilbert" />
</region>
</state>
<state name="Germany">
<region name="West Germany">
<city name="Bonn" />
<city name="Cologne" />
</region>
</state>
</list>
XML;
$doc = new \DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->loadXML($xml);
$xpath = new \DOMXPath($doc);
// XPath query to match all elements with
// attribute name equals to your searched phrase
$locations = $xpath->query("//*[#name='Cologne']");
function parse($list) {
$response = [];
foreach ($list as $node) {
$response[] = $node->attributes->getNamedItem('name')->nodeValue;
$parentNode = $node->parentNode;
// traverse up to root element
// root element has no attributes
// feel free to use any other condition, such as checking to element's name
while ($parentNode->hasAttributes()) {
$response[] = $parentNode->attributes->getNamedItem('name')->nodeValue;
$parentNode = $parentNode->parentNode;
}
}
return $response;
}
$parsedLocations = array_reverse(parse($locations));
echo implode(' → ', $parsedLocations), PHP_EOL;
Here is a possible strategy that builds up the path piece by piece: you start from the first level of the array and you check whether the searc term equals the key. If not, you check the value and otherwise if the value is an array (is_array()) you repeat the search recursively by using a prefix.
The data set:
$str = array(
"USA" => array(
"Alabama" => array(
"Montgomery",
"Birmingham"
),
"Arizona" => array(
"Phoenix",
"",
"Gilbert"
),
"West Germany" => array(
"Bonn",
"",
"Cologne"
)
),
"Germany" => array(
"West Germany" => array(
"Bonn",
"Mesa",
"Cologne"
)
)
);
The function:
function getPath($haystack, $needle, $prefix=""){
$path = "";
foreach($haystack as $key=>$value){
if($path!="")break;
if($key===$needle){
return $prefix.$key;
break;
}
elseif($value===$needle) {
return $prefix.$value;
break;
}
elseif(is_array($value)) {
$path.=getPath($value,$needle,$prefix.$key."=>");
}
}
return $path;
}
a test:
echo getPath($str,"Mesa");
In case of duplicates you will get the first result. If the search term is not found, you get an empty string.
Since "data structure" is very vague, and your only hint is that you're using PHP, I will assume that your "data structure" means the following:
[
'USA' =>
[
'Alabama' =>
[
'Montgomery',
'Birmingham'
],
'Arizona' =>
[
'Phoenix',
'Mesa',
'Gilbert'
]
],
'Germany' =>
[
'West Germany' =>
[
'Bonn',
'Cologne'
]
]
]
And I assume that you want your result in the form
['USA', 'Alabama', 'Birmingham']
If this is not the case, please inform us about how your data is actually available and how you want your result.
Is there in PHP simple way to search in such structures?
That depends on your definition of "simple".
For me, a solution that fits into a single function is "simple".
However, there is no out-of-the-box solution for this that you can use in a one-liner.
If you only need to find the "leafs", you could use a RecursiveIteratorIterator over a RecursiveArrayIterator as in this StackOverflow question.
But since you need to find intermediary keys too, that it not really an option.
The same goes for array_walk_recursive.
You could probably use ArrayIterator or array_walk, but in this example they can't really do anything a foreach loop can't, besides complicate things.
So I'd just go with a foreach loop:
function findMyThing($needle, $haystack) // Keep argument order from PHP array functions
{
// We need to set up a stack array + a while loop to avoid recursive functions for those are evil.
// Recursive functions would also complicate things further in regard of returning.
$stack =
[
[
'prefix' => [],
'value' => $haystack
]
];
// As long as there's still something there, don't stop
while(count($stack) > 0)
{
// Copy the current stack and create a new, empty one
$currentStack = $stack;
$stack = [];
// Work the stack
for($i = 0; $i < count($currentStack); $i++)
{
// Iterate over the actual array
foreach($currentStack[$i]['value'] as $key => $value)
{
// If the value is an array, then
// 1. the key is a string (so we need to match against it)
// 2. we might have to go deeper
if(is_array($value))
{
// We need to build the current prefix list regardless of what we're gonna do below
$prefix = $currentStack[$i]['prefix'];
$prefix[] = $key;
// If the current key, is the one we're looking for, heureka!
if($key == $needle)
{
return $prefix;
}
// Otherwise, push prefix & value onto the stack for the next loop to pick up
else
{
$stack[] =
[
'prefix' => $prefix,
'value' => $value
];
}
}
// If the value is NOT an array, then
// 1. the key is an integer, so we DO NOT want to match against it
// 2. we need to match against the value itself
elseif($value == $needle)
{
// This time append $value, not $key
$prefix = $currentStack[$i]['prefix'];
$prefix[] = $value;
return $prefix;
}
}
}
}
// At this point we searched the entire array and didn't find anything, so we return an empty array
return [];
}
Then just use it like
$path = findMyThing('Alabama', $array);
#Siguza
avoid recursive functions for those are evil
Recursion is not evil (or eval) and works well with stacks to
function df($v,array &$in,array &$stack,$search) {
$stack[] = $v;
if ( $v == $search ) {
return [true,$stack];
}
if ( is_array($in) ) {
foreach ($in as $vv => $k) {
if ( is_array($k) ) {
$r = df($vv, $k, $stack, $search);
if ($r[0]) {
return $r;
}
}
else if ($k == $search) {
$stack[] = $k;
return [true,$stack];
}
}
}
array_pop($stack);
return [false,null];
}
Usage:
$s = [];
$r = df('',$in,$s,'Bonn');
print_r($r);
$s = [];
$r = df('',$in,$s,'West Germany');
print_r($r);
$s = [];
$r = df('',$in,$s,'NtFound');
print_r($r);
Output:
Array
(
[0] => 1
[1] => Array
(
[0] =>
[1] => Germany
[2] => West Germany
[3] => Bonn
)
)
Array
(
[0] => 1
[1] => Array
(
[0] =>
[1] => Germany
[2] => West Germany
)
)
Array
(
[0] =>
[1] =>
)
According to you data structure.
$data['USA'] = ['Alabama' => ['Montgomery','Birmingham'],'Arizona' => ['Phoenix','Mesa','Gilbert']];
$data['Germany'] = ['West Germany' => ['Bonn','Cologne']];
function getHierarchy($location, $data){
$totalCountries = count($data);
//Get Array Keys of rows eg countries.
$keys = array_keys($data);
$hierarchy= [];
//Loop Through Countries
for($i = 0; $i < $totalCountries; $i++){
//If we have found the country then return it.
if($location == $keys[$i]) return [$keys[$i]];
$hierarchy[] = $keys[$i];
foreach($data[$keys[$i]] as $city => $places){
// if we have found the city then return it with country.
if($city == $location){
$hierarchy[] = $city;
return $hierarchy;
}
// if we have found the place in our places array then return it with country -> city -> place.
if(in_array($location, $places)){
$hierarchy[] = $city;
$hierarchy[] = $location;
return $hierarchy;
}
}
// Reset Hirarcy if we do not found our location in previous country.
$hierarchy = [];
}
}
$found = getHierarchy('Birmingham', $data);
if($found){
echo implode(' -> ', $found);
// Output will be USA -> Alabama -> Birmingham
}
It can only find only one country city and places and if any location is found then it will break the whole function and return the first location with city and place.
Here is more improved version which can find multiple locations as well.
https://gist.github.com/touqeershafi/bf89351f3b226aae1a29
Hope it helps you.
Ok I'm seriously stuck, I've been working on a nav menu that I just cannot get to function how I want it to so i've changed tack but am now stuck again so any help would be much appreciated and desperately needed!
I have the code below and am trying to do the following - I have an array that holds info for all the pages of a site and then another array that holds the ids of the pages that are child pages. What I want to do is use a foreach loop to loop through all the pages of the first array and check whether their ids are in the array of child ids or not. If they are not then they are top level nav pages and I want to output some code and then set up another foreach loop which will check whether any subpages have a parent id of the current page and so on.
I can't seem to work out how to compare $b with the ids in the $childpages array no matter what I try! Is this even possible and if so how please?
This is the first section of what im trying at present
<?php function buildMenu4 ($allpages, $childpages) {
foreach ($allpages as $pages){
$a = $pages['parentid'];
$b = $pages['id'];
$c = $childpages;
echo "<ul>\n";
if (!in_array($b, $c)) {
DO SOMETHING..........
Array contents of $c:
Array
(
[0] => Array ( [id] => 6 )
[1] => Array ( [id] => 15 )
[2] => Array ( [id] => 100 )
[3] => Array ( [id] => 101 )
[4] => Array ( [id] => 103 )
[5] => Array ( [id] => 104 )
[6] => Array ( [id] => 105 )
)
edit ---------------------------------
I have reworked my code and am back to a variation of where I was a couple of days ago!! Anyway the code below works as intended until I try to loop it and then it just echoes the results of the first foreach loop e.g. foreach ($allpages as $pages){..... but fails to do anything else.
I am trying to make a function called loopMenu and then run this recursively until there are no more pages to be displayed. I have tried to write the function as shown with the pusedo code in the code block below but I just can't get it to work. I may have muddled up some of the arguments or parameters or perhaps I have just made a big mistake somewhere but I can't see it - any help would be hugely appreciated and desperately needed!
<?php function buildMenu6 ($allpages, $childpageids, $childpages, $subchildpages) {
foreach ($childpageids as $childid){
$c[] = $childid['id'];
};
echo "<ul>\n";
foreach ($allpages as $pages){
$a = $pages['parentid'];
$b = $pages['id'];
if (!in_array($b, $c)){
echo "<li>" . $pages['linklabel'] . "";
WHERE I WANT THE FUNCTION TO START E.G. function loopMenu($childpages, $subchildpages){...the code that follows....
echo"<ul>\n";
foreach ($childpages as $childparent) {
$d = $childparent['parentid'];
$e = $childparent['id'];
if (($d == $b) or ($d == $g)) {
echo "<li>" . $childparent['linklabel'] . "";
echo "<ul>\n";
foreach ($subchildpages as $subchild){
$g = $subchild['id'];
$f = $subchild['parentid'];
if ($f == $e){
echo "<li>" . $subchild['linklabel'] . "";
WHERE I TRY TO RERUN THE FUNCTION USING loopMenu($childparent, $subchild);
echo "<li/>";
};
};
echo"</ul>\n";
echo "</li>";
};
};
echo "</ul>\n";
WHERE I WANT MY FUNCTION TO END E.G. };
echo "</li>";
};
};
echo "</ul>\n";
}; ?>
Then I call the main buildMenu6 function like so:
<?php buildMenu6($pageids, $childPageIds, $childPageArray, $childPageArray); ?>
You need a nested foreach (I've changed your var names or used the original ones for readability):
foreach($allpages as $page) {
foreach($childpages as $child) {
if($page['id'] == $child['id']) {
//do something
break;
}
}
}
Or PHP >= 5.5.0 use array_column:
$childids = array_column($childpages, 'id');
foreach($allpages as $page) {
if(in_array($page['id'], $childids)) {
//do something
}
}
As a kind of hybrid:
foreach($childpages as $child) {
$childids[] = $child['id'];
}
foreach($allpages as $page) {
if(in_array($page['id'], $childids)) {
//do something
}
}
foreach ($allpages as $pages){
$a = $pages['parentid'];
$b = $pages['id'];
$c = $childpages;
echo "<ul>\n";
// In array isn't aware of the 'id' keys
$found = false;
foreach ($c as $id => $value) {
if ($value == $b) {
$found = true;
}
}
if ($found) {
// DO SOMETHING
}
according to THIS SO ANSWER, array_key_exists is (marginally) the fastest array lookup for php.
since, from your description, it seems reasonable to suppose that [id] is a PRIMARY key and, therefore, unique, i would change the [id] dimension and put values directly in its lieu:
$c[105] = NULL; // or include some value, link page URL
... // some code
$needle = 105;
... // some more code
if (array_key_exists($needle,$c)) {
instead of
$c[5] = 105; // $c is the haystack
... // some code
$needle = 105;
... // some more code
foreach ($c as $tempValue) {
if ($tempValue == $needle) {
in case you want to put values in $c, then you could also use isset (it will return FALSE if array value is NULL for said key).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
String with array structure to Array
I have a string "db/yum/user", and I'm trying to explode it so each element of / becomes a deeper dimension.
So the direct method of creating the data variable would be
$config['db']['yum']['user'] = "val";
My attempt so far:
$config = array();
function set_config($key,$value){
global $config;
//Multi deminsional config
$multi_configs = explode('/',$key);
if($multi_configs!==false){
$build_up = array();
$c =& $build_up;
foreach($multi_configs as $multi_config){
$c[$multi_config] = array();
$c =& $c[$multi_config];
}
//$c = $value;
array_merge($config,$c);
return;
}
$config[$key] = $value;
}
set_config('db/yum/user','val');
set_config('db/yum/server','val2');
//etc,etc,etc, this was modified to make more sense in this context.
This is probably what you are looking for:
#!/usr/bin/php
<?php
$config = array();
function set_config($key, $value) {
global $config;
if (FALSE=== ($levels=explode('/',$key)))
return;
$pointer = &$config;
for ($i=0; $i<sizeof($levels); $i++) {
if (!isset($pointer[$levels[$i]]))
$pointer[$levels[$i]]=array();
$pointer=&$pointer[$levels[$i]];
} // for
$pointer=$value;
} // set_config
set_config('db/yum/user','val');
set_config('db/yum/server','val2');
print_r($config);
?>
The output is:
Array
(
[db] => Array
(
[yum] => Array
(
[user] => val
[server] => val2
)
)
)
You can also achieve the same solution using a tree structure in the array . Here is the code to construct the array :
$arr = array (5,6);
$new_arr=array ();
$prev=0;
foreach ($arr as $val) {
$new_arr[$prev] = $val;
$prev=$val;
}
$new_arr[$prev]="value";
Here is the code to retrieve the value:
function retrieve ($arr) {
$prev=0;
while (1) {
if (! isset($arr[$prev] ) )
break;
else $prev = $arr[$prev];
}
return $prev;
}
Here is example how my array should look like:
$library = array(
'book' => array(
array(
'authorFirst' => 'Mark',
'authorLast' => 'Twain',
'title' => 'The Innocents Abroad'
),
array(
'authorFirst' => 'Charles',
'authorLast' => 'Dickens',
'title' => 'Oliver Twist'
)
)
);
When I get results from oracle database:
$row = oci_fetch_array($refcur, OCI_ASSOC+OCI_RETURN_NULLS);
But when I execute my code I only get one row.
For example: <books><book></book><name></name></books>
But I want all rows to be shown in xml.
EDIT:
This is my class for converting array to xml:
public static function toXml($data, $rootNodeName = 'data', &$xml=null)
{
// turn off compatibility mode as simple xml throws a wobbly if you don't.
if (ini_get('zend.ze1_compatibility_mode') == 1)
{
ini_set ('zend.ze1_compatibility_mode', 0);
}
if (is_null($xml))
{
$xml = simplexml_load_string("<".key($data)."/>");
}
// loop through the data passed in.
foreach($data as $key => $value)
{
// if numeric key, assume array of rootNodeName elements
if (is_numeric($key))
{
$key = $rootNodeName;
}
// delete any char not allowed in XML element names
$key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
// if there is another array found recrusively call this function
if (is_array($value))
{
// create a new node unless this is an array of elements
$node = ArrayToXML::isAssoc($value) ? $xml->addChild($key) : $xml;
// recrusive call - pass $key as the new rootNodeName
ArrayToXML::toXml($value, $key, $node);
}
else
{
// add single node.
$value = htmlentities($value);
$xml->addChild($key,$value);
}
}
// pass back as string. or simple xml object if you want!
return $xml->asXML();
}
// determine if a variable is an associative array
public static function isAssoc( $array ) {
return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
}
}
?>
Now with below responde I have tried problem is I get following output: <book>...</book> tags after each row.. then I tried 3 dimensional array now I get: <book><book>...</book></book> on the proper place but I have 2 of them.
This is the line where I have determine which is root on that array and that's why I get this output. But don't know how to change it : $xml = simplexml_load_string("<".key($data)."/>");
Thank you.
oci_fetch_array() will always return a single row, you need to call it until there are no more rows to fetch in order to get all of them:
while ($row = oci_fetch_array($refcur, OCI_ASSOC+OCI_RETURN_NULLS))
{
$library['book'][] = $row;
}