Extracting data from xpath reference of SimpleXMLElement Object - php

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

Related

SimpleXmlElement count

I'm trying to count the amount of children in a SimpleXmlElement. I've searched on StackOverflow but I can't seem to find anything;
$xml = simplexml_load_string($xml);
foreach($xml as $key => $field) {
if (count($field) == 0){
$field[0][0] = 'test';
}
}
Some of my XmlElement are empty. Yet count gives 0 on all the elements. The only way I've found to do what I want is this:
if ($field[0][0] == '')
I've tried using $field->count() as specified on http://php.net/manual/en/simplexmlelement.count.php, but no matter what is in $field, it always returns 0.
Isn't there a better way to do this?
Here is the format of the xml through print_r:
SimpleXMLElement Object
(
[firstName] => Test
[lastName] => Test2
[middleName] => SimpleXMLElement Object
(
)
)
You can use the count() function like this:
$elem = new SimpleXMLElement($xml);
$elem->count();
http://php.net/manual/en/simplexmlelement.count.php for reference.

query xpath with php

I wrote following php code to extract nodes information from this xml:
<sioctBoardPost rdfabout="http//boards.ie/vbulletin/showpost.php?p=67075">
<rdftype rdfresource="http//rdfs.org/sioc/ns#Post" />
<dctitle>hib team</dctitle>
<siochas_creator>
<siocUser rdfabout="http//boards.ie/vbulletin/member.php?u=497#user">
<rdfsseeAlso rdfresource="http//boards.ie/vbulletin/sioc.php?sioc_type=user&sioc_id=497" />
</siocUser>
</siochas_creator>
<dctermscreated>1998-04-25T213200Z</dctermscreated>
<sioccontent>zero, those players that are trialing 300 -400 pingers? umm..mager lagg and even worse/</sioccontent>
</sioctBoardPost>
<?php
$xml = simplexml_load_file("boards.xml");
$products[0] = $xml->xpath("/sioctBoardPost/sioccontent");
$products[1] = $xml->xpath("/sioctBoardPost/dctermscreated");
$products[2] = $xml->xpath("/sioctBoardPost/#rdfabout");
print_r($products);
?>
This gives following output:
Array (
[0] => Array ( [0] => SimpleXMLElement Object ( [0] => zero, those players that are trialing for hib team, (hpb's) most of them are like 300 -400 pingers? umm..mager lagg and even worse when they play on uk server's i bet/ ) ) [1] => Array ( [0] => SimpleXMLElement Object ( [0] => 1998-04-25T213200Z ) ) [2] => Array ( [0] => SimpleXMLElement Object ( [#attributes] => Array ( [rdfabout] => http//boards.ie/vbulletin/showpost.php?p=67075 ) ) )
)
But I need only nodes content as an output i.e without Array([0] => Array etc.
Output should be like this:
zero, those players that are trialing for hib team, (hpb's) most of them are like 300 -400 pingers? umm..mager lagg and even worse when they play on uk server's i bet
1998-04-25T213200Z
http//boards.ie/vbulletin/showpost.php?p=67075
Thanks in advance
You can use current() to only get the first element of each XPath result (which is an array) and then use a (string) cast to get the node contents:
$products[0] = (string)current($xml->xpath("/sioctBoardPost/sioccontent"));
$products[1] = (string)current($xml->xpath("/sioctBoardPost/dctermscreated"));
$products[2] = (string)current($xml->xpath("/sioctBoardPost/#rdfabout"));
print_r($products);
As you have observed, the xpath() method returns an array of matched nodes, so you need to deal with the elements of the returned arrays. I believe this should work in this case:
$xml = simplexml_load_file("boards.xml");
$products[0] = $xml->xpath("/sioctBoardPost/sioccontent")[0];
$products[1] = $xml->xpath("/sioctBoardPost/dctermscreated")[0];
$products[2] = $xml->xpath("/sioctBoardPost/#rdfabout")[0];
print_r($products);
This should get you what you need...
foreach ($products as $product) { // iterate through the $products array
print $product[0]->nodeValue // output the node value of the SimpleXMLElement Object
}

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

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
)

Why aren't these values being added to my array as strings?

Further to my question here, I'm actually wondering why I'm not getting strings added to my array with the following code.
I get some HTML from an external source with this:
$doc = new DOMDocument();
#$doc->loadHTML($html);
$xml = #simplexml_import_dom($doc); // just to make xpath more simple
$images = $xml->xpath('//img');
$sources = array();
Here is the images array:
Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[alt] => techcrunch logo
[src] => http://s2.wp.com/wp-content/themes/vip/tctechcrunch/images/logos_small/techcrunch2.png?m=1265111136g
)
)
...
)
Then I added the sources to my array with:
foreach ($images as $i) {
array_push($sources, $i['src']);
}
But when I print the results:
echo "<pre>";
print_r($sources);
die();
I get this:
Array
(
[0] => SimpleXMLElement Object
(
[0] => http://www.domain.com/someimages.jpg
)
...
)
Why isn't $i['src'] treated as a string? Isn't the original [src] element noted where I print $images a string inside there?
To put it another way $images[0] is a SimpleXMLElement, I understand that. But why is the 'src' attribute of THAT object not being but into $sources as a string when I reference it as $i['src']?
Why isn't $i['src'] treated as a string?
Becaue it isn't one - it's a SimpleXMLElement object that gets cast to a string if used in a string context, but it still remains a SimpleXMLElement at heart.
To make it a real string, force cast it:
array_push($sources, (string) $i['src']);
Because SimpleXMLElement::xpath() (quoting) :
Returns an array of SimpleXMLElement
objects
and not an array of strings.
So, the items of your $images array are SimpleXMLElement objects, and not strings -- which is why you have to cast them to strings, if you want strings.

Extract data from an XML object

How do I extract the data from that XML object, which is a value of a certain array:
Array (
[Title] => SimpleXMLElement Object (
[0] => The Key of Life; A Metaphysical Investigation
)
[ASIN] => SimpleXMLElement Object ( [0] => 0982385099 ) ...
)
I did a foreach of the array like:
foreach ($ArrayName as $FieldLabel => $FieldValue) {
$Variable = $FieldValue[0]....
}
...but still, it gets the whole XML object as the field value. I wanted it to extract the value only not the whole object.
All simple xml objects are iteratable. Basically think of any object as a set, and some set's just happen to contain one object.
To extract your value do this
foreach($title as $item)
{
$list_of_titles = (string) $item;
}
print_r($list_of_titles);
So basically I typecast every item into a string from an object.

Categories