Access index number of a node inside an XML file - php

For a structure such as
SimpleXMLElement Object
(
[id] => https://itunes.apple.com/us/rss/topfreeapplications/limit=2/genre=6014/xml
[title] => iTunes Store: Top Free Applications in Games
[updated] => 2013-02-04T07:18:54-07:00
[icon] => http://itunes.apple.com/favicon.ico
[entry] => Array
(
[0] => SimpleXMLElement Object
(
[updated] => 2013-02-04T07:18:54-07:00
[id] => https://itunes.apple.com/us/app/whats-word-new-quiz-pics-words/id573511269?mt=8&uo=2
[title] => What is the Word? - new quiz with pics and words - RedSpell
)
[1] => SimpleXMLElement Object
(
[updated] => 2013-02-04T07:18:54-07:00
[id] => https://itunes.apple.com/us/app/temple-run-2/id572395608?mt=8&uo=2
[title] => Temple Run 2 - Imangi Studios, LLC
)
)
)
I'm using the following code to target the entry node as each entry node stands for a game.
$xml = simplexml_load_file('the path to file');
foreach ($xml->entry as $val)
{
$gameTitle = $val->title;
$gameLink = $val->id;
}
WHAT I'M LOOKING FOR
Target the index of the entry node, i.e. 0, 1, 2 and so on; i.e.
[0] => SimpleXMLElement Object // <-- this fella here, capture 0
(
[updated] => 2013-02-04T07:18:54-07:00
[id] => https://itunes.apple.com/us/app/whats-word-new-quiz-pics-words/id573511269?mt=8&uo=2
[title] => What is the Word? - new quiz with pics and words - RedSpell
)
[1] => SimpleXMLElement Object // <-- this fella here, capture 1
(
[updated] => 2013-02-04T07:18:54-07:00
[id] => https://itunes.apple.com/us/app/temple-run-2/id572395608?mt=8&uo=2
[title] => Temple Run 2 - Imangi Studios, LLC
)
Whatever I do, I just can't seem to get the index of the current node.
UPDATE
Just for you people to test it out Code Viper

You are looking for a function called iteator_to_array setting the second parameter to false:
$entries = iterator_to_array($xml->entry, false);
foreach ($entries as $index => $val)
{
$gameTitle = $val->title;
echo "<p>$gameTitle</p><p>Index = $index</p>";
}
Demo. Actually you do not must use that function you could also just count:
$index = 0;
foreach ($xml->entry as $val)
{
echo "<p>{$val->title}</p><p>Index = $index</p>";
$index++;
}
By default the $key (as in your example code) is the tagname of the XML element. So you can not use it for the index number by default.

Related

Get data from OMDb API with xml

I'l try to get the movie title and info from the omdb API. This is my code:
<?php
$enter = $_GET["enter"];
$content = file_get_contents("https://www.omdbapi.com/?s=$enter&r=xml");
$xml = simplexml_load_string($content);
if($xml) {
echo "<h2>" .$xml->title. "</h2>";
}
else
{
echo "Nothing found. Add the info manualy";
}
?>
The "enter" value is from the search form with AJAX. He create only an empty h2 tag. How can i get also the data from the API?
Thank you,
Julian
You should familiarize yourself with the structure of the xml to know how to access its elements. print_r(get_object_vars($xml)) will show you a structure like this:
Array
(
[#attributes] => Array
(
[totalResults] => 3651
[response] => True
)
[result] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[title] => World War Z
[year] => 2013
[imdbID] => tt0816711
[type] => movie
[poster] => https://images-na.ssl-images-amazon.com/images/M/MV5BMTg0NTgxMjIxOF5BMl5BanBnXkFtZTcwMDM0MDY1OQ##._V1_SX300.jpg
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[title] => Captain America: Civil War
[year] => 2016
[imdbID] => tt3498820
[type] => movie
[poster] => https://images-na.ssl-images-amazon.com/images/M/MV5BMjQ0MTgyNjAxMV5BMl5BanBnXkFtZTgwNjUzMDkyODE#._V1_SX300.jpg
)
)
...
...
...
[9] => SimpleXMLElement Object
(
[#attributes] => Array
(
[title] => War
[year] => 2007
[imdbID] => tt0499556
[type] => movie
[poster] => https://images-na.ssl-images-amazon.com/images/M/MV5BMTgzNTA4MTc3OF5BMl5BanBnXkFtZTcwOTA0ODk0MQ##._V1_SX300.jpg
)
)
)
)
So you receive an array with results where you need to pick from. Alternatively if you know the exact title the API has the t=title option which only returns a single result (see documentation).
So assuming you use the s=title option which returns multiple results, you can use something like this to pick information from the first result:
<?php
$enter = $_GET["enter"];
$content = file_get_contents("https://www.omdbapi.com/?s=$enter&r=xml");
$xml = simplexml_load_string($content);
# show the structure of the xml
# print_r(get_object_vars($xml));
if($xml) {
print "<h2>" .$xml->result[0]['title']. "</h2>";
print "<br>imdbID=" . $xml->result[0]['imdbID'] ;
} else {
echo "Nothing found. Add the info manualy";
}
?>

