Десериализовать Xml с пустыми элементами в C # - PullRequest
19 голосов
/ 03 июня 2010

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

Xml Snippit:


1

C # Класс:

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

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

Ответы [ 4 ]

13 голосов
/ 03 июня 2010

Наиболее унифицированным способом очистки этих узлов является добавление фильтра 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 "";}
9 голосов
/ 31 октября 2013

Другой вариант, если у вас нет контроля над входящим 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; }
  }
}

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

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

9 голосов
/ 03 июня 2010

См. Эту статью: Может ли 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

0 голосов
/ 03 июня 2010

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

XmlNode node = xml.SelectSingleNode ("foo/PropOne");
if (node != null)
{
     propOneValue = node.innerText;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...