Deserialize Xml с пустыми элементами в С#

Попытка десериализации некоторых фрагментов xml от поставщика в объекты. Проблема в том, что я получаю недопустимый формат для каждого тега элемента empy. Я могу десериализовать объект без проблем, когда все элементы имеют значения. Или пустые элементы опущены.

Xml Snippit:

<foo>
<propOne> 1 </propOne>
< propTwo/ >
</foo>

Класс С#:

[Serialilbe()]     
public class foo
{ 
   public foo(){}
   [XmlElementAttribute(IsNullable = true)]
   public int? propOne {get;set;} 
   [XmlElementAttribute(IsNullable = true)]
   public int? propTwo {get;set;}   
 }

Есть ли параметр в классе, который я могу сделать для настройки разбора?
или
Есть ли простой способ применить xsl для удаления этих элементов?
или
Должен ли я использовать regEx для удаления пустых элементов перед десриализацией?
или
еще лучший способ?

Ответы

Ответ 1

Наиболее единообразным способом очистки этих узлов является добавление фильтра RegEx к десериализатору.

    public static T Deserialize<T>(string xml){
        XmlSerializer xs = new XmlSerializer(typeof(T));
        string cleanXml = Regex.Replace(xml, @"<[a-zA-Z].[^(><.)]+/>",
                                        new MatchEvaluator(RemoveText));
        MemoryStream memoryStream = new MemoryStream((new UTF8Encoding()).GetBytes(cleanXml));
        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
        return (T)xs.Deserialize(memoryStream);
    }
  static string RemoveText(Match m) { return "";}

Ответ 2

См. статью: Может ли XmlSerializer десериализоваться в Nullable?

В двух словах ваш Xml должен выглядеть так, если вы хотите использовать типы Nullable:

<foo xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
<propOne>1</propOne>
<propTwo xsi:nil='true'/>
</foo>

Два изменения добавляют пространство имен и явно устанавливают xsi: nil в true для нулевого элемента.

Если у вас нет контроля над вашим Xml, существует более сложная методика, описанная здесь: Использование XmlSerializer для десериализации в Nullable

Ответ 3

Другой вариант, если вы не контролируете входящий XML, заключается в том, чтобы обойти это, если десериализатор делает вид, что переменная является строкой:

[Serializable()]     
public class foo
{ 
  public foo(){}

  [XmlElement("propOne")]
  [EditorBrowsable(EditorBrowsableState.Never)]
  public string propOneString {get;set;}

  [XmlIgnore]
  private int? propOneInternal = null;
  [XmlIgnore]
  private bool propOneSet = false;

  [XmlIgnore]
  public int? propOne
  {
    get
    {
      if (!propOneSet)
      {
        if(!string.IsNullOrEmpty(propOneString)
        {
          propOneInternal = int.Parse(propOneString);
        }
        //else leave as pre-set default: null
        propOneSet = true;
      }
      return propOneInternal;
    }
    set { propOneInternal = value; }
  }
}

Deserialiser с удовольствием разбирает строковый элемент, когда он пуст, поэтому вы его используете.

Это не особенно приятно, но это будет сделано, если у вас есть только один или два тега для покрытия

Ответ 4

реализовать IXmlSerializable для Foo, все остальное будет хакерским.

Ответ 5

Для простоты, почему бы вам не разобрать xml явно с помощью XmlDocument и XPath? Используйте XPath для явного доступа к каждому xml node, например.

XmlNode node = xml.SelectSingleNode ("foo/PropOne");
if (node != null)
{
     propOneValue = node.innerText;
}