Xml Serialization - Disable Rendering Root Element of Array

XML Serialization - Disable rendering root element of array

To disable rendering of root element of collection, you must replace the attribute [XmlArrayItem] with [XmlElement] in your code.

For removing the xsi and xsd namespaces, create an XmlSerializerNamespaces instance with an empty namespace and pass it when you need to serialize your object.

Take a look on this example:

[XmlRoot("SHOPITEM")]
public class ShopItem
{
[XmlElement("PRODUCTNAME")]
public string ProductName { get; set; }

[XmlElement("VARIANT")] // was [XmlArrayItem]
public List<ShopItem> Variants { get; set; }
}

// ...

ShopItem item = new ShopItem()
{
ProductName = "test",
Variants = new List<ShopItem>()
{
new ShopItem{ ProductName = "hi 1" },
new ShopItem{ ProductName = "hi 2" }
}
};

// This will remove the xsi/xsd namespaces from serialization
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");

XmlSerializer ser = new XmlSerializer(typeof(ShopItem));
ser.Serialize(Console.Out, item, ns); // Inform the XmlSerializerNamespaces here

I got this output:

<?xml version="1.0" encoding="ibm850"?>
<SHOPITEM>
<PRODUCTNAME>test</PRODUCTNAME>
<VARIANT>
<PRODUCTNAME>hi 1</PRODUCTNAME>
</VARIANT>
<VARIANT>
<PRODUCTNAME>hi 2</PRODUCTNAME>
</VARIANT>
</SHOPITEM>

How to NOT have a wrapper element for list elements after XML serialization

Just define your Loans as a XmlElement:

public class Payment
{
public decimal Amount { get; set; }
[XmlElement("Loan")]
public List<Loan> Loans { get; set; }
}
public class Loan
{
public decimal Debt { get; set; }
public string Lender { get; set; }
}

Replace ArrayOf* Root Element using API Controller in Visual Studio C#

Apologies for the delay in response... The data I was using was from a ADO.NET connection to my SQL Server DB. My attempts at trying to serialize an Array was never going to work so I ended up creating a "ParsedDeptData" Class to serialize and redefine the elements for delivery.

My parsed data class ended up looking like this:





using DeptDataAccess;

using System.Xml.Serialization;


namespace TempNamespace.DepartmentPClass

{

[XmlType("DocumentElement")]


public class Items : List<Item>

{

public Items()

{


using (DeptDBEntities entities = new DeptDBEntities())

{

foreach (Department entity in entities.Departments)

{

Item item = new Item(entity);

this.Add(item);

}

}

}

}


public class Item

{

public int ID { get; set; }

public string Text_1 { get; set; }

public string Text_2 { get; set; }

public string Company { get; set; }


public Item()

{

this.ID = 0;

this.Text_1 = string.Empty;

this.Text_2 = string.Empty;

this.Company = string.Empty;

}


public Item(int id, string text_1, string text_2, string company)

{

this.ID = id;

this.Text_1 = text_1;

this.Text_2 = text_2;

this.Company = company;

}


public Item(Department entity)

{

this.ID = entity.ID;

this.Text_1 = entity.Text_1;

this.Text_2 = entity.Text_2;

this.Company = entity.Company;

}

}

}

Using XMLSerializer deserialise with array of elements the same type as the root element

See this question and answer.


[XmlRootAttribute("playlist")]
public class PlaylistResponse
{
public int id;
public string title;
public string description;

[XmlArray(ElementName="childPlaylists")]
[XmlArrayItem(typeof(PlaylistResponse), ElementName="playlist")]
public PlaylistResponse[] ChildPlaylists;
}

XmlReader reader = XmlReader.Create(new StringReader(xml)); // your xml above
XmlSerializer serializer = new XmlSerializer(typeof(PlaylistResponse));
PlaylistResponse response = (PlaylistResponse)serializer.Deserialize(reader);

int count = response.ChildPlaylists.Length; // 4

C# xml serialization remove jagged array element name

It appears that what you’re trying to accomplish isn’t supported natively; there’s no way of applying an XmlElement attribute to a jagged array. See XmlSerializer bug when serializing collection of collections without root element?

However, what you can do is decompose your Field[][] jagged array into a simple array of a new type – let’s name it Batch – which would in turn contain an array of your Field type. The following code generates the XML you’re after:

public class MainRequest
{
[XmlElementAttribute("Parameters")]
public Request Parameters { get; set; }
}

public class Request
{
[XmlElementAttribute(IsNullable = true)]
public RequestSize RequestSize { get; set; }

[XmlElement("BatchEntry")]
public Batch[] Batches { get; set; }
}

public class RequestSize
{
[XmlAttributeAttribute]
public string Count { get; set; }

[XmlTextAttribute]
public string Value { get; set; }
}

public class Batch
{
[XmlElementAttribute("ParameterEntry")]
public Field[] Fields { get; set; }
}

public class Field
{
[XmlAttributeAttribute(AttributeName = "name")]
public string Name { get; set; }

[XmlTextAttribute]
public string Value { get; set; }
}

public static void Main(string[] args)
{
var request = new MainRequest
{
Parameters = new Request
{
RequestSize = new RequestSize
{
Count = "1",
Value = "2",
},
Batches = new Batch[]
{
new Batch
{
Fields = new Field[]
{
new Field { Name = "AAA", Value = "111"},
new Field { Name = "BBB", Value = "222"},
new Field { Name = "CCC", Value = "333"},
}
}
}
}
};

using (var stream = new MemoryStream())
using (var reader = new StreamReader(stream))
{
XmlSerializer serializer = new XmlSerializer(typeof(MainRequest));
serializer.Serialize(stream, request);

stream.Seek(0, SeekOrigin.Begin);
var str = reader.ReadToEnd();
}
}

