Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В. Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Разбор RSS вне зависимости от порядка элементов
 
 автор: 1999   (23.03.2007 в 10:21)   письмо автору
 
 

В продолжение темы http://softtime.ru/forum/read.php?id_forum=1&id_theme=32573&page=1
Хотел сделать ф-цию, которая разбирает все спортивные RSS-потоки (например адрес RSS передается в параметре ф-ции), но вот обе ф-ции, представленные в той теме, например

<?php
$content 
file_get_contents("http://news.yandex.ru/Russia/computers.rss");
preg_match_all("!<item>\s*<title>(.+)</title>\s*".
               
"<link>(.+)</link>\s*".
               
"<description>(.+)</description>\s*".
               
"<pubDate>(.+)</pubDate>.+</item>!isU"$content$m);
for ( 
$i 0$i count($m[0]); $i++ ) {
  print 
'<h3><a href="'.$m[2][$i].'">'.$m[1][$i]."</a></h3>\n".
        
"<p>".htmlspecialchars_decode($m[3][$i]).
        
"</br>\n".$m[4][$i]."</p></br>\n\n";

?>

не работают если дата и описание новости меняются местами итд. А именно:
1) поток яндекса
<item>
<title>Сборная России по футболу оказалась под арестом</title>
<link>http://news.yandex.ru/yandsearch?cl4url=www.utro.ru/news/2007/03/23/635194.shtml&amp;country=Russia</link>

<description>Сборная России в преддверие матча против команды Эстонии оказалась под арестом.&lt;br&gt;Однако, несмотря на это, Кержаков, Сычев, Малафеев и молодой Савин все равно ушли на прогулку по городу.&lt;br&gt;</description>
<pubDate>Fri, 23 Mar 2007 09:47:58 +0300</pubDate>
<guid>http://news.yandex.ru/yandsearch?cl4url=www.utro.ru/news/2007/03/23/635194.shtml&amp;country=Russia</guid>
</item>

2) поток sportsdaily

<item>
<title>Оба Гуса решают кадровые проблемы</title>
<pubDate>Fri, 23 Mar 2007 17:58:55 GMT</pubDate>
<description>Сборная Эстонии ни разу не пробивалась на крупные международные турниры. В рамках же отборочных турниров к чемпионату Европы она одержала лишь четыре победы в 21 матче. Но даже на этом безрадостном фоне очередная отборочная кампания выглядит удручающе: эстонская сборная под руководством голландского наставника Йелле Гуса в трех матчах не набрала ни одного очка, уступив Македонии, Израилю и России. При этом эстонцы не сумели забить ни одного мяча. После серии неудач пошли оживленные разговоры о том, что Гус может потерять свой пост. Тем не менее голландцу был дан еще один шанс выстроить новую команду с прицелом на будущее.</description>

<link>http://www.sportsdaily.ru/issue.aspx/390/9006</link>
<guid>http://www.sportsdaily.ru/issue.aspx/390/9006</guid>
<category>Статьи</category>
<author> Дмитрий Нечипоренко</author>
</item>


можно ли как-то сделать, чтоб разбор этих лент шел одинаково вне зависимости от того, в каком порядке следуют элементы?

   
 
 автор: ZuArt   (23.03.2007 в 10:44)   письмо автору
 
   для: 1999   (23.03.2007 в 10:21)
 

вырезать текст и дату регулярными выражениями и все...

набор регулярных выражений (а не одно) для разный сайтов-источников для вырезки того или иного блока и потом вывод в своем формате.

   
 
 автор: 1999   (23.03.2007 в 10:50)   письмо автору
 
   для: ZuArt   (23.03.2007 в 10:44)
 

ну к слову в первом посте разбор и идет регулярными...
не писать же к каждому сайту свое регулярное выражение... или все же придется?

   
 
 автор: ZuArt   (23.03.2007 в 10:59)   письмо автору
 
   для: 1999   (23.03.2007 в 10:50)
 

на самом деле ничего нету проще...

даж простой пример (катаю навскидку - требуется правка)

$item = " Считанный блок всей новости";
$reg = array();
$reg[сайт 1] = array("ttl"=>"<title>...</title>", "desc"=>".....");
$reg[сайт 2] = array("ttl"=>"<title>...</title>", "desc"=>".....");
$reg[сайт 3] = array("ttl"=>"<title>...</title>", "desc"=>".....");

