#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 )?)