2010-05-12 3 views
1

Код:System.ServiceModel.Syndication.SyndicationFeed бросает, когда RSS документ включает в себя <script> блок, встроенный в элемент

using (XmlReader xmlr = XmlReader.Create(new StringReader(allXml))) 
{ 
    var items = from item in SyndicationFeed.Load(xmlr).Items 
     select item; 
} 

Исключение:

Exception: System.Xml.XmlException: Unexpected node type Element. 
    ReadElementString method can only be called on elements with simple or empty content. Line 11, position 25. 
    at System.Xml.XmlReader.ReadElementString() 
    at System.ServiceModel.Syndication.Rss20FeedFormatter.ReadXml(XmlReader reader, SyndicationFeed result) 
    at System.ServiceModel.Syndication.Rss20FeedFormatter.ReadFeed(XmlReader reader) 
    at System.ServiceModel.Syndication.Rss20FeedFormatter.ReadFrom(XmlReader reader) 
    at System.ServiceModel.Syndication.SyndicationFeed.Load[TSyndicationFeed](XmlReader reader) 
    at System.ServiceModel.Syndication.SyndicationFeed.Load(XmlReader reader) 
    at Ionic.ToolsAndTests.ReadRss.Run() in c:\dev\dotnet\ReadRss.cs:line 90 

Содержание XML:

<?xml version="1.0" encoding="utf-8"?> 
<?xml-stylesheet type="text/xsl" href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/roller-ui/styles/rss.xsl" media="screen"?><rss version="2.0" 
    xmlns:dc="http://purl.org/dc/elements/1.1/" 
    xmlns:atom="http://www.w3.org/2005/Atom" > 
<channel> 
    <title>Software architecture, software engineering, and Renaissance Jazz</title> 
    <link>https://www.ibm.com/developerworks/mydeveloperworks/blogs/gradybooch</link> 
    <atom:link rel="self" type="application/rss+xml" href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/gradybooch/feed/entries/rss?lang=en" /> 
    <description>Software architecture, software engineering, and Renaissance Jazz</description> 
    <language>en-us</language> 
    <copyright>Copyright <script type='text/javascript'> document.write(blogsDate.date.localize (1273534889181));</script></copyright> 
    <lastBuildDate>Mon, 10 May 2010 19:41:29 -0400</lastBuildDate> 

Как вы можете видеть, в строке 11, в позиции 25, есть блок сценария внутри <copyright> элемент.

Прочие people have reported similar errors с другими документами XML.

Как я работал вокруг этого было сделать StreamReader.ReadToEnd, а затем сделать Regex.Replace на результат, что дергать блок сценария до прохождения модифицированной строки в XmlReader.Create(). Чувствует себя как взлома.


  1. Кто-нибудь есть лучший подход? Мне это не нравится, потому что я должен читать строку 125k в памяти.

  2. Действительно ли rss включает «сложный контент», такой как блок сценария внутри элемента?

+0

Посмотрите на XSD для RSS и посмотреть, что содержание действительно для элемент ''. Скорее всего, просто текст. –

+0

ну нет формального RSS2.0 XSD, но Jorgen Thelin создал тот, который довольно хорош, доступен по адресу http://rss2schema.codeplex.com/. * Формальное * определение RSS 2.0 представлено в англоязычном HTML-документе: http://cyber.law.harvard.edu/rss/rss.html. Для элемента авторского права или любого элемента не существует типа W3C. Есть только примеры. В схеме XSD от Thelin авторское право - это xs: string, что означает, что он не должен включать угловые скобки. Я думаю, что rss, предоставленный IBM в этом случае, нарушен, несовместим. Но браузеры проглатывают его, потому что они делают скрипт. – Cheeso

+1

ps: Встраивание javascript в RSS кажется грубым нарушением одного или нескольких моральных или эстетических стандартов. – Cheeso

ответ

0

Вы можете создать подкласс XmlTextReader и переопределить ReadElementString пропустить или изменить элемент обижая, как это читается. Все еще чувствует себя как хак, но, по крайней мере, избегает предварительной обработки с помощью регулярного выражения.

Вот простая реализация, которая получает работу:


class BrokenFeedXmlReader : XmlTextReader 
{ 
    // Additional XmlTextReader constructors can be added in 
    // similar fashion as needed 
    public BrokenFeedXmlReader(TextReader input) 
     : base(input) 
    { 
    } 

    public override string ReadElementString() 
    { 
     if ("copyright" == Name) 
     { 
      base.Skip(); 
      return String.Empty; 
     } 

     return base.ReadElementString(); 
    }    
} 

Ваш пример кода будет выглядеть примерно так:


using (XmlReader xmlr = new BrokenFeedXmlReader(new StringReader(allXml))) 
{ 
    var items = from item in SyndicationFeed.Load(xmlr).Items 
       select item; 
}