Ваш город: г. Москва

1С-Битрикс: Управление сайтом ASP.Net: расширенная агрегация RSS

Попробуем в рамках лицензионной программы «1С-Битрикс: Управление сайтом ASP. NET» осуществить расширенную агрегацию RSS в информационные блоки. Под расширенной агрегацией понимаем следующее: возможность получения и распределения RSS сообщений по различным папкам в зависимости от ключевых слов, заданных в свойствах информационного блока.

Ключевым моментом технологии продуктов компании 1С-Битрикс для любой платформы (PHP, ASP.NET) является информационный блок.

Информационный блок - сущность, позволяющая каталогизировать и управлять различными типами (блоками) однородной информации.

Информационный блок позволяет очень гибко подходить к информации любого типа, хранить, обрабатывать и выводить ее в нужном для пользователя качестве и виде. В нашем примере информационный блок будет использован как инструмент для расширенной агрегации RSS.

RSS — семейство XML-форматов, предназначенных для описания лент новостей, анонсов статей, изменений в блогах и т. п. Технология, родившаяся из потребностей представить на своем сайте самую актуальную и свежую информацию.

Попробуем в рамках «1С-Битрикс: Управление сайтом ASP. NET» осуществить расширенную агрегацию RSS в информационные блоки. Под расширенной агрегацией понимаем следующее: возможность получения и распределения RSS сообщений по различным папкам в зависимости от ключевых слов, заданных в свойствах информационного блока.

Решаемая задача

Реальная задача, которая может решаться такой расширенной агрегацией. Сайт сообщества по какой-либо тематике нуждается в получении и сортировке большого числа новостей с разных источников.

Предположим, что вы создаете на базе решения «Сайт сообщества» CMS «1С-Битрикс: Управление сайтом ASP.NET» некий Клуб любителей новых технологий. Вам с нескольких источников приходят новости IT-технологий «вообще», то есть и новости программного обеспечения и новости компьютерного «железа». Эти новости нужно рассортировать по темам и вывести на разных страницах сайта.

Предлагаемый здесь вариант позволяет сортировать сообщения по папкам любой глубины вложения. То есть, например, раздел по программному обеспечению можно делить до сколь угодно подробной рубрикации, вплоть до отдельных программ, а в случае с «железом» до отдельного вида продукции конкретного производителя.

Для решения задачи расширенной агрегации нам нужно сделать следующее:

· Создать тип информационного блока, который будет обслуживать решение задачи.

· Создать отдельный информационный блок (ib1) для RSS сообщений.

· Создать отдельный информационный блок (ib2) для вывода сообщений на страницах сайта.

· Создать структуру разделов в рамках ib2 для вывода на страницах сайта.

· Создать файлы, обслуживающие агрегатор RSS.

· Создать страницы на сайте и обеспечить вывод данных из ib2 стандартными средствами CMS.

Чтобы легче было понять о смысл этой задачи, посмотрите рабочий пример такой расширенной интеграции: http://www.gotdotnet.ru/technologies/.

Создание Типа инфоблока

Создание Типа информационного блока выполняется обычным для "1С-Битрикс: Управление сайтом ASP.NET" способом на странице Контент > Информ. блоки > Типы информ. блоков в Административной части системы. Единственный нюанс, который надо учесть – это установить флажок в поле Использовать древовидный классификатор элементов по разделам, так как нам надо будет использовать разделы для вывода RSS новостей. Пусть тип инфоблока называется Aggregator.

1С-Битрикс
Создание типа инфоблока

Создание первого инфоблока

В рамках созданного типа инфоблока создадим первый инфоблок. Создание инфоблока происходит на странице Контент > Aggregator в Административной части системы.

Ib1 отвечает за получение самих RSS сообщений с сайта-источника. Поэтому при создании инфоблока нам нужно создать поля элементов информационного блока, обеспечивающие выполнение этой задачи. Вот эти поля:

· Адрес RSS (код SOURCE_URL). Поле для ввода адреса подписки.

· Период загрузки RSS в часах (код PERIOD). Указание для системы как часто проверять новые сообщения на сайте-источнике.

· Время хранения записей в днях (0 - навсегда) (код STORAGE_TIME). Параметр, по которому будет проставляться период активности записи. Начало активности – это дата загрузки, конец активности – это дата загрузки + число дней, указанных в этом поле.

