Vytvoření jednoduché RSS čtečky pomocí XSLT

Pachollini, 5. července 2004, 13:55

Nemohu si nějak pomoci, ale některé články na Intervalu.cz mne poslední dobou provokují. (Jinak ovšem považuji Interval.cz za nejlepší webový magazín pro kodéry v našich zemích.) Naposledy se taková provokace podařila Petru Hellerovi článkem PHP pro pokročilé - ICONV a RSS čtečka.

Článek má podle mne dvě zásadní chyby. Za prvé nepříliš šikovně demonstruje funkčnost knihovny iconv, protože k ukázce jejího použití přidává asi 100 řádků kódového balastu. (Navíc ve skriptu vůbec neošetřuje případ, kdy mají vstupní parametry funkce iconv() jiné hodnoty než jsou specifikované v hlavičce XML dokumentu, nehledě k případu, kdy specifikace kódování chybí – což klidně může, pokud je dokument v UTF-8.)

Za druhé nabízí IMHO naprosto špatný postup, jak na RSS. Připadá mi trochu jako snaha jet automobilové závody traktorem. Předvedené řešení má jedinou výhodu: lze ho použít i na serveru bez podpory zpracování XML. Ta má v PHP kromě dalších tři základní podoby: XML parser, DOM XML a XSLT. Parser je poměrně „nízkoúrovňová“ metoda, která se myslím hodí hlavně na jednorázové, jednoúčelové a rychlé zpracování XML dokumentu. Mnohem sofistikovanější metody nabízí modul DOM XML, který umožňuje snadný přístup k jakékoliv části XML dokumentu, jeho modifikaci, umí XPath dotazy a navíc (jak je zřejmé již z názvu) jde o implementaci standardu DOM, takže co se tady naučíš, v JavaScriptu, Javě, ASP, a dalších jazycích jako když najdeš. Poslední uvedená technologie, XSLT slouží k převodu XML dokumentu na jiný dokument, nejčastěji XML, ale v zásadě na jakýkoliv textový dokument, např. CSV. Zájemcům o úvod do XML doporučuji seriál Jakuba Havla o XML, který vycházel na Živě. Co se týče podpory na serverech, podle mých zkušeností jsou dnes již standardně dostupné i moduly DOM XML a XSLT (ale přicházím do styku pouze s komerčními hostingy), instalaci PHP bez XML parseru jsem ještě neviděl.

O svém nadšení pro technologii XSLT jsem už psal, takže celkem nepřekvapivě zkusím demonstrovat jak na RSS efektivněji. Pokud váš webhoster XSLT nepodporuje, zatlačte na něj. Slibuji, že nebudete litovat vynaloženého úsilí. Pokud o XSLT nic nevíte, nezoufejte a přečtěte si seriál Petra Břízy Kompletní průvodce XSLT na Intervalu.cz, zabruste na skvělý web Jiřího Koska, podívejte se na ZVON a jistě budete za chvíli ve jmenném prostoru http://www.w3.org/1999/XSL/Transform jako doma.

Tak tedy: úplně jednoduchá čtečka RSS s využitím XSLT

Samotné vyvolání XSLT transformace vyžaduje v PHP několik příkazů, proto se vyplatí vytvořit si na ně jednoduchou funkci (ta je mimochodem i základem Seků, ale o tom někdy příště):

