Ajax RSS-reader

Используйте Ajax для создания RSS-reader

В этой статье вы узнаете, как создавать программу RSS-reader (Really Simple Syndication) с помощью Ajax (Asynchronous JavaScript and XML), а также web-компоненты, которые вы сможете разместить на любой сайт, чтобы просматривать статьи в формате RSS ленты (feed).

Джек Ди Геррингтон, главный разработчик программного обеспечения, Leverage Software, Inc.

Главный разработчик программного обеспечения с более чем двадцатилетним стажем, Джек Геррингтон (Jack Herrington) написал три книги: Code Generation in Action, Podcasting Hacks и PHP Hacks. Он также является автором более 30 статей. Вы можете связаться с ним по адресу jherr@pobox.com.



12.05.2006

Первое, о чем я подумал, когда прочитал о формировании запросов на расширяемом языке разметки (XML) с помощью JavaScript с web-страницы, было найти какой-нибудь RSS и отобразить его. Но я тут же столкнулся с проблемой безопасности протокола передачи гипертекста (HTTP) XML, где страница, загруженная с www.mysite.com, не может быть получена из других источников, кроме www.mysite.com. Мои планы создания общего RSS-reader были разрушены. Но интернет 2.0 - полезное изобретение, а решение проблемы создания RSS-reader с XMLHTTP будет хорошим уроком программирования в интенет 2.0.

В этой статье мы рассмотрим создание RSS-reader с помощью Ajax, используя и XMLHTTP, и теги <script> в качестве транспорта.

Построение на стороне сервера

Загрузите коды для этой статьи

В самой статье приведены неполные листинги кодов, необходимые для создания RSS-reader. Полные коды вы можете найти в разделе Загрузка.

Серверная часть нашего уравнения состоит из двух частей. Первая - база данных, а вторая - набор PHP страниц, которые позволят добавлять ленты, запрашивать списки лент и получать статьи, связанные с определенной лентой. Начнем с базы данных.

База данных

В этой статье я использую базу данных MySQL. В листинге 1 показана её схема.

Листинг 1. Схема для базы данных
CREATE TABLE rss_feeds (
        rss_feed_id MEDIUMINT NOT NULL AUTO_INCREMENT,
        url TEXT NOT NULL,
        name TEXT NOT NULL,
        last_update TIMESTAMP,
        PRIMARY KEY ( rss_feed_id )
);

CREATE TABLE rss_articles (
        rss_feed_id MEDIUMINT NOT NULL,
        link TEXT NOT NULL,
        title TEXT NOT NULL,
        description TEXT NOT NULL
);

Здесь две таблицы. Таблица rss_feeds содержит список лент. Таблица rss_articles содержит список статей, связанных с соответствующими лентами. Когда система обновляет статьи, она удаляет текущие статьи, связанные с данным номером rss_feed_id и затем обновляет таблицу новым набором статей.

Упаковщик базы данных

На следующем шаге мы упакуем базу данных набором классов PHP, которые построят бизнес-логику для приложения. Начнем с синглтона DatabaseConnection, который передает соединение базе данных, как показано в листинге 2.

Листинг 2. Синглтон DatabaseConnection в файле rss_db.php
<?php
require_once 'DB.php';
require_once 'XML/RSS.php';

class DatabaseConnection
{
  public static function get()
  {
    static $db = null;
    if ( $db == null )
      $db = new DatabaseConnection();
    return $db;
  }

  private $_handle = null;

  private function __construct()
  {
    $dsn = 'mysql://root:password@localhost/rss';
    $this->_handle =& DB::Connect( $dsn, array() );
  }
  
  public function handle()
  {
    return $this->_handle;
  }
}

Это стандартный синглтон-шаблон PHP. Он подключается к базе данных и возвращает управление с помощью метода handle. Две строчки require_once - еще одна интересная часть кода. Первая такая строка ссылается на модуль DB в хранилище расширений и приложений PHP (PHP Extension and Application Repository - PEAR), этот модуль подсоединяется к базе данных. Вторая строка ссылается на модуль XML_RSS, который разбирает RSS-ленты. Здесь я использую модули, чтобы не беспокоиться о парсинге всех этих различных форм RSS. Если вы еще не установили эти модули, добавьте это в командную строку:

% pear install DB

и:

% pear install XML_RSS

Обычно модуль DB установлен, а модуль XML_RSS - нет.

