2014-09-11 3 views
1

Я обращаюсь к стороннему API и извлекаю XML. Я также смог получить доступ к xsd для него, и я использую xsd для генерации объектов для десериализации с помощью XmlSerializer.Переопределение синтаксического анализа datetime в XmlSerializer без изменения сгенерированного кода

XML, содержащий даты, как это:

<modified>2014-08-19T06:39:13.269-0400</modified> 

Сгенерированный код выглядит следующим образом:

[System.Xml.Serialization.XmlElementAttribute(DataType="time")] 
    public System.DateTime modified { 
     get { 
      return this.modifiedField; 
     } 
     set { 
      this.modifiedField = value; 
     } 
    } 

К сожалению, это приводит к ошибкам при попытке десериализации.

я могу обойти эту проблему, выделив его с атрибутом XmlIgnore и добавления кода, как это к частичному классу:

[XmlElement("modified")] 
    public string modifiedAsString 
    { 
     get { return this.modified.ToString(); } 
     set { this.modified = System.DateTime.Parse(value); } 
    } 

Однако игнорируемых часть является изменение сгенерированных классов, и я бы чтобы сотня этих изменений учитывались для всех дат.

Я попробовал объект MetadataType, чтобы применить к нему атрибут снаружи, но, к сожалению, XmlSerializer не выбирает это.

Есть ли у кого-нибудь предложение о том, как я могу разобрать это без изменения сгенерированного кода или входного XML (который вышел из-под контроля)?

+0

Если вы хотите изменить свой 'System.DateTime' в пользовательский класс упаковки с неявными операторами в/из' System.DateTime', это возможно. Хотя я подозреваю, что это может быть даже более резким изменением, чем игнорируемое вспомогательное свойство. –

ответ

1

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

Вы можете создать нестандартный тип, который будет обертывать базовый DateTime и выполнить необходимый для/от разбора.Кроме того, вы можете воспользоваться XmlTextAttribute для управления выводом, чтобы соответствовать <modified>2014-08-19T06:39:13.269-0400</modified> схеме:

public struct CustomDateTime 
{ 
    private DateTime UnderlyingDateTime; 

    [XmlText] 
    public string CustomFormat 
    { 
     get { return UnderlyingDateTime.ToString(); } 
     set { UnderlyingDateTime = System.DateTime.Parse(value); } 
    } 

    public static implicit operator DateTime(CustomDateTime custom) 
    { 
     return custom.UnderlyingDateTime; 
    } 

    public static implicit operator CustomDateTime(DateTime datetime) 
    { 
     return new CustomDateTime { UnderlyingDateTime = datetime }; 
    } 
} 

А вот класс, который содержит свойство Modified (вы не упоминаете имя, так что я просто называют его Foo):

public class Foo 
{ 
    public CustomDateTime Modified { get; set; } 
} 

неявные операторы позволяют читать/писать DateTime значения непосредственно в большинстве случаев:

Foo f = new Foo(); 
f.Modified = DateTime.Parse("2014-08-19T06:39:13.269-0400"); 

Он поддерживает ваш стандарт вспышки XmlSerializer сериализации:

XmlSerializer serializer = new XmlSerializer(typeof(Foo)); 
var textwriter = new StringWriter(); 
serializer.Serialize(textwriter, f); 

string xml = textwriter.ToString(); 

Console.WriteLine(xml); 

Полученный XML (я раздел некоторые из оберточного мусора, который, как правило, находиться в корневом узле):

<Foo> 
    <Modified>2014-08-19 6:39:13 AM</Modified> 
</Foo> 

десериализация что выше XML:

Foo deserialized = (Foo)serializer.Deserialize(new StringReader(xml)); 

DateTime datetime = deserialized.Modified; 

Console.WriteLine(datetime); 

Результаты с DateTime выхода: 2014-08-19 6:39:13 AM

Теперь это не соответствует XML-контенту точно, то есть показывает «2014-08-19 6:39:13 AM» вместо «2014-08-19T06: 39: 13.269-0400 », но только потому, что я следую verbatim вашего использования DateTime.ToString() и DateTime.Parse для get/set собственности, как у вас есть.

Однако, он будет читать в содержание XML просто отлично, то есть, если ваш входящий XML является:

<Foo> 
    <Modified>2014-08-19T06:39:13.269-0400</Modified> 
</Foo> 

Он по-прежнему читает его таким же образом (по сути это будет вызывать System.DateTime.Parse("2014-08-19T06:39:13.269-0400")).

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

public class Foo 
{ 
    public DateTime Modified { get; set; } 
} 

Для этого:

public class Foo 
{ 
    public CustomDateTime Modified { get; set; } 
} 

Я не уверен если поведение атрибута [System.Xml.Serialization.XmlElementAttribute(DataType="time")] эмулируется правильно в этом использовании, но если это не так, вы легко должны иметь гибкость для реализации независимо от того, что разобрался в CustomDateTime.CustomFormat свойство getter и setter.

Смежные вопросы