function xslt_transform( 
    // vrátí kód vytvořený xslt transformací podle dané šablony
  $xml, // řetězec
  $stylesheet, // cesta k souboru
  $params=array(), // další parametry v poli
  $pretty=true, // zachovat whitespace
  $replace_ent=true 
    /* změnit tvar & amp;ent; na & ent;
    hodí se při převodu XML na HTML pokud nechceme 
    deklarovat všechny HTML entity */ 
  )
{
@$stylesheet=implode("",file($stylesheet)); // načte XSLT stylesheet
$arguments = array('/_xml' => $xml, '/_xsl' => $stylesheet );
  // nastaví parametry pro volání procesoru
$xh = xslt_create(); // vytvoří procesor
xslt_set_base( $xh, 'file://'.__FILE__); 
  /* nastaví výchozí cestu; je třeba pokud v XSLT
   využíváme další XML dokumenty pomocí funkce document() 
  a máme starší verzi php */
$result=xslt_process($xh, 'arg:/_xml', 'arg:/_xsl', NULL, 
  $arguments, $params); // provede transformaci
xslt_free($xh); // odstraní parser
if($result)
  {
  if($replace_ent)$result=
    preg_replace("/<([[:alnum:]]+);/i","<\\1;",$result); 
    // převede entity
  if(!$pretty) $result=preg_replace("/>[[:space:]]*</",
    "><",$result); // vypustí whitespace
  return $result; // vrátí výsledek
  }
}

Pro převod RSS do XML požijeme následující XSLT styl (pro zjednodušení předpokládáme verzi RSS 0.91):

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method = "xml"  version="1.0" 
  omit-xml-declaration="yes" indent="yes"  />
  
  <xsl:template match="/">
    <xsl:apply-templates select="rss/channel"/>
  </xsl:template>
  
  <xsl:template match="channel">
    <div class="channel">
      <h2>
        <a href="{link}"><xsl:value-of select="title"/></a>
      </h2>
      <xsl:apply-templates select="image|description|item"/>
    </div>
  </xsl:template>
  
  <xsl:template match="image">
    <img src="{url}" title="{title}" alt="{title}" 
      width="{width}" height="{height}"/>
  </xsl:template>
  
  <xsl:template match="description">
    <p class="description">
      <xsl:value-of select="text()"/>
    </p>
  </xsl:template>
  
  <xsl:template match="item">
    <div class="item">
      <h3>
        <a href="{link}">
          <xsl:value-of select="title"/>
        </a>
      </h3>
      <p><xsl:value-of select="description"/></p>
    </div>
  </xsl:template>
</xsl:stylesheet>

A konečně skript, který načte RSS zdroje a vypíše je:

<?
$mojekanaly=array(
  "http://seky.nahory.net/seky.rss",
  "http://cyber.law.harvard.edu/blogs/gems/tech/sampleRss091.xml"); 
    // seznam zdrojů
for($i=0;$i<count($mojekanaly);$i++)
  {
  $file=@implode("\n",file($mojekanaly[$i])); // načtení zdroje
  if($file)
    {
    preg_match("/\<\?xml[^>]+encoding=[\"']([a-zA-Z0-9\-]+)[\"']/i",
      $file, $pole); // zjištění kódování
    $charset=$pole[1]?$pole[1]:"utf-8"; 
      // pokud nebylo uvedeno, použije se utf-8
    $charset=preg_replace("/windows\-/i","CP",$charset); 
      // pokud je windows, převede argument pro funkci iconv()
    if(strtolower($charset)!="utf-8")
      {
      $file=iconv($charset."//TRANSLIT","utf-8",$file); 
        // převede se na utf-8
      $file=preg_replace(
        "/\<\?xml([^>]+)(encoding=[\"']([a-zA-Z0-9\-]+)[\"'])/i", 
        "<?xml\\1", $file); // odstraní údaj o kódování z xml
      }
    $vysledek=xslt_transform($file,"stylesheet.xsl"); 
      // provede xslt transormaci
    if($vysledek) echo $vysledek; 
      // pokud proběhla správně, vypíše výsledek
    else echo"<div>Nepodařilo se provést transformaci zdroje: ".
      $mojekanaly[$i]."</div>".$file;
    }
  else echo"<div>Nepodařilo se načíst zdroj: ".
    $mojekanaly[$i]."</div>";
  }
?>

K dispozi je ukázka provedení a zazipovaný balíček ke stažení.

Toť vše, dneska to byl opravdu jen takový sek.

Co vy na to?

zobrazit všechny komentáře

Aktuální Seky

.