Reputation: 31743
I am using c# and the XmlSerialiser class to create xml from DTO Objects.
Now I have to generate such xml text:
<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>
I use Attributes to decorate my classes and everything works fine.
One thing I couldn't solve yet. I need to generate a tag Positions
with different tag TextPosition, ItemPosition, ValuePosition, ...
inside.
How do I achive this in c#?
Currently my class Order contains a
[XmlElement("Positions")]
public PositionList Positions { get; set; }
PositionList is a class with
public class PositionList
{
[XmlElement("Positions")]
public List<Object> Positions { get; set; }
}
In order to avoid a InvalidOperationException I added
[XmlInclude(typeof(Textposition))]
[XmlInclude(typeof(ItemPosition))]
[XmlInclude(typeof(SumPosition))]
to my Order class.
However, instead of generating
<Positions>
<TextPosition>...</TextPosition>
</Positions>
the serializer generates:
<Position d4p1:type="TextPosition" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">...</Position>
The thing is, In don't need to deserialize it my self but provide a XML-file in a very strict format for one customer. Is there a way to achive this?
Upvotes: 1
Views: 1832
Reputation: 273784
When you need XML in a a very strict format, using a serializer might not be the best option. With a serializer you give up control for convenience, and right now you are fighting to get that control back.
Consider using Linq to XML, the XDocument class.
var doc =
new XElement("Order",
new XElement ("OrderNo", 123456),
new XElement ("Positions",
myPositions.Select(p => new XElement("Position", .... ) ) );
Upvotes: 1
Reputation: 50028
There is a way:
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; }
}
Example serializing it to an XML file:
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());
}
}
Result:
<?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>
Upvotes: 2