Welcome Guest, Not a member yet? Register   Sign In
SimpleXML to return a few items at a time
#1

[eluser]ModernM[/eluser]
I am using simple XML to grab the data from a cURL response in XML. Now I can get everything back using this

Code:
<?php $Items = new SimpleXMLElement($res);?>
    
    
      <div class="row-fluid">
        <div class="span10">
         <ul class="thumbnails">
          &lt;?php foreach ($Items->SearchResults->Items->Item as $ProductID){
   echo '<li class="span3">
             <div class="thumbnail"> <img src="'.$ProductID-&gt;ThumbPicLink.'" alt="'.$ProductID-&gt;PrName.'">
      <h5>'.$ProductID->PrName.'</h5>
      <p>Short Description</p>
      <h6>Item Number:'.$ProductID->ProductID.'</h6>
            </div>
          </li>';
    }?&gt;
        </ul>
        </div>

How do I express this so it returns 10 items at a time, what I am trying to do is paginate the data instead of returning 10000 items at once.

Thanks
#2

[eluser]pickupman[/eluser]
Depends on it the XML is local or if you are fetching it, but it maybe wise to cache the contents as an array. I would convert the XML to an array using one of the recursive functions on the php.net [url="http://php.net/manual/en/book.simplexml.php"]simplexml[/url] documentation. Once you have it as an array, you could count the indexes to create your total rows. Then pass the pagination offsets to a for loop.
Code:
$i = $this->uri->segment(3,0);
for($i < ($i + 10); $i++)
{
   echo $arrayFromXML[$i]['ProductID']['PrName'];
}
#3

[eluser]ModernM[/eluser]
Yes I'm getting the data from a provider using curl. It comes back as all records. When you say cache do you mean store it in a database or a file? Use to working with MySQL for data. The. Data comes back as a variable $res. so should I do this in the controller? Also should I put the data request curl in a model? Right now I dynamically change what catalog items I want with a variable in the XML. Curl request which I don't think is efficient.

I'll try your solution tomorrow and report back. So far I think I'm doing pretty good for my first ci project and thanks for all the help on this forum!
#4

[eluser]pickupman[/eluser]
From a MVC standpoint, getting data should be in a model. So I would write a model that fetches the XML. You can cache it using the [url="http://ellislab.com/codeigniter/user-guide/libraries/caching.html"]Cache driver[/url]. This will save it to a file. I would suggest using the model to fetch the data, iterate the xml into an array and save the array to a cache key. Remember to use a unique key depending on the variable in your xml you are fetching. Then on subsequent requests the model will call the cache for the array and return it. The calls to your model should be in your controller. Only display logic should be in your views.
Code:
//Model
puhlic function get_xml($key)
{
   if( ! $res = $this->cache->get('xml_'.$key))
   {
       //Curl XML
       $res = simple_xml_load_file($key); //Fetch XML string from server
       $res = $this->_xml2array($res);  //Convert xml to array in a private method
       $this->cache->set('xml_'.$key, 360); // Cache for 5 minutes
   }
   return $res;
}

private function _xml2array($res)
{
   //iterate xml here and return it
   return $res;
}


This way you only have to fetch the xml every 5 minutes or however long you think the data will be valid. And by caching it as an array, you will save this processing overhead on each request that comes from the cache.
#5

[eluser]ModernM[/eluser]
Ok,
So the data I am fecthing is a catalog that updates maybe once a month. And if it updates more than that its not a huge deal, as long as I get the new updates each month.

So far this is what I have in my function, that I WILL put into a Model since I want to do things the right way.

Code:
&lt;?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Catalog extends CI_Controller {


function index(){

  $catid = $_GET['catid'];
  // for testing - $catid = 'aprons';
  //echo 'This is the cat ID called by the URL => '.$catid;
  
  $post = '&lt;?xml version=\“1.0\” encoding=\“UTF-8\”?&gt;\n\n';
  $post .= '&lt;XMLDataStreamRequest&gt;\n';
  $post .= '<Auth>\n';
  $post .= '<AcctID>xxxxx</AcctID>\n';
  $post .= '<LoginID>xxxxxx</LoginID>\n';
  $post .= '<Password>xxxxxx</Password>\n';
  
  $post .= '<Search>\n';
  $post .= '<Category>'.$catid.'</Category>\n';
  $post .= '</Search>\n';
  $post .= '&lt;/XMLDataStreamRequest&gt;\n';
  
  //theme
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL,'https://www.promoplace.com/ws/ws.dll/XMLDataStream');
  curl_setopt($ch, CURLOPT_POST, TRUE);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  $res = curl_exec($ch);
  curl_close ($ch);
  echo $res;
  
  /*
  $Items = new SimpleXMLElement($res);
  foreach ($Items->SearchResults->Items->Item as $ProductID){
   echo 'ID: '.$ProductID->ProductID.'<br />';
   }
  */
  
  
  //$data['res'] = $res;
  //$this->load->view('list_view', $data);
  
  
  }

So this dumps into my view everything.

So should my model have the curl posts, and then return the $res variable to the proposed code for caching in the previous post? Is that correct? I am just confused on what code would go where, not actually what the code does per say.

I will post this and try to write a Model with your suggested cache options and see what I get. and I will post my findings.

Thanks
#6

[eluser]ModernM[/eluser]
Why and I getting 10 of each items instead of showing only 10 at a time?

