2016-08-25 11 views
0

Компоновка Я иду, как компоновщика ниже (это является частью более крупной структуры):C# XML сериализации исключающих писать имя класса

 <Products> 
      <R001 Retail=\"2.289\" Rank=\"1\" Code=\"001\" /> 
      <R002 Retail=\"2.289\" Rank=\"2\" Code=\"002\" /> 
      <R003 Retail=\"2.889\" Rank=\"3\" Code=\"003\" /> 
      <R004 Retail=\"0\" Rank=\"4\" Code=\"0\" /> 
      <R011 Retail=\"0\" Rank=\"7\" Code=\"0\" /> 
     </Products> 

Поэтому у меня есть класс, который имеет свойство Продукты , Это свойство представляет собой список классов, которые я вызываю ProductExport. ProductExport имеет 3 свойства, которые я отмечаю атрибутом XmlAttribute, и они называются Retail, Rank, Code. В ProductExport я реализую IXmlSerializable, поэтому я могу реализовать WriteXml(), в котором я делаю теги именами те теги R00X. Все работает отлично, но поскольку ProductExport - это собственный класс, XmlSerializer записывает тег для каждого ProductExport в списке. Я не хочу тег ProductExport. Я бы подумал, реализуя IXmlSerializable в ProductExport. Я бы контролировал все, как писал ProductExport, в том числе НЕ записывая его имя класса, но, похоже, это не так. Как ограничить запись имени класса?

public class StoresExport 
    { 
     public int ID { get; set; } 
     public int Name { get; set; } 
     public string State { get; set; } 
     public int DistrictID { get; set; } 
     public int? RegionID { get; set; } 
     public decimal Latitude { get; set; } 
     public decimal Longitude { get; set; } 
     public List<CompetitorLocation> RelatedLocations { get; set; } 
     public List<ProductExport> Products { get; set; } 
    } 



public class ProductExport : IXmlSerializable 
    { 
     public float Retail { get; set; } 
     public int Rank { get; set; } 
     public string Code { get; set; } 

     public XmlSchema GetSchema() 
     { 
      return null; 
     } 

     public void ReadXml(XmlReader reader) 
     { 
      // we aren't ever reading just writing 
     } 

     public void WriteXml(XmlWriter writer) 
     { 
      writer.WriteStartElement("R" + Code); 

      writer.WriteAttributeString("Retail", Retail.ToString()); 
      writer.WriteAttributeString("Rank", Rank.ToString()); 
      writer.WriteAttributeString("Code", Code); 

      writer.WriteEndElement(); 
     } 
    } 

С этим кодом это выход, который я не хочу:

<Products> 
      <ProductExport> 
       <R001 Retail=\"0\" Rank=\"1\" Code=\"001\" /> 
      </ProductExport> 
      <ProductExport> 
       <R002 Retail=\"0\" Rank=\"2\" Code=\"002\" /> 
      </ProductExport> 
      <ProductExport> 
       <R003 Retail=\"0\" Rank=\"3\" Code=\"003\" /> 
      </ProductExport> 
      <ProductExport> 
       <R004 Retail=\"0\" Rank=\"4\" Code=\"004\" /> 
      </ProductExport> 
      <ProductExport> 
       <R011 Retail=\"0\" Rank=\"7\" Code=\"011\" /> 
      </ProductExport> 
     </Products> 
+0

Я бы предпочел не реализовывать IXmlSerializable в классе StoreExports, так как другие атрибуты экспортируются просто отлично, и это будет больше набрав, чем нужно, чтобы подавление тега ProductExport было бы более идеальным, если это возможно. – user441521

ответ

3

Per the docs, это родительский элемент, который будет записывать начальные и конечные элементы для ProductExport:

Реализация WriteXml, которую вы предоставляете, должна записывать XML-представление объекта. Структура записывает элемент оболочки и позиционирует XML-запись после ее начала. Ваша реализация может написать ее содержимое, включая дочерние элементы. Рамка затем закрывает оберточный элемент.

Чтобы сделать это, вам нужно написать имя элемента, которое вы хотите, в пределах Products. Самый простой способ сделать это - заменить List<ProductExport> на свой собственный класс, который также реализует IXmlSerializable.

Если это сериализовано, инфраструктура уже написала элемент Product (и закроет его после), поэтому, придерживаясь контракта, все, что вам нужно написать, это начальный и конечный элементы для каждого из ваших элементов и делегировать написание их содержания их реализации IXmlSerializable:

public class Products : IXmlSerializable, IEnumerable<ProductExport> 
{ 
    private readonly List<ProductExport> _products = new List<ProductExport>(); 

    public void Add(ProductExport product) => _products.Add(product); 

    public XmlSchema GetSchema() => null;  

    public void ReadXml(XmlReader reader) 
    { 
     throw new NotSupportedException(); 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     foreach (var product in this) 
     { 
      writer.WriteStartElement("R" + product.Code); 
      product.WriteXml(writer); 
      writer.WriteEndElement(); 
     }   
    } 

    public IEnumerator<ProductExport> GetEnumerator() => _products.GetEnumerator(); 

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 
} 

См this fiddle для рабочей демонстрации.

+0

Странно, поэтому в продуктах вы вызываете реализацию ProductExports WriteXml(). Таким образом, Serializer не будет называть это самостоятельно, так как ProductExport также реализует Serializer? – user441521

+0

@ user441521 framework ничего не сделает для любых членов 'Продукты', потому что вы удалили элемент управления из фреймворка, выполнив' IXmlSerializable'. –

+0

Не поймите меня неправильно, это отлично работает, но я все еще просто смущен. Структура вызывает WriteXml(), так как я реализовал IXmlSerializable. Это называется «Продукты». Почему он не вызывает это на ProductExport? Мы явно называем это «Продукты», но я думаю, что фреймворки видят, что мы также реализуем его на ProductExport и называем его там. Поэтому я бы подумал, что WriteXml() будет дважды вызываться для ProductExport. Однажды из рамки, так как она видит, что мы реализовали ее на ProductExport и один раз от нас в Product, где мы вручную вызываем ее на каждый ProductExport. – user441521

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