Ilan Huberman Ilan Huberman - 3 months ago 14
C# Question

How to serialize byte array to XML using XmlSerializer in C#?

Say we have a struct that it's data is provided by un-managed byte array using Marshal.PtrToStructure.

The C# struct layout:

[StructLayout(LayoutKind.Sequential, Size = 128, CharSet = CharSet.Ansi, Pack = 1)]
public struct MNG_Y_Params
{
public byte Number;
public byte Version;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] OliNumber;
public byte InterfaceType;
}


The byte array represent a (ascii) string in the un-managed code.

This struct is a member of another struct (that has some other members):

public struct MyData
{
public int ID;
public StructType structType;
[XmlElement(ElementName="MNG_Y_Params")]
public MNG_Y_Params y_params;
[XmlElement(ElementName = "SimpleStruct2")]
public SimpleStruct2 ss2;
};


So we also have this support code

public class XMLIgnore
{
static public XmlSerializer customserialiser(MyData d)
{
XmlAttributes attrs = new XmlAttributes();
attrs.XmlIgnore = true;
XmlAttributeOverrides xmlOveride = new XmlAttributeOverrides();
switch (d.structType)
{
case StructType.ST_1:
xmlOveride.Add(typeof(MyData), "ss2", attrs);
break;
case StructType.ST_2:
xmlOveride.Add(typeof(MyData), "y_params", attrs);
break;
default:
break;
}
return new XmlSerializer(typeof(MyData), xmlOveride);
}
}


and the save method

static void SaveToXml(object obj, string fileName, XmlSerializer writer)
{
//XmlSerializer writer = new XmlSerializer(obj.GetType());
using (StreamWriter file = new StreamWriter(fileName))
{
writer.Serialize(file, obj);
}
}


For the example we'd just generate some data.

MNG_Y_Params yParams = new MNG_Y_Params();
yParams.Version = 1;
yParams.InterfaceType = 15;
yParams.Number = 35;
ASCIIEncoding enc = new ASCIIEncoding();
yParams.OliNumber = enc.GetBytes("#1");

MyData md1 = new MyData();
md1.ID = 1;
md1.structType = StructType.ST_1;
md1.y_params = yParams;

XmlSerializer writer = XMLIgnore.customserialiser(md1);
SaveToXml(md1, @"C:\temp\dataOne.xml", writer);


Expected XML:

<?xml version="1.0" encoding="utf-8"?>
<MyData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>1</ID>
<structType>ST_1</structType>
<MNG_Y_Params>
<Number>35</Number>
<Version>1</Version>
<OliNumber>#1</OliNumber>
<InterfaceType>15</InterfaceType>
</MNG_Y_Params>
</MyData>


Result XML:

<?xml version="1.0" encoding="utf-8"?>
<MyData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>1</ID>
<structType>ST_1</structType>
<MNG_Y_Params>
<Number>35</Number>
<Version>1</Version>
<OliNumber>IzE=</OliNumber>
<InterfaceType>15</InterfaceType>
</MNG_Y_Params>
</MyData>


Please focus on the byte array member (OliNumber) result.

Is there an attribute that we could use here?
What am I missing?

Thanks for your time and help.

Ilan

For reference

Answer

The XmlSerializer by default will encode the byte arrays using base 64 encoding. If you use this site and paste in IzE=, and decode it, the result will be #1. You can change the encoding by setting the XmlElementAttribute.DataType. I'm not sure if [XmlElement(DataType = "string")] will work, but you can try it. Using [XmlElement(DataType = "hexBinary")] will generate the raw bytes.

Comments