Синдикация
Когда мы впервые столкнулись с выполнением запросов XmlHttpRequests с помощью WinJS.XHR в Главе 3 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", мы запрашивали RSS-ленту из Блога для разработчиков приложений для Windows 8, пользуясь URI http://blogs.msdn.com/b/windowsappdev/rss.aspx . Затем мы узнали, что WinJS.xhr возвращает promise-объект, результат которого содержит свойство responseXML , которое имеет тип DomParser, с его помощью можно обойти структуру DOM и так далее.
Работа с синдицированными веб-каналами, наподобие вышеупомянутой, полностью поддерживается приложениями для Магазина Windows. На самом деле, материал "Доступ к сводному содержимому и управление им" (http://msdn.microsoft.com/ru-ru/library/windows/apps/hh452973.aspx) описывает именно этот процесс, компоненты которого показаны в примере "Интеграция содержимого и элементов управления веб-сервисов" (http://code.msdn.microsoft.com/windowsapps/Mashup-Sample-10689f5b).
Тем не менее, WinRT предлагает дополнительные API для работы с синдицированным содержимым. Один из них, Windows.Web.Syndication, предлагает более структурированный подход для работы с RSS-каналами. Другой, Windows.Web.AtomPub, предоставляет средства для публикации записей каналов и управления ими. И то и другое предоставлены в WinRT для языков, у которых нет средств для достижения тех же целей, но, как у разработчика, работающего с JavaScript, у вас есть выбор.
Чтение RSS-каналов
Основной класс в Windows.Web.Syndication (http://msdn.microsoft.com/library/windows/apps/br244529.aspx) это SyndicationClient (http://msdn.microsoft.com/library/windows/apps/windows.web.syndication.syndicationclient.aspx). Для работы с любым каналом сначала создают экземпляр этого класса и задают необходимые свойства. Это следующие свойства: serverCredential (типа PasswordCredential), proxyCredential (еще одно свойство типа PasswordCredential), timeout (в миллисекундах, по умолчанию 30000 или 30 секунд), maxResponseBufferSize (средство для защиты от потенциальных серверов злоумышленников), и bypassCacheOnRetrieve (логическое значение, которое указывает на то, всегда ли нужно получать новые данные с сервера ). Так же можно произвести необходимое количество вызовов его метода setRequestHeader (передавая имя и значение) для настройки заголовка XmlHttpRequest.
Последний шаг заключается в вызове метода SyndicationClient.retrieveFeedAsync с URI нужного RSS-канала (типа Windows.Foundation.Uri). Вот код, взятый из примера "Синдикация" (http://code.msdn.microsoft.com/windowsapps/Syndication-sample-07ef6b0d), который получает RSS-канал блога "Создание Windows 8" (http://blogs.msdn.com/b/b8/rss.aspx):
uri = new Windows.Foundation.Uri("http://blogs.msdn.com/b/b8/rss.aspx"); var client = new Windows.Web.Syndication.SyndicationClient(); client.bypassCacheOnRetrieve = true; client.setRequestHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"); client.retrieveFeedAsync(uri).done(function (feed) { // feed это объект SyndicationFeed
Результат выполнения retrieveFeedAsync – это объект Windows.Web.Syndication.SyndicationFeed (http://msdn.microsoft.com/library/windows/apps/windows.web.syndication.syndicationfeed.aspx), то есть, SyndicationClient это то, что вы использовали для взаимодействия с свервисом, и когд вы получаете канал, вы получаете объект, с помощью которого вы можете затем обработать полученные данные. Если вы взглянете на SyndicationFeed , воспользовавшись вышеприведенной ссылкой, вы увидите, что он наполнен свойствами, которые представляют собой все части канала, такие, как authors, categories, items, title, и так далее. Некоторые из них представлены другими классами в Windows.Web.Syndication, или их коллекциями, когда более простых типов недостаточно: SyndicationAttribute, SyndicationCategory, SyndicationContent, SyndicationGenerator, SyndicationItem, SyndicationLink, SyndicationNode, SyndicationPerson, и SyndicationText. Оставляю разъяснение подробностей обо всём этом документации.
Кое-что из этого мы можем увидеть в примере, взятом из обработчика завершения для retrieveFeedAsync. Позвольте мне представить аннотированный вариант этого кода:
client.retrieveFeedAsync(uri).done(function (feed) { currentFeed = feed; var title = "(no title)"; // currentFeed.title это объект SyndicationText if (currentFeed.title) { title = currentFeed.title.text; } // currentFeed.items это коллекция SyndicationItem (массив) currentItemIndex = 0; if (currentFeed.items.size>0) { displayCurrentItem(); } } // ... function displayCurrentItem() { // Элемент будет иметь тип SyndicationItem var item = currentFeed.items[currentItemIndex]; // Отображение номера элемента. document.getElementById("scenario1Index").innerText = (currentItemIndex + 1) + " of " + currentFeed.items.size; // Отображение заголовка (item.title это еще один SyndicationText). var title = "(no title)"; if (item.title) { title = item.title.text; } document.getElementById("scenario1ItemTitle").innerText = title; // Отображение основной ссылки (item.links это коллекция объектов SyndicationLink). var link = ""; if (item.links.size>0) { link = item.links[0].uri.absoluteUri; } var scenario1Link = document.getElementById("scenario1Link"); scenario1Link.innerText = link; scenario1Link.href = link; // Отображение тела в виде HTML (item.content это объект SyndicationContent, item.summary это // объект SyndicationText object). var content = "(no content)"; if (item.content) { content = item.content.text; } else if (item.summary) { content = item.summary.text; } document.getElementById("scenario1WebView").innerHTML = window.toStaticHTML(content); // Отображение расширений элемента. Коллекция elementExtensions содержит дополнительные // дочерние элементы в текущем элементе, которые не принадлежат станартам Atom или RSS // (например, элементы расширения Dublin Core). Создавая их массив, мы можем создать // WinJS.Binding.List, который можно легко вывести в ListView. var bindableNodes = []; for (var i = 0; i<item.elementExtensions.size; i++) { var bindableNode = { nodeName: item.elementExtensions[i].nodeName, nodeNamespace: item.elementExtensions[i].nodeNamespace, nodeValue: item.elementExtensions[i].nodeValue, }; bindableNodes.push(bindableNode); } var dataList = new WinJS.Binding.List(bindableNodes); var listView = document.getElementById("extensionsListView").winControl; WinJS.UI.setOptions(listView, { itemDataSource: dataList.dataSource }); }
Видимо, это очевидно, что API, лежащие в основе всего этого, скорее всего, просто используют API XmlDocument для получения этих свойств канала. На самом деле его getXmlDocument возвращает этот XmlDocument, если вам понадобится доступ к нему в собственных целях.
Так же вы можете создать объект SyndicationFeed на основе XML для канала, который у вас уже есть. Например, если вы получили содержимое канала с использованием WinJS.xhr, вы можете создать новый объект SyndicationFeed и вызвать его метод load со свойством XHR responseXML. Затем вы можете работать с каналом с помощью иерархии класса. При использовании API Windows.Web.AtomPub для управления каналом, вы так же создаете новый или обновленный элемент SyndicationItem для передачи по каналам связи, устанавливаете его значения посредством других объектов в его иерархии. Скоро мы это увидим.
Еще одно примечание: если retrieveFeedAsync выдает исключение, которое можно получить с помощью обработчика ошибок, который вы предоставили в метод done соответствующего promise-объекта, вы можете преобразовать код ошибки в значение SyndicationErrorStatus. Вот, как это используется в обработчике ошибок примера:
function onError(err) { // Сранивает номер ошибки со значением SyndicationErrorStatus. Используйте // Windows.Web.WebErrorStatus.getStatus() для получения кодов статусов HTTP - ошибок. var errorStatus = Windows.Web.Syndication.SyndicationError.getStatus(err.number); if (errorStatus === Windows.Web.Syndication.SyndicationErrorStatus.invalidXml) { displayLog("An invalid XML exception was thrown. Please make sure to use a URI that" + "points to a RSS or Atom feed."); } }