我编写了一段代码,使用System.ServiceModel.Syndication
库来解析RSS提要。
问题是,对于我的一个提要(由facebook提供),我在响应结束时得到以下行,并且Syndication库无法解析提要,因为它说文本是无效的XML并且它说它是因为这部分:
...
</channel>
<access:restriction relationship="deny" xmlns:access="http://www.bloglines.com/about/specs/fac-1.0" />
</rss>
我确信这里有一些东西,因为提要和解析库都来自大公司(分别是Facebook和微软)。
你们任何人都可以帮忙吗?或者更好的解析器,它不依赖于XML的有效性?
P.S。这是我的RSS提要网址:
http://www.facebook.com/feeds/page.php?id=202296766494181&format=rss20
以下是我正在解析Feed响应的方法:
var stringReader = new StringReader(resp);
var xreader = XmlReader.Create(stringReader);
var xfeed = System.ServiceModel.Syndication.SyndicationFeed.Load(xreader);
我得到的例外:
System.Xml.XmlException: 'Element' is an invalid XmlNodeType. Line 282, position 4.
在System.Xml.XmlReader.ReadEndElement()...
答案 0 :(得分:8)
似乎SyndicationFeed遇到了facebook使用的access:restriction元素的问题。查看http://social.msdn.microsoft.com/Forums/ar/xmlandnetfx/thread/7045dc1c-1bd9-409a-9568-543e74f4578d
上的最近帖子 Michael Sun(MSFT)写道:“刚看到Martin的帖子!非常有帮助!我也对这个问题进行了一些研究。这个元素来自Bloglines,http://www.bloglines.com/index.html。这听起来像facebook正在使用它的RSS 2.0 feed,http://www.feedforall.com/access-namespace.htm。从这篇文章看,似乎Rss20FeedFormatter并不是唯一不支持元素的人。我同意Martin使用XDocument(LINQ to XML)来解析RSS提要。或者,如果您通过C#构建一些大型应用程序,Facebook C#SDK也可以提供帮助,http://facebooksdk.codeplex.com/“
编辑:
然而,似乎Atomfeed没有遭受这个问题。这么简单的解决方案
将使用此链接(http://www.facebook.com/feeds/page.php?id=202296766494181&format=atom10)。从而将格式参数从rss20更改为 atom10
HttpWebRequest req = WebRequest.Create(@"http://www.facebook.com/feeds/page.php?id=202296766494181&format=atom10") as HttpWebRequest;
req.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";
using (Stream responseStream = req.GetResponse().GetResponseStream())
{
using (XmlReader xr = XmlReader.Create(responseStream))
{
SyndicationFeed feed = SyndicationFeed.Load(xr);
}
}
其他替代方法是在通道关闭标记之后跳过任何元素来编写一个覆盖ReadEndElement方法的继承XMLTextReader。(请注意下面的代码没有任何保证,因为我认为自己仍然是新手c#开发人员。请随时纠正任何可能的错误)
public class FaceBookReader : XmlTextReader
{
public FaceBookReader(Stream stream)
: base(stream) { }
public FaceBookReader(String url)
: base(url) { }
public override void ReadEndElement()
{
string elementTag = this.LocalName.ToLower();
base.ReadEndElement();
// When we've read the channel End Tag, we're going to skip all tags
// until we reach the a new Ending Tag which should be that of rss
if (elementTag == "channel")
{
while (base.IsStartElement())
{
base.Skip();
}
}
}
}