Get value from XML Array in PHP - php

I'm trying to get 1 value from my XML Array.
This is the code:
<?php
function objectsIntoArray($arrObjData, $arrSkipIndices = array())
{
$arrData = array();
// if input is object, convert into array
if (is_object($arrObjData)) {
$arrObjData = get_object_vars($arrObjData);
}
if (is_array($arrObjData)) {
foreach ($arrObjData as $index => $value) {
if (is_object($value) || is_array($value)) {
$value = objectsIntoArray($value, $arrSkipIndices); // recursive call
}
if (in_array($index, $arrSkipIndices)) {
continue;
}
$arrData[$index] = $value;
}
}
return $arrData;
}
?>
Result:
<?php
$xmlUrl = "http://radiourl:port/status.xsl"; // XML feed file/URL
$xmlStr = file_get_contents($xmlUrl);
$xmlObj = simplexml_load_string($xmlStr);
$arrXml = objectsIntoArray($xmlObj);
print_r($arrXml);
?>
The result of print_r($arrXml); is this:
Array (
[Mount-Point] => /listen.mp3
[Stream-Title] => VibboStream
[Stream-Description] => name
[Content-Type] => audio/mpeg
[Mount-started] => 14/Jun/2016:04:28:49 -0500
[Bitrate] => 128
[Current-Listeners] => 1
[Peak-Listeners] => 3
[Stream-Genre] => Various
[Stream-URL] => http://url [ice-bitrate] => 128
[icy-info] => ice-samplerate=44100;ice-bitrate=128;ice-channels=2
[Current-Song] => Artist - Title
)
So what I'm trying to get is the part [Current-Song] => Artist - Title.
When I echo it I'd like to only see Artist - Title
Can someone help me with this?

You already have the xml object. Just use it.
$artistTitle = $xmlObj->{'Current-Song'};
And just use it from there.
More info on that curly brace syntax here

Related

Parse SOAP with multiple namespaces request in PHP [duplicate]

