how to read only part of an xml file with php xmlreader - php

I have an RSS xml file that is pretty large, with more than 700 nodes.
I am using XMLReader Iterator library to parse it and display the results as 10 per page.
This is my sample code for parsing xml:
<?php
require('xmlreader-iterators.php');
$xmlFile = 'http://www.example.com/rss.xml';
$reader = new XMLReader();
$reader->open($xmlFile);
$itemIterator = new XMLElementIterator($reader, 'item');
$items = array();
foreach ($itemIterator as $item) {
$xml = $item->asSimpleXML();
$items[] = array(
'title' => (string)$xml->title,
'link' => (string)$xml->link
);
}
// Logic for displaying the array values, based on the current page.
// page = 1 means $items[0] to $items[9]
for($i = 0; $i <= 9; $i++)
{
echo ''.$items[$i]['title'].'<br>';
}
?>
But the problem is that, for every page, i am parsing the entire xml file and then just displaying the corresponding page results, like: if the page is 1, displaying the 1 to 10 nodes, and if the page is 5, displaying 41 to 50 nodes.
It is causing delay in displaying data. Is it possible to read just the nodes corresponding to the requested page? So for the first page, i can read nodes from 1 to 10 positions, instead of parsing all the xml file and then display first 10 nodes. In other words, can i apply a limit while parsing an xml file?
I came across this answer of Gordon that addresses a similar question, but it is using SimpleXML, which is not recommended for parsing large xml files.

use array_splice to extract the portion of array
require ('xmlreader-iterators.php');
$xmlFile = 'http://www.example.com/rss.xml';
$reader = new XMLReader();
$reader->open($xmlFile);
$itemIterator = new XMLElementIterator($reader, 'item');
$items = array();
$curr_page = (0 === (int) $_GET['page']) ? 1 : $_GET['page'];
$pages = 0;
$max = 10;
foreach ($itemIterator as $item) {
$xml = $item->asSimpleXML();
$items[] = array(
'title' => (string) $xml->title,
'link' => (string) $xml->link
);
}
// Take the length of the array
$len = count($items);
// Get the number of pages
$pages = ceil($len / $max);
// Calculate the starting point
$start = ceil(($curr_page - 1) * $max);
// return the portion of results
$arrayItem = array_slice($items, $start, $max);
for ($i = 0; $i <= 9; $i ++) {
echo '' . $arrayItem[$i]['title'] . '<br>';
}
// pagining stuff
for ($i = 1; $i <= $pages; $i ++) {
if ($i === (int) $page) {
// current page
$str[] = sprintf('<span style="color:red">%d</span>', $i);
} else {
$str[] = sprintf('%d', $i, $i);
}
}
echo implode('', $str);

Use cache in this case, since you cannot parse partially an XML.

Check this
<?php
if($_GET['page']!=""){
$startPagenew = $_GET['page'];
$startPage = $startPagenew-1;
}
else{
$startPage = 0;
}
$perPage = 10;
$currentRecord = 0;
$xml = new SimpleXMLElement('http://sports.yahoo.com/mlb/teams/bos/rss.xml', 0, true);
echo $startPage * $perPage;
foreach($xml->channel->item as $key => $value)
{
$currentRecord += 1;
if($currentRecord > ($startPage * $perPage) && $currentRecord < ($startPage * $perPage + $perPage)){
echo "$value->title";
echo "<br>";
}
}
//and the pagination:
//echo $currentRecord;
for ($i = 1; $i <= ($currentRecord / $perPage); $i++) {
echo("<a href='xmlpagination.php?page=".$i."'>".$i."</a>");
} ?>
Updated
Check this Link
http://www.phpclasses.org/package/5667-PHP-Parse-XML-documents-and-return-arrays-of-elements.html

You can use Dom and Xpath. It should be much faster, since Xpath allows you to select nodes by their position in a list.
<?php
$string = file_get_contents("http://oar.icrisat.org/cgi/exportview/subjects/s1=2E2/RSS2/s1=2E2.xml");
$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadXML($string);
$string = "";
$xpath = new DOMXPath($dom);
$channel = $dom->getElementsByTagName('channel')->item(0);
$numItems = $xpath->evaluate("count(item)", $channel);
// get your paging logic
$start = 10;
$end = 20;
$items = $xpath->evaluate("item[position() >= $start and not(position() > $end)]", $channel);
$count = $start;
foreach($items as $item) {
print_r("\r\n_____Node number $count ");
print_r( $item->nodeName);
$childNodes = $item->childNodes;
foreach($childNodes as $childNode) {
print_r($childNode->nodeValue);
}
$count ++;
}

Related

looping through an array by slices, not each item

