System.ServiceModel.Syndication.SyndicationFeed выдает, когда документ RSS содержит блок <script>, встроенный в элемент - PullRequest
1 голос
/ 12 мая 2010

код:

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> находится блок скрипта.

Другие люди сообщили о подобных ошибках с другими документами XML.

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


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

  2. Допустимо ли rss включать «сложное содержимое», подобное этому, - блок скрипта внутри элемента?

1 Ответ

0 голосов
/ 18 июля 2010

Вы можете создать подкласс 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;
} 
...