На следующем шаге мы создаем класс, который будет работать со списком лент, чтобы мы смогли добавить ленту, получить набор лент и так далее. Этот класс показан в листинге 3.

Листинг 3. Класс FeedList в rss_db.php
class FeedList {
  public static function add( $url ) {
    if ( FeedList::getFeedByUrl( $url ) != null ) return;

    $db = DatabaseConnection::get()->handle();

    $rss =& new XML_RSS( $url );
    $rss->parse();
    $info = $rss->getChannelInfo();

    $isth = $db->prepare( "INSERT INTO rss_feeds VALUES( null, ?, ?, null )" );
    $db->execute( $isth, array( $url, $info['title'] ) );

    $info = FeedList::getFeedByUrl( $url );
    Feed::update( $info['rss_feed_id'] );
  }

  public static function getAll( ) {
    $db = DatabaseConnection::get()->handle();
    $res = $db->query( "SELECT * FROM rss_feeds" );
    $rows = array();
    while( $res->fetchInto( $row, DB_FETCHMODE_ASSOC ) ) { $rows []= $row; }
    return $rows;
  }

  public static function getFeedInfo( $id ) {
    $db = DatabaseConnection::get()->handle();
    $res = $db->query( "SELECT * FROM rss_feeds WHERE rss_feed_id=?",
      array( $id ) );
    while( $res->fetchInto( $row, DB_FETCHMODE_ASSOC ) ) { return $row; }
    return $null;
  }

  public static function getFeedByUrl( $url ) {
    $db = DatabaseConnection::get()->handle();
    $res = $db->query( "SELECT * FROM rss_feeds WHERE url=?", array( $url ) );
    while( $res->fetchInto( $row, DB_FETCHMODE_ASSOC ) ) { return $row; }
    return null;
  }

  public static function update() {
    $db = DatabaseConnection::get()->handle();

    $usth1 = $db->prepare( "UPDATE rss_feeds SET name='' WHERE rss_feed_id=?" );
    $usth2 = $db->prepare( "UPDATE rss_feeds SET name=? WHERE rss_feed_id=?" );

    $res = $db->query(
   "SELECT rss_feed_id,name FROM rss_feeds WHERE last_update<now()-600" );
    while( $res->fetchInto( $row, DB_FETCHMODE_ASSOC ) ) {
      Feed::update( $row['rss_feed_id'] );
      $db->execute( $usth1, array( $row['rss_feed_id'] ) );
      $db->execute( $usth2, array( $row['name'], $row['rss_feed_id'] ) );
    }
  }
}

Метод add добавляет ленту в список и обновляет его. Метод getAll возвращает список лент. Метод getFeedInfo возвращает информацию по заданной ленте. Метод getFeedByUrl делает то же, что и метод getFeedInfo, разница в том, что он использует URL ленты в качестве ключа. И наконец функция update вызывает метод update для заданной ленты, если она не обновлялась последние десять минут.

В листинге 4 показан класс Feed - последний класс в бизнес-логике классов. Он содержит методы, которые работают с отдельными лентами.

Листинг 4. Класс Feed из rss_db.php
class Feed
{
  public static function update( $id )
  {
    $db = DatabaseConnection::get()->handle();

    $info = FeedList::getFeedInfo( $id );
    $rss =& new XML_RSS( $info['url'] );
    $rss->parse();

    $dsth = $db->prepare( "DELETE FROM rss_articles WHERE rss_feed_id=?" );
    $db->execute( $dsth, array( $id ) );

    $isth = $db->prepare( "INSERT INTO rss_articles VALUES( ?, ?, ?, ? )" );

    foreach ($rss->getItems() as $item) {
      $db->execute( $isth, array( $id,
        $item['link'], $item['title'],
        $item['description'] ) );
    }
  }

  public static function get( $id )
  {
    $db = DatabaseConnection::get()->handle();
    $res = $db->query( "SELECT * FROM rss_articles WHERE rss_feed_id=?",
      array( $id ) );
    $rows = array();
    while( $res->fetchInto( $row, DB_FETCHMODE_ASSOC ) )
    {
      $rows []= $row;
    }
    return $rows;
  }
}
?>

Для получения ленты и обновления базы данных метод update использует парсер RSS. А метод get возвращает текущие содержания таблицы статей для заданной ленты.

Служебные страницы PHP