I have an array of potentially 1000s of items that I need to feed to and API that can handle 10 at a time. So, can I do something like this?
$data = [ ... ];
$start = 0;
$step = 10;
foreach (api_function(array_slice($data, $start, $step))){
$start += $step;
}
Using Nigel Ren's answer the final code looks like this:
$results = BC_cust_query($qlist, true);
$start = 0;
$step = 10;
$stop = count($results);
while ($start < $stop){
print_r(array_slice($results, $start, $step));
$start += $step;
}
Where print_r() will be replace by the API call
You would need to keep repeating the call to the API for each slice, until there is no more data left (check the start against the length of the array). Assuming it returns blank, some thing like
$data = [ ... ];
$start = 0;
$step = 10;
$countData = count($data);
// Fetch block of data whilst some data to fetch.
while ($start < $countData &&
$dataBlock = api_function(array_slice($data, $start, $step))){
// Loop over this block
foreach ( $dataBlock as $dataItem) {
// Process item
}
// Move onto next block
$start += $step;
}
or use a for loop...
$data = [ ... ];
$step = 10;
$countData = count($data);
// Fetch block of data whilst some data to fetch.
for ($start = 0;$start < $countData; $start += $step) {
$dataBlock = api_function(array_slice($data, $start, $step));
// Loop over this block
foreach ( $dataBlock as $dataItem) {
// Process item
}
}

How to Generate a Dynamic Text in a html List

