1

私のMVCWebアプリケーションでは、Newsstand Atomフィード(AppleのNewsstand用)を返す関数を開発しました。このフィードの要件の1つは、UTF-8で効果的にエンコードされ、BOMを含めてはならないことです。これが私の見解をコーディングした方法です(クラス名は会社のプライバシーを保護するために架空のものです):

<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage(Of IEnumerable (Of AtomFeed))" ContentType="application/atom+xml" ResponseEncoding="UTF-8" %><?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:news="http://itunes.apple.com/2011/Newsstand"><%="" %><%  If Not Model Is Nothing Then%><%  Dim updateDate As String = ViewData("feedUpdate")%><% If (Not String.IsNullOrEmpty(updateDate)) Then%>
<updated><%= updateDate %></updated><%
End If%><% For Each f In Model%>
<entry>
    <id><%= f.id%></id>
    <updated><%= f.updated%></updated>
    <published><%= f.published%></published>
    <news:end_date><%= f.endDate%></news:end_date>
    <summary><%= f.summaryText%></summary>
    <news:cover_art_icons>
        <news:cover_art_icon size="SOURCE" src="<%= f.newspaperCover %>"/>
    </news:cover_art_icons>
</entry><%
        Next%><%
End If%>
</feed>

今日、iTunesから、XMLをインポートできなかったというメールが届きましたが、失敗した理由がわかりませんでした。レンダリングされたXMLは要件に準拠しているため、ビューのエンコードに問題があると推測されます。

BOMなしでUTF-8でこのビューを正しく返すにはどうすればよいですか?指定されたURLからXMLをプルするときに、正しく処理されるようにするにはどうすればよいですか?

編集:

ダリンの実装を使用した後、私は次のフィードになりました

    <?xml version="1.0" encoding="utf-8"?>
<feed xmlns:news="http://itunes.apple.com/2011/Newsstand"
xmlns="http://www.w3.org/2005/Atom">
  <title type="text"></title>
  <id>uuid:5fc48c36-a1d3-4280-a856-a1a0528e2552;id=1</id>
  <updated>2012-07-23T00:40:00Z</updated>
  <entry>
    <id>23.07.2012</id>
    <title type="text"></title>
    <summary type="text">...</summary>
    <updated>2012-07-23T00:40:00Z</updated>
    <published xmlns="">2012-07-23T00:40:00Z</published>
    <news:end_date>2012-07-24T00:40:00Z</news:end_date>
    <news:cover_art_icons>
      <news:cover_art_icon size="SOURCE"
      src="https://www.someurl.com" />
    </news:cover_art_icons>
  </entry>
  <entry>
    <id>22.07.2012</id>
    <title type="text"></title>
    <summary type="text">...</summary>
    <updated>2012-07-22T00:40:00Z</updated>
    <published xmlns="">2012-07-22T00:40:00Z</published>
    <news:end_date>2012-07-23T00:40:00Z</news:end_date>
    <news:cover_art_icons>
      <news:cover_art_icon size="SOURCE"
      src="https://www.someurl.com" />
    </news:cover_art_icons>
  </entry>
</feed>

現在、AppleのNewsstandは、このフィードのエントリ要素に要素が見つからないと言っているため、次のフィードをインポートできません。

4

1 に答える 1

1

ビューでXMLフィードを手動で生成する代わりに、その目的のために設計されたSyndicationFeedクラスを使用することをお勧めします。

したがって、データを表すドメインモデルがあると仮定しましょう。

public class NewsstandFeed
{
    public DateTime? Updated { get; set; }
    public IEnumerable<AtomFeed> Items { get; set; }
}

public class AtomFeed
{
    public int Id { get; set; }
    public DateTime Updated { get; set; }
    public DateTime Published { get; set; }
    public DateTime EndDate { get; set; }
    public string SummaryText { get; set; }
    public string NewspaperCover { get; set; }
}

次に、ドメインモデルを取得するためにDALにクエリを実行するコントローラー:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        // Normally this will come from a database or something,
        // but I am hardcoding it for demonstration purposes here
        var model = new NewsstandFeed
        {
            Updated = DateTime.Now,
            Items = new[]
            {
                new AtomFeed 
                {
                    Id = 1,
                    Updated = DateTime.Now,
                    Published = DateTime.Now,
                    EndDate = DateTime.Now,
                    SummaryText = "some summary",
                    NewspaperCover = "http://www.google.com"
                }
            }
        };

        return new NewsstandFeedResult(model);
    }
}

NewsstandFeedResultコントローラのアクションが戻ることに注意してください。それを実装しましょう:

public class NewsstandFeedResult : ActionResult
{
    public const string NewsstandNS = "http://itunes.apple.com/2011/Newsstand";
    public NewsstandFeed Model { get; private set; }

    public NewsstandFeedResult(NewsstandFeed model)
    {
        Model = model;
        if (model.Items == null)
        {
            model.Items = Enumerable.Empty<AtomFeed>();
        }
    }

    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.HttpContext.Response;
        response.ContentType = "application/atom+xml";

        var feed = new SyndicationFeed();
        var n = new XmlQualifiedName("news", "http://www.w3.org/2000/xmlns/");
        XNamespace newsstandNs = NewsstandNS;
        feed.AttributeExtensions.Add(n, newsstandNs.ToString());
        if (Model.Updated.HasValue)
        {
            feed.LastUpdatedTime = new DateTimeOffset(Model.Updated.Value.ToUniversalTime());
        }

        var items = new List<SyndicationItem>();
        foreach (var item in Model.Items)
        {
            var si = new SyndicationItem();
            si.Id = item.Id.ToString();
            si.LastUpdatedTime = new DateTimeOffset(item.Updated.ToUniversalTime());
            si.Summary = new TextSyndicationContent(item.SummaryText);

            si.ElementExtensions.Add(new XElement(newsstandNs + "end_date", item.EndDate.ToUniversalTime()));
            si.ElementExtensions.Add(
                new XElement(
                    newsstandNs + "cover_art_icons",
                    new XElement(
                        newsstandNs + "cover_art_icon", 
                        new XAttribute("size", "SOURCE"), 
                        new XAttribute("src", item.NewspaperCover)
                    )
                )
            );
            items.Add(si);
        }
        feed.Items = items;

        using (var writer = XmlWriter.Create(response.OutputStream))
        {
            var formatter = new Atom10FeedFormatter(feed);
            formatter.WriteTo(writer);
        }
    }
}

それでおしまい。に移動するだけで/home/index、すべての業界標準を尊重する有効なAtomフィードを取得できるため、BOMなどについて心配する必要はありません。

于 2012-07-19T13:32:21.590 に答える