#c# #xmlreader
#c# #xmlreader
Вопрос:
Я хочу определить, изменился ли канал, единственный способ, который я могу придумать, — это хэшировать содержимое xml-документа и сравнивать его с последним хэшем канала.
Я использую XmlReader, потому что SyndicationFeed использует его, поэтому в идеале я не хочу загружать канал синдикации, если канал не был обновлен.
XmlReader reader = XmlReader.Create("http://www.extremetech.com/feed");
SyndicationFeed feed = SyndicationFeed.Load(reader);
Комментарии:
1. Каковы последствия столкновения хэшей? То есть предположим, что два документа имеют одинаковый хэш. Что самое худшее, что может случиться?
2. Я провел еще несколько тестов, если это ваш точный канал, в этом канале есть некоторые комментарии, которые периодически меняются, даже если теги xml без комментариев никогда не меняются, поэтому я не думаю, что хэш-подход вообще будет работать
3. @MerickOWA Я думаю, я просто использую идентификатор, который находится в SyndicationItem .. может быть проще 🙂 И таким образом, если заголовок или статья фида будут отредактированы, это не будет проблемой!
4. @superlogical Я добавил еще одну возможность, которая не зависит от хеширования и которая, вероятно, должна работать в целом, хотя она зависит от сервера.
Ответ №1:
Почему бы просто не проверить LastUpdatedTime фида? Это встроенный способ сообщить вам, является ли что-то новым или нет. Вместо хэширования и сохранения хэша вы бы просто отслеживали LastUpdatedTime и периодически сравнивали его с последним LastUpdatedTime:
using System;
using System.ServiceModel.Syndication;
using System.Xml;
public class MyClass
{
private static DateTime _lastFeedTime = new DateTime(2011, 10, 10);
public static void Main()
{
XmlReader reader = XmlReader.Create("http://www.extremetech.com/feed");
SyndicationFeed feed = SyndicationFeed.Load(reader);
if (feed.LastUpdatedTime.LocalDateTime > _lastFeedTime)
{
_lastFeedTime = feed.LastUpdatedTime.LocalDateTime;
// load feed...
}
}
}
Комментарии:
1. Да, я подумал об этом, но я просто не знаю, насколько это будет надежно, учитывая, что некоторые каналы могут не обновлять это значение. Но опять же, я могу быть совершенно неправ 🙂 Всегда ли WordPress хорошо справляется с этим? Большинство каналов, которые я хочу проиндексировать, будут основаны на WordPress
2. Значение LastUpdatedTime совершенно ненадежно, поскольку оно зависит от взаимодействующего сервера.
3. Сначала попробуйте использовать DateTime. Не предполагайте и не решайте проблему, если в этом нет необходимости. И да, вы зависите от третьей стороны, соответствующей стандарту, но это происходит постоянно. И я не могу придумать более полезную часть метаданных, чем LastUpdatedTime для соответствия. Несоблюдение должно привести к физическому наказанию. 😉
4. @PaulSasik Я думаю, я просто использую идентификатор, который находится в SyndicationItem
Ответ №2:
Если вы действительно хотите использовать хэш-способ, вы можете сделать следующее:
var client = new WebClient();
var content = client.DownloadData("http://www.extremetech.com/feed");
var hash = MD5.Create().ComputeHash(content);
var hashString = Convert.ToBase64String(hash);
// you can then compare hashes and if changed load it this way
XmlReader reader = XmlReader.Create(new MemoryStream(content));
Конечно, идя таким образом, вы обнаружите любые изменения в содержимом, даже малейшие.
ИМХО, лучший способ — загрузить фид в любом случае и хэшировать только содержимое статей, вы можете хэшировать любую строку следующим образом:
var toHash = "string to hash";
var hash = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(toHash);
var hashString = Convert.ToBase64String(hash);
Надеюсь, это поможет.
Ответ №3:
В этом случае хэш-подход не будет работать из-за комментария XML, добавленного некоторым кэшированием на стороне сервера, которое постоянно очень часто, даже когда фактический фид никогда не меняется.
Одна вещь, которую вы можете сделать, которая работает для этого фида, — это использовать условные запросы HTTP, чтобы попросить сервер предоставить вам данные, только если они действительно были изменены с момента последнего запроса.
Например:
У вас должна быть глобальная переменная / член для хранения даты и времени последнего изменения из вашего фида
var lastModified = DateTime.MinValue;
Затем каждый раз, когда вы делаете запрос, подобный следующему
var request = (HttpWebRequest)WebRequest.Create( "http://www.extremetech.com/feed" );
request.IfModifiedSince = lastModified;
try {
using ( var response = (HttpWebResponse)request.GetResponse() ) {
lastModified = response.LastModified;
using ( var stream = response.GetResponseStream() ) {
//*** parsing the stream
var reader = XmlReader.Create( stream );
SyndicationFeed feed = SyndicationFeed.Load( reader );
}
}
}
catch ( WebException e ) {
var response = (HttpWebResponse)e.Response;
if ( response.StatusCode != HttpStatusCode.NotModified )
throw; // rethrow an unexpected web exception
}
Комментарии:
1. 1 за правильное использование HTTP. Вы также можете использовать заголовок EXPIRES в ответе (если он есть) и метаданные в фиде (дата последнего обновления, период обновления и частота обновления), чтобы указать, когда / как часто вам следует проверять наличие обновлений.