· Имя автора записей по умолчанию (код AUTHOR_NAME). Поле для указания автора записи, как правило, это выводимое название источника.

· Автоматические теги для записей подписки (код TAGS). Поле для задания собственных тегов. Применяется для подписок, в тематике которых разработчик уверен. При распределении новостей по разделам система будет складывать теги сообщения и теги, введенные в это поле, и по этой сумме производить сортировку.

· Загружать только анонс (ссылка записи будет открывать оригинальный сайт) (код PREVIEW_ONLY). Система будет загружать только анонсы сообщений, детальное сообщение будет просматриваться пользователем на сайте-источнике. Рекомендуется для сайтов с большой посещаемостью.

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

1С-Битрикс
Свойства элементов ib1

Создание второго инфоблока

Второй инфоблок служит непосредственно инструментом вывода RSS новостей для показа пользователям сайта. Поэтому он получается несколько сложнее. Надо будет создавать не только поля для свойств для элементов, но и поля свойств для разделов.

Поля свойств для элементов информационного блока:

· Имя автора (код AUTHOR_NAME). Проставляется системой автоматически из свойств сообщения.

· Ссылка на оригинал записи (код SOURCE_URL). Проставляется системой автоматически из свойств сообщения.

· Ссылка на комментарии (код COMMENTS_URL). Проставляется системой автоматически из свойств сообщения.

1С-Битрикс
Свойства элементов ib2

Поле свойств для разделов ib2 необходимо только одно: Время хранения записей в днях (0 - навсегда) с кодом STORAGE_TIME. Значение поля аналогично значению одноименного свойства в ib1.

1С-Битрикс
Свойства разделов ib2

Создание элемента инфоблока ib1

Создавая элемент ib1 мы создаем подписку на определенный канал RSS. Для создания подписки просто заполните поля формы создания элемента:

1С-Битрикс
Создание подписки

Создание разделов во втором инфоблоке

Создание структуры разделов ib2 выполняется типовым для CMS способом. Вложенность разделов может быть произвольной.

1С-Битрикс
Созданная структура разделов ib2

При создании разделов необходимо использовать штатное поле раздела Внешний ключ закладки Дополнительно для ввода ключевых слов, по которым будут распределяться загруженные новости. В поле Внешний ключ может быть добавлено несколько ключевых слов. Ключевые слова могут повторяться в разных папках. Сообщение будет добавлено в каждую папку, в которой есть хотя бы одно ключевое слово.

1С-Битрикс
Заполняем поле Внешний ключ

Для задания ограничения хранения новостей по времени используется свойство Время хранения записей в днях.

Создание файлов, обслуживающих агрегатор RSS

Для работы создаваемого механизма не достаточно штатных возможностей "1С-Битрикс: Управление сайтом ASP.NET". Необходимо создать еще несколько файлов, которые и будут выполнять функцию сортировки и контроля за актуальностью сообщений.

Для начала необходимо в корне сайта создать папку App_Code, где будут размещены файлы, обслуживающие агрегатор. Это стандартная для ASP.NET папка для файлов с пользовательским кодом.

После этого создадим три файла:

Agent.cs – код технологии агентов. При любом изменении элементов вышеописанных инфоблоков автоматически перенастраиваются агенты. Перенастройка агентов производится системными обработчиками событий.

Агенты - это технология, позволяющая запускать произвольный .NET код (агенты) с заданной периодичностью.

Event.cs – код обработчиков событий.

Иногда бывает необходимо повлиять на ход выполнения какой-нибудь API функции. Но если ее изменить, то эти изменения будут утеряны при очередном обновлении. Для таких случаев и разработана система событий. В ходе выполнения некоторых API функций, в определённых точках установлены вызовы определенных функций, так называемых обработчиков события.

Tech.cs – код непосредственно для загрузки новостей.

Совместная работа этих файлов создает три типа агентов:

Первый. Для каждой подписки создается свой собственный агент, который работает в фоновом режиме. Он производит анализ тегов приходящих сообщений в рамках работы ib1, сортирует их и распределяет по разделам ib2.

Второй. Агент на удаление записей, чей срок активности истек.

Третий. Агент на удаление записей, чей срок истек по настройкам ib1, а не по настройкам раздела.

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

Коды файлов:

Agent.cs

using System;
using Bitrix.DataLayer;
using Bitrix.DataTypes;
using Bitrix.IBlock;
using Bitrix.Services;

namespace Bitrix.Demo
{

public class AggregatorRssDownloadExecutor : IBXAgentExecutor
{
public bool Execute(BXSchedulerAgent agent, BXParamsBag<object> parameters)
{
object param;
BXIBlockElement element;
if (parameters == null || !parameters.TryGetValue("ElementId", out param) || (element = BXIBlockElement.GetById(param)) == null)
{
//Удаляем агент если элемента-подписки не существует
agent.Delete();
return false;
}

RssFeedSettings settings = Aggregator.GetSettings(element);

if (!element.Active || settings == null)
{
//если элемент неактивный - агент тоже неактивный
agent.Active = false;
return true;
}

try
{
Aggregator.LoadRssItems(settings);
//выставляем период, заданный в настройках подписки
agent.Period = TimeSpan.FromHours(settings.AgentPeriod);
}
catch (Exception ex)
{
BXLogService.LogAll(ex, BXLogMessageType.Error, String.Format("Aggregator. Ошибка загрузки RSS. (ID={0})", element.Id));

//увеличиваем период запуска
agent.Period = agent.Period.Add(new TimeSpan(1,0,0));
}

return true;
}
}
public class AggregatorRemoveItemsInSection : IBXAgentExecutor
{
public bool Execute(BXSchedulerAgent agent, BXParamsBag<object> parameters)
{
object param;
BXIBlockSection section;
if (parameters == null || !parameters.TryGetValue("SectionId", out param)
|| (section = BXIBlockSection.GetById(param)) == null || section.CustomPublicValues.GetInt32("STORAGE_TIME", 0) <= 0)
{
agent.Delete();
return false;
}

int maxElements = 30;
if (parameters.ContainsKey("MaxElements") && parameters["MaxElements"] is int)
maxElements = (int)parameters["MaxElements"];

int days = section.CustomPublicValues.GetInt32("STORAGE_TIME", 30);

BXIBlockElementCollection elements = BXIBlockElement.GetList(
new BXFilter(
new BXFilterItem(BXIBlockElement.Fields.CreateDate, BXSqlFilterOperators.LessOrEqual, DateTime.Now.AddDays(-(days + 1))), //+1 день - погрешность запусков агентов по загрузке и удалению записей.
new BXFilterItem(BXIBlockElement.Fields.Sections.Section.ID, BXSqlFilterOperators.Equal, section.Id)
),
null,
new BXSelectAdd(BXIBlockElement.Fields.Sections.Section.ID),
new BXQueryParams(new BXPagingOptions(0, maxElements))
);

foreach (BXIBlockElement element in elements)
{
//Если привязка к одной секции
if (element.Sections.Count <= 1)
{
if (element.ActiveFromDate == DateTime.MinValue)
{
//деактивируем, если запись без даты
element.Active = false;
element.Save();
}
else
{
//удаляем
element.Delete();
}
}
else
{
//иначе отвязываем элемент от секции
foreach (var link in element.Sections)
{
if (link.SectionId == section.Id)
{
element.Sections.Remove(link);
element.Save();
break;
}
}
}
}

return true;
}
}
public class AggregatorRemoveInactiveIBlockItems : IBXAgentExecutor
{
public bool Execute(BXSchedulerAgent agent, BXParamsBag<object> parameters)
{
object param;
BXIBlock iblock;
if (parameters == null || !parameters.TryGetValue("IBlockId", out param) || (iblock = BXIBlock.GetById(param)) == null)
{
agent.Delete();
return false;
}

int maxElements = 30;
if (parameters.ContainsKey("MaxElements") && parameters["MaxElements"] is int)
maxElements = (int)parameters["MaxElements"];

BXIBlockElementCollection elements = BXIBlockElement.GetList(
new BXFilter(
new BXFilterItem(BXIBlockElement.Fields.ActiveDate, BXSqlFilterOperators.Equal, false),
new BXFilterItem(BXIBlockElement.Fields.IBlock.ID, BXSqlFilterOperators.Equal, iblock.Id)
),
null,
null,
new BXQueryParams(new BXPagingOptions(0, maxElements))
);

foreach (BXIBlockElement element in elements)
element.Delete();

return true;
}
}
}

Event.cs

using System;
using System.Web.Configuration;
using Bitrix.IBlock;
using Bitrix.Modules;
using Bitrix.Services;

namespace Bitrix.Demo
{
[BXMessageReceiver]
public static class EventHandlers
{
//Создание элемента инфоблока
[BXEventListener("Bitrix.IBlock.IBlockElement.OnAfterCreate")]
public static void OnIBlockElementCreate(BXCommand command)
{
BXIBlockElement element = command.Parameters["Entity"] as BXIBlockElement;
if (element == null || !String.Equals(element.IBlockId.ToString(), WebConfigurationManager.AppSettings["RssFeedsIBlockId"], StringComparison.Ordinal))
return;

BXSchedulerAgent agent = new BXSchedulerAgent("Bitrix.Demo.Aggregator.Feed." + element.Id);

agent.Active = element.Active;
agent.Periodic = false;
agent.Period = TimeSpan.FromDays(0.5);
agent.StartTime = DateTime.Now.AddMinutes(0.1);
agent.Parameters["ElementId"] = element.Id;
agent.SetClassNameAndAssembly(typeof(AggregatorRssDownloadExecutor));
agent.Save();

}

//Обновление элемента инфоблока
[BXEventListener("Bitrix.IBlock.IBlockElement.OnAfterUpdate")]
public static void OnIBlockElementUpdate(BXCommand command)
{
BXIBlockElement element = command.Parameters["Entity"] as BXIBlockElement;
if (element == null || !String.Equals(element.IBlockId.ToString(), WebConfigurationManager.AppSettings["RssFeedsIBlockId"], StringComparison.Ordinal))
return;

BXSchedulerAgent agent = BXSchedulerAgent.GetByName("Bitrix.Demo.Aggregator.Feed." + element.Id);
if (agent != null)
{
agent.StartTime = DateTime.Now.AddMinutes(0.1);
agent.Active = element.Active;
agent.Save();
}
else
OnIBlockElementCreate(command);
}

//Создание раздела инфоблока
[BXEventListener("Bitrix.IBlock.IBlockSection.OnAfterCreate")]
public static void OnIBlockSectionCreate(BXCommand command)
{
BXIBlockSection section = command.Parameters["Entity"] as BXIBlockSection;
if (section == null || !String.Equals(section.IBlockId.ToString(), WebConfigurationManager.AppSettings["TechnologyIBlockId"], StringComparison.Ordinal))
return;

Aggregator.ClearTechnologyTreeCache();

BXSchedulerAgent agent = new BXSchedulerAgent("Bitrix.Demo.Aggregator.Technology." + section.Id);

agent.Active = section.Active;
agent.Periodic = false;
agent.Period = TimeSpan.FromDays(0.6);
agent.StartTime = DateTime.Now.AddMinutes(1.0);
agent.Parameters["SectionId"] = section.Id;
agent.SetClassNameAndAssembly(typeof(AggregatorRemoveItemsInSection));
agent.Save();

}

//Обновление раздела инфоблока
[BXEventListener("Bitrix.IBlock.IBlockSection.OnAfterUpdate")]
public static void OnIBlockSectionUpdate(BXCommand command)
{
BXIBlockSection section = command.Parameters["Entity"] as BXIBlockSection;
if (section == null || !String.Equals(section.IBlockId.ToString(), WebConfigurationManager.AppSettings["TechnologyIBlockId"], StringComparison.Ordinal))
return;

Aggregator.ClearTechnologyTreeCache();

BXSchedulerAgent agent = BXSchedulerAgent.GetByName("Bitrix.Demo.Aggregator.Technology." + section.Id);
if (agent != null)
{
agent.StartTime = DateTime.Now.AddMinutes(1);
agent.Active = section.Active;
agent.Save();
}
else
OnIBlockSectionCreate(command);
}
}
}

Tech.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Configuration;
using Bitrix.DataLayer;
using Bitrix.IBlock;
using Bitrix.Services;
using Bitrix.Services.Syndication;
using Bitrix.Services.Text;