PHP - Converting XML to array misses some information from XML string

I am using curl to get an external XML document and convert it to an array.
The code works almost perfect, apart from one node in the XML isn't being processed and put in my array.
Under <drivers> there is a code for each driver: <driver code="TM1"> but this doesn't get picked up by my array as an #attribute array like the others such as <collection date="20160324">
Does anybody know why this is happening?
XML:
<findit xmlns="http://www.URL.COM" version="8" type="TIX" date="20160323">
<account code="XXXXXX">
<customers>
<customer code="12345">
<status code="0">Success</status>
<logistic-jobs>
<logistic-job id="12345" date="20160324" status="PLA" modified="201603231420">
<number>
<number1>479599</number1>
<number3>11221</number3>
</number>
<collection date="20160324" time="0500">
<name>JOHN SMITH</name>
<address1>UNIT 3 DAVEY ROAD</address1>
<address2>FIELDS END BUSINESS PARK</address2>
<address3>GOLDTHORPE</address3>
<address4>ROTHERHAM</address4>
<address5>S63 0JF</address5>
</collection>
<delivery date="20160324" time="1200">
<address1>EXAMPLE</address1>
<address2>GLENEAFLES FARM</address2>
<address3>GLENEAGLES CLOSE</address3>
<address4>STANWELL, MIDDLESEX</address4>
<address5>TW19 7PD</address5>
</delivery>
<extra>
<address1>45FT C/SIDER</address1>
<address2>No</address2>
<address4>CEMENT</address4>
</extra>
<drivers>
<driver code="TM1">DAVE SMITH (DAYS)</driver>
</drivers>
<load weight="27600.00" volume="0.00">
<pallets full="23" half="0" quarter="0" blue="0" oversize="0"/>
</load>
</logistic-job>
</logistic-jobs>
</customer>
</customers>
</account>
</findit>
PHP:
$job_array = json_decode(json_encode(simplexml_load_string($xml)), true);
if(is_array($job_array['account']['customers']['customer'])) {
// Foreach customer in array
foreach($job_array['account']['customers']['customer'] as $i => $customer) {
// If status is set to success
if($customer['status'] == "Success") {
// For each job
foreach($customer['logistic-jobs']['logistic-job'] as $i => $job) {
echo '<pre>'; print_r($job); echo '</pre>';
}
}
}
}
OUTPUT:
Array
(
[#attributes] => Array
(
[id] => 12345
[date] => 20160324
[status] => PLA
[modified] => 201603231420
)
[number] => Array
(
[number1] => 479599
[number3] => 11221
)
[collection] => Array
(
[#attributes] => Array
(
[date] => 20160324
[time] => 0500
)
[name] => JOHN SMITH
[address1] => UNIT 3 DAVEY ROAD
[address2] => FIELDS END BUSINESS PARK
[address3] => GOLDTHORPE
[address4] => ROTHERHAM
[address5] => S63 0JF
)
[delivery] => Array
(
[#attributes] => Array
(
[date] => 20160324
[time] => 1200
)
[address1] => EXAMPLE
[address2] => GLENEAFLES FARM
[address3] => GLENEAGLES CLOSE
[address4] => STANWELL, MIDDLESEX
[address5] = TW19 7PD
)
[extra] => Array
(
[address1] => 45FT C/SIDER
[address2] => No
[address4] => CEMENT
)
[drivers] => Array
(
[driver] => DAVE SMITH (DAYS)
)
[load] => Array
(
[#attributes] => Array
(
[weight] => 21509.00
[volume] => 0.00
)
[pallets] => Array
(
[#attributes] => Array
(
[full] => 52
[half] => 0
[quarter] => 0
[blue] => 0
[oversize] => 0
)
)
)
)
I have a simple answer for you: don't convert XML to an array. SimpleXML has a really useful API for traversing through the XML document and finding the data you want; throw away the horrible json_decode(json_encode( hack and look at the examples in the PHP manual.
In this case, echo $driver would give you the contents (driver name) and echo $driver['code'] would give you the attribute value; clearly, a plain array can't have that convenient magic, which is why converting to one is giving you problems.
Just remember that print_r will also hide things from you, and you might want a dedicated debugging function.
Here's an example (with live demo) of getting the code and name of each driver:
$job_simple = simplexml_load_string($xml);
if(isset($job_simple->account->customers->customer)) {
// Foreach customer in array
foreach($job_simple->account->customers->customer as $i => $customer) {
// If status is set to success
if((string)$customer->status == "Success") {
// For each job
foreach($customer->{'logistic-jobs'}->{'logistic-job'} as $i => $job) {
echo "<ul>\n";
foreach ( $job->drivers->driver as $driver ) {
echo "<li> {$driver['code']}: $driver\n";
}
echo "</ul>\n";
}
}
}
}

Foreach loop Multidimensional Array

I am working with an multidimensional array which I am receiving from a third party source so can not change the layout of it. Its for a collge and I want to loop the module names but not the ID's.
When using this foreachloop
<?php echo "<ul>";
foreach($array['Course']['Modules']['Module'] as $key => $value)
{
foreach($value as $keys => $values)
{
echo "<li>";
foreach($values as $thirdkey => $thirdvalues)
{
echo $thirdvalues . " " ;
}
echo "</li>";
}
}
echo "</ul>"
?>
I get the following which is fine but I don't need the moduleID:
003646 T.I.G. WELDING ALUMINIMUM INTERMEDIATE
003644 T.I.G. WELDING STAINLESS STEEL INTERMEDIATE
003633 MIG WELDING INTERMEDIATE
003552 MANUAL METAL ARC WELDING INTERMEDIATE
000016 MOUNTING OF ABRASIVE WHEELS
003299 MACHINE TOOLS (WELDING)
000001 INDUCTION
000002 CAREER PLANNING AND JOB SEEKING SKILLS
000029 OXY-ACETYLENE CUTTING
003757 THEORY OF WELDING
000003 IN-COMPANY
000664 SAFEPASS
This is my array, can anyone help me return just the Module Title???
Array
([Certification] => IT Systems Support - PC Maintenance (L1)
[Modules] => Array
(
[Module] => Array
(
[0] => Array
(
[#attributes] => Array
(
[ModuleID] => 004839
[Title] => IT SYSTEMS SUPPORT- PC MAINTENANCE
)
)
[1] => Array
(
[#attributes] => Array
(
[ModuleID] => 007685
[Title] => COMPTIA A+ - 220 801
)
)
[2] => Array
(
[#attributes] => Array
(
[ModuleID] => 007684
[Title] => COMPTIA A+ - 220-802
)
)
[3] => Array
(
[#attributes] => Array
(
[ModuleID] => 004757
[Title] => PREPARING FOR WORK
)
)
)
)
)
Thank in advance :)
You could just directly point to it.
foreach($array['Course']['Modules']['Module'] as $key => $value) {
echo "<li>{$value['#attributes']['Title']}</li>";
}
Sidenote: Most likely this is a SimpleXML object, fed into a json encode/decode.
$array = json_decode(json_encode($xml), true); // actually don't need to do this one
I'd suggest just use SimpleXML all through out as it is already capable of getting all those values.
You didn't care to try $thirdvalues["Title"] right?, looks like a mess but I don't see why it wouldn't work if you got it to print that.
can also do if( $key == "Title" ) echo $value

Getting position number from an array

If I have the following array in session, can I get a item position number in each [cat]:
Array
(
[0] => stdClass Object
(
[id] => 1
[cat] => 1
[que] => Description here.
)
[1] => stdClass Object
(
[id] => 2
[cat] => 1
[que] => Description here.
)
[2] => stdClass Object
(
[id] => 3
[cat] => 1
[que] => Description here.
)
)
For example the following will give me the second description, but how do I get that it has position #2 (out of 3) in [cat] == 1:
$item = $_SESSION['questions'][2]->que;
The actual array is much larger and has more than 1 [cat]. The count I am trying to get is withing each such group.
I'm sure you're looking for a more native way, but worse case scenario, you could add another element to hold the index value.
By adding a dummy entry at the beginning of the array:
array_unshift($_SESSION['questions'], array());
$item = $_SESSION['questions'][2]->que;
foreach($_SESSION['questions'] as $key=>$val)
{
if($val->id == 3)
echo $key;
}
//or
foreach($_SESSION['questions'] as $key=>$val)
{
if($val->que == "Description here.")
echo $key;
}
//do what ever you want

How to get past [#attributes] in SimpleXMLElement? [duplicate]

This question already has answers here:
simplexml_load_file parse [#attributes] => Array
(3 answers)
Closed 9 years ago.
The goal: Using PHP/CodeIgniter, I need to get a list of users and their custom field names and values in a usable array. If I can just get to the items, I can do what I need. Please see OUTPUT with notes for "// <<< " so you can see where I'm stuck. I just can't get past the dang [#attributes].
I'm using PHP to connect to Redmine using ActiveResource.php and their built in REST API. I want to get a list of all the users and am getting the OUTPUT below.
Models/Employees_model.php:
<?php
require_once ('ActiveResource.php');
class Employees_model extends ActiveResource {
var $site = 'http://user:password#localhost:8080/redmine/';
var $element_name = 'user';
var $request_format = 'xml';
function __construct() {
parent::__construct();
}
}
?>
controllers/employees.php:
public function employees () {
$employees = new Employees_model();
$data['employeeList'] = $employees->find('all');
$this->load->view('customers/ajaxEmployees', $data);
}
view/ajaxEmployees.php:
<?php
//I can get the following with no problem
echo $employee->id . "<br/>";
echo $employee->firstname . "<br/>";
echo $employee->lastname . "<br/>";
//This is where I'm stuck (see OUTPUT for [#attributes] and "// <<<" notes)
echo $employee->custom_fields->custom_field;
?>
OUTPUT:
Array
(
[0] => Employees_model Object
(
[id] =>
[site] => http://user:password#localhost:8080/redmine/
[element_name] => user
[request_format] => xml
[extra_params] =>
[user] =>
[password] =>
[element_name_plural] => users
[_data] => Array
(
[id] => 16
[login] => jschmoe
[firstname] => Joe
[lastname] => Schmoe
[mail] => joe#example.com
[created_on] => 2012-08-24T01:58:21Z
[last_login_on] => SimpleXMLElement Object
(
)
[custom_fields] => SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => array
)
[custom_field] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => Quality Control //<<< I need this
[id] => 2
)
[value] => 1 //<<< I need this to know that QualityControl = 1
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => Technical Contractor // <<< I need this
[id] => 3
)
[value] => 0 // <<< I need this to know that TechnicalContractor = 0
)
[2] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => Content //<<< I need this
[id] => 4
)
[value] => 0 // <<< I need this to know Content = 1
)
)
)
)
)
)
Thank you all so much for your help. After wasting many hours searching around, trying everything I came across and everything I could think of - I figured I'd better wave my little white flag. :(
$employee->custom_fields->custom_field; is an array, and you can foreach over it to get each name attribute and its corresponding value using SimpleXMLElement::attributes().
foreach ($employee->custom_fields->custom_field as $cf) {
// Loop over the custom field nodes and read the name of each
switch ($cf->attributes()->name) {
// Load a variable on each matching name attribute
// or do whatever you need with them.
case "Quality Control":
$quality_control = $cf->value;
break;
case "Technical Contractor":
$technical_contractor = $cf->value;
break;
case "Content":
$content = $cf->value;
break;
}
}
Or if you don't know in advance all the ones you'll need, load them into an array:
$employee_attrs = array();
foreach ($employee->custom_fields->custom_field as $cf) {
// Add an array key of the name, whose value is the value
$attrs[$cf->attributes()->name] = $cf->value;
}
var_dump($employee_attrs);
The attributes() function is what you're looking for I think. For example
foreach ($employee->custom_fields->custom_field as $line) {
echo "[" . $line->attributes()->name . "]" . $line->value . "\n";
}
Also you might have to use this instead:
foreach ($employee->_data->custom_fields->custom_field as $line) {
(not sure, try both)

Categories