RSS/Atom 피드

중요 API

Windows.Web.Syndication 네임스페이스의 기능을 사용하여 RSS 및 Atom 표준에 따라 생성된 신디케이티드 피드로 인기 있는 최신 웹 콘텐츠를 검색하거나 만듭니다.

피드란?

웹 피드는 텍스트, 링크 및 이미지로 구성된 개별 항목을 수량 제한 없이 포함하는 문서입니다. 피드에 대한 업데이트는 웹 전체에서 최신 콘텐츠를 승격하는 데 사용되는 새 항목의 형태로 이루어집니다. 콘텐츠 소비자는 피드 읽기 권한자 앱을 사용하여 여러 개별 콘텐츠 작성자의 피드를 집계하고 모니터링하여 최신 콘텐츠에 빠르고 편리하게 액세스할 수 있습니다.

어떤 피드 형식 표준이 지원되나요?

UWP(유니버설 Windows 플랫폼)는 0.91부터 RSS 2.0까지의 RSS 형식 표준과 0.3부터 1.0까지의 Atom 표준에 대한 피드 검색을 지원합니다. Windows.Web.Syndication 네임스페이스의 클래스는 RSS 및 Atom 요소를 모두 나타낼 수 있는 피드 및 피드 항목을 정의할 수 있습니다.

또한 Atom 1.0 및 RSS 2.0 형식에서는 피드 문서에 공식 사양에 정의되지 않은 요소나 특성이 포함될 수 있습니다. 시간이 지남에 따라 이러한 사용자 지정 요소와 특성은 GData 및 OData와 같은 다른 웹 서비스 데이터 서식에서 사용되는 도메인별 정보를 정의하는 방법이 되었습니다. 이 추가된 기능을 지원하기 위해 SyndicationNode 클래스는 일반 XML 요소를 나타냅니다. Windows.Data.Xml.Dom 네임스페이스의 클래스와 함께 SyndicationNode를 사용하면 앱이 포함된 특성, 확장 및 모든 콘텐츠에 액세스할 수 있습니다.

공동 배급 콘텐츠 게시의 경우 Atom 게시 프로토콜(Windows.Web.AtomPub))의 UWP 구현은 Atom 및 Atom 게시 표준에 따른 피드 콘텐츠 작업만 지원합니다.

네트워크 격리와 함께 공동 배급 콘텐츠 사용

UWP의 네트워크 격리 기능을 사용하면 개발자가 UWP 앱의 네트워크 액세스를 제어하고 제한할 수 있습니다. 모든 앱이 네트워크에 액세스해야 하는 것은 아닙니다. 그러나 이를 수행하는 앱의 경우 UWP는 적절한 기능을 선택하여 사용하도록 설정할 수 있는 네트워크에 대한 다양한 수준의 액세스를 제공합니다.

네트워크 격리를 통해 개발자는 각 앱에 필요한 네트워크 액세스 범위를 정의할 수 있습니다. 적절한 범위가 정의되지 않은 앱은 지정된 형식의 네트워크 및 특정 형식의 네트워크 요청(아웃바운드 클라이언트가 시작한 요청 또는 인바운드 원치 않는 요청과 아웃바운드 클라이언트가 시작한 요청 모두)에 액세스할 수 없습니다. 네트워크 격리를 설정하고 적용하는 기능을 통해 앱이 손상되더라도 앱에 명시적으로 액세스 권한이 부여된 네트워크에만 액세스할 수 있습니다. 이렇게 하면 다른 애플리케이션과 Windows에 미치는 영향의 범위가 크게 줄어듭니다.

네트워크 격리는 네트워크에 액세스하려고 시도하는 Windows.Web.SyndicationWindows.Web.AtomPub 네임스페이스의 모든 클래스 요소에 영향을 미칩니다. Windows는 네트워크 격리를 적극적으로 적용합니다. 네트워크 액세스를 초래하는 Windows.Web.Syndication 또는 Windows.Web.AtomPub 네임스페이스의 클래스 요소에 대한 호출은 적절한 네트워크 기능이 사용하도록 설정되지 않은 경우. 없으면 네트워크 격리로 인해 실패할 수 있습니다

앱의 네트워크 기능은 앱이 빌드될 때 앱 매니페스트에서 구성됩니다. 네트워크 접근 권한 값은 일반적으로 앱을 개발할 때 Microsoft Visual Studio 2015를 사용하여 추가합니다. 텍스트 편집기를 사용하여 앱 매니페스트 파일에서 네트워크 기능을 수동으로 설정할 수도 있습니다.

네트워크 격리 및 네트워킹 기능에 대한 자세한 내용은 네트워킹 기본 사항 항목의 "기능" 섹션을 참조하세요.

웹 피드에 액세스하는 방법

이 섹션에서는 C# 또는 JavaScript로 작성된 UWP 앱에서 Windows.Web.Syndication 네임스페이스의 클래스를 사용하여 웹 피드를 검색하고 표시하는 방법을 보여 줍니다.

필수 구성 요소

UWP 앱이 네트워크에 준비되어 있는지 확인하려면 프로젝트 Package.appxmanifest 파일에 필요한 네트워크 기능을 설정해야 합니다. 앱이 인터넷의 원격 서비스에 클라이언트로 연결해야 하는 경우 internetClient 기능이 필요합니다. 자세한 내용은 네트워킹 기본 사항 항목의 "기능" 섹션을 참조하세요.

웹 피드에서 신디케이티드 콘텐츠 검색

이제 피드를 검색한 다음 피드에 포함된 각 개별 항목을 표시하는 방법을 보여 주는 일부 코드를 검토할 예정입니다. 요청을 구성하고 보내기 전에 작업 중에 사용할 몇 가지 변수를 정의하고 메서드와 속성을 정의하는 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.
}
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를 통해 항목과 해당 콘텐츠를 목록으로 표시합니다.

대부분의 비동기 네트워크 메서드를 호출할 때 예외를 처리하는 코드를 작성해야 합니다. 예외 처리기는 예외의 원인에 대해 보다 자세한 정보를 검색하므로 오류를 더 잘 이해하고 적절한 의사 결정을 내릴 수 있습니다.

RetrieveFeedAsync 메서드는 HTTP 서버와의 연결을 설정할 수 없거나 Uri 개체가 유효한 AtomPub 또는 RSS 피드를 가리키지 않는 경우 예외를 throw합니다. JavaScript 샘플 코드는 onError 함수를 사용하여 예외를 catch하고 오류가 발생할 경우 예외에 대한 자세한 정보를 인쇄합니다.

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는 요청된 피드 콘텐츠를 반환했으며 코드 예는 사용 가능한 피드 항목을 반복하는 작업을 시작했습니다. 이러한 각 항목은 관련 배포 표준(RSS 또는 Atom)에서 제공하는 모든 항목 속성과 콘텐츠가 포함된 SyndicationItem 개체를 사용하여 표시됩니다. 다음 예에서는 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 link = document.getElementById("Link");
    link.innerText = link;
    link.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 피드는 그렇지 않습니다. 그러나 두 표준 중 하나에서 지원하지 않는 피드 항목에 포함된 확장 요소(예: 더블린 코어 확장 요소)는 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
    });
}