Rss20FeedFormatter 忽略 SyndicateItem.Summary 的 TextSynminationContent 类型

发布于 2024-12-01 14:04:26 字数 3316 浏览 1 评论 0原文

在 WCF 项目中使用 Rss20FeedFormatter 类时,我尝试使用 部分包装描述元素的内容。我发现无论我做什么,描述元素的 HTML 内容总是被编码,并且 CDATA 部分从未被添加。在查看 Rss20FeedFormatter 的源代码后,我发现在构建 Summary 节点时,它基本上创建了一个新的 TextSyndicateContent 实例,该实例会清除之前指定的任何设置(我认为)。

我的代码

public class CDataSyndicationContent : TextSyndicationContent
{
    public CDataSyndicationContent(TextSyndicationContent content)
        : base(content)
    {
    }

    protected override void WriteContentsTo(System.Xml.XmlWriter writer)
    {
        writer.WriteCData(Text);
    }
}

...(以下代码应使用 CDATA 部分包装摘要)

SyndicationItem item = new SyndicationItem();
item.Title = new TextSyndicationContent(name);
item.Summary = new CDataSyndicationContent(
                   new TextSyndicationContent(
                         "<div>This is a test</div>", 
                         TextSyndicationContentKind.Html));

Rss20FeedFormatter 代码 (据我所知,由于这种逻辑,上述代码不起作用)

...
else if (reader.IsStartElement("description", ""))
   result.Summary = new TextSyndicationContent(reader.ReadElementString());
...

作为一种解决方法,我求助于使用 RSS20FeedFormatter 来构建 RSS,然后手动修补 RSS。例如:

        StringBuilder buffer = new StringBuilder();
        XmlTextWriter writer = new XmlTextWriter(new StringWriter(buffer));
        feedFormatter.WriteTo(writer ); // feedFormatter = RSS20FeedFormatter

        PostProcessOutputBuffer(buffer);
        WebOperationContext.Current.OutgoingResponse.ContentType = 
                                   "application/xml; charset=utf-8";
        return new MemoryStream(Encoding.UTF8.GetBytes(buffer.ToString()));      

...

    public void PostProcessOutputBuffer(StringBuilder buffer)
    {
        var xmlDoc = XDocument.Parse(buffer.ToString());
        foreach (var element in xmlDoc.Descendants("channel").First()
                                      .Descendants("item")
                                      .Descendants("description"))
        {
            VerifyCdataHtmlEncoding(buffer, element);
        }

        foreach (var element in xmlDoc.Descendants("channel").First()
                                      .Descendants("description"))
        {
            VerifyCdataHtmlEncoding(buffer, element);
        }

        buffer.Replace(" xmlns:a10=\"http://www.w3.org/2005/Atom\"",
                       " xmlns:atom=\"http://www.w3.org/2005/Atom\"");
        buffer.Replace("a10:", "atom:");
    }

    private static void VerifyCdataHtmlEncoding(StringBuilder buffer,
                                                XElement element)
    {
        if (!element.Value.Contains("<") || !element.Value.Contains(">"))
        {
            return;
        }

        var cdataValue = string.Format("<{0}><![CDATA[{1}]]></{2}>",
                                       element.Name,
                                       element.Value, 
                                       element.Name);
        buffer.Replace(element.ToString(), cdataValue);
    }

此解决方法的想法来自以下位置,我只是对其进行了调整以与 WCF 而不是 MVC 一起使用。 是否

我只是想知道 这只是 Rss20FeedFormatter 中的一个错误还是设计使然?另外,如果有人有更好的解决方案,我很想听听!

While using the Rss20FeedFormatter class in a WCF project, I was trying to wrap the content of my description elements with a <![CDATA[ ]]> section. I found that no matter what I did, the HTML content of the description elements was always encoded and the CDATA section was never added. After peering into the source code of Rss20FeedFormatter, I found that when building the Summary node, it basically creates a new TextSyndicationContent instance which wipes out whatever settings were previously specified (I think).

My Code

public class CDataSyndicationContent : TextSyndicationContent
{
    public CDataSyndicationContent(TextSyndicationContent content)
        : base(content)
    {
    }

    protected override void WriteContentsTo(System.Xml.XmlWriter writer)
    {
        writer.WriteCData(Text);
    }
}

... (The following code should wrap the Summary with a CDATA section)

SyndicationItem item = new SyndicationItem();
item.Title = new TextSyndicationContent(name);
item.Summary = new CDataSyndicationContent(
                   new TextSyndicationContent(
                         "<div>This is a test</div>", 
                         TextSyndicationContentKind.Html));

