RSS/Atom 源

重要的 API

使用 Windows.Web.Syndication 命名空间中的功能,借助按照 RSS 和 Atom 标准生成的聚合源检索或创建最新和最热门的 Web 内容。

注释

Windows.Web.SyndicationWindows.Web.AtomPub API 是可在 WinUI 3(Windows 应用 SDK) 桌面应用以及 UWP 应用中工作的Windows 运行时 (WinRT) API。

什么是订阅源?

Web 订阅源是一个文档,其中包含任意数量的由文本、链接和图像所组成的单个条目。 对订阅源的更新是以新条目的形式来进行的,这些新条目用于在整个 Web 上推广最新的内容。 内容使用者可以使用源读取器应用聚合和监视来自任意数量的单个内容作者的源,从而快速方便地访问最新内容。

支持哪些 Feed 格式标准?

Windows支持从 0.91 到 RSS 2.0 的 RSS 格式标准的源检索,以及从 0.3 到 1.0 的 Atom 标准。 Windows.Web.Syndication 命名空间中的类可定义订阅源和能够表示 RSS 和 Atom 元素的订阅源项目。

此外,Atom 1.0 和 RSS 2.0 格式都允许其源文档包含官方规范中未定义的元素或属性。 随着时间的推移,这些自定义元素和属性已成为定义其他 Web 服务数据格式(如 GData 和 OData)使用的特定于域的信息的方法。 为了支持此功能, SyndicationNode 类表示泛型 XML 元素。 将 SyndicationNodeWindows.Data.Xml.Dom 命名空间中的类结合使用,可使应用访问属性、扩展以及这些属性和扩展可能包含的任何内容。

请注意,对于聚合内容的发布,Atom 发布协议的 Windows 实现(Windows.Web.AtomPub)仅支持符合 Atom 和 Atom 发布标准的订阅源内容操作。

使用带有网络隔离功能的综合内容

Windows中的网络隔离功能使开发人员能够控制和限制Windows应用的网络访问。 并非所有应用都需要访问网络。 但是,对于确实需要网络访问的应用,Windows 提供了不同级别的网络访问权限,可以通过选择相应的功能来启用这些权限。

网络隔离允许开发人员为每个应用定义所需的网络访问范围。 如果应用未定义适当的范围,则无法访问指定的网络类型以及特定类型的网络请求(出站客户端发起的请求或入站未请求的请求和出站客户端发起的请求)。 设置和强制实施网络隔离的功能可确保如果应用遭到入侵,则只能访问已显式授予应用访问权限的网络。 这大大减少了对其他应用程序和Windows的影响范围。

网络隔离会影响 Windows.Web.SyndicationWindows.Web.AtomPub 命名空间中任何尝试访问网络的类元素。 Windows主动强制实施网络隔离。 如果未启用相应的网络功能,对 Windows.Web.SyndicationWindows.Web.AtomPub 命名空间中类元素的调用在导致网络访问时,可能会因网络隔离而失败。

生成应用时,应用的网络功能在应用清单中配置。 开发应用时,通常使用Visual Studio添加网络功能。 还可以使用文本编辑器在应用清单文件中手动设置网络功能。

有关网络隔离和网络功能的详细信息,请参阅 网络基础知识 主题中的“功能”部分。

如何访问 Web 订阅源

本节介绍如何在用 C# 编写的 Windows 应用中,使用 Windows.Web.Syndication 命名空间中的类来检索和显示 Web 源。

Prerequisites

若要确保Windows应用已准备就绪,必须设置项目 Package.appxmanifest 文件中所需的任何网络功能。 如果你的应用需要以客户端身份连接到 Internet 上的远程服务,则需要 InternetClient 功能。 有关详细信息,请参阅 网络基础知识 主题中的“功能”部分。

从 Web 源检索聚合内容

现在,我们将查看一些代码,该代码演示如何检索源,然后显示源包含的每个单独项。 在配置和发送请求之前,我们将定义一些将在操作期间使用的变量,并初始化 SyndicationClient 的实例,该实例定义用于检索和显示源的方法和属性。

如果传递给构造函数的 uriString 不是有效的 URI,Uri 构造函数将引发异常。 因此,我们使用 try/catch 块验证 uriString

Windows.Web.Syndication.SyndicationClient client = new Windows.Web.Syndication.SyndicationClient();
Windows.Web.Syndication.SyndicationFeed feed;
// The URI is validated by catching exceptions thrown by the Uri constructor.
Uri uri = null;
// Use your own uriString for the feed you are connecting to.
string uriString = "";
try
{
    uri = new Uri(uriString);
}
catch (Exception ex)
{
    // Handle the invalid URI here.
}

注释

本文中的 JavaScript 示例使用 WinJS (Windows JavaScript 库),这是 UWP JavaScript 应用的旧框架。 这些示例仅供参考,不建议用于新应用开发。

var currentFeed = null;
var currentItemIndex = 0;
var client = new Windows.Web.Syndication.SyndicationClient();
// The URI is validated by catching exceptions thrown by the Uri constructor.
var uri = null;
try {
    uri = new Windows.Foundation.Uri(uriString);
} catch (error) {
    WinJS.log && WinJS.log("Error: Invalid URI");
    return;
}