I want to convert below XML to PHP array. Any suggestions on how I can do this?
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd Id="id:pass" />
<eeee name="hearaman" age="24" />
</cccc>
</bbb>
</aaaa>
easy!
$xml = simplexml_load_string($xmlstring, "SimpleXMLElement", LIBXML_NOCDATA);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
Another option is the SimpleXML extension (I believe it comes standard with most php installs.)
http://php.net/manual/en/book.simplexml.php
The syntax looks something like this for your example
$xml = new SimpleXMLElement($xmlString);
echo $xml->bbb->cccc->dddd['Id'];
echo $xml->bbb->cccc->eeee['name'];
// or...........
foreach ($xml->bbb->cccc as $element) {
foreach($element as $key => $val) {
echo "{$key}: {$val}";
}
}
Converting an XML string ($buffer) into a simplified array ignoring attributes and grouping child-elements with the same names:
function XML2Array(SimpleXMLElement $parent)
{
$array = array();
foreach ($parent as $name => $element) {
($node = & $array[$name])
&& (1 === count($node) ? $node = array($node) : 1)
&& $node = & $node[];
$node = $element->count() ? XML2Array($element) : trim($element);
}
return $array;
}
$xml = simplexml_load_string($buffer);
$array = XML2Array($xml);
$array = array($xml->getName() => $array);
Result:
Array
(
[aaaa] => Array
(
[bbb] => Array
(
[cccc] => Array
(
[dddd] =>
[eeee] =>
)
)
)
)
If you also want to have the attributes, they are available via JSON encoding/decoding of SimpleXMLElement. This is often the most easy quick'n'dirty solution:
$xml = simplexml_load_string($buffer);
$array = json_decode(json_encode((array) $xml), true);
$array = array($xml->getName() => $array);
Result:
Array
(
[aaaa] => Array
(
[#attributes] => Array
(
[Version] => 1.0
)
[bbb] => Array
(
[cccc] => Array
(
[dddd] => Array
(
[#attributes] => Array
(
[Id] => id:pass
)
)
[eeee] => Array
(
[#attributes] => Array
(
[name] => hearaman
[age] => 24
)
)
)
)
)
)
Take note that all these methods only work in the namespace of the XML document.
$array = json_decode(json_encode((array)simplexml_load_string($xml)),true);
The method used in the accepted answer drop attributes when encountering child elements with only a text node. For example:
$xml = '<container><element attribute="123">abcd</element></container>';
print_r(json_decode(json_encode(simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA)),1));
Array
(
[element] => abcd
)
My solution (and I wish I could give credit here because I'm sure I adapted this from something):
function XMLtoArray($xml) {
$previous_value = libxml_use_internal_errors(true);
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false;
$dom->loadXml($xml);
libxml_use_internal_errors($previous_value);
if (libxml_get_errors()) {
return [];
}
return DOMtoArray($dom);
}
function DOMtoArray($root) {
$result = array();
if ($root->hasAttributes()) {
$attrs = $root->attributes;
foreach ($attrs as $attr) {
$result['#attributes'][$attr->name] = $attr->value;
}
}
if ($root->hasChildNodes()) {
$children = $root->childNodes;
if ($children->length == 1) {
$child = $children->item(0);
if (in_array($child->nodeType,[XML_TEXT_NODE,XML_CDATA_SECTION_NODE])) {
$result['_value'] = $child->nodeValue;
return count($result) == 1
? $result['_value']
: $result;
}
}
$groups = array();
foreach ($children as $child) {
if (!isset($result[$child->nodeName])) {
$result[$child->nodeName] = DOMtoArray($child);
} else {
if (!isset($groups[$child->nodeName])) {
$result[$child->nodeName] = array($result[$child->nodeName]);
$groups[$child->nodeName] = 1;
}
$result[$child->nodeName][] = DOMtoArray($child);
}
}
}
return $result;
}
$xml = '
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd id="123" />
<eeee name="john" age="24" />
<ffff type="employee">Supervisor</ffff>
</cccc>
</bbb>
</aaaa>
';
print_r(XMLtoArray($xml));
Array
(
[aaaa] => Array
(
[#attributes] => Array
(
[Version] => 1.0
)
[bbb] => Array
(
[cccc] => Array
(
[dddd] => Array
(
[#attributes] => Array
(
[id] => 123
)
)
[eeee] => Array
(
[#attributes] => Array
(
[name] => john
[age] => 24
)
)
[ffff] => Array
(
[#attributes] => Array
(
[type] => employee
)
[_value] => Supervisor
)
)
)
)
)
See https://github.com/gaarf/XML-string-to-PHP-array/blob/master/xmlstr_to_array.php
<?php
/**
* convert xml string to php array - useful to get a serializable value
*
* #param string $xmlstr
* #return array
*
* #author Adrien aka Gaarf & contributors
* #see http://gaarf.info/2009/08/13/xml-string-to-php-array/
*/
function xmlstr_to_array($xmlstr) {
$doc = new DOMDocument();
$doc->loadXML($xmlstr);
$root = $doc->documentElement;
$output = domnode_to_array($root);
$output['#root'] = $root->tagName;
return $output;
}
function domnode_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 = domnode_to_array($child);
if(isset($child->tagName)) {
$t = $child->tagName;
if(!isset($output[$t])) {
$output[$t] = array();
}
$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 = array('#content'=>$output); //Change output into an array.
}
if(is_array($output)) {
if($node->attributes->length) {
$a = array();
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;
}
Surprised no one mentioned xml_parse_into_struct:
$simple = "<para><note>simple note</note></para>";
$p = xml_parser_create();
xml_parse_into_struct($p, $simple, $vals, $index);
xml_parser_free($p);
echo "Index array\n";
print_r($index);
echo "\nVals array\n";
print_r($vals);
XML To Array
More Details Visit https://github.com/sapankumarmohanty/lamp/blob/master/Crate-XML-2-Array
//Convert XML to array and SOAP XML to array
function xml2array($contents, $get_attributes = 1, $priority = 'tag')
{
if (!$contents) return array();
if (!function_exists('xml_parser_create')) {
// print "'xml_parser_create()' function not found!";
return array();
}
// Get the XML parser of PHP - PHP must have this module for the parser to work
$parser = xml_parser_create('');
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8"); // http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
xml_parse_into_struct($parser, trim($contents) , $xml_values);
xml_parser_free($parser);
if (!$xml_values) return; //Hmm...
// Initializations
$xml_array = array();
$parents = array();
$opened_tags = array();
$arr = array();
$current = & $xml_array; //Refference
// Go through the tags.
$repeated_tag_index = array(); //Multiple tags with same name will be turned into an array
foreach($xml_values as $data) {
unset($attributes, $value); //Remove existing values, or there will be trouble
// This command will extract these variables into the foreach scope
// tag(string), type(string), level(int), attributes(array).
extract($data); //We could use the array by itself, but this cooler.
$result = array();
$attributes_data = array();
if (isset($value)) {
if ($priority == 'tag') $result = $value;
else $result['value'] = $value; //Put the value in a assoc array if we are in the 'Attribute' mode
}
// Set the attributes too.
if (isset($attributes) and $get_attributes) {
foreach($attributes as $attr => $val) {
if ( $attr == 'ResStatus' ) {
$current[$attr][] = $val;
}
if ($priority == 'tag') $attributes_data[$attr] = $val;
else $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
}
}
// See tag status and do the needed.
//echo"<br/> Type:".$type;
if ($type == "open") { //The starting of the tag '<tag>'
$parent[$level - 1] = & $current;
if (!is_array($current) or (!in_array($tag, array_keys($current)))) { //Insert New tag
$current[$tag] = $result;
if ($attributes_data) $current[$tag . '_attr'] = $attributes_data;
//print_r($current[$tag . '_attr']);
$repeated_tag_index[$tag . '_' . $level] = 1;
$current = & $current[$tag];
}
else { //There was another element with the same tag name
if (isset($current[$tag][0])) { //If there is a 0th element it is already an array
$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
$repeated_tag_index[$tag . '_' . $level]++;
}
else { //This section will make the value an array if multiple tags with the same name appear together
$current[$tag] = array(
$current[$tag],
$result
); //This will combine the existing item and the new item together to make an array
$repeated_tag_index[$tag . '_' . $level] = 2;
if (isset($current[$tag . '_attr'])) { //The attribute of the last(0th) tag must be moved as well
$current[$tag]['0_attr'] = $current[$tag . '_attr'];
unset($current[$tag . '_attr']);
}
}
$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
$current = & $current[$tag][$last_item_index];
}
}
elseif ($type == "complete") { //Tags that ends in 1 line '<tag />'
// See if the key is already taken.
if (!isset($current[$tag])) { //New Key
$current[$tag] = $result;
$repeated_tag_index[$tag . '_' . $level] = 1;
if ($priority == 'tag' and $attributes_data) $current[$tag . '_attr'] = $attributes_data;
}
else { //If taken, put all things inside a list(array)
if (isset($current[$tag][0]) and is_array($current[$tag])) { //If it is already an array...
// ...push the new element into that array.
$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
if ($priority == 'tag' and $get_attributes and $attributes_data) {
$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
}
$repeated_tag_index[$tag . '_' . $level]++;
}
else { //If it is not an array...
$current[$tag] = array(
$current[$tag],
$result
); //...Make it an array using using the existing value and the new value
$repeated_tag_index[$tag . '_' . $level] = 1;
if ($priority == 'tag' and $get_attributes) {
if (isset($current[$tag . '_attr'])) { //The attribute of the last(0th) tag must be moved as well
$current[$tag]['0_attr'] = $current[$tag . '_attr'];
unset($current[$tag . '_attr']);
}
if ($attributes_data) {
$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
}
}
$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
}
}
}
elseif ($type == 'close') { //End of tag '</tag>'
$current = & $parent[$level - 1];
}
}
return ($xml_array);
}
// Let's call the this above function xml2array
xml2array($xmlContent, $get_attributes = 3, $priority = 'tag'); // it will work 100% if not ping me #skype: sapan.mohannty
// Enjoy coding
Two lines of code (https://www.php.net/manual/en/book.simplexml.php#113485)
$xml = new SimpleXMLElement("<your><xml><string>ok</string></xml></your>");
$array = (array)$xml;
I know I'm 1 billion years late, but I had the same problem as you and needed a more complex solution, so here is a function (xml_decode()) I made to convert SimpleXMLElements into PHP arrays without losing attributes and with arguments for a more customizable use.
The val() function is meant for you to customize how element values shall be treated - in case you want to transform <elem>true</elem> into true instead of "true" for example.
Disclaimer: I know it is easier to just use the PHP SimpleXML extension, but I needed to transform lots of XML files into JSON files for a big change in a project of mine. Also, the question is about how to transform XML to PHP arrays, not how to use XML in PHP.
<?php
function val($input) {
return strval($input);
}
/**
* Transform an SimpleXMLElement into an associative array.
*
* #param SimpleXMLElement $xml The XML element to be decoded.
*
* #param bool $attributes_key If the element attributes should be grouped into a single element.
*
* Example: <elem foo="true" bar="false" />
*
* If true, xml_decode() will output
* array("attributes" => array("foo" => "true", "bar" => "false"))
*
* If false, xml_decode() will output
* array("foo" => "true", "bar" => "false")
*
* #param bool $reduce If unecessary keys created due to XML structure should be eliminated.
*
* Example: <fruits><fruit>apple</fruit><fruit>banana</fruit></fruits>
*
* If true, xml_decode() will output the element as
* array("fruits" => array(0 => "apple", 1 => "banana"))
*
* If false, xml_decode() will output the element as
* array("fruits" => array("fruit" => array(0 => "apple", 1 => "banana")))
*
* #param array $always_array List of which childs should be treated aways as an array.
*
* Example: <fruits><fruit>apple</fruit></fruits>
*
* If array("fruit") is passed as $aways_array, xml_decode() will output the element as
* array("fruits" => array("fruit" => array(0 => "apple")))
*
* If not, xml_decode() will output the element as
* array("fruits" => array("fruit" => "apple"))
*
* #param array $value_keys List of custom element's value names. This argument is only
* used when values need to passed as elements because of attributes or other reasons.
*
* The default value key name is "value".
*
* Example: <fruits><fruit id="123">apple</fruit></fruits>
*
* If array("fruit" => "name) is passed as $value_keys, xml_decode() will output the element as
* array("fruits" => array("fruit" => array("attributes" => array("id" => "123"), "name" => "apple")))
*
* If not, xml_decode() will output the element as
* array("fruits" => array("fruit" => array("attributes" => array("id" => "123"), "value" => "apple")))
*/
function xml_decode(SimpleXMLElement $xml, bool $attributes_key = true, bool $reduce = true,
array $always_array = array(), array $value_keys = array()): string|array {
// Inicialize the array.
$arr = array();
// XML tag name.
$xml_name = $xml->getName();
// Turn attributes into elements.
foreach ($xml->attributes() as $key => $value) {
// Use a key for attributes if $attributes_key argument is true.
if ($attributes_key) {
$arr['attributes'][val($key)] = val($value);
} else {
$arr[val($key)] = val($value);
}
}
// Count children.
$children_count = $xml->children()->count();
// No children? Value will be text.
if ($children_count == 0) {
// If attributes were found and turned into elements
// the value shall be an element.
if (count($arr) > 0) {
// If attributes were found previosly.
$key = $value_keys[$xml_name] ?? $value_keys['*'] ?? "value";
$arr[$key] = val($xml);
// Else, no need for an array.
} else {
$arr = val($xml);
}
// Children? Loop continues.
} else {
// Defines if there are unecessary array keys - due to the XML structure - to be cut.
// Example: <fruits><fruit /><fruit /><fruits />
// could be turned into arr['fruits'][0] and arr['fruits'][1] instead of
// arr['fruits']['fruit'][0] and arr['fruits']['fruit'][1] for a
// cleaner organization.
$children_names = array();
foreach ($xml->children() as $child) {
$child_name = $child->getName();
in_array($child_name, $children_names) or $children_names[] = $child_name;
}
$reducible = empty($arr) && count($children_names) === 1;
foreach ($xml->children() as $child) {
// Child's name shall be the element key.
$name = $child->getName();
// Children with the same name will be turned into a list.
// Example: $arr['repeating-child'][...] = $value;
if ($xml->$name->count() > 1 || in_array($name, $always_array)) {
// Reduction, if possible and requested by the $reduce argument.
if ($reduce && $reducible) {
$arr[] = xml_decode($child, $attributes_key, $reduce, $always_array, $value_keys);
} else {
$arr[$name][] = xml_decode($child, $attributes_key, $reduce, $always_array, $value_keys);
}
// Normal children will be normally decoded.
// Example: $arr['no-repeating-child] = $value;
} else {
$arr[$name] = xml_decode($child, $attributes_key, $reduce, $always_array, $value_keys);
}
}
}
return $arr;
}
Resuming all the documentation and comments, the function transforms attributes and elements values into simple array elements and uses a loop with itself to process elements which contain children.
The arguments allow you to:
Group attributes into separate keys;
Cut unecessary keys generated due to the XML structure conversion (Example: fruits->fruit to $arr['fruits']['fruit'][n]);
Set elements which should aways be treated as lists (because sometimes it will have only one child element but you still need it to be a list);
Set a name for array element keys which will represent an XML element text value - which will be needed when attributes are converted to array elements.
Usage example with your XML elements (I think you already solved it after 11 years, but I'm answering it, so...):
test.xml
<test>
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd Id="id:pass" />
<eeee name="hearaman" age="24" />
</cccc>
</bbb>
</aaaa>
</test>
PHP
$xml = simplexml_load_file("test.xml");
$decode = xml_decode($xml);
echo "<pre>" . print_r($decode,true) . "</pre>";
Output
Array
(
[aaaa] => Array
(
[attributes] => Array
(
[Version] => 1.0
)
[bbb] => Array
(
[cccc] => Array
(
[dddd] => Array
(
[attributes] => Array
(
[Id] => id:pass
)
[value] =>
)
[eeee] => Array
(
[attributes] => Array
(
[name] => hearaman
[age] => 24
)
[value] =>
)
)
)
)
)
I liked this question and some answers was helpful to me, but i need to convert the xml to one domination array, so i will post my solution maybe someone need it later:
<?php
$xml = json_decode(json_encode((array)simplexml_load_string($xml)),1);
$finalItem = getChild($xml);
var_dump($finalItem);
function getChild($xml, $finalItem = []){
foreach($xml as $key=>$value){
if(!is_array($value)){
$finalItem[$key] = $value;
}else{
$finalItem = getChild($value, $finalItem);
}
}
return $finalItem;
}
?>
/* Creating an XML file (Optional): Create an XML file which need to convert into the array. test.xml */
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd Id="id:pass" />
<eeee name="hearaman" age="24" />
</cccc>
</bbb>
</aaaa>
<?php
// xml file path
$path = "text.xml"; // set your according path for dynamic.
// Read entire file into string
$xmlfile = file_get_contents($path);
// Convert xml string into an object
$new = simplexml_load_string($xmlfile);
// Convert into json
$con = json_encode($new);
// Convert into associative array
$newArr = json_decode($con, true);
print_r($newArr);
?>
Output: Result of XML conversion to PHP Array
[
'aaaa' => [
'bbb' => [
'cccc' => [
'dddd' => [
'#value' => '',
'#attributes' => [
'Id' => 'id:pass',
],
],
'eeee' => [
'#value' => '',
'#attributes' => [
'name' => 'hearaman',
'age' => '24',
],
],
],
],
'#attributes' => [
'Version' => '1.0',
],
],
]

PHP can't get inner text from XML tag [duplicate]

I have something like this:
$url = "http://ws.geonames.org/findNearbyPostalCodes?country=pl&placename=";
$url .= rawurlencode($city[$i]);
$xml = simplexml_load_file($url);
echo $url."\n";
$cityCode[] = array(
'city' => $city[$i],
'lat' => $xml->code[0]->lat,
'lng' => $xml->code[0]->lng
);
It's supposed to download XML from geonames. If I do print_r($xml) I get :
SimpleXMLElement Object
(
[code] => Array
(
[0] => SimpleXMLElement Object
(
[postalcode] => 01-935
[name] => Warszawa
[countryCode] => PL
[lat] => 52.25
[lng] => 21.0
[adminCode1] => SimpleXMLElement Object
(
)
[adminName1] => Mazowieckie
[adminCode2] => SimpleXMLElement Object
(
)
[adminName2] => Warszawa
[adminCode3] => SimpleXMLElement Object
(
)
[adminName3] => SimpleXMLElement Object
(
)
[distance] => 0.0
)
I do as you can see $xml->code[0]->lat and it returns an object. How can i get the value?
You have to cast simpleXML Object to a string.
$value = (string) $xml->code[0]->lat;
You can also use the magic method __toString()
$xml->code[0]->lat->__toString()
If you know that the value of the XML element is a float number (latitude, longitude, distance), you can use (float)
$value = (float) $xml->code[0]->lat;
Also, (int) for integer number:
$value = (int) $xml->code[0]->distance;
if you don't know the value of XML Element, you can use
$value = (string) $xml->code[0]->lat;
if (ctype_digit($value)) {
// the value is probably an integer because consists only of digits
}
It works when you need to determine if value is a number, because (string) will always return string and is_int($value) returns false
Quick Solution if you in hurry.
convert a Xml-Object to an array (or object),
function loadXml2Array($file,$array=true){
$xml = simplexml_load_file($file);
$json_string = json_encode($xml);
return json_decode($json_string, $array);
}
This is the function that has always helped me convert the xml related values to array
function _xml2array ( $xmlObject, $out = array () ){
foreach ( (array) $xmlObject as $index => $node )
$out[$index] = ( is_object ( $node ) ) ? _xml2array ( $node ) : $node;
return $out;
}
you can use the '{}' to access you property, and then you can do as you wish.
Save it or display the content.
$varName = $xml->{'key'};
From your example her's the code
$filePath = __DIR__ . 'Your path ';
$fileName = 'YourFilename.xml';
if (file_exists($filePath . $fileName)) {
$xml = simplexml_load_file($filePath . $fileName);
$mainNode = $xml->{'code'};
$cityArray = array();
foreach ($mainNode as $key => $data) {
$cityArray[..] = $mainNode[$key]['cityCode'];
....
}
}
try current($xml->code[0]->lat)
it returns element under current pointer of array, which is 0, so you will get value
header("Content-Type: text/html; charset=utf8");
$url = simplexml_load_file("http://URI.com");
foreach ($url->PRODUCT as $product) {
foreach($urun->attributes() as $k => $v) {
echo $k." : ".$v.' <br />';
}
echo '<hr/>';
}
you can convert array with this function
function xml2array($xml){
$arr = array();
foreach ($xml->children() as $r)
{
$t = array();
if(count($r->children()) == 0)
{
$arr[$r->getName()] = strval($r);
}
else
{
$arr[$r->getName()][] = xml2array($r);
}
}
return $arr;
}
$codeZero = null;
foreach ($xml->code->children() as $child) {
$codeZero = $child;
}
$lat = null;
foreach ($codeZero->children() as $child) {
if (isset($child->lat)) {
$lat = $child->lat;
}
}
foreach($xml->code as $vals )
{
unset($geonames);
$vals=(array)$vals;
foreach($vals as $key => $value)
{
$value=(array)$value;
$geonames[$key]=$value[0];
}
}
print_r($geonames);

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);
}
}
}

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
)
)
)

Get value from SimpleXMLElement Object

I have something like this:
$url = "http://ws.geonames.org/findNearbyPostalCodes?country=pl&placename=";
$url .= rawurlencode($city[$i]);
$xml = simplexml_load_file($url);
echo $url."\n";
$cityCode[] = array(
'city' => $city[$i],
'lat' => $xml->code[0]->lat,
'lng' => $xml->code[0]->lng
);
It's supposed to download XML from geonames. If I do print_r($xml) I get :
SimpleXMLElement Object
(
[code] => Array
(
[0] => SimpleXMLElement Object
(
[postalcode] => 01-935
[name] => Warszawa
[countryCode] => PL
[lat] => 52.25
[lng] => 21.0
[adminCode1] => SimpleXMLElement Object
(
)
[adminName1] => Mazowieckie
[adminCode2] => SimpleXMLElement Object
(
)
[adminName2] => Warszawa
[adminCode3] => SimpleXMLElement Object
(
)
[adminName3] => SimpleXMLElement Object
(
)
[distance] => 0.0
)
I do as you can see $xml->code[0]->lat and it returns an object. How can i get the value?
You have to cast simpleXML Object to a string.
$value = (string) $xml->code[0]->lat;
You can also use the magic method __toString()
$xml->code[0]->lat->__toString()
If you know that the value of the XML element is a float number (latitude, longitude, distance), you can use (float)
$value = (float) $xml->code[0]->lat;
Also, (int) for integer number:
$value = (int) $xml->code[0]->distance;
if you don't know the value of XML Element, you can use
$value = (string) $xml->code[0]->lat;
if (ctype_digit($value)) {
// the value is probably an integer because consists only of digits
}
It works when you need to determine if value is a number, because (string) will always return string and is_int($value) returns false
Quick Solution if you in hurry.
convert a Xml-Object to an array (or object),
function loadXml2Array($file,$array=true){
$xml = simplexml_load_file($file);
$json_string = json_encode($xml);
return json_decode($json_string, $array);
}
This is the function that has always helped me convert the xml related values to array
function _xml2array ( $xmlObject, $out = array () ){
foreach ( (array) $xmlObject as $index => $node )
$out[$index] = ( is_object ( $node ) ) ? _xml2array ( $node ) : $node;
return $out;
}
you can use the '{}' to access you property, and then you can do as you wish.
Save it or display the content.
$varName = $xml->{'key'};
From your example her's the code
$filePath = __DIR__ . 'Your path ';
$fileName = 'YourFilename.xml';
if (file_exists($filePath . $fileName)) {
$xml = simplexml_load_file($filePath . $fileName);
$mainNode = $xml->{'code'};
$cityArray = array();
foreach ($mainNode as $key => $data) {
$cityArray[..] = $mainNode[$key]['cityCode'];
....
}
}
try current($xml->code[0]->lat)
it returns element under current pointer of array, which is 0, so you will get value
header("Content-Type: text/html; charset=utf8");
$url = simplexml_load_file("http://URI.com");
foreach ($url->PRODUCT as $product) {
foreach($urun->attributes() as $k => $v) {
echo $k." : ".$v.' <br />';
}
echo '<hr/>';
}
you can convert array with this function
function xml2array($xml){
$arr = array();
foreach ($xml->children() as $r)
{
$t = array();
if(count($r->children()) == 0)
{
$arr[$r->getName()] = strval($r);
}
else
{
$arr[$r->getName()][] = xml2array($r);
}
}
return $arr;
}
$codeZero = null;
foreach ($xml->code->children() as $child) {
$codeZero = $child;
}
$lat = null;
foreach ($codeZero->children() as $child) {
if (isset($child->lat)) {
$lat = $child->lat;
}
}
foreach($xml->code as $vals )
{
unset($geonames);
$vals=(array)$vals;
foreach($vals as $key => $value)
{
$value=(array)$value;
$geonames[$key]=$value[0];
}
}
print_r($geonames);

Categories