$itm = array();
foreach($reg[нужный сайт] as $key => $val)
{
 if(preg_match($val, $item, $tmp));
  $itm[$key] = $tmp[...];
};


И независимо от сайта и способа его публикации в массиве $itm будет ЧЕТКО структурированный набор его элементов.

   
 
 автор: ZuArt   (23.03.2007 в 11:02)   письмо автору
 
   для: ZuArt   (23.03.2007 в 10:59)
 

ЗЫ. Набор регулярных выражений можно вообще вынести в отдельный файл - тогда править их, если что, будет совсем просто - не придется трогать основной код воообще... поправил нужные строчки для нужного сайта и не морочишься =)

а индексами такого массива могут просто быть адреса или url-ы =))) типа
$arr["sport.yandex.ru"] = array(...)
$arr["sport.ru"] = array(...)

и т.д.

   
 
 автор: 1999   (23.03.2007 в 11:33)   письмо автору
 
   для: 1999   (23.03.2007 в 10:21)
 

т.е. в любом случае адреса сайтов указываются изначально и для каждого надо писать свое регулярное выражение. так?

   
 
 автор: ZuArt   (23.03.2007 в 11:43)   письмо автору
 
   для: 1999   (23.03.2007 в 11:33)
 

не обязательно =)
можно указать один из наборов как общий... и просто проверять типа


$tpls = $arr["общий набор шаблонов"];
if(isset($arr["сайт"]))
 $tpls = $arr["сайт"];


и делее в цикле работать не с $arr[сайт] а с $tpls =)

А описывать доп шаблоны тока в случае расхождения с общим...

а в плане разделения регилярного выражения на неск блоков - оно того стоит - просто логику просще отлавливать и праить... Но в принципе можно создавать и целостное рег. выражения для сайта - типа как изначально в теме... просто для каждого сайта свое большое выражение + одно общее для всех остальных =) но я бы так делать не стал, т.к. более трудоемкая операция отладки при изменениях =)

   
 
 автор: 1999   (23.03.2007 в 11:50)   письмо автору
 
   для: 1999   (23.03.2007 в 11:33)
 

не блин... в FireFox все RSS разбираются вне зависимости от того, в каком порядке следуют элементы...
как же это реализовано там?

   
 
 автор: ZuArt   (23.03.2007 в 12:25)   письмо автору
 
   для: 1999   (23.03.2007 в 11:50)
 

не путай FF - браузер клиент (встроенный механизм разбора ЕСТЬ и как там реализовано - знают ток разработчики FF)... и СКРИПТ, который получает данные в том виде, котором есть и в котором нужно механим разбора РЕАЛИЗОВАТЬ!

   
 
 автор: 1999   (23.03.2007 в 19:25)   письмо автору
 
   для: ZuArt   (23.03.2007 в 12:25)
 

да это-то все ясно... просто как-то глупо под каждую ленту новостей писать свой обработчик( ну или свое регулярное выражение

   
 
 автор: ddhvvn   (23.03.2007 в 19:35)   письмо автору
 
   для: 1999   (23.03.2007 в 19:25)
 

Так и не надо!
Напишите одно универсальное рег. выражение и все!

   
 
 автор: 1999   (23.03.2007 в 19:41)   письмо автору
 
   для: ddhvvn   (23.03.2007 в 19:35)
 

гы) так тема-то как раз об этом))
вот вы можете написать ТАКОЕ универсальное выражение?

   
 
 автор: Trianon   (23.03.2007 в 19:56)   письмо автору
 
   для: 1999   (23.03.2007 в 19:41)
 

Если разбирать RSS стандартными средствами анализа XML-документов (xml_parse_into_struct к примеру) таких проблем не возникает.

   
 
 автор: 1999   (23.03.2007 в 20:01)   письмо автору
 
   для: Trianon   (23.03.2007 в 19:56)
 

о... это интересно уже.. а по скорости как? будет уступать разбору регулярными или DOM'ом?
и не могли бы вы пример разбора написать?

   
 
 автор: Trianon   (26.03.2007 в 19:20)   письмо автору
 
   для: 1999   (23.03.2007 в 20:01)
 


<?php
include('config.inc.php');

function 
get_url($url)
{
   
$r curl_init();
   
curl_setopt($rCURLOPT_NOPROGRESS0);
   
curl_setopt($rCURLOPT_RETURNTRANSFER1);
   
curl_setopt($rCURLOPT_URL$url);

   
$res curl_exec($r);
   return 
$res;
}
   
