SimpleXML and XML collections - how to get the attribute value as an array key? - php

I'm just trying to figure out how to cleanly and nicely transform a XML collection into an appropriate object. See, I've got this very simple XML string :
$x = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<apiKeys>
<apiKey application="app1">HfxaoMBJJ9pLe</apiKey>
<apiKey application="app2">HfxaoMBJJ9pLeClsSHsh</apiKey>
<apiKey application="app3">HfxaoMBJJ9pLeClsSHshTI9qX</apiKey>
</apiKeys>';
Which I transform using :
$O_xmlElement = simplexml_load_string ($x);
This is what I get :
SimpleXMLElement Object
(
[apiKey] => Array
(
[0] => HfxaoMBJJ9pLe
[1] => HfxaoMBJJ9pLeClsSHsh
[2] => HfxaoMBJJ9pLeClsSHshTI9qX
)
)
And I'd rather have (I expected !) something like :
SimpleXMLElement Object
(
[apiKey] => Array
(
['app1'] => HfxaoMBJJ9pLe
['app2'] => HfxaoMBJJ9pLeClsSHsh
['app3'] => HfxaoMBJJ9pLeClsSHshTI9qX
)
)
Thank you very much for your help people

SimpleXML won't do what you want automatically. You'll have to build the object yourself:
$O_xmlElement = simplexml_load_string($x);
$myObject = new stdClass();
foreach ($O_xmlElement->apiKey as $apiKey) {
$key = (string) $apiKey['application'];
$myObject->${key} = (string) $apiKey;
}
Refer to the basic usage example in the PHP manual for good examples of dealing with child elements and attributes.
When getting attributes from a SimpleXMLElement, remember that each attribute will be a SimpleXMLElement and not a string. You'll want to explicitly cast each attribute to string before using it as an array key or object property name.

Not sure you can do it exactly as you want it, but you can check out php.net's docs here:
http://www.php.net/manual/en/simplexmlelement.attributes.php
Basically the attributes can be found inside an object attached to each of the apiKey objects.

You can use the following code:
$xml = simplexml_load_string($x);
$newArray = array();
$count=0;
foreach($xml as $value){
$key= (string)($xml->apiKey[$count++]->attributes()->application);
$newArray[$key] = $value[0];
}
$newArray = array_map("trim", $newArray);
print_r($newArray);
This will generate the following output:
Array
(
[app1] => HfxaoMBJJ9pLe
[app2] => HfxaoMBJJ9pLeClsSHsh
[app3] => HfxaoMBJJ9pLeClsSHshTI9qX
)

Related

Transform array into normal array

My Array looks like this
Array (
[title] => SimpleXMLElement Object (
[0] => Car String
)
)
And should look like this:
Array (
title => Car String
)
I got this array by doing curl_exec a xml file and changed it with "new SimpleXMLElement".
Every solution i could find didn't work.
So how can i transform the array? Or is there a more efficient way to get a xml with http header options?
When you build your array, you need to cast the SimpleXMLElement Object into the desired type. In your case you need to cast into a string element.
There is the simple way to do that :
$xmlString = "<element><title>Car String</title></element>";
$xml = new SimpleXMLElement($string);
$array = [
'title' => (string)$xml->title;
];
or
$xmlString = "<element><title>Car String</title></element>";
$xml = new SimpleXMLElement($string);
$array = [
'title' => $xml->title->__toString();
];

simplexml_load_file() does not getting node content

I cannot get XML node contents and attributes at the same time with SimpleXML library:
I have the following XML, and want to get content#name attribute and node's contents:
<page id="id1">
<content name="abc">def</content>
</page>
Method simplexml_load_string()
print_r(simplexml_load_string('<page id="id1"><content name="abc">def</content></page>'));
outputs this:
SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => id1
)
[content] => def
)
As you can see, contents of the content node is present, but attributes are missing. How can I receive the contents and attributes?
Thanks!
The attributes of content are present. This is just a trick of print_r() and how it works with XML objects in memory.
$x = simplexml_load_string('<page id="id1"><content name="abc">def</content></page>');
print_r($x->content);
print_r($x->content['name']);
SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => abc
)
[0] => def
)
SimpleXMLElement Object
(
[0] => abc
)
In simplexml, accessing elements returns SimpleXMLElement objects. You can view the content of these objects using var_dump.
$book=simplexml_load_string('<page id="id1"><content name="abc">def</content></page>');
$content=$book->content;
var_dump($content);
You can access these objects with foreach loop.
foreach($obj as $value) {
if (is_array($value)) {
foreach ($value as $name=>$value) {
print $name.": ".$value."\n";}
}
else print $value;
}
You can not only retrieve contents (such as elements and attributes) but also add and remove them. You can also use Xpath to navigate values in complex XML tree. You just need to go through the methods of SimpleXMLElement class here.
$x = simplexml_load_string('<page id="id1"><content name="abc">def</content></page>');
To get the node's attributes:
$attributes = $x->content->attributes(); //where content is the name of the node
$name = $attributes['name'];
To get the content node's content:
$c = $x->content;
Interesting, that $c can be used as string and as object, i.e.
echo $c; //prints string
print_r($c) //prints it out as object

php implode doesn't work as expected