Rss20FeedFormatter Code
(AFAIK, the above code does not work because of this logic)

...
else if (reader.IsStartElement("description", ""))
   result.Summary = new TextSyndicationContent(reader.ReadElementString());
...

As a workaround, I've resorted to using the RSS20FeedFormatter to build the RSS, and then patch the RSS manually. For example:

        StringBuilder buffer = new StringBuilder();
        XmlTextWriter writer = new XmlTextWriter(new StringWriter(buffer));
        feedFormatter.WriteTo(writer ); // feedFormatter = RSS20FeedFormatter

        PostProcessOutputBuffer(buffer);
        WebOperationContext.Current.OutgoingResponse.ContentType = 
                                   "application/xml; charset=utf-8";
        return new MemoryStream(Encoding.UTF8.GetBytes(buffer.ToString()));      

...

    public void PostProcessOutputBuffer(StringBuilder buffer)
    {
        var xmlDoc = XDocument.Parse(buffer.ToString());
        foreach (var element in xmlDoc.Descendants("channel").First()
                                      .Descendants("item")
                                      .Descendants("description"))
        {
            VerifyCdataHtmlEncoding(buffer, element);
        }

        foreach (var element in xmlDoc.Descendants("channel").First()
                                      .Descendants("description"))
        {
            VerifyCdataHtmlEncoding(buffer, element);
        }

        buffer.Replace(" xmlns:a10=\"http://www.w3.org/2005/Atom\"",
                       " xmlns:atom=\"http://www.w3.org/2005/Atom\"");
        buffer.Replace("a10:", "atom:");
    }

    private static void VerifyCdataHtmlEncoding(StringBuilder buffer,
                                                XElement element)
    {
        if (!element.Value.Contains("<") || !element.Value.Contains(">"))
        {
            return;
        }

        var cdataValue = string.Format("<{0}><![CDATA[{1}]]></{2}>",
                                       element.Name,
                                       element.Value, 
                                       element.Name);
        buffer.Replace(element.ToString(), cdataValue);
    }

The idea for this workaround came from the following location, I just adapted it to work with WCF instead of MVC. http://localhost:8732/Design_Time_Addresses/SyndicationServiceLibrary1/Feed1/

I'm just wondering if this is simply a bug in Rss20FeedFormatter or is it by design? Also, if anyone has a better solution, I'd love to hear it!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

拥抱我好吗 2024-12-08 14:04:26

好吧@Page Brooks,我认为这更多地是一个解决方案,而不是一个问题:)。谢谢!!!并回答你的问题(;)),是的,我绝对认为这是 Rss20FeedFormatter 中的一个错误(尽管我没有追究它那么远),因为遇到了与你描述的完全相同的问题。

您的帖子中有“localhost:8732”推荐,但它在我的本地主机上不可用;)。我认为您的意思是将“PostProcessOutputBuffer”解决方法归功于这篇文章:
http://damieng.com/ blog/2010/04/26/creating-rss-feeds-in-asp-net-mvc

或者实际上它不在这篇文章中,而是在 David Whitney 的评论中,后来他在这里单独提出了要点:
https://gist.github.com/davidwhitney/1027181

感谢您提供的改编这个解决方法更符合我的需求,因为我也找到了解决方法,但仍在努力适应 MVC。现在我只需要调整您的解决方案,将 RSS 提要放入我正在使用的 .ashx 处理程序中的当前 Http 请求。

基本上,我猜测您提到的使用 CDataSyndicateContent 的修复是从 2011 年 2 月开始的,假设你从这篇文章中得到了它(至少我做到了):
SynminationFeed:内容为 CDATA?

此修复程序在某些较新的 ASP.NET 版本或其他版本中停止工作,由于 Rss20FeedFormatter 的代码更改为您在帖子中放置的内容。此代码更改也可能是对 MVC 框架中其他内容的改进,但对于那些使用 CDataSyndicateContent 修复的人来说,它肯定会导致错误!

Well @Page Brooks, I see this more as a solution then as a question :). Thanks!!! And to answer your question ( ;) ), yes, I definitely think this is a bug in the Rss20FeedFormatter (though I did not chase it as far), because had encountered precisely the same issue that you described.

You have a 'localhost:8732' referral in your post, but it wasn't available on my localhost ;). I think you meant to credit the 'PostProcessOutputBuffer' workaround to this post:
http://damieng.com/blog/2010/04/26/creating-rss-feeds-in-asp-net-mvc

Or actually it is not in this post, but in a comment to it by David Whitney, which he later put in a seperate gist here:
https://gist.github.com/davidwhitney/1027181