Первая страница, которая нам понадобится для добавления лент в список, называется add.php (см. листинг 5).

Листинг 5. add.php
<?php
require_once 'rss_db.php';

header( 'Content-type: text/xml' );

FeedList::add( $_GET['url'] );
?>
<done />

Это очень простой упаковщик метода add в классе FeedList. Тег <done> в последней строке служит для того, чтобы возвращать тип XML-файла, указывающего на успешное или неуспешное выполнение процесса.

Следующая страница - list.php (см. листинг 6) возвращает список лент в базе данных.

Листинг 6. list.php
<?php
require_once 'rss_db.php';

$rows = FeedList::getAll();

$dom = new DomDocument();
$dom->formatOutput = true;

$root = $dom->createElement( 'feeds' );
$dom->appendChild( $root );

foreach( $rows as $row )
{
  $an = $dom->createElement( 'feed' );
  $an->setAttribute( 'id', $row['rss_feed_id'] );
  $an->setAttribute( 'link', $row['url'] );
  $an->setAttribute( 'name', $row['name'] );
  $root->appendChild( $an );
}

header( "Content-type: text/xml" );
echo $dom->saveXML();
?>

Чтобы проще было создавать правильные документы XML, я использую функции объектной модели документов (Document Object Model - DOM) в ядре PHP, чтобы на лету создавать XML DOM. Затем я использую функцию saveXML, чтобы отформатировать документ для вывода.

Для отображения этой страницы я использовал браузер Firefox®; результат показан на рисунке 1.

Рисунок 1. Страница XML со списком лент
Страница XML со списком лент

Конечно, это после того, как я добавил в список восемь лент.

Последняя страница, которую надо создать прежде, чем перейти к клиентской части, это страница read.php (см. листинг 7), эта страница возвращает статьи, связанные с ID данной ленты.

Листинг 7. read.php
<?php
require_once 'rss_db.php';

FeedList::update();

$rows = Feed::get( $_GET['id'] );

$dom = new DomDocument();
$dom->formatOutput = true;

$root = $dom->createElement( 'articles' );
$dom->appendChild( $root );

foreach( $rows as $row )
{
  $an = $dom->createElement( 'article' );
  $an->setAttribute( 'title', $row['title'] );
  $an->setAttribute( 'link', $row['link'] );
  $an->appendChild( $dom->createTextNode( $row['description'] ) );
  $root->appendChild( $an );
}

header( "Content-type: text/xml" );
echo $dom->saveXML();
?>

По форме это очень похоже на страницу list.php. Для получения списка статей я использовал класс Feed. Затем я использовал объект XML DOM, чтобы создать и отобразить документ XML. Страница, отображенная в браузере Firefox, показана на рисунке 2.

Рисунок 2. XML, полученный из страницы read.php
XML, полученный из страницы read.php

Мы закончили с серверной частью уравнения. Теперь нам понадобится динамический язык разметки гипертекста (Dynamic Hyper Text Markup Language - DHTML), использующий Ajax, чтобы применить наши PHP страницы.

Построение клиента

На следующем шаге мы создадим клиента, который будет использовать PHP страницы. Я буду строить клиента в три этапа, так что вы можете проследить весь процесс. Первая версия в листинге 8 показывает управление, которое отображает список лент.

Листинг 8. index2.html
<html> <head> <title>Ajax RSS Reader</title>
<style>
body { font-family: arial, verdana, sans-serif; }
</style>
<script>
var g_homeDirectory = 'http://localhost/rss/';

var req = null;
function processReqChange( handler ) {
  if (req.readyState == 4 && req.status == 200 && req.responseXML ) {
    handler( req.responseXML ); }
}

function loadXMLDoc( url, handler ) {
  if(window.XMLHttpRequest) {
    try { req = new XMLHttpRequest(); } catch(e) { req = false; }
  }
  else if(window.ActiveXObject)
  {
    try { req = new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) {
    try { req = new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) { req = false; } }
  }

  if(req) {
    req.onreadystatechange = function() { processReqChange( handler ); };
    req.open("GET", url, true);
    req.send("");
  }
}