接下来,我们通过设置所需的任何服务器凭据( ServerCredential 属性)、代理凭据( ProxyCredential 属性)和 HTTP 标头( SetRequestHeader 方法)来配置请求。 配置基本请求参数后,使用应用提供的源 URI 字符串创建有效的 Uri 对象。 然后, Uri 对象将传递给 RetrieveFeedAsync 函数以请求源。

假设返回了所需的源内容,则示例代码循环访问每个源项,调用 displayCurrentItem (我们下一步定义),以通过 UI 将项及其内容显示为列表。

调用大多数异步网络方法时,必须编写代码来处理异常。 异常处理程序可以检索有关异常原因的更多详细信息,以便更好地了解失败并做出适当的决策。

如果无法与 HTTP 服务器建立连接,或者 Uri 对象不指向有效的 AtomPub 或 RSS 源,则 RetrieveFeedAsync 方法将引发异常。 JavaScript 示例代码使用 onError 函数捕获任何异常,并在发生错误时输出有关异常的更多详细信息。

try
{
    // Although most HTTP servers do not require User-Agent header, 
    // others will reject the request or return a different response if this header is missing.
    // Use the setRequestHeader() method to add custom headers.
    client.SetRequestHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
    feed = await client.RetrieveFeedAsync(uri);
    // Retrieve the title of the feed and store it in a string.
    string title = feed.Title.Text;
    // Iterate through each feed item.
    foreach (Windows.Web.Syndication.SyndicationItem item in feed.Items)
    {
        displayCurrentItem(item);
    }
}
catch (Exception ex)
{
    // Handle the exception here.
}
function onError(err) {
    WinJS.log && WinJS.log(err, "sample", "error");
    // Match error number with an ErrorStatus value.
    // Use Windows.Web.WebErrorStatus.getStatus() to retrieve HTTP error status codes.
    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.");
    }
}
// Retrieve and display feed at given feed address.
function retreiveFeed(uri) {
    // Although most HTTP servers do not require User-Agent header, 
    // others will reject the request or return a different response if this header is missing.
    // Use the setRequestHeader() method to add custom headers.
    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) {
        currentFeed = feed;
        WinJS.log && WinJS.log("Feed download complete.", "sample", "status");
        var title = "(no title)";
        if (currentFeed.title) {
            title = currentFeed.title.text;
        }
        document.getElementById("CurrentFeedTitle").innerText = title;
        currentItemIndex = 0;
        if (currentFeed.items.size > 0) {
            displayCurrentItem();
        }
        // List the items.
        displayLog("Items: " + currentFeed.items.size);
     }, onError);
}

在上一步中, RetrieveFeedAsync 返回请求的源内容,示例代码可以循环访问可用的源项。 其中每个项都使用 SyndicationItem 对象表示,该对象包含相关联合标准(RSS 或 Atom)提供的所有项属性和内容。 在下面的示例中,我们观察 displayCurrentItem 函数处理每个项,并通过各种命名 UI 元素显示其内容。

private void displayCurrentItem(Windows.Web.Syndication.SyndicationItem item)
{
    string itemTitle = item.Title == null ? "No title" : item.Title.Text;
    string itemLink = item.Links == null ? "No link" : item.Links.FirstOrDefault().ToString();
    string itemContent = item.Content == null ? "No content" : item.Content.Text;
    //displayCurrentItem is continued below.
function displayCurrentItem() {
    var item = currentFeed.items[currentItemIndex];
    // Display item number.
    document.getElementById("Index").innerText = (currentItemIndex + 1) + " of " + currentFeed.items.size;
    // Display title.
    var title = "(no title)";
    if (item.title) {
        title = item.title.text;
    }
    document.getElementById("ItemTitle").innerText = title;
    // Display the main link.
    var link = "";
    if (item.links.size > 0) {
        link = item.links[0].uri.absoluteUri;
    }
    var linkElement = document.getElementById("Link");
    linkElement.innerText = link;
    linkElement.href = link;
    // Display the body as HTML.
    var content = "(no content)";
    if (item.content) {
        content = item.content.text;
    }
    else if (item.summary) {
        content = item.summary.text;
    }
    document.getElementById("WebView").innerHTML = window.toStaticHTML(content);
                //displayCurrentItem is continued below.

如前所述, SyndicationItem 对象表示的内容类型将有所不同,具体取决于用于发布源的源标准(RSS 或 Atom)。 例如,Atom 源能够提供 参与者列表,但 RSS 源不是。 但是,对于源条目中包含的、既不受这两种标准支持的扩展元素(例如 Dublin Core 扩展元素),可以使用 SyndicationItem.ElementExtensions 属性访问它们,然后按照以下示例代码所示将其显示出来。

    //displayCurrentItem continued.
    string extensions = "";
    foreach (Windows.Web.Syndication.SyndicationNode node in item.ElementExtensions)
    {
        string nodeName = node.NodeName;
        string nodeNamespace = node.NodeNamespace;
        string nodeValue = node.NodeValue;
        extensions += nodeName + "\n" + nodeNamespace + "\n" + nodeValue + "\n";
    }
    this.listView.Items.Add(itemTitle + "\n" + itemLink + "\n" + itemContent + "\n" + extensions);
}
    // displayCurrentItem function continued.
    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
    });
}