$url "http://news.yandex.ru/Russia/computers.rss";
   
$res get_url($url);
//   $f=fopen('computers.rss', 'wb');   fwrite($f, $res);  fclose($f);die("ready");
//   $res = file_get_contents("computers.rss");
   //   $x = simplexml_load_string($res);      print_r($x);
   
function start_element($par$name$atr)
   {
       
$tmp = array('data' => '''name' => $name'atr' => $atr);

       global 
$heap$l = ++$heap['level']; $lp $l 1;
       
$heap['stack'][$l] = $heap['ref'];
       
$heap['ref'] = array('data' => '');
       if(!empty(
$atr)) $heap['ref']['atr'] = $atr;
   }
   function 
end_element($par$name)
   {
       global 
$heap$l = --$heap['level']; $ln $l 1;
       
$tmp $heap['ref'];
       
$heap['ref'] = $heap['stack'][$ln];
       unset(
$heap['stack'][$ln]);
       
$heap['ref']['sub'][$name][] =  $tmp;
   }
   function 
element_data($par$data)
   {
       global 
$heap;
       if(
'' != trim($data))
           
$heap['ref']['data'].=iconv("utf-8""windows-1251"$data);
   }

   
$p xml_parser_create("");

   
$heap['level'] = 0;
   
$heap['ref'] = array();
   
xml_set_element_handler($p'start_element''end_element');
   
xml_set_character_data_handler($p'element_data');
   
xml_parse($p$res);
   echo 
'<pre>';
   
print_r($heap);

   
 
 автор: 1999   (01.04.2007 в 21:56)   письмо автору
 
   для: Trianon   (26.03.2007 в 19:20)
 

Вопрос в первую очередь к Trianon

Такая проблема вышла - нижнюю итоговую часть (начиная с xml_parser_create и заканчивая xml_parse) необходимо использовать внутри функции(( как ни извращался - $heap не виден функциям start_element итд. Пытался извратиться вобще так:

<?
class rss_feed
{
    public 
$heap = array();
    public 
$url;

    public function 
__construct()
    {
        
$this->rss_feed();
    }

    public function 
rss_feed()
    {
        
$this->heap['level'] = 0;
        
$this->heap['ref'] = array();
    }

    
// Загрузка фида через file_get_contents
    
public function load$ext_url )
    {
        
$this->url file_get_contents$ext_url );
    }

    
// Загрузка фида через URL
    
public function load_through_curl$ext_url )
    {
        
$r curl_init();
        
curl_setopt$r,CURLOPT_NOPROGRESS,);
        
curl_setopt$r,CURLOPT_RETURNTRANSFER,);
        
curl_setopt$r,CURLOPT_URL,$ext_url );
        
$this->url curl_exec$r );


    
// Процессинг фида
    
public function process()
    {
        
$p xml_parser_create();
        
xml_set_element_handler$p,"start_element","end_element" );
        
xml_set_character_data_handler$p,"element_data" );
        
xml_parse$p,$url );

        echo 
"<pre>";
        
print_r$this->heap );
    }

    private function 
start_element$par,$name,$atr )
    {
        
$tmp = array( "data" => "",
                      
"name" => $name,
                      
"atr" => $atr );

        
$l $this->heap['level'] + 1;
        
$lp $l 1;
        
$this->heap['stack'][$l] = $this->heap['ref'];
        
$this->heap['ref'] = array( "data" => "" );
        if ( !empty( 
$atr ) ) $this->heap['ref']['atr'] = $atr;
    }

    private function 
end_element$par,$name )
    {
        
$l $this->heap['level'] - 1;
        
$ln $l 1;
        
$tmp $this->heap['ref'];
        
$this->heap['ref'] = $this->heap['stack'][$ln];
        unset( 
$this->heap['stack'][$ln] );
        
$this->heap['ref']['sub'][$name][] = $tmp;
    }

    private function 
element_data$par,$data )
    {
        if( 
trim$data ) != "" )
        {
            
$this->heap['ref']['data'] .= iconv"UTF-8","WINDOWS-1251",$data );
        }
    }
}
?>


но опять же - на выходе просто

<?
Array
(
    [
level] => 0
    
[ref] => Array
        (
        )
)
?>


почему? и если делать без объектов, то как сделать, чтоб функции start_element итд видели переменную $heap, которая уже находится внутри своей функции?

   
 
 автор: 1999   (02.04.2007 в 00:11)   письмо автору
 
   для: 1999   (01.04.2007 в 21:56)
 

.

   
 
 автор: 1999   (02.04.2007 в 20:51)   письмо автору
 
   для: 1999   (02.04.2007 в 00:11)
 

бьюсь как рыба об лед башкой и понимаю что я ламер страшный, раз такого не понимаю...
вот код теперь:

<?php

class rss_feed
{
    public 
$feed_content;

    public function 
__construct$url )
    {
        
$this->rss_feed$url );
    }

    public function 
rss_feed$url )
    {
        
$this->feed_content $this->load_through_fgc$url );
    }

    
// Загрузка через file_get_contents
    
private function load_through_fgc$url )
    {
        
$this->feed_content file_get_contents$url );
    }

    
// Загрузка через CURL
    
public function load_through_curl$url )
    {
        
$r curl_init();
        
curl_setopt$r,CURLOPT_NOPROGRESS,);
        
curl_setopt$r,CURLOPT_RETURNTRANSFER,);
        
curl_setopt$r,CURLOPT_URL,$url );
        
$this->feed_content curl_exec$r );
    }

    
// Процессинг фида
    
public function process()
    {
        global 
$heap;

        
$p xml_parser_create();
        
xml_set_element_handler$p,"start_element","end_element" );
        
xml_set_character_data_handler$p,"element_data" );
        
xml_parse$p,$url );

        echo 
"<pre>";
        
print_r$heap );
    }

    private function 
start_element$par,$name,$atr )
    {
        global 
$heap;

        
$tmp = array( "data" => "",
                      
"name" => $name,
                      
"atr" => $atr );

        
$l $heap['level'] + 1;
        
$lp $l 1;
        
$heap['stack'][$l] = $heap['ref'];
        
$heap['ref'] = array( "data" => "" );
        if ( !empty( 
$atr ) ) $heap['ref']['atr'] = $atr;
    }

    private function 
end_element$par,$name )
    {
        global 
$heap;

        
$l $heap['level'] - 1;
        
$ln $l 1;
        
$tmp $heap['ref'];
        
$heap['ref'] = $heap['stack'][$ln];
        unset( 
$heap['stack'][$ln] );
        
$heap['ref']['sub'][$name][] = $tmp;
    }

    private function 
element_data$par,$data )
    {
        global 
$heap;

        if( 
trim$data ) != "" )
        {
            
$heap['ref']['data'] .= iconv"UTF-8","WINDOWS-1251",$data );
        }
    }
}

$heap['level'] = 0;
$heap['ref'] = array();

$feed = new rss_feed"http://news.yandex.ru/Russia/computers.rss" );
$feed->process();

?>


вроде и heap уже гломальна, но тем не менее воз и ныне там((

   
 
 автор: Trianon   (02.04.2007 в 20:56)   письмо автору
 
   для: 1999   (02.04.2007 в 20:51)
 

вот эти две строки

$heap['level'] = 0; 
$heap['ref'] = array(); 
снизу надо убрать.

А метод изменить так:

  public function process() 
    { 
        global $heap; 

        $p = xml_parser_create(); 
        xml_set_element_handler( $p,"start_element","end_element" ); 
        xml_set_character_data_handler( $p,"element_data" ); 
        
        $heap = array('level' => 0, 'ref' => array());
        xml_parse( $p,$url ); 
        echo "<pre>";         print_r( $heap ); // вместо этой строки нужно поставить код  упрощения и переноса дерева в объект.
        $heap = array();
    } 


Функции start_element, end_element и element_data из методов класса - выкинуть.
Поставить обычными функциями с глобальной областью видимости и временем жизни .

   
 
 автор: 1999   (02.04.2007 в 20:56)   письмо автору
 
   для: 1999   (02.04.2007 в 00:11)
 

бьюсь как рыба об лед башкой и понимаю что я ламер страшный, раз такого не понимаю...
вот код теперь:

<?php

class rss_feed
{
    public 
$feed_content;

    public function 
__construct$url )
    {
        
$this->rss_feed$url );
    }

    public function 
rss_feed$url )
    {
        
$this->feed_content $this->load_through_fgc$url );
    }

    
// Загрузка через file_get_contents
    
private function load_through_fgc$url )
    {
        
$this->feed_content file_get_contents$url );
    }

    
// Загрузка через CURL
    
public function load_through_curl$url )
    {
        
$r curl_init();
        
curl_setopt$r,CURLOPT_NOPROGRESS,);
        
curl_setopt$r,CURLOPT_RETURNTRANSFER,);
        
curl_setopt$r,CURLOPT_URL,$url );
        
$this->feed_content curl_exec$r );
    }

    
// Процессинг фида
    
public function process()
    {
        global 
$heap;

        
$p xml_parser_create();
        
xml_set_element_handler$p,"start_element","end_element" );
        
xml_set_character_data_handler$p,"element_data" );
        
xml_parse$p,$url );

        echo 
"<pre>";
        
print_r$heap );
    }

    private function 
start_element$par,$name,$atr )
    {
        global 
$heap;

        
$tmp = array( "data" => "",
                      
"name" => $name,
                      
"atr" => $atr );

        
$l $heap['level'] + 1;
        
$lp $l 1;
        
$heap['stack'][$l] = $heap['ref'];
        
$heap['ref'] = array( "data" => "" );
        if ( !empty( 
$atr ) ) $heap['ref']['atr'] = $atr;
    }

    private function 
end_element$par,$name )
    {
        global 
$heap;

        
$l $heap['level'] - 1;
        
$ln $l 1;
        
$tmp $heap['ref'];
        
$heap['ref'] = $heap['stack'][$ln];
        unset( 
$heap['stack'][$ln] );
        
$heap['ref']['sub'][$name][] = $tmp;
    }

    private function 
element_data$par,$data )
    {
        global 
$heap;

        if( 
trim$data ) != "" )
        {
            
$heap['ref']['data'] .= iconv"UTF-8","WINDOWS-1251",$data );
        }
    }
}

$heap['level'] = 0;
$heap['ref'] = array();

$feed = new rss_feed"http://news.yandex.ru/Russia/computers.rss" );
$feed->process();

?>


вроде и heap уже гломальна, но тем не менее воз и ныне там((

   
 
 автор: Trianon   (02.04.2007 в 09:48)   письмо автору
 
   для: 1999   (01.04.2007 в 21:56)
 

> Такая проблема вышла - нижнюю итоговую часть (начиная с xml_parser_create и заканчивая
> xml_parse) необходимо использовать внутри функции(( как ни извращался - $heap не
> виден функциям start_element итд. Пытался извратиться вобще так:

Я в Вашем коде не нашел функций start_element, end_element, element_data. Нашел только методы. Методы и функции - разные вещи.

механизм xml_parse требует именно функций. Функциям этим негде взять контекст выполнения, кроме как из некоторой переменной с глобальной областью видимости.

Делать глобальным сам объект, передавая его в парсер, или оставить глобальной кучу результата, а потом обращаться к ней в конце разбора и переносить результат в объект - дело вкуса. Но некоторую глобальную сущность придется оставить - у функций разбора нет доп. параметра, через который передавался бы контекст выполнения.

   
 
 автор: 1999   (02.04.2007 в 10:10)   письмо автору
 
   для: Trianon   (02.04.2007 в 09:48)
 

эх... я даж вроде как примерно понял, но вот реализовать все ваши умные слова не могу((
может подскажете, где и что исправить, чтобы все работало?..

   
 
 автор: 1999   (02.04.2007 в 19:30)   письмо автору
 
   для: Trianon   (02.04.2007 в 09:48)
 

.

   
 
 автор: Trianon   (02.04.2007 в 19:50)   письмо автору
 
   для: 1999   (02.04.2007 в 19:30)
 

.

   
 
 автор: 1999   (02.04.2007 в 20:18)   письмо автору
 
   для: Trianon   (02.04.2007 в 19:50)
 

ну я реально не понимаю как сделать, чтобы эта $heap была видна в других местах((

   
 
 автор: Trianon   (02.04.2007 в 20:28)   письмо автору
 
   для: 1999   (02.04.2007 в 20:18)
 

global $heap;

Она не только должна быть видна в других местах. Она не должна являться членом(полем) класса. Впрочем, возможно её можно сделать ссылкой на такое поле. Но этого я не проверял. Собственно, если реентерабельность не требуется (не требуется разбирать в обдом скрипте два RSS-потока параллельно) то я не очень себе представляюю смысл всех этих ухищрений.

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования