Can I use SimpleXML & Xpath to directly select an Elements Attribute? - php

i.e. - i want to return a string "yellow" using something like xpath expression "//banana/#color" and the following example xml...
<fruits>
<kiwi color="green" texture="hairy"/>
<banana color="yellow" texture="waxy"/>
</fruits>
$fruits = simplexml_load_string(
'<fruits>
<kiwi color="green" texture="hairy"/>
<banana color="yellow" texture="waxy"/>
</fruits>');
print_r($fruits->xpath('//banana/#color'));
produces
Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[color] => yellow
)
)
)
whereas i would prefer something like...
Array
(
[0] => SimpleXMLElement Object
(
[0] => yellow
)
)
...so that i don't need to write a special case into the application i'm writing.
thanks very much! :)

I just gave your test a shot because i was curious and I found that it does actually produce the string value yellow when converted to string.
$fruits = simplexml_load_string(
'<fruits>
<kiwi color="green" texture="hairy"/>
<banana color="yellow" texture="waxy"/>
</fruits>');
$found = $fruits->xpath('//banana/#color');
echo $found[0];
It would seem this is just how SimpleXmlElement attribute nodes are represented. So you can use this as (string) $found[0] if you are not printing/echoing it directly.
Of course if your depending on the value remaining a SimpleXMLElement then that could be an issue I suppose. But i would think just remembering to cast as string when you go to use the node later would still be doable.
IF you really need a detailed interface for Nodes that supports an Attribute as a node then you may want to just switch to DOMDocument. You code will get more verbose, but the implementation is more clear.

Related

Cannot get attributes of nested SimpleXMLElement

Clearly I'm missing something simple.
I have the following xml string which I parse using simplexml_load_string:
$xmlString = '<root><Title>Heading Text</Title><Image><img src="https://image.com?id=123" alt="alt text" /></Image></root>';
$xml = simplexml_load_string($xmlString);
However, I cannot access the img tag inside Image.
I would think I would use $xml->Image[0]->img to get the element and
$xml->Image[0]->img['src'] to get the url of the image. But I keep getting the error:
Trying to get property 'img' of non-object
$xml->Image[0] tests out as type SimpleXMLElement, and when I print_r() I get:
SimpleXMLElement Object (
[img] => SimpleXMLElement Object (
[#attributes] => Array (
[src] => https://image.com?id=123
[alt] => alt text
)
)
)
Like I said, I know I'm missing something really obvious, so any help would be appreciated.
You are correct, $xml->Image[0]->img['src'] will give you the src attribute, but it will give it to you as an object.
If you run print_r($xml->Image[0]->img['src']); it will show you this:
SimpleXMLElement Object
(
[0] => https://image.com?id=123
)
But if you run echo $xml->Image[0]->img['src']; instead, it will give you this:
https://image.com?id=123
The reason is that the SimpleXMLElement class implements the magic overload method __toString (or its equivalent in internal C code), so that whenever you cast the object to string, it will give you the string contents. Since echo always needs a string, it does this implicitly, but you can do it explicitly with (string), e.g.:
$imageSrc = (string)$xml->Image[0]->img['src'];
var_dump($imageSrc);
(As a side-note, the [0] is always optional - if you don't give a number, SimpleXML assumes you want the only or first child with that name, so $xml->Image->img['src'], $xml->Image[0]->img['src'], $xml->Image->img[0]['src'] and $xml->Image[0]->img[0]['src'] will all give the same result.)

PHP: Get specific value from simplexml array

I am pretty new to PHP an XML and hope you can help me with this.
Searching the forum didn't help me yet to find an answer to my specific issue.
I have a PHP page with a simplexml array that looks like the following, just longer:
SimpleXMLElement Object
(
[textID] => Array
(
[0] => SimpleXMLElement Object
(
[textID] => 1
[content] => Text1
)
[1] => SimpleXMLElement Object
(
[textID] => 2
[content] => Text2
)
[2] => SimpleXMLElement Object
(
[textID] => 3
[content] => Text3
)
)
)
Now I am trying to echo out a specific value from this array by referring to its ID which is an integer.
The only way I get this working is the following but this just goes by the order within the array, not by the actual ID:
<?php echo $objTexts->textID[1]->content; ?>
Can someone tell me what I am missing here ?
Thanks, Tim
SimpleXML has no way of knowing that the textID identifies which node is which - it is just another element in the XML.
Based on your sample output, your XML is a little confusing as you have multiple elements called textID which each have a single child, also called textID, which has a different meaning. Nonetheless, what you want to do can be achieved either by looping through all the outer textID elements and testing the value of their inner textID element:
foreach ( $objTexts->textID as $item )
{
if ( $item->textID == '2' )
{
...
}
}
Or, you could use XPath, which is a fairly simple query language for XML, and is supported within SimpleXML in the form of the ->xpath() method. In your case, you want to find a textID node which contains a textID child with a particular value, so the code would look something like this:
// ->xpath always returns a plain PHP array - not a SimpleXML object
$xpath_results = $objTexts->xpath('//textID[textID=2]');
// If you're certain you only want the first result:
echo $xpath_results[0]->content;
// If you might want multiple matches
foreach ( $xpath_results as $item )
{
...
}

Access SimpleXMLElement Object Values

I have the following SimpleXMLElement Object http://pastebin.com/qEP0UUPJ
I can query it using xpath $xaugbp = $xml->xpath("/query/results/rate"); but this just narrows down the search:
http://pastebin.com/Xwezx4bZ
I wish to access the following object:
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => XAUGBP
)
[Name] => XAU to GBP
[Rate] => 1030.5784
[Date] => 7/27/2012
[Time] => 5:55pm
[Ask] => 1027.5662
[Bid] => 1033.5896
I can get that particular object using
$ob = $xmlObject->xpath("//query/results/rate[contains(#id, 'XAUGBP')]");
I can get 'Ask' by using
$ob = $xmlObject->xpath("//query/results/rate[contains(#id, 'XAUGBP')]/Ask");
But how do I turn that object into a variable. e.g. so that I can do calculations on it?
Is xpath the only way of doing this? Is there a better / more efficient / quicker way? Is it possible to convert this to an associative array for easy access?
Preface
Before you do anything, (re)familiarise yourself with SimpleXML's peculiar way of doing things. The best place to start is the SimpleXML basic usage manual page.
The example below shows you:
Getting a single <rate> element object based on an attribute's value, and how to display it.
Looping over all of the <rate> elements and displaying their values.
Basic example code
$query = simplexml_load_file('…');
// Get a <rate> element by its id attribute
$rates = $query->xpath('results/rate[#id = "XAUGBP"]');
$rate = $rates[0];
echo "$rate->Name was at $rate->Rate at $rate->Time on $rate->Date\n";
echo "-----\n";
// or, loop over all of the <rate> elements
foreach ($query->results->rate as $rate) {
echo "$rate->Name was at $rate->Rate at $rate->Time on $rate->Date\n";
}
The above example outputs:
XAU to GBP was at 1030.5784 at 5:55pm on 7/27/2012
-----
XAU to GBP was at 1030.5784 at 5:55pm on 7/27/2012
XAG to GBPZ 999 N was at 17.4502 at 5:55pm on 7/27/2012
XPT to GBPZ 999 was at 893.3414 at 5:55pm on 7/27/2012
XPD to GBP1 UZ was at 362.652 at 5:55pm on 7/27/2012
(See this example running online)
XML to array
I see this being asked time and time and time again. Rather than turning a tree of SimpleXMLElement objects into some "friendly" array, please instead take the time to learn how to use SimpleXML: once you have done that, there is no need to take the intermediate step of turning the objects into arrays to work with. The "basic usage" page referred to above should get you going, but key points to know are:
Child nodes use property syntax: $parent->child
Attributes use array-style syntax: $element["attr_name"]
Cast objects into friendly types when desired: (string) $element->child
XPath query should be "//query/results/rate[contains(#id, 'XAUGBP')]"

Getting value from SimpleXMLElement Object

Hi I have this following segment of XML:
......
<Result number="4" position="1" points="25">
<Driver driverId="button" url="http://en.wikipedia.org/wiki/Jenson_Button">
<GivenName>Jenson</GivenName>
<FamilyName>Button</FamilyName>
<DateOfBirth>1980-01-19</DateOfBirth>
<Nationality>British</Nationality>
</Driver>
......
I can use the following easily to get the GivenName:
$item->Driver->GivenName;
But when I use:
$item->Driver->FamilyName;
I get SimpleXMLElement Object ()
I have looked around and found that it might be something to do with passing it to a string but then I get nothing on screen. Not even SimpleXMLElement Object.
I don't understand as it's a sibling of GivenName and that works.
You get a SimpleXMLElement object in both cases, which you'll see if you use print_r():
print_r ($item->Driver->GivenName);
print_r ($item->Driver->FamilyName);
Outputs:
SimpleXMLElement Object
(
[0] => Jenson
)
SimpleXMLElement Object
(
[0] => Button
)
You can use an explicit cast to get the values as strings:
$givenNameString = (string) $item->Driver->GivenName;
$familyNameString = (string) $item->Driver->FamilyName;
To make PHP understand you have to give typecasting forcefully on object like below:
$givenName = (array) $item->Driver->GivenName;
$familyName = (array) $item->Driver->FamilyName;
print_r($givenName);
print_r($familyName);
OUTPUT :
Array ([0] => 'Jenson')
Array ([0] => 'Button')

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 ) ...
Do string typecasting of the object.
$variable = (string) $FieldValue[0];
That would work, as SimpleXml has all the children in object type and not string.
say $X is the object, so to print
The Key of Life; A Metaphysical
Investigation
you do:
echo $X->Title[0]
It's important to understand that you're not working with an array — you're working with a SimpleXMLElement object, which is not the same.
Instead of doing $array['key']['subkey'], you would do $xml->tag->subtag.
SimpleXML nodes are not strings or arrays, although they behave string-like and array-like. Make sure you always typecast the value to an explicit string.
If you're accessing the first node, you don't need to use [0]. It's assumed.
You can convert SimpleXMLElement objects into true associative arrays in PHP 5.2 or newer with:
$array = json_decode(json_encode($xml), true);

Categories