简体   繁体   中英

C# Serialize List to XML with Sequence attribute autogenerated?

I have to generate (serialize to) XML from object with array of (Order) elements. Order class generated from XSD has sequence attribute:

    [System.Xml.Serialization.XmlAttributeAttribute(DataType = "token")]
    public string Sequence;

I am using .Net XMLSerializer, but it does not generate automagically for every Order element Sequence attribute.

Having:

 Order[] Orders = new Order[2] {...}

I have to get:

<Order Sequence="1">..</Order>
<Order Sequence="2">..</Order>

And for just one, single element it should render:

    <Order Sequence="1">..</Order>

Does anyone know how to make XMLSerialzier renders this attribute automagically? Or do I need to manually set Sequence for every Order element?

Cheers

AFAIK there is no way to achieve this with out-of-the-box methods. This leaves you with the following options:

IXmlSerializable

Implement IXmlSerializable on the object that contains the array of Orders. This way, you can either serialize the Orders manually or set the sequence number of the Order before serializing the object into the XmlWriter using the XmlSerializer.Serialize method:

public class OrdersContainer : IXmlSerializable
{
    public Order[] Orders;

    public void WriteXml(XmlWriter writer)
    {
        // Serialize other properties
        writer.WriteStartElement("Orders");
        var ser = new XmlSerializer(typeof(Order));
        for(var i = 0; i < Orders.Length; i++)
        {
            Orders[i].Sequence = (i + 1).ToString();
            ser.Serialize(writer, Orders[i]);
        }
        writer.WriteEndElement(); // Orders
    }

    // ...
}

This generated the following XML:

<?xml version="1.0" encoding="utf-16"?>
<OrdersContainer>
  <Orders>
    <Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Sequence="1">
      <Name>Order 1</Name>
    </Order>
    <Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Sequence="2">
      <Name>Order 2</Name>
    </Order>
  </Orders>
</OrdersContainer>

The XmlSerializer places some namespace declarations on the Order elements, but that doesn't hurt. My sample class had a Name property on the Order class.

The downside of this approach is that you have to implement the serialization of the OrdersContainer class manually, including the deserialization.

Linq to XML

The second option is to use Linq to XML for the serialization part. You'd also have to implement the serialization manually, but you could use the otb XmlSerializer for deserialization (on the other hand you might want to avoid to mix two different frameworks). You could serialize the OrdersContainer class as follows and also write the sequence number:

var doc = new XDocument(new XElement("OrdersContainer", 
    new XElement("Orders", 
        cont.Orders.Select((x, i) => new XElement("Order", 
            new XAttribute("Sequence", (i + 1).ToString()), 
            new XElement("Name", x.Name))))));
doc.Save(writer);

This created the following XML:

<?xml version="1.0" encoding="utf-16"?>
<OrdersContainer>
  <Orders>
    <Order Sequence="1">
      <Name>Order 1</Name>
    </Order>
    <Order Sequence="2">
      <Name>Order 2</Name>
    </Order>
  </Orders>
</OrdersContainer>

Please note that the sample uses an overload of the Select method that also receives the index of the item so that the sequence number can be created based upon the position in the array.

If order is a class of yours, you can add a property with [XmlAttributeAttribute]

class Order {
    [XmlAttribute()]
    public int Sequence { get; set; }

But you should set this Sequence property in all items of your list.

this works fine -

var o = new XmlSerializerNamespaces();
o.Add("", "");

var ser = new XmlSerializer(typeof(List<Order>), "");


using (var sw = new StringWriter())
{
     ser.Serialize(sw, new List<Order> { 
                new Order { sequence = "1", MyProperty = 1 }, 
                new Order { sequence = "2", MyProperty = 2 } },
                o);
     var t = sw.ToString();
}


AND 
[XmlAttribute(AttributeName = "sequence", DataType = "string")]
public string sequence { get; set; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM