Преобразование календаря Google в DDay.iCal

#c# #google-api #deserialization #icalendar #dday

#c# #google-api #десериализация #icalendar #dday

Вопрос:

Я работаю над приложением, которое переводит Календарь Google через Google API в DDay.iCal

Основные атрибуты, свойства обрабатываются легко … ev.Summary = evt.Название.Текст;

Проблема в том, что когда я получаю повторяющееся событие, XML содержит поле типа:

 <gd:recurrence>
    DTSTART;VALUE=DATE:20100916
    DTEND;VALUE=DATE:20100917
    RRULE:FREQ=YEARLY
</gd:recurrence>
  

или

 <gd:recurrence>
  DTSTART:20100915T220000Z
  DTEND:20100916T220000Z
  RRULE:FREQ=YEARLY;BYMONTH=9;WKST=SU"
</gd:recurrence>
  

используя следующий код:

     String[] lines = 
evt.Recurrence.Value.Split(new char[] { 'n', 'r' }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (String line in lines)
                    {

                        if (line.StartsWith("R"))
                        {
                            RecurrencePattern rp = new RecurrencePattern(line);
                            ev.RecurrenceRules.Add(rp);
                        }
                        else 
                        {
                            ISerializationContext ctx = new SerializationContext();
                            ISerializerFactory factory = new DDay.iCal.Serialization.iCalendar.SerializerFactory();

                            ICalendarProperty property = new CalendarProperty();

                            IStringSerializer serializer = factory.Build(property.GetType(), ctx) as IStringSerializer;

                            property = (ICalendarProperty)serializer.Deserialize(new StringReader(line));

                            ev.Properties.Add(property);
                            Console.Out.WriteLine(property.Name   " - "   property.Value);
                        }

                    }
  

RRULEs проанализированы правильно, но проблема в том, что другие значения свойства (datetimes) пусты…

Комментарии:

1. Вы имели в виду использовать двоеточия после DTSTART и DTEND в вашем первом примере? И подразумевается ли двойная кавычка после SU во втором примере?

Ответ №1:

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

RRULE:(?:FREQ=(DAILY|WEEKLY|SECONDLY|MINUTELY|HOURLY|DAILY|WEEKLY|MONTHLY|YEARLY);)?(?:COUNT=([0-9] );)?(?:INTERVAL=([0-9] );)?(?:BYDAY=([A-Z,] );)?(?:UNTIL=([0-9] );)?

Я создаю это с помощью http://regexstorm.net/tester.

Тестовый ввод, который я использую, является:

DTSTART;TZID=America/Chicago:20140711T133000nDTEND;TZID=America/Chicago:20140711T163000nRRULE:FREQ=WEEKLY;INTERVAL=8;BYDAY=FR;UNTIL=20141101

DTSTART;TZID=America/Chicago:20140711T133000nDTEND;TZID=America/Chicago:20140711T163000nRRULE:FREQ=WEEKLY;COUNT=5;INTERVAL=8;BYDAY=FR;UNTIL=20141101

DTSTART;TZID=America/Chicago:20140711T133000nDTEND;TZID=America/Chicago:20140711T163000nRRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20141101

Примерные результаты сопоставления будут выглядеть следующим образом:

 Index    Position    Matched String                                                 $1      $2  $3  $4  $5
0        90          RRULE:FREQ=WEEKLY;INTERVAL=8;BYDAY=FR;UNTIL=20141101           WEEKLY      8   FR  20141101
1        236         RRULE:FREQ=WEEKLY;COUNT=5;INTERVAL=8;BYDAY=FR;UNTIL=20141101   WEEKLY  5   8   FR  20141101
2        390         RRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20141101                      WEEKLY          FR  20141101
  

Использование похоже:

 string freqPattern = @"RRULE:(?:FREQ=(DAILY|WEEKLY|SECONDLY|MINUTELY|HOURLY|DAILY|WEEKLY|MONTHLY|YEARLY);?)?(?:COUNT=([0-9] );?)?(?:INTERVAL=([0-9] );?)?(?:BYDAY=([A-Z,] );?)?(?:UNTIL=([0-9] );?)?";
MatchCollection mc = Regex.Matches(rule, freqPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
foreach (Match m in mc)
{
    string frequency = m.Groups[1].ToString();
    string count = m.Groups[2].ToString();
    string interval = m.Groups[3].ToString();
    string byday = m.Groups[4].ToString();
    string until = m.Groups[5].ToString();
    System.Console.WriteLine("recurrence => frequency: "{0}", count: "{1}", interval: "{2}", byday: "{3}", until: "{4}"", frequency, count, interval, byday, until);
}
  

Ответ №2:

Это отличный пример того, когда следует использовать регулярные выражения. Попробуйте это для общего синтаксического анализа:

 s*(w ):((w =w ;) (w =w )?|w )
  

Или вы можете решить использовать что-то более специфичное для схемы.

 s*(?:DTSTART:)(?'Start'w )
s*(?:DTEND:)(?'End'w )
s*(?:RRULE:)(?'Rule'(w =w ;) (w =w )?)