2015-10-15 3 views
2

У меня есть XML Serializable класс со свойством NameDeserialize XML элемент из InnerText и значение атрибута

[Serializable] 
public class Item 
{ 
    [XmlElement("name")] 
    public string Name { get; set; } 
} 

и я хочу, чтобы иметь возможность десериализации XML-файл, который у меня есть двумя способами:

<item> 
    <name>Name</name> 
</item> 

и

<item> 
    <name value="Name" /> 
</item> 

первые отлично работает, но то, что я должен сделать, чтобы быть в состоянии десериализации SECO nd также с тем же классом?

+0

IMO это невозможно. Вам нужно будет доработать формат входных XML-файлов. Это интересный вопрос. – niksofteng

ответ

0

Я нашел другой способ решить мою проблему, используя только один класс, может быть, кто-то найдет это полезным

[Serializable] 
public class Item 
{ 
    [XmlElement("name")] 
    public NameElement NameElement { get; set; } 
} 

public class NameElement 
{ 
    [XmlAttribute("value")] 
    public string Value { get; set; } 

    [XmlText] 
    public string Text { get; set; } 

    [XmlIgnore] 
    public string Name 
    { 
     get { return String.IsNullOrEmpty(this.Value) ? this.Text : this.Value; } 
     set { this.Value = value; } 
    } 
} 

Может быть, это не очень элегантно, но он работает в обоих случаях и использует тот же класс.

2

Атрибуты XML Serialization работают как с сериализацией, так и с десериализацией. Если мы предположим, что возможно использовать атрибуты для десериализации экземпляра Item из двух разных структур xml, то как будет выполняться сериализация - следует ли сериализовать имя экземпляра на значение элемента или атрибут? Или для обоих? Вот почему вы не можете десериализовать две разные структуры xml в один класс. Используйте два разных класса или десериализуйте их вручную без использования атрибутов XML Serialization.

+0

Правильно, я думал, что, возможно, внутренний текст элемента xml каким-то образом переведен в атрибут value. Я использую внешний api, и в зависимости от запроса я получаю элементы с другим условным обозначением элемента name:/ – Brazol

+1

Тогда, вероятно, лучшим решением для вас является создание другого класса «Item2» для другого соглашения (конечно, вы должны использовать более лучшее имя, которое описывает разница между вашими запросами). И десериализуйте ответ на «Item2», если вы отправляете запрос другого типа. Вы можете сделать так, чтобы «Item» и «Item2» реализовали один и тот же интерфейс. Таким образом, другие части вашего кода могут использовать его, не зная, какой именно тип вы передали. –

0

Поскольку вы упомянули, что данные XML поступают из внешних источников, очевидно, что у вас нет контроля над этим.

Таким образом, вы можете следовать любой опции, как показано ниже:

  1. Создать отдельный класс за структуру данных XML, потому что, насколько я знаю, нет никакого способа управлять XML десериализации при использовании XmlSerializer
  2. Вы можете используйте XDocument, чтобы прочитать XML самостоятельно, чтобы преодолеть это ограничение.

Если вы идете по второй идее, я создал небольшое консольное приложение, чтобы продемонстрировать это.

Главный кусок кода, как показано ниже:

MemoryStream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData)); 
XDocument doc = XDocument.Load(xmlStream); 

var records = from record in doc.Descendants("item").Descendants() 
       select new Item(!record.IsEmpty ? record.Value : record.Attribute("value").Value); 

Здесь я читаю элемент, используя LinqToXml и проверки, если элемент не является пустым, т.е. Value не пустым, а затем использовать Value иначе чтения значение от элемента Attribute.

Console приложение (полный код):

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Xml.Linq; 
using System.Xml.Serialization; 

namespace Console.TestApp 
{ 
    class Program 
    { 
     static string xmltypeFirst = @"<item> 
    <name>John</name> 
</item>"; 

     static string xmltypeSecond = @"<item> 
    <name value='Smith' /> 
</item>"; 

     static void Main(string[] args) 
     { 
      var data = xmltypeFirst; 
      var result = Deserialize(data).ToList(); 
      Console.WriteLine("Name: " + result[0].Name); 

      data = xmltypeSecond; 
      result = Deserialize(data).ToList(); 
      Console.WriteLine("Name: " + result[0].Name); 

      Console.WriteLine("Press any to key to exit.."); 
      Console.ReadLine(); 
     } 

     private static IEnumerable<Item> Deserialize(string xmlData) 
     { 
      MemoryStream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData)); 
      XDocument doc = XDocument.Load(xmlStream); 

      var records = from record in doc.Descendants("item").Descendants() 
          select new Item(!record.IsEmpty ? record.Value : record.Attribute("value").Value); 
      return records; 
     } 
    } 

    [Serializable] 
    public class Item 
    { 
     public Item(string name) 
     { 
      this.Name = name; 
     } 

     [XmlElement("name")] 
     public string Name { get; set; } 
    } 
} 

Примечание: Для запуска этого вам нужно будет добавить ссылку на System.Xml.Linq.dll в вашем проекте.

Ссылка: here

+0

Хорошая идея, но мой пример был только для иллюстрации проблемы, и xml намного сложнее, поэтому было бы гораздо более целесообразно десериализовать его с помощью XmlDocument, чем с помощью класса Serializable. – Brazol

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