function parseFeedList( dom ) {
  var elfl = document.getElementById( 'elFeedList' );
  elfl.innerHTML = '';

  var nl = req.responseXML.getElementsByTagName( 'feed' );
  for( var i = 0; i < nl.length; i++ ) {
    var nli = nl.item( i );
    var id = nli.getAttribute( 'id' );
    var link = nli.getAttribute( 'link' );
    var name = nli.getAttribute( 'name' );

    var elOption = document.createElement( 'option' );
    elOption.value = id;
    elOption.innerHTML = name;
    elfl.appendChild( elOption );
  }
}

function getFeedList()
{
  loadXMLDoc( g_homeDirectory+'list.php', parseFeedList );
}
</script> </head> <body>
<select id="elFeedList"> </select>
<script> getFeedList(); </script>
</body> </html>

На этой странице один управляющий элемент - <select>. В этом элементе содержится функция getFeedList, которая запрашивает страницу list.php с сервера. Когда страница загрузилась, функция parseFeedList добавляет элементы в управляющий элемент <select>.

На рисунке 3 показан результат в браузере Firefox.

Рисунок 3. Первая версия RSS reader
Первая версия RSS reader

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

На следующем шаге нам надо отобразить содержание выбранной ленты. В листинге 9 обновленный код.

Листинг 9. index3.html
<html> <head> <title>Ajax RSS Reader</title>
<style>
body { font-family: arial, verdana, sans-serif; }
.title { font-size: 14pt; border-bottom: 1px solid black; }
.title a { text-decoration: none; }
.title a:hover { text-decoration: none; }
.title a:visited { text-decoration: none; }
.title a:active { text-decoration: none; }
.title a:link { text-decoration: none; }
.description { font-size: 9pt; margin-left: 20px; }
</style>
<script>
var g_homeDirectory = 'http://localhost/rss/';

var req = null;
function processReqChange( handler ) { ...  }

function loadXMLDoc( url, handler ) { ...  }

function parseFeed( dom ) {
  var ela = document.getElementById( 'elArticles' );
  ela.innerHTML = '';

  var elTable = document.createElement( 'table' );
  var elTBody = document.createElement( 'tbody' );
  elTable.appendChild( elTBody );

  var nl = req.responseXML.getElementsByTagName( 'article' );
  for( var i = 0; i < nl.length; i++ ) {
    var nli = nl.item( i );
    var title = nli.getAttribute( 'title' );
    var link = nli.getAttribute( 'link' );
    var description = nli.firstChild.nodeValue;

    var elTR = document.createElement( 'tr' );
    elTBody.appendChild( elTR );

    var elTD = document.createElement( 'td' );
    elTR.appendChild( elTD );

    var elTitle = document.createElement( 'h1' );
    elTitle.className = 'title';
    elTD.appendChild( elTitle );

    var elTitleLink = document.createElement( 'a' );
    elTitleLink.href = link;
    elTitleLink.innerHTML = title;
    elTitleLink.target = '_blank';
    elTitle.appendChild( elTitleLink );

    var elDescription = document.createElement( 'p' );
    elDescription.className = 'description';
    elDescription.innerHTML = description;
    elTD.appendChild( elDescription );
  }

  ela.appendChild( elTable );
}

function parseFeedList( dom ) {
  var elfl = document.getElementById( 'elFeedList' );
  elfl.innerHTML = '';

  var nl = req.responseXML.getElementsByTagName( 'feed' );
  var firstId = null;
  for( var i = 0; i < nl.length; i++ ) {
    var nli = nl.item( i );
    var id = nli.getAttribute( 'id' );
    var link = nli.getAttribute( 'link' );
    var name = nli.getAttribute( 'name' );

    var elOption = document.createElement( 'option' );
    elOption.value = id;
    elOption.innerHTML = name;
    elfl.appendChild( elOption );

    if ( firstId == null ) firstId = id;
  }
  loadFeed( firstId );
}

function loadFeed( id ) { loadXMLDoc( g_homeDirectory+'read.php?id='+id, parseFeed ); }

function getFeedList() { loadXMLDoc( g_homeDirectory+'list.php', parseFeedList ); }
</script> </head> <body> <div style="width:600px;">
<select id="elFeedList" 
  onchange="loadFeed( this.options[this.selectedIndex].value )"> </select>
<div id="elArticles"> </div>
<script> getFeedList(); </script>
</div> </body> </html>

Я пропустил функции processReqChange и loadXMLDoc, потому что они остались прежними. Код изменен в функциях loadFeed и parseFeed; они запрашивают данные со страницы read.php, анализируют их и добавляют на страницу.

