2012-03-15 1 views
1

Я использую C# и класс XmlSerialiser для создания xml из объектов DTO.Сериализовать узел с различными дочерними узлами из объектов DTO

Теперь я должен создать такой XML-текст:

<Order> 
    <OrderNo>123456</OrderNo> 
    <Positions> 
     <TextPosition> 
      <Text>This is Order No 123456</Text> 
     </TextPosition> 
     <ItemPosition> 
      <ItemId>14789</ItemId> 
      <ItemName>Product 1</ItemName> 
     </ItemPosition> 
     </TextPosition> 
     <ItemPosition> 
      <ItemId>456</ItemId> 
      <ItemName>Product 2</ItemName> 
     </ItemPosition> 
     <TextPosition> 
      <Text>Good bye</Text> 
     </TextPosition> 
     <SumPosition> 
      <Value>123.45 USD</Value> 
     </SumPosition> 
    </Positions> 
</Order> 

я использую атрибуты для украшения своих классов и все работает отлично. Одна вещь, которую я еще не мог решить. Мне нужно сгенерировать тег Positions с другим тегом TextPosition, ItemPosition, ValuePosition, ... внутри.

Как добиться этого в C#?

В настоящее время мой класс Order содержит

[XmlElement("Positions")] 
public PositionList Positions { get; set; } 

PositionList класс с

public class PositionList 
{ 
    [XmlElement("Positions")] 
    public List<Object> Positions { get; set; } 
} 

Для того, чтобы избежать InvalidOperationException я добавил

[XmlInclude(typeof(Textposition))] 
[XmlInclude(typeof(ItemPosition))] 
[XmlInclude(typeof(SumPosition))] 

мой класс Order.

Однако, вместо генерации

<Positions> 
    <TextPosition>...</TextPosition> 
</Positions> 

сериализатор генерирует:

<Position d4p1:type="TextPosition" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">...</Position> 

Дело в том, В не нужно десериализации это мой сам, но предоставить XML-файл в очень строгий формат для одного клиента. Есть ли способ достичь этого?

ответ

2

Существует способ:

public class Order 
{ 
    public List<BasePosition> Positions { get; set; } 
    public Order() { Positions = new List<BasePosition>(); } 
} 

public class BasePosition 
{ 

} 

public class TextPosition : BasePosition 
{ 
    public string Text { get; set; } 
} 

public class ItemPosition : BasePosition 
{ 
    public int ItemId { get; set; } 
    public string ItemName { get; set; } 
} 

public class SumPosition : BasePosition 
{ 
    public string Value { get; set; } 
} 

Пример сериализации в файл XML:

Order o = new Order(); 
o.Positions.Add(new TextPosition() { Text = "This is Order No 123456" }); 
o.Positions.Add(new ItemPosition() { ItemId = 14789, ItemName = "Product 1" }); 
o.Positions.Add(new TextPosition()); 
o.Positions.Add(new ItemPosition() { ItemId = 456, ItemName = "Product 2" }); 
o.Positions.Add(new SumPosition() { Value = "123.45 USB" }); 
XmlAttributeOverrides specific_attributes = new XmlAttributeOverrides(); 
XmlAttributes attrs = new XmlAttributes(); 
attrs.XmlElements.Add(new XmlElementAttribute(typeof(TextPosition))); 
attrs.XmlElements.Add(new XmlElementAttribute(typeof(ItemPosition))); 
attrs.XmlElements.Add(new XmlElementAttribute(typeof(SumPosition))); 
specific_attributes.Add(typeof(Order), "Positions", attrs); 
XmlSerializer ser = new XmlSerializer(typeof(Order), specific_attributes); 

using(MemoryStream mem_stream = new MemoryStream()) 
{ 
    ser.Serialize(mem_stream, o); 
    using (BinaryWriter bw = new BinaryWriter(new FileStream("orders.xml", FileMode.Create))) 
    { 
     bw.Write(mem_stream.ToArray()); 
    } 
} 

Результат:

<?xml version="1.0"?> 
<Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <TextPosition> 
    <Text>This is Order No 123456</Text> 
    </TextPosition> 
    <ItemPosition> 
    <ItemId>14789</ItemId> 
    <ItemName>Product 1</ItemName> 
    </ItemPosition> 
    <TextPosition /> 
    <ItemPosition> 
    <ItemId>456</ItemId> 
    <ItemName>Product 2</ItemName> 
    </ItemPosition> 
    <SumPosition> 
    <Value>123.45 USB</Value> 
    </SumPosition> 
</Order> 
+1

Удивительный! Я добавил вспомогательный класс PositionList с одним свойством 'public List Positions {get; set;}', чтобы получить дополнительный тег '' между порядком и позициями, но да, это сделало трюк.Большое спасибо. –

+0

Без проблем, рад, что я мог бы помочь, извините, я пропустил лишний тег :) – SwDevMan81

1

Когда вам нужен XML в очень строгом формате, использование сериализатора может быть не лучшим вариантом. С помощью сериализатора вы отказываетесь от контроля для удобства, и прямо сейчас вы боретесь за получение этого контроля.

Рассмотрите возможность использования Linq для XML, класса XDocument.

var doc = 
    new XElement("Order", 
     new XElement ("OrderNo", 123456), 
     new XElement ("Positions", 
     myPositions.Select(p => new XElement("Position", ....))); 
+0

«Вы отказываетесь управления для удобства, и прямо сейчас вы боретесь за то, чтобы вернуть этот контроль ». Это очень хорошо сказано. –

+0

'Вы отказываетесь от контроля для удобства, и прямо сейчас вы боретесь за то, чтобы вернуть этот контроль' Я не согласен с этим. AOP-подход с атрибутами и XmlSerializer очень эффективен и с помощью 'XmlAttributeOverrides' я могу создать нужный мне результат. Поскольку классы DTO живут в другой dll, чем сериализатор, я могу применять обновления в будущем без изменения самой логики. В любом случае +1 для подхода XDocument выглядит многообещающим (возможно, я буду использовать его для другой задачи в будущем). –

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