I made some SimpleXMLObject and converted it into an array and implode them
but the result is not imploded string but the first element of array alone.
funnier thing is it's working as expected in my local server whose version is 5.4.4
but that malfunction is happening in my live server whose php version is 5.3.13
this is what my implode looks like
$im_data = implode( '#', (array)$sync->datas->data);
the target array is as follows :
[datas] => SimpleXMLElement Object
(
[data] => Array
(
[0] => AAzdfAA
[1] => BBdBB
[2] => BBDD
[3] => CCCCzsdfC
)
)
but the result is NOT AAzdfAA#BBdBB#BBDD#CCCCzsdfC but only AAzdfAA in my live server.
well in my local server it works as expected : AAzdfAA#BBdBB#BBDD#CCCCzsdfC
I was able to reproduce your issue on my end. And used this workaround to get the desire output:
<?php
$xml = "<xml>
<datas>
<data>AAzdfAA</data>
<data>BBdBB</data>
<data>BBDD</data>
<data>CCCCzsdfC</data>
</datas>
</xml>";
$sync = simplexml_load_string($xml);
$data = (array)$sync->datas;
$im_data = implode( '#', $data['data']);
echo $im_data; //Outputs: AAzdfAA#BBdBB#BBDD#CCCCzsdfC
Hope this helps.
The problem here is in how the SimpleXML objects get converted to other types: first in your explicit request to turn the object into an array, and secondly to take the array of objects that will (hopefully) return and them into strings that can be handled by implode.
You'll need to test the different cases, but it sounds like the behaviour of casting to array was changed in PHP 5.4. To be sure it does the right thing, loop over the elements manually rather than relying on the cast.
you can try this for converting XML Object to Array
<?php
function xml2array ( $xmlObject, $out = array () )
{
foreach ( (array) $xmlObject as $index => $node )
$out[$index] = ( is_object ( $node ) ) ? xml2array ( $node ) : $node;
return $out;
}
$xml_arr=xml2array($xml_obj);
$im_data = implode( '#',$xml_arr);
?>
i hope it will give you expected output

Extracting data from xpath reference of SimpleXMLElement Object

I'm trying to read an XML file into an array and I'm having a little bit of trouble. Here is what my code looks like so far:
$inst = new SimpleXMLElement($xml);
foreach( $inst->xpath("record[#id='" . $range . "']") as $u ) {
foreach($fields as $field) {
$results[$field] = $u->$field;
}
}
But when I do print_r($results), this is what's outputted:
Array
(
[field1] => SimpleXMLElement Object
(
[0] => field1Data
)
[field2] => SimpleXMLElement Object
(
[0] => field2Data
)
[field3] => SimpleXMLElement Object
(
[0] => field3Data
)
)
How can I get the data straight from the SimpleXMLElement Object and store it in the array rather than having it do this? I tried accessing it as an array like $u->$field[0] but that didn't work either.
Casting a SimpleXMLElement to string is the general solution(see "Forcing a SimpleXML Object to a string, regardless of context" for the canonical question), for a complete array containing all SimpleXMLElements like returned by xpath() or like you create it your own, a common way is to map the array onto trim:
$results = array_map('trim', $results);
or strval:
$results = array_map('strval', $results);
For example:
$inst = new SimpleXMLElement($xml);
list($u) = $inst->xpath("record[#id='" . $range . "']")
foreach ($fields as $field) {
$results[$field] = $u->$field;
}
$results = array_map('strval', $results);

add to associative array

I have some xml that looks like this:
<?xml version="1.0"?>
<data>
<items>
<item><timestamp>2011-07-11T09:01:42Z</timestamp><title><![CDATA[ some data here ]]></title><link>http://twitter.com/aurl</link></item>
<item><timestamp>2011-05-11T09:01:42Z</timestamp><title><![CDATA[ some data here ]]></title><link>http://twitter.com/aurlhere</link></item>
</items>
and I'm trying to loop over it and add it to an array:
foreach($xml->items->item as $e) {
$feedData['timestamp'] = $e->timestamp;
$feedData['title'] = $e->title;
$feedData['link'] = $e->link;
$feedData['type'] = $e->type;
}
print_r($feedData);
The xml is there and if I put an echo in the foreach I get back 10 responses (whcih are how many items I have) but when I print the array out all I get is one line (which is the last entry in the xml doc).
Array ( [timestamp] => SimpleXMLElement Object ( [0] => 2011-07-08T08:05:19Z ) [title] => SimpleXMLElement Object ( ) [link] => SimpleXMLElement Object ( [0] => http://twitter.com.aurl ) [type] => SimpleXMLElement Object ( ) )
I suspoect I'm overwriting the array on each loop. But why ? It should be adding to the array. Sorry my php isn't great...hence what Is suspect is a bit of a stupid question.
$i = 0;
foreach($xml->items->item as $e) {
$feedData[$i]['timestamp'] = $e->timestamp;
$feedData[$i]['title'] = $e->title;
$feedData[$i]['link'] = $e->link;
$feedData[$i]['type'] = $e->type;
$i++;
}
print_r($feedData);
Well, there is only one $feedData array and you are always setting the value for some specific keys, e.g. $feedData['timestamp']. How do you think this should add to the array? Keys are unique, the same key cannot appear twice, so yes, you are just overwriting the values.
It seems you want an array of arrays:
$feedData = array();
foreach($xml->items->item as $e) {
$feedData[] = array(
'timestamp' => $e->timestamp;
'title' => $e->title;
'link' => $e->link;
'type' => $e->type;
);
}
Have a look at the array manual [docs] for more information about arrays.

Categories