На рисунке 4 показан результат в браузере Firefox.

Рисунок 4. Обновленная страница со списком статей
Обновленная страница со списком статей

Чтобы закончить страницу сделаем возможным добавление ленты к списку через страницу add.php. Последняя версия кода в листинге 10.

Листинг 10. index.html
<html> <head> <title>Ajax RSS Reader</title>
<style>
...
</style>
<script>
var g_homeDirectory = 'http://localhost/rss/';

//Та же функция преобразования, что и раньше

function addFeed()
{
  var url = prompt( "Url" );
  loadXMLDoc( g_homeDirectory+'add.php?url='+escape( url ), parseAddReturn );
  window.setTimeout( getFeedList, 1000 );
}

function loadFeed( id ) { loadXMLDoc( g_homeDirectory+'read.php?id='+id, parseFeed ); }

function getFeedList() { loadXMLDoc( g_homeDirectory+'list.php', parseFeedList ); }
</script> </head> <body> <div style="width:600px;">
<select id="elFeedList" onchange="loadFeed( this.options[this.selectedIndex].value )">
</select>
<input type="button" onclick="addFeed()" value="Add Feed..." />
<div id="elArticles"> </div>
<script> getFeedList(); </script>
</div> </body> </html>

Большая часть кода осталась неизменной, я только добавил новую кнопку Add Feed... (Добавить ленту), она выводит диалоговое окно, где вы можете вставить новый адрес URL в список лент. Для удобства я сделал задержку для браузера в две секунды, чтобы затем получить новый список после добавления ленты.

На рисунке 5 показана итоговая страница.

Рисунок 5. Итоговая страница
Итоговая страница

Вот теперь все в порядке. Но я не чувствую удовлетворения, потому что безопасность протокола XMLHTTP запрещает мне брать код JavaScript со страницы и копировать его в блоги, так чтобы любой мог посмотреть на ленты. Чтобы это стало возможным, мне надо переписать службы, чтобы использовать тег <script> и синтаксис JavaScript Object Notation (JSON) .

Переход от XML к JSON

В рамках этой статьи мне надо только чтобы ленты можно было просматривать через синтаксис скрипта, хотя на самом деле я могу повторить весь путь, используя теги скрипта для передачи данных. Чтобы добраться до лент, мне нужен список лент, написанный на JavaScript. Итак, создаем страницу list_js.php, как показано в листинге 11.

Листинг 11. list_js.php
<?php
require_once 'rss_db.php';

header( 'Content-type: text/javascript' );

$rows = FeedList::getAll();

$feeds = array();

foreach( $rows as $row )
{
  $feed = "{ id:".$row['rss_feed_id'];
  $feed .= ", link:'".$row['url']."'";
  $feed .= ", name:'".$row['name']."' }";
  $feeds []= $feed;
}
?>
setFeeds( [ <?php echo( join( ', ', $feeds ) ); ?> ] );

Запустив этот скрипт через командную строку, получим результат, показанный в листинге 12.

Листинг 12. Результат list_js.php
setFeeds( [
{ id:1, link:'http://muttmansion.com/ds/index.xml', name:'Driving Sideways' },
{ id:2, link:'http://slashdot.org/slashdot.rdf', name:'Slashdot' },
{ id:3, link:'http://muttmansion.com/vl/index.xml', name:'Visible Light' },
{ id:4, link:'http://muttmansion.com/sor/index.xml', name:'Socks on a Rooster' },
{ id:5, link:'http://muttmansion.com/dd/index.xml', name:'Doxie Digest' },
{ id:6, link:'http://rss.cnn.com/rss/cnn_topstories.rss', name:'CNN.com' },
{ id:7, link:'http://rss.cnn.com/rss/cnn_world.rss', name:'CNN.com - World' },
{ id:8, link:'http://rss.cnn.com/rss/cnn_us.rss', name:'CNN.com - U.S.' } ] );

Это привело нас к тегу <script>. Когда браузер загружает эту страницу, вызывается функция setFeeds вместе со списком лент. Далее устанавливается управляющий элемент <select> и загружается первая лента.

Мне также нужен эквивалент функции read.php, чтобы получать данные статьи как код JavaScript, а не в XML. В листинге 13 показана страница read_js.php.

Листинг 13. read_js.php
<?php
require_once 'rss_db.php';