namespace Bitrix.Demo
{
public class RssFeedSettings
{
private string url;
private int iblockId;
private int agentPeriod;
private int elementActivePeriod;
private string defaultAuthorName;
private bool onlyPreview;
private string[] automaticTags;

public string DefaultAuthorName
{
get { return defaultAuthorName; }
set { defaultAuthorName = value; }
}

public string Url
{
get { return url; }
set { url = value; }
}

public int IBlockId
{
get { return iblockId; }
set { iblockId = value; }
}

public int AgentPeriod
{
get { return agentPeriod; }
set { agentPeriod = value; }
}

public int ElementActivePeriod
{
get { return elementActivePeriod; }
set { elementActivePeriod = value; }
}

public bool OnlyPreview
{
get { return onlyPreview; }
set { onlyPreview = value; }
}

public string[] AutomaticTags
{
get { return automaticTags; }
set { automaticTags = value; }
}

public RssFeedSettings(string url, int iblockId, string defaultAuthorName)
{
this.url = url;
this.defaultAuthorName = defaultAuthorName;
this.iblockId = iblockId;

this.agentPeriod = 10;
this.elementActivePeriod = 0;
this.onlyPreview = false;
}
}

public class TechnologyItem
{
private string code;
private int id;
private List<TechnologyItem> childs;
private TechnologyItem defaultChild;
private int storageTime;

public string Code
{
get { return code; }
}

public int Id
{
get { return id; }
}

public TechnologyItem DefaultChild
{
get { return defaultChild; }
set { defaultChild = value; }
}

public int StorageTime
{
get { return storageTime; }
set { storageTime = value; }
}

public List<TechnologyItem> Childs
{
get { return childs ?? (childs = new List<TechnologyItem>()); }
}

public TechnologyItem(int id, string code, int storageTime)
: this(id, code)
{
this.storageTime = storageTime;
}

public TechnologyItem(int id, string code)
{
this.id = id;
this.code = code;
}

}

public static class Aggregator
{
static List<TechnologyItem> technoloryTree = null;

public static void LoadRssItems(RssFeedSettings settings)
{
BXRss20Feed feed = BXRss20Feed.CreateByUrl(settings.Url, 1000 * 20);

if (feed == null || feed.Channels.Count < 1)
return;

foreach (BXRss20ChannelItem item in feed.Channels[0].Items)
{
string guid = GetItemGuid(item);
if (BXStringUtility.IsNullOrTrimEmpty(item.Title) || BXStringUtility.IsNullOrTrimEmpty(item.Description) ||
BXStringUtility.IsNullOrTrimEmpty(item.Link) || guid == null)
continue;

if (settings.AutomaticTags != null)
foreach (string tag in settings.AutomaticTags)
item.Categories.Add(new BXRss20Category(tag));

var technologySections = GetSections(item);
if (technologySections.Count < 1)
continue;

BXIBlockElement element = GetElement(guid, item.Link, settings.IBlockId);
if (element == null)
{
string preview = GetPreview(item.Description, 400);
if (BXStringUtility.IsNullOrTrimEmpty(preview))
continue;

try
{
element = new BXIBlockElement();
element.Name = item.Title;
element.PreviewTextType = BXTextType.Text;
element.DetailTextType = BXTextType.Html;
element.IBlockId = settings.IBlockId;
element.XmlId = guid;
element.PreviewText = preview;

//Сохраняем орининальную дату
if (item.PubDate.HasValue)
element.ActiveFromDate = item.PubDate.Value;

//Если для записей подписки указано время жизни
if (settings.ElementActivePeriod > 0)
element.ActiveToDate = DateTime.Now.AddDays(settings.ElementActivePeriod);

if (!settings.OnlyPreview)
element.DetailText = item.Description;

element.Sections.AddRange(technologySections);

string tags = "";
foreach (var tag in item.Categories)
{
if (!String.IsNullOrEmpty(tags))
tags += ", ";
tags += tag.Name;
}
element.Tags = tags;

element.CustomPublicValues["AUTHOR_NAME"] = GetAuthorName(item, settings.DefaultAuthorName);
element.CustomPublicValues["SOURCE_URL"] = item.Link;
element.CustomPublicValues["COMMENTS_URL"] = BXStringUtility.IsNullOrTrimEmpty(item.Comments) ? item.Link : item.Comments;

element.Save();
}
catch (Exception ex)
{
BXLogService.LogAll(ex, BXLogMessageType.Error, String.Format("Aggregator. Ошибка сохранения элемента.({0}) ", item.Link));
}
}
}
}

public static RssFeedSettings GetSettings(BXIBlockElement iblockElement)
{
RssFeedSettings settings = null;
if (iblockElement == null)
return settings;

string url = iblockElement.CustomPublicValues.GetString("SOURCE_URL");
string defaultAuthorName = iblockElement.CustomPublicValues.GetString("AUTHOR_NAME");
int iblockId;

if (!BXStringUtility.IsNullOrTrimEmpty(url) && !BXStringUtility.IsNullOrTrimEmpty(defaultAuthorName) && int.TryParse(WebConfigurationManager.AppSettings["TechnologyIBlockId"], out iblockId))
{
settings = new RssFeedSettings(url, iblockId, defaultAuthorName);
settings.AgentPeriod = iblockElement.CustomPublicValues.GetInt32("PERIOD", 10);
settings.ElementActivePeriod = iblockElement.CustomPublicValues.GetInt32("STORAGE_TIME", 0);
settings.OnlyPreview = iblockElement.CustomPublicValues.GetBoolean("PREVIEW_ONLY", false);

string tags = iblockElement.CustomPublicValues.GetString("TAGS");
if (tags != null && !BXStringUtility.IsNullOrTrimEmpty(tags))
settings.AutomaticTags = tags.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}

return settings;
}

public static void ClearTechnologyTreeCache()
{
technoloryTree = null;
}

public static void InitTechnologyTree()
{
technoloryTree = new List<TechnologyItem>();

int iblockId;
if (!int.TryParse(WebConfigurationManager.AppSettings["TechnologyIBlockId"], out iblockId))
return;

BXIBlockSectionCollection sections = BXIBlockSection.GetList(
new BXFilter(
new BXFilterItem(BXIBlockSection.Fields.IBlock.ID, BXSqlFilterOperators.Equal, iblockId),
new BXFilterItem(BXIBlockSection.Fields.ActiveGlobal, BXSqlFilterOperators.Equal, "Y"),
new BXFilterItem(BXIBlockSection.Fields.DepthLevel, BXSqlFilterOperators.LessOrEqual, 2)
),
new BXOrderBy(new BXOrderByPair(BXIBlockSection.Fields.LeftMargin, BXOrderByDirection.Asc)),
null,
null,
BXTextEncoder.EmptyTextEncoder
);

TechnologyItem previousSection = null;
foreach (BXIBlockSection section in sections)
{
string code = GetTechnologyItemsTag(section);
int storageTime = section.CustomPublicValues.GetInt32("STORAGE_TIME", 0);

if (section.DepthLevel == 1)
{
previousSection = new TechnologyItem(section.Id, code, storageTime);
technoloryTree.Add(previousSection);
}
else if (section.DepthLevel == 2 && previousSection != null)
{
TechnologyItem child = new TechnologyItem(section.Id, code, storageTime);
if (code == null)
previousSection.DefaultChild = child;
previousSection.Childs.Add(child);
}
}
}

private static string GetTechnologyItemsTag(BXIBlockSection section)
{
if (section == null || BXStringUtility.IsNullOrTrimEmpty(section.XmlId))
return null;

StringBuilder result = new StringBuilder();
string[] tags = section.XmlId.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
foreach (string tag in tags)
{
result.Append('{');
result.Append(tag.Trim());
result.Append('}');
}

return result.ToString().ToUpper();
}

private static BXIBlockElement GetElement(string guid, string url, int iblockId)
{
BXIBlockElementCollection elements = BXIBlockElement.GetList(
new BXFilter(
new BXFilterItem(BXIBlockElement.Fields.IBlock.ID, BXSqlFilterOperators.Equal, iblockId),
new BXFilterItem(BXIBlockElement.Fields.XmlId, BXSqlFilterOperators.Equal, guid)
),
null
);

//Если элементов с таким xmlId несколько, сравним их адреса
if (elements.Count > 1)
{
BXIBlockElement trueElement = null;
foreach (var element in elements)
{
if (element.CustomValues != null && String.Equals(element.CustomPublicValues.GetString("SOURCE_URL"), url, StringComparison.OrdinalIgnoreCase))
{
trueElement = element;
break;
}
}
return trueElement ?? elements[0];
}
else if (elements.Count == 1)
return elements[0];
else
return null;
}

private static string GetPreview(string originalText, int maxLength)
{
string preview = BXStringUtility.StripOffSimpleTags(originalText);
preview = HttpUtility.HtmlDecode(preview);
preview = preview.Trim(' ', '\n', '\t', '\r');

if (maxLength > 0 && preview.Length > maxLength)
preview = preview.Substring(0, maxLength) + " ...";

return preview;
}

private static BXIBlockElement.BXInfoBlockElementSectionCollection GetSections(BXRss20ChannelItem rssItem)
{
BXIBlockElement.BXInfoBlockElementSectionCollection result = new BXIBlockElement.BXInfoBlockElementSectionCollection();

if (technoloryTree == null)
InitTechnologyTree();

List<TechnologyItem> rootSections = GetSection(rssItem, technoloryTree, false);
foreach (TechnologyItem rootSection in rootSections)
{
List<TechnologyItem> childSections = GetSection(rssItem, rootSection.Childs, false);

if (childSections.Count > 0)
{
result.Add(childSections[0].Id);
}
else if (rootSection.DefaultChild != null && !(rootSection.DefaultChild.StorageTime > 0 && rssItem.PubDate.HasValue && rssItem.PubDate.Value <= DateTime.Now.AddDays(-rootSection.DefaultChild.StorageTime)))
{
//если никуда не попал, значит в дефолтовую категорию
result.Add(rootSection.DefaultChild.Id);
}
}

return result;
}

private static List<TechnologyItem> GetSection(BXRss20ChannelItem rssItem, IEnumerable<TechnologyItem> sections, bool onlyFirst)
{
List<TechnologyItem> result = new List<TechnologyItem>();

foreach (var category in rssItem.Categories)
{
if (BXStringUtility.IsNullOrTrimEmpty(category.Name))
continue;

string categoryName = String.Concat("{", category.Name.ToUpper().Trim(), "}");

foreach (TechnologyItem item in sections)
{
//если дата записи меньше, чем время хранения в разделе, то не добавляем такой элемент
if (item.StorageTime > 0 && rssItem.PubDate.HasValue && rssItem.PubDate.Value <= DateTime.Now.AddDays(-item.StorageTime))
continue;

if (item.Code != null && item.Code.IndexOf(categoryName) != -1 && !result.Contains(item))
{
result.Add(item);

if (onlyFirst)
return result;
}
}
}

return result;
}

private static string GetItemGuid(BXRss20ChannelItem item)
{
string guid = null;

if (item.Guid != null && !BXStringUtility.IsNullOrTrimEmpty(item.Guid.Guid))
guid = item.Guid.Guid;
else if (!BXStringUtility.IsNullOrTrimEmpty(item.Link))
guid = item.Link;

return guid;
}

private static string GetAuthorName(BXRss20ChannelItem item, string defaultName)
{
foreach (var tag in new[] { "dc:creator", "lj:poster" })
{
var names = item.ElementExtensions.FindByName(tag);
if (names.Length > 0 && !BXStringUtility.IsNullOrTrimEmpty(names[0].InnerXml))
return names[0].InnerXml;
}

if (!BXStringUtility.IsNullOrTrimEmpty(item.Author))
return item.Author;

return defaultName;
}
}
}

Вывод данных на страницах сайта

Вывод полученных новостей на страницах сайта осуществляется типовыми компонентами системы "1С-Битрикс: Управление сайтом ASP.NET". Например, можно использовать комплексный компонент Каталог, разместив его на нужной странице и настроив на тип информационного блока Aggregator и на информационный блок ib2.

1С-Битрикс
Выведенные анонсы RSS сообщения на странице сайта

Резюме

Система "1С-Битрикс: Управление сайтом ASP.NET" обладает достаточно гибкими возможностями в плане модификаций. Возможно как редактирование самих компонентов системы, их шаблонов, так и использование сторонних файлов, обращающихся к API системы. Успех решения той или иной задачи во многом зависит от уровня подготовки программиста.

Роберт Басыров

Все права защищены. По вопросам использования статьи обращайтесь к администраторам сайта

Вы можете оставить комментарий:

Хотите обсудить вопрос по Вашей задаче?

Введите интересующую информацию и наш менеджер Вам ответит