Generated XML:

<?xml version="1.0"?>
<MainRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Parameters>
<RequestSize Count="1">2</RequestSize>
<BatchEntry>
<ParameterEntry name="AAA">111</ParameterEntry>
<ParameterEntry name="BBB">222</ParameterEntry>
<ParameterEntry name="CCC">333</ParameterEntry>
</BatchEntry>
</Parameters>
</MainRequest>

The advantage of this approach is that it would still work if you define multiple batches. For example:

    var request = new MainRequest
{
Parameters = new Request
{
RequestSize = new RequestSize
{
Count = "2",
Value = "5",
},
Batches = new Batch[]
{
new Batch
{
Fields = new Field[]
{
new Field { Name = "AAA", Value = "111"},
new Field { Name = "BBB", Value = "222"},
new Field { Name = "CCC", Value = "333"},
}
},
new Batch
{
Fields = new Field[]
{
new Field { Name = "DDD", Value = "444"},
new Field { Name = "EEE", Value = "555"},
}
}
}
}
};

…would generate:

<?xml version="1.0"?>
<MainRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Parameters>
<RequestSize Count="2">5</RequestSize>
<BatchEntry>
<ParameterEntry name="AAA">111</ParameterEntry>
<ParameterEntry name="BBB">222</ParameterEntry>
<ParameterEntry name="CCC">333</ParameterEntry>
</BatchEntry>
<BatchEntry>
<ParameterEntry name="DDD">444</ParameterEntry>
<ParameterEntry name="EEE">555</ParameterEntry>
</BatchEntry>
</Parameters>
</MainRequest>

C# XML Serialization removing wrapper element

Before the actual explanation, let me point out a couple of very important things:

  • This XML is not very well designed and will cause a lot of other problems along the line (I'm guessing it is actually a lot more complicated than this).
  • The naming convention is inconsistent (e-Invoice and TradeInvoce)
  • The version number looks out of place, make sure this is really what they (whoever told you to do this) want before investing additional time.
  • This XML defines no namespaces (and probably doesn't have an XSD or DTD either)
  • Take a look at Google's XML design guidelines. You'll realize there is a lot of room for improvement.

There are a lot of different ways to do this, this is just one of them. I recommend you instead take it up with whoever is responsible for this design and try to change their mind.

Since you want to serialize e-Invoice and TradeInvoce without a wrapper element but still keep the order of elements (because they belong together) you need to make sure they have a common base class so they can be serialized from the same collection.

This abstract Invoice class simply tells the serializer which classes should be included during serialization via the XmlInclude attribute.

[XmlInclude(typeof(EInvoice))]
[XmlInclude(typeof(TradeInvoice))]
public abstract class Invoice
{
}

Your actual classes will be mostly unchanged

[XmlRoot("e-Invoice")]
public class EInvoice : Invoice
{
[XmlElement("Version")]
public string Version { get; set; }
}

[XmlRoot("TradeInvoice")]
public class TradeInvoice : Invoice
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Value")]
public int Value { get; set; }
}

Your data class doesn't need any XML-related Attributes anymore because as it is now, it can't be serialized into that format directly.

public class InvoicePair
{
public InvoicePair(EInvoice eInvoice, TradeInvoice tradeInvoice)
{
TradeInvoice = tradeInvoice;
EInvoiceInfo = eInvoice;
}

public EInvoice EInvoiceInfo { get; set; }

public TradeInvoice TradeInvoice { get; set; }
}

Your Root class has to be simplified a bit. Since we want EInvoce and TradeInvoice Elements on the same level but mixed together, we need to put them in the same collection. The XmlElement attributes will tell the serializer how to handle elements of different types without relying on the xsi:type attribute.

[XmlRoot("RootXML")]
public class Root
{
public Root()
{
RootBodies = new List<Invoice>();
}

[XmlElement(Type = typeof(EInvoice), ElementName = "e-Invoice")]
[XmlElement(Type = typeof(TradeInvoice), ElementName = "TradeInvoice")]
public List<Invoice> RootBodies { get; set; }
}

Serialization is quite straight-forward at this point. Simply add all elements to the collection of elements one after another:

public static void Serialize(IEnumerable<InvoicePair> invoices, Stream stream)
{
Root root = new Root();
foreach (var invoice in invoices)
{
root.RootBodies.Add(invoice.EInvoiceInfo);
root.RootBodies.Add(invoice.TradeInvoice);
}

XmlSerializer serializer = new XmlSerializer(typeof(Root));
serializer.Serialize(stream, root);
}

Deserialization isn't very hard either, but very prone to erros and makes a lot of assumptions:

public static IEnumerable<InvoicePair> Deserialize(Stream stream)
{
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = serializer.Deserialize(stream) as Root;

for (int i = 0; i < root.RootBodies.Count; i += 2)
{
yield return new InvoicePair(
(EInvoice) root.RootBodies[i],
(TradeInvoice) root.RootBodies[i+1]
);
}
}

Here is a working Demo Fiddle, that outputs the XML

How do I get XmlSerializer to not serialize list container tags?

Specify an element name in your [XmlElement] attribute:

[XmlElement("MyDatum", Type = typeof(MyDatum))]
public List<MyDatum> Items {
// ...
}

According to this article on MSDN, this will remove the wrapper element around serialized items.



Related Topics



Leave a reply



Submit