function js_clean( $str )
{
  $str = preg_replace( "/\'/", "", $str );
  return $str;
}

FeedList::update();

$id = array_key_exists( 'id', $_GET ) ? $_GET['id'] : 1;

$rows = Feed::get( $id );

$items = array();

foreach( $rows as $row )
{
  $js = "{ title:'".js_clean($row['title'])."'";
  $js .= ", link:'".js_clean($row['link'])."'";
  $js .= ", description:'".js_clean($row['description'])."' }";
  $items []= $js;
}
?>
addFeed( <?php echo( $id ); ?>,
[ <?php echo( join( ', ', $items ) ); ?> ] );

Еще раз запускаем этот скрипт в командной строке; результат показан в листинге 14.

Листинг 14. Результат read_js.php
addFeed( 1,
[ { title:'War',
  link:'http://www.muttmansion.com/ds/archives/002816.html',
  description:'The...' }, ... ] );

Я сократил листинг, но суть осталась. Функция addFeed вызывается вместе с ID ленты и данными статьи в формате JavaScript.

С этими сервисами, доступными на JavaScript, мы можем теперь создать новую страницу, которая будет их использовать. В листинге 15 показана эта новая страница.

Листинг 15. script.html
<html> <head> <title>Script Component Test</title>
<style>
...
</style>
<script>
var g_homeDirectory = 'http://localhost/rss/';

function loadScript( url ) {
  var elScript = document.createElement( 'script' );
  elScript.src = url;
  document.body.appendChild( elScript );
}

function addFeed( id, articles ) {
  var ela = document.getElementById( 'elArticles' );
  ela.innerHTML = '';

  var elTable = document.createElement( 'table' );
  var elTBody = document.createElement( 'tbody' );
  elTable.appendChild( elTBody );

  for( var a in articles ) {
    var title = articles[a].title;
    var link = articles[a].link;
    var description = articles[a].description;

	// Создаем элементы как и раньше...
  }

  ela.appendChild( elTable );
}

function setFeeds( feeds ) {
  var elfl = document.getElementById( 'elFeedList' );
  elfl.innerHTML = '';

  var firstId = null;
  for( var f in feeds ) {
    var elOption = document.createElement( 'option' );
    elOption.value = feeds[f].id;
    elOption.innerHTML = feeds[f].name;
    elfl.appendChild( elOption );

    if ( firstId == null ) firstId = feeds[f].id;
  }
  loadFeed( firstId );
}

function loadFeed( id ) { loadScript( g_homeDirectory+'read_js.php?id='+id ); }

function getFeedList() { loadScript( g_homeDirectory+'list_js.php' ); }
</script> </head> <body>
<div class="rssControl"> <div class="rssControlTitle">
<select id="elFeedList" 
  onchange="loadFeed( this.options[this.selectedIndex].value )">
</select> </div> <div id="elArticles"> </div> </div>
<script> getFeedList(); </script>
</body> </html>

Эта страница похожа на первоначальную index.html. Однако вместо функции loadXMLDoc я использую новую функцию - loadScript, которая динамически создает тег <script>. Затем тег <script> загружает код JavaScript из указанной ссылки.

Эти теги вызывают страницы read_js.php и list_js.php. А страницы в свою очередь создают код на JavaScript, который вызывает функции setFeeds и addFeed на главной странице.

Когда я запускаю страницу, браузер отображает мне то, что показано на рисунке 6.

Рисунок 6. RSS reader использует теги <script> для данных
RSS reader использует теги <script> для данных

Большое преимущество этого кода в том, что он может использовать команду View Source, чтобы посмотреть скрипт страницы и скопировать код на свои собственные страницы. Затем эти страницы будут использовать PHP сервисы, которые возвращают код на JavaScript, чтобы обновить страницу.

Заключение

В этой статье мы посмотрели два разных подхода динамического доступа к информации на web-странице для создания RSS-reader. К счастью, вы можете использовать идеи и код, приведенные в статье, чтобы улучшить свои приложения, не переделывая весь свой код. Вот в чем настоящая ценность Ajax - если вы знакомы с web технологиями, то вам не составит труда добавить несколько сервисов к серверной части и немного дописать код на стороне клиента.


Загрузка

ОписаниеИмяРазмер
Source codex-ajaxrss-code.zip8KB

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML, Open source
ArticleID=160459
ArticleTitle=Ajax RSS-reader
publish-date=05122006