Сериализация узла с различными дочерними узлами от объектов DTO - PullRequest
1 голос
/ 15 марта 2012

Я использую c # и класс XmlSerialiser для создания xml из объектов 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))]

к моему классу заказа.

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

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

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

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

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

Ответы [ 2 ]

2 голосов
/ 15 марта 2012

Есть способ:

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 голос
/ 15 марта 2012

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

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

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