Thank you for providing the adaption of this workaround more to my needs, because I had found the workaround too, but was still struggling to do the adaptation from MVC. Now I only needed to tweak your solution to put the RSS feed to the current Http request in the .ashx handler that I was using it in.

Basically I'm guessing that the fix you mentioned using the CDataSyndicationContent, is from feb 2011, assuming you got it from this post (at least I did):
SyndicationFeed: Content as CDATA?

This fix stopped working in some newer ASP.NET version or something, due to the code of the Rss20FeedFormatter changing to what you put in your post. This code change might as well have been an improvement for other stuff that IS in the MVC framework, but for those using the CDataSyndicationContent fix it definitely causes a bug!

平生欢 2024-12-08 14:04:26
string stylesheet = @"<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""><xsl:output cdata-section-elements=""description"" method=""xml"" indent=""yes""/></xsl:stylesheet>";
XmlReader reader = XmlReader.Create(new StringReader(stylesheet));
XslCompiledTransform t = new XslCompiledTransform(true);
t.Load(reader);

using (MemoryStream ms = new MemoryStream())
{
    XmlWriter writer = XmlWriter.Create(ms, t.OutputSettings);
    rssFeed.WriteTo(writer);  // rssFeed is Rss20FeedFormatter 
    writer.Flush();
    ms.Position = 0;
    string niko = Encoding.UTF8.GetString(ms.ToArray());
}

我确信已经有人指出了这一点,但这是我使用的一个愚蠢的解决方法。
t.OutputSettings 是 XmlWriterSettings 类型,其中 cdataSections 填充有单个 XmlQualifiedName“描述”。

希望它对其他人有帮助。

string stylesheet = @"<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""><xsl:output cdata-section-elements=""description"" method=""xml"" indent=""yes""/></xsl:stylesheet>";
XmlReader reader = XmlReader.Create(new StringReader(stylesheet));
XslCompiledTransform t = new XslCompiledTransform(true);
t.Load(reader);

using (MemoryStream ms = new MemoryStream())
{
    XmlWriter writer = XmlWriter.Create(ms, t.OutputSettings);
    rssFeed.WriteTo(writer);  // rssFeed is Rss20FeedFormatter 
    writer.Flush();
    ms.Position = 0;
    string niko = Encoding.UTF8.GetString(ms.ToArray());
}

I'm sure someone pointed this out already but this a stupid workaround I used.
t.OutputSettings is of type XmlWriterSettings with cdataSections being populated with a single XmlQualifiedName "description".

Hope it helps someone else.

厌味 2024-12-08 14:04:26

我在其他地方找到了 Cdata 的代码,

    public class CDataSyndicationContent : TextSyndicationContent
{
    public CDataSyndicationContent(TextSyndicationContent content)
        : base(content)
    {
    }

    protected override void WriteContentsTo(System.Xml.XmlWriter writer)
    {
        writer.WriteCData(Text);
    }
}

代码将其称为类似的内容:

item.Content = new Helpers.CDataSyndicationContent(new TextSyndicationContent("<span>TEST2</span>", TextSyndicationContentKind.Html));

但是“WriteContentsTo”函数没有被调用。

我尝试了 Atom10FeedFormatter,而不是 Rss20FeedFormatter - 并且它有效!
显然,这提供了 Atom feed,而不是传统的 RSS - 但值得一提。

输出代码为:

//var formatter = new Rss20FeedFormatter(feed);
    Atom10FeedFormatter formatter = new Atom10FeedFormatter(feed);
    using (var writer = XmlWriter.Create(response.Output, new XmlWriterSettings { Indent = true }))
    {
        formatter.WriteTo(writer);
    }

I found the code for Cdata elsewhere

    public class CDataSyndicationContent : TextSyndicationContent
{
    public CDataSyndicationContent(TextSyndicationContent content)
        : base(content)
    {
    }

    protected override void WriteContentsTo(System.Xml.XmlWriter writer)
    {
        writer.WriteCData(Text);
    }
}

Code to call it something along the lines:

item.Content = new Helpers.CDataSyndicationContent(new TextSyndicationContent("<span>TEST2</span>", TextSyndicationContentKind.Html));

However the "WriteContentsTo" function wasn't being called.

Instead of Rss20FeedFormatter I tried Atom10FeedFormatter - and it worked!
Obviously this gives Atom feed rather than traditional RSS - but worth mentioning.

Output code is:

//var formatter = new Rss20FeedFormatter(feed);
    Atom10FeedFormatter formatter = new Atom10FeedFormatter(feed);
    using (var writer = XmlWriter.Create(response.Output, new XmlWriterSettings { Indent = true }))
    {
        formatter.WriteTo(writer);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文