I have a codeigniter app that queryies an api and gets a simplexml object. I had hard coded the values I wanted from the simplexml object, but found out later that the structure of the object isn't always the same, so I can't use casting to get the values I need.
Is there an array_search like function that I could use for this so I can use the "classid" to get the value? Here is a sampling of the simplexml object:
[Package] => SimpleXMLElement Object
(
[#attributes] => Array
(
[ID] => e981b9a72cd305c7d97cc530ef9b3015
)
[Postage] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[CLASSID] => 3
)
[MailService] => Express Mail<sup>®</sup>
[Rate] => 57.60
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[CLASSID] => 2
)
[MailService] => Express Mail<sup>®</sup> Hold For Pickup
[Rate] => 57.60
)
[2] => SimpleXMLElement Object
(
[#attributes] => Array
(
[CLASSID] => 55
)
[MailService] => Express Mail<sup>®</sup> Flat Rate Boxes
[Rate] => 39.95
)
I was using this to get the [Rate] value:
$usps->Package->Postage[0]->Rate
The problem is I need to use [CLASSID] because that is consistant where the data in the number key(?) changes.
Use XPath
You can not only search for specific elements, but do all kinds of crazy searches using various axes.
This should work, but I have no way of testing it without the raw XML:
$rates = array();
foreach ($usps->Package->Postage as $postage)
$rates[$postage->attributes()->CLASSID] = $postage->Rate;
Related
I am trying to create a wordpress shortcode which returns the price of a book from an API.
Ideally, I would like to be able to create a shortcode with this format [currency_isbn13] but for the moment I'd be happy to just create a fixed shortcode for each book and currency.
After various attempts, I was able to put together the following php code, but it is not working as it should
function Price() {
$isbn13 = 9783899735215;
$url = 'https://api.bookdepository.com/search/lookup?isbn13='.$isbn13.'&clientId={redact}&authenticationKey={redact}&IP={redact}¤cies=GBP';
$sxml = simplexml_load_file($url);
print_r($sxml);
return $sxml->price;
}
add_shortcode('isbn13', 'Price');
I would expect the shortcode to return the price of the book, but I get the following:
How can I fix this? I'm sure it is very simple but can't figure it out
SimpleXMLElement Object ( [resultset] => SimpleXMLElement Object ( [status] => Success [results] => 1 [totalResults] => 1 [currentPage] => 1 [totalPages] => 1 ) [items] => SimpleXMLElement Object ( [item] => SimpleXMLElement Object ( [identifiers] => SimpleXMLElement Object ( [isbn13] => 9783899735215 ) [url] => https://www.bookdepository.com/Crocodile-Newts-Axel-Hernandez/9783899735215 [biblio] => SimpleXMLElement Object ( [title] => Crocodile Newts [format] => Hardback ) [availability] => Available - dispatched from the UK in 4 business days [pricing] => SimpleXMLElement Object ( [price] => SimpleXMLElement Object ( [#attributes] => Array ( [currency] => GBP ) [selling] => 50.27 ) ) [contributors] => SimpleXMLElement Object ( [contributor] => SimpleXMLElement Object ( [name] => Axel Hernandez [roleDescription] => By (author) [url] => https://www.bookdepository.com/author/Axel-Hernandez ) ) ) ) )
Looks as though you need to expand
return $sxml->price;
as your structure is more complex. Looks as though
return (string)$sxml->items->item->pricing->price->selling;
The cast to (string) makes the value easier to use elsewhere.
When looping through the below xml object, I need to get the data out of each attribute, and if attributes dont exist, move on. I am not sure how to check to see if #attributes even exists. Currently, if it doesn't my loop dies.
I have tried:
if(isset($v[0]->user->attributes())){
....
but that gives me a php error:
Cannot use isset() on the result of an expression (you can use "null !== expression" instead)
So I am not sure how to check if it exist, if it does i can run through the loop. if it doesnt i can move on...
[server] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => 17980
)
[user] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => 1075159
[default-loc] => 50000
[status] => 1
[license] => high,standard
[password] => aebecf880f2060c31e44f820785e0aa63ea4cc44
[primary] => 50000
[username] => 17980_50000
)
[description] => Customer X
)
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => 14642
)
[user] => Array
(
[0] => SimpleXMLElement Object
(
[description] => Customer Y
)
)
[2] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => 24151
)
[user] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => 1075159
[default-loc] => 50000
[status] => 1
[license] => high,low
[password] => aebecf880f2060c31e44f820785e0aa63ea4cc44
[primary] => 51412
[username] => 17980_51412
)
[description] => Customer Z
)
)
)
)
I am not sure how much this will help you, but when trying to iterate through an XML. I find its best to use recursion instead of looping. Your question doesn't show if you are using a recursive function or a loop but you do say "When looping through..."
If you solve this recursively, you can simply stop and perform your required operation whenever you detect you are at a leaf node that is of type attribute.
This should eliminate any potential null pointer exceptions you may encounter when simply "looping" through the XML.
I have a simpleXML output of:
SimpleXMLElement Object
(
[#attributes] => Array
(
[version] => 2
)
[currentTime] => 2013-02-05 21:26:09
[result] => SimpleXMLElement Object
(
[rowset] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => characters
[key] => characterID
[columns] => name,characterID,corporationName,corporationID
)
[row] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => Wrytha Cy
[characterID] => 209668693
[corporationName] => Deep Core Mining Inc.
[corporationID] => 1000006
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => Eve Mae
[characterID] => 624980803
[corporationName] => Viziam
[corporationID] => 1000066
)
)
[2] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => Wrytha
[characterID] => 709227913
[corporationName] => The Flying Tigers
[corporationID] => 669350666
)
)
)
)
)
[cachedUntil] => 2013-02-05 21:35:04
)
I would like to loop through with my php loop and get "name' and "characterID". I've trying something like:
$simpleXML = simplexml_load_string($xml);
foreach ($simpleXML->result->rowset->row as $row) {
print_r($row);
$name = $row['#attributes']['name'];
echo $name.'<br>';
}
but $name is not being set. It's gonna be something simple, just not seeing it in my haste and first time with simpleXML.
Attributes are accessed using the syntax $element['attribute_name'], so in your case, you need $row['name'].
It's important to remember that SimpleXML objects are kind of magic - the $element->child, $element_list[0] and $element['foo'] syntax overloads the normal PHP logic to be useful. Similarly, (string)$element will give you the full textual content of an element, however it is broken up in the actual XML.
As such, the print_r output will not give you a "real" view of the object, so should be used with care. There are a couple of alternative debug functions I've written here which give a more accurate idea of how the object will behave.
I am having trouble on my php simple xml object.
I have the following xml data in my log
SimpleXMLElement Object
(
[#attributes] => Array
(
[title] => test
[scanner] => Data
[id] => WordData
[position] => 1800
[error] => false
[num] => 6
)
[subpod] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[title] => Surnames
)
[plaintext] => Common (US population: 650 people, white: 63% | black: 35%)
[img] => SimpleXMLElement Object
(
[#attributes] => Array
(
[alt] => Common (US population: 650 people, white: 63% | black: 35%)
[title] => Common (US population: 650 people, white: 63% | black: 35%)
[width] => 349
[height] => 18
)
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[title] => Cities
)
[plaintext] => Littleton Common (Massachusetts, 2789 people)
[img] => SimpleXMLElement Object
(
[#attributes] => Array
(
[alt] => Littleton Common (Massachusetts, 2789 people)
[title] => Littleton Common (Massachusetts, 2789 people)
[width] => 287
[height] => 18
)
)
)
[2] => SimpleXMLElement Object
(
[#attributes] => Array
(
[title] => Buildings
)
[plaintext] => Rotunda on Woolwich Common (London, Greater London)
[img] => SimpleXMLElement Object
(
[#attributes] => Array
(
[alt] => Rotunda on Woolwich Common (London, Greater London)
[title] => Rotunda on Woolwich Common (London, Greater London)
[width] => 356
[height] => 18
)
)
)
.....more simpleXmlElement object
)
)
my php varible $xmlObj = SimpleXMLElement Object but when I have the following
if (is_array($xmlObj->subpod)){
echo 'is array';
}else {
echo 'not array';
}
the output is always 'not array' and I want my codes to echo 'is array'
I thought $xmlObj->subpod is an array.
When I test $xmlObj->subpod[0]->plaintext, it will actually return strings.
I am not sure how to solve this problem. Can anyone help?
If you were to var_dump($xmlObj->subpod), you would see that it is still a SimpleXMLElement object. However, it can still be called as if it were an array. (See the note after this example, which hints that the class implements ArrayAccess, even though the class documentation doesn't.)
The correct way to check for this structure would be using SimpleXMLElement::count():
if ($xmlObj->subpod->count() > 0) { ... }
Edit: The output in your question is presumably from print_r, which is sometimes rather unhelpful in its output (e.g. telling you something is an array when it's not). Try using var_dump instead, as it's generally more useful for debugging. The only caveat here is that you don't get to see the entire nested object structure for SimpleXMLElement objects!
Inside SimpleXMLElement Object everything is SimpleXMLElement Object, print_r and var_dump sometimes lie about arrays -they are traversable objects, but you can perform most operations on them as if they were arrays. If you insist on having pure array, you can cast this node to array:
$subpod = (array)$xmlObj->subpod;
It's pretty straightforward, I have an array with a number of nodes of the same structure available as Simple XML objects (extracted from different XML documents). What's the easiest way to add them to a single XML document, so I can output the combined XML? I've searched, but I can't find a good solution.
Edit: Array looks like this, how do I combine these objects in one single XML object?
Array (
[0] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[no] => 23432423
[type] => Array
)
[id] => 40043030
[title] => Cars
[cinemadate] => 2011-07-06
[changedate] => 2011-07-27T10:19:00
[year] => 2011
[length] => 112
[genres] => SimpleXMLElement Object
(
[genre] => animatie
)
[1] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[no] => 48050593
[type] => Array
)
[id] => 1231676
[title] => Arrietty
[cinemadate] => 2011-07-06
[changedate] => 2011-06-21T10:39:00
[genres] => SimpleXMLElement Object
(
[genre] => animatie
)
Iterate over the array and add the data to the existing simplexml object. You have not provided much information in your question how the array data looks like nor have you provided an example simplexml object / xml chunk, so there is not much more to say specifically.