Code:
&lt;?php $Items = new SimpleXMLElement($res);?&gt;
    
    
      <div class="row-fluid">
        <div class="span10">
         <ul class="thumbnails">
            
          &lt;?php foreach ($Items->SearchResults->Items->Item as $ProductID){
     for ($i = 1; $i <= 10; $i++) {
      echo '<li class="span3">
             <div class="thumbnail"> <img src="'.$ProductID-&gt;ThumbPicLink.'" alt="'.$ProductID-&gt;PrName.'">
      <h5>'.$ProductID->PrName.'</h5>
      <p>Short Description</p>
      <h6>Item Number:'.$ProductID->ProductID.'</h6>
            </div>
          </li>';
    }}?&gt;
        </ul>
        </div>
#7

[eluser]pickupman[/eluser]
You don't want to echo the variable $res, as this will output all of the xml to the browser you only want to fetch it. You are really close with your model. You need to integrate the code I had shown above.

1.) Check if xml is saved as an array in the cache
2.) If cache does not exists, use curl to fetch xml.
3.) Convert xml response to an array in a private method
4.) Save converted array to the cache
5.) Return array to controller.

Not sure exactly why you have the for loop inside of the foreach loop. It seems like you are trying to iterate the xml using both methods. What you really need to be doing is iterating the converted array. This allows you to reference the index to paginate the results. SimpleXML doesn't allow this feature directly unless you have the SimpleXML iterator class avaialble. I think the conversion of the xml will be much easier to support.

Then you can pass the array to your view, using the pagination class and the array, create the pagination links based on the number of keys (products) in the array. Then you can use the code I first posted, using the 3rd segment to offset the start of your for loop.
Code:
$this->load->library('pagination');
$this->load->model('catalog_model');

$xml = $this->catalog_model->get_xml($catid); //Get xml/array for catid

$config['base_url'] = site_url('products/'.$catid . '/');
$config['total_rows'] = count($xml);
$config['per_page'] = 20;
$this->pagination->initialize($config);

$data['pagination'] = $this->pagination->create_links(); //Pagination links for view

$i = $this->uri->segment(3,0); //Start array index based on 3rd uri segment (0 = default)

$data['products'] = '';
for($i < ($i + $config['per_page']); $i++)
{
   $data['products'] .= $xml[$i]['ProductID']['PrName'] . '<br/>'; //Append some data here
}

$this->load->view('catalog/products', $data);

//In view
<div id="products">
  &lt;?php echo $products;?&gt;
</div>
#8

[eluser]ModernM[/eluser]
Here is my model, I think im off here not sure where
Code:
&lt;?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Catalog_Model extends CI_Model {


public function get_xml($key)
{
  if( ! $res = $this->cache->get('xml_'.$key))
  
  {
  
  //Curl XML
     $post = '&lt;?xml version=\“1.0\” encoding=\“UTF-8\”?&gt;\n\n';
  $post .= '&lt;XMLDataStreamRequest&gt;\n';
  $post .= '<Auth>\n';
  $post .= '<AcctID>qwe</AcctID>\n';
  $post .= '<LoginID>qwe</LoginID>\n';
  $post .= '<Password>qwe</Password>\n';
  $post .= '<Search>\n';
  $post .= '<Category>'.$catid.'</Category>\n';
  $post .= '</Search>\n';
  $post .= '&lt;/XMLDataStreamRequest&gt;\n';
  
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL,'https://www.promoplace.com/ws/ws.dll/XMLDataStream');
  curl_setopt($ch, CURLOPT_POST, TRUE);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  $res = curl_exec($ch);
  curl_close ($ch);
  
  
  $res = simple_xml_load_file($key); //Fetch XML string from server
  $res = $this->_xml2array($res);  //Convert xml to array in a private method
  $this->cache->set('xml_'.$key, 360); // Cache for 5 minutes
  }
  
  return $res;
}

private function _xml2array($res)
{
  //iterate xml here and return it
  return $res;
}


}

Now i get these
--------
A PHP Error was encountered

Severity: Notice

Message: Undefined variable: catid

Filename: controllers/catalog.php

Line Number: 11
A PHP Error was encountered

Severity: Notice

Message: Undefined property: Catalog::$cache

Filename: core/Model.php

Line Number: 51
.----

Should the curl post be in the model with the cache key for $res?

Also I am getting a syntax error with this

Code:
for($i < ($i + $config['per_page']); $i++)
#9

[eluser]pickupman[/eluser]
Um....the code wasn't written in a literal sense although it was close. You will need to do some of the work. Since you are posting via curl and getting the response, you would need to use [url="http://us.php.net/manual/en/function.simplexml-load-string.php"]simplexml_load_string()[/url] install of load_file.

Code:
//Curl stuff here then
$res = simplexml_load_string($res); //Fetch XML string from server

You need to load the cache class if you haven't loaded it already, just like with every other library/driver. The $catid was only used as an example for fetching a category id. Use whatever you are using in your code already. You will need to add the code to the _xml2array method. Use code from [url="www.php.net/manual/en/function.xml-parse.php#97556"]here[/url].
#10

[eluser]pickupman[/eluser]
Oh, and the for loop should be:
Code:
for($i = $this->uri->segment(3,0); $i < ($i + $config['per_page']); $i++)




Theme © iAndrew 2016 - Forum software by © MyBB