Подтвердить что ты не робот

Как сериализовать массив байтов в XML с помощью XmlSerializer в С#?

Скажем, что у нас есть структура, которая предоставляет данные с помощью массива без управления с помощью Marshal.PtrToStructure.

Структура структуры С#:

[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;
}

Байт-массив представляет строку (ascii) в неуправляемом коде.

Эта структура является членом другой структуры (которая имеет некоторые другие элементы):

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;
};

Таким образом, у нас также есть этот код поддержки

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);
    }
}

и метод сохранения

    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);
        }
    }

В этом примере мы просто сгенерируем некоторые данные.

        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);

Ожидаемый 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>

Результат 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>

Обратите внимание на результат элемента массива байтов (OliNumber).

Есть ли атрибут, который мы могли бы использовать здесь? Что мне не хватает?

Спасибо за ваше время и помощь.

Илан

Для справки

4b9b3361

Ответ 1

XmlSerializer по умолчанию будет кодировать массивы байтов, используя базовую кодировку 64. Если вы используете этот сайт и вставляете IzE= и декодируете его, результат будет #1. Вы можете изменить кодировку, установив XmlElementAttribute.DataType. Я не уверен, что [XmlElement(DataType = "string")] будет работать, но вы можете попробовать. Использование [XmlElement(DataType = "hexBinary")] будет генерировать необработанные байты.

Ответ 2

Я получил это для работы, используя следующее:

  public class MySerializableClass
  {   
    [XmlIgnore]
    public string NaughtyXmlCharactersAsString { get; set; }

    [XmlElement(ElementName = "NaughtyXmlCharacters", DataType = "hexBinary")]
    public byte[] NaughtyXmlCharactersAsBytes
    {
        get { return Encoding.UTF8.GetBytes(NaughtyCharactersAsString ?? string.Empty); }
        set { NaughtyXmlCharactersAsString = Encoding.UTF8.GetString(value); }
    }

Тогда я бы получил доступ только к версии свойства AsString.

Ответ 3

Вот как я это сделал:

public class MySerializableClass
{
    private string dummy;

    [XmlElement("NaughtyXmlCharacters")]
    public string NaughtyXmlCharactersAsString
    {
       get 
       {
           return BitConverter.ToString(NaughtyXmlCharacters);
       }
       set
       {
           // without this, the property is not serialized.
           dummy = value;
       }
    }

    [XmlIgnore]
    public byte[] NaughtyXmlCharacters
    {
        get;
        set;
    }
}

Затем байты отформатируются как шестнадцатеричные значения и разделяются знаком минус: 00-AF-B1