I need to generate a dynamic text in accordance with the number of data that comes from the database.
In a html List, I need to display the following text as example:
GROUP A
GROUP B
GROUP C
If the amount of records coming from the DB is only 1000, then only one item list is displayed. 1000 records equals 1 Item list.
The text must be dynamically changed as described above.
Each text in the list is displayed for 1000 records.
The code below statically displays 11 items
I've made a few tries on the code below but still to no avail.
This code is working, but it display only the static text.
$return .= "<div id='test_id'><ul>";
// $qty = 10424 / $limit = 1000
// $tabs = $qty / $limit = 10,424
$tabs = $qty/$limit;
for ($i=0; $i < $tabs ; $i++)
{
$start = $i * $limit + 1;
$end = ($i + 1) * $limit;
$color = 'classpA';
$message = '<small>GROUP A</small>';
if ($i < $tab_selected) {
$color = 'classB';
$message = 'RESERVED';
}
$active = $i == $tab_selected ? "active" : "";
$return .= "<li class='tab {$color} {$active}' tab-id='#tab-".$i."'>
<span class='available {$color}_text'><small>{$message}</small></span>
<a href='#' class='{$color}_text'>".$start." - ".min($end,$qty)."</a></li>";
}
$return .= "</ul></div>";
And this is that logic that i`m trying to apply
$qty = 18424;
$limit = 1000;
$tabs = ($qty / $limit);
$group = $tabs / $limit;
$alphabet = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
for($i = 0; $i < $group; $i++) {
echo "Group {$alphabet[$i]}".'<br>';
}
echo 'Qtd Group= '.$group.' Value Var Tabs= '.$tabs;
https://www.tehplayground.com/zyVzmaeYnTyyA4S9
How can I make the magic happen?
Your logic is fine, just the limit to the for loop seems to be miscalculated.
Right now, for the variable group = (qty/limit)/limit, you have an extra division by limit here.
Whatever your need maybe for that division, you can simply use the value of tabs in your for loop condition, or assign it to another temporary variable its up to you.
for($i = 0; $i < $tabs; $i++) {
echo "Group {$alphabet[$i]}".'<br>';
}
Cheers!
Maybe this could helps you
<?php
//$tabs = ($qty / $limit);
//$group = $tabs / $limit;
$alphabet = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
$return = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
$a = array_chunk($return, 3);
//$a = array_chunk($return, $limit);
$key = 0;
$group = array();
$r = count($a);
foreach($alphabet as $v)
{
if($key < $r)
{
if(!isset($group[$v]))
{
$group[$v] = array();
}
$group[$v] = $a[$key];
$key++;
}
}
print_r($group);
Here
https://www.tehplayground.com/bfmZOubIMdmBcjhu

Got stuck parsing tabular content from a website

I've written a script in PHP to get the tabular data from a webpage. When I execute my script I can get them in a single column. However, I wish to parse them as a list, as in how they look like in that webpage.
Website link
To be clearer:
My current output are like:
978
EMU
EUR
1
118.2078
36
Australija
AUD
1
73.1439
My expected output are like:
['978', 'EMU', 'EUR', '1', '118.2078']
['36', 'Australija', 'AUD', '1', '73.1439']
['124', 'Kanada', 'CAD', '1', '77.7325']
['156', 'Kina', 'CNY', '1', '14.6565']
['191', 'Hrvatska', 'HRK', '1', '15.9097']
This is my try so far:
<?php
$url = "http://www.nbs.rs/kursnaListaModul/srednjiKurs.faces?lang=lat";
$dom = new DomDocument;
$dom->loadHtmlFile($url);
$xpath = new DomXPath($dom);
$rowData = array();
foreach ($xpath->query('//tbody[#id="index:srednjiKursList:tbody_element"]//tr') as $node) {
foreach ($xpath->query('td', $node) as $cell) {
$rowData[] = $cell->nodeValue;
}
}
foreach($rowData as $rows){
echo $rows . "<br/>";
}
?>
You are adding each element one at a time to the output array, you probably wanted to build up a row at a time and output that...
$rowData = array();
foreach ($xpath->query('//tbody[#id="index:srednjiKursList:tbody_element"]//tr') as $node) {
$row = array();
foreach ($xpath->query('td', $node) as $cell) {
$row[] = $cell->nodeValue;
}
$rowData[] = $row;
}
foreach($rowData as $rows){
print_r($rows); // Format the data as needed
}
Try this.
$htmlContent = file_get_contents("http://www.nbs.rs/kursnaListaModul/srednjiKurs.faces?lang=lat");
$DOM = new DOMDocument();
$DOM->loadHTML($htmlContent);
$Header = $DOM->getElementsByTagName('th');
$Detail = $DOM->getElementsByTagName('td');
//#Get header name of the table
foreach($Header as $NodeHeader)
{
$aDataTableHeaderHTML[] = trim($NodeHeader->textContent);
}
//#Get row data/detail table without header name as key
$i = 0;
$j = 0;
foreach($Detail as $sNodeDetail)
{
$aDataTableDetailHTML[$j][] = trim($sNodeDetail->textContent);
$i = $i + 1;
$j = $i % count($aDataTableHeaderHTML) == 0 ? $j + 1 : $j;
}
//print_r($aDataTableDetailHTML)
//#Get row data/detail table with header name as key and outer array index as row number
for($i = 0; $i < count($aDataTableDetailHTML); $i++)
{
for($j = 0; $j < count($aDataTableHeaderHTML); $j++)
{
#$aTempData[$i][$aDataTableHeaderHTML[$j]] = $aDataTableDetailHTML[$i][$j];
}
}
$aDataTableDetailHTML = $aTempData; unset($aTempData);
print_r($aDataTableDetailHTML);

Array is bigger then my XML tags? (PHP)

I want to add a child with a specified value which I get from my array. But my problem is that my array is bigger then my amount of XML products...
This is why I get this error message:
PHP Notice: Undefined offset: 1589 in C:\Users\Jan\PhpstormProjects\censored\test.php on line 63
PHP Fatal error: Uncaught Error: Call to a member function appendChild() on null in C:\Users\Jan\PhpstormProjects\censored\test.php:64
To check that I made two loops which say me that I have 1588 names and 1588 products, both loops say that. Thats logical!
$markerProduct = $root->getElementsByTagName("product");
for($i = $markerProduct->length - 1; $i >= 0; $i--){
$productCounter = $productCounter + 1;
}
$markerTitle = $root->getElementsByTagName("name");
for($i = 0; $i < $markerTitle->length; $i++){
$nameCounter = $nameCounter + 1;
}
But my array in which I store the specified value for each product is 1589 (0 - 1588) values big... And I don't know.
Can anyone help me and tell me the error?
$searches = ["Steam", "Uplay", "Xbox", "Nintendo", "PS3", "PS4", "PSN"];
function isContaining($searches, $titleTag, $urlTag, $productTag, $path){
$dom = new DOMDocument('1.0', 'utf-8');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->load($path);
$root = $dom->documentElement;
$markerTitle = $root->getElementsByTagName($titleTag);
$markerURL = $root->getElementsByTagName($urlTag);
$plat = array();
for($i = $markerTitle->length - 1; $i >= 0 ; $i--){
$title = $markerTitle->item($i)->textContent;
$url = $markerURL->item($i)->textContent;
$co = count($searches);
$productFound = false;
for($j = 0; $j < $co; $j++){
if(stripos($title, $searches[$j]) !== false){
if($j > 3){
array_push($plat, "PlayStation");
}else{
array_push($plat, $searches[$j]);
}
$productFound = true;
}elseif(stripos($url, $searches[$j]) !== false){
if($j > 3){
array_push($plat, "PlayStation");
}else{
array_push($plat, $searches[$j]);
}
$productFound = true;
}
}
if($productFound == false){
array_push($plat, "Nothing");
}
}
print_r($plat);
$c = count($plat);
echo $c;
for($i = $c - 1; $i >= 0; $i--){
$node = $dom->createElement('plat', $plat[$c]);
$dom->getElementsByTagName($productTag)->item($i)->appendChild($node);
}
$dom->saveXML();
$dom->save('data/gamesplanet2.xml');
}
Error is in line 63:
$node = $dom->createElement('plat', $plat[$c]);
Greetings and Thank You!

Multiplication with a simplexml_load_file() object doesn't work

I extract values from an XML with PHP
<?php
$url = 'list.xml';
$xml = simplexml_load_file($url);
$entries = $xml->item;
$i = 0;
$total = 1;
foreach($entries as $entry){
$i++;
$number[$i] = $entry->total;
$total *= $number[$i];
}
echo $total;
?>
How can I build a total based on each $number extracted from the XML? Right now, my total is zero.
So for all loops together something like:
$total = $number[1] * $number[2] * $number[3] * $number[4] ....
This should work for you:
(You have to cast the return of simplexml_load_file() to double)
$url = "list.xml";
$xml = simplexml_load_file($url);
$entries = $xml->results->rate;
$count = 0;
$total = 1;
$number = array();
foreach($entries as $entry){
$count++;
$number[$count] = $entry->Bid;
$total *= (double)$number[$count];
}
echo "Total: " . $total;

Categories