2011-03-21 21 views
12

Digamos que tenemos una estructura que se trata de datos es proporcionada por el conjunto de bytes no-administrado con Marshal.PtrToStructure.¿Cómo serializar la matriz de bytes a XML usando XmlSerializer en C#?

El diseño # struct C:

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

La matriz de bytes representan una cadena (ASCII) en el código-un administrado.

Esta estructura es un miembro de otra estructura (que tiene algunos otros miembros):

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

Así que también tenemos el código de apoyo

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

y el método Save

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

Por ejemplo, solo generaríamos algunos datos.

 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 esperado:

<?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> 

Resultado 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> 

Por favor, se centran en el (OliNumber) Resultado miembro de la matriz de bytes.

¿Hay un atributo que podríamos utilizar aquí? ¿Qué me estoy perdiendo?

Gracias por su tiempo y ayuda.

Ilan

Para reference

+0

Al deserializar, es usted datos en OliNumber diferente de antes de la serialización? El valor en el XML puede ser bueno, tal vez solo sea el formato que XMLSerializer usa para la matriz de bytes. – Kipotlov

+0

@Kipotlov Gracias por tu comentario. La deserialización funciona bien, sin embargo, el objetivo es representar en el XML los datos del código no administrado, donde el conjunto de bytes representa una cadena (ascii). –

+0

El serializador trata 'byte []' como datos binarios, no como una cadena, por lo que utiliza la codificación de transferencia (base64) para permitir que los datos binarios arbitrarios pasen a través de XML. Lea la especificación, XML no permite la mayoría de los caracteres que no se imprimen en el contenido. Si está enviando una cadena, llámelo 'String'. –

Respuesta

7

El XmlSerializer por defecto codificará las matrices de bytes usando la base 64 de codificación. Si utiliza this sitio y pegar en IzE= y decodificarlo, el resultado será #1. Puede cambiar la codificación configurando XmlElementAttribute.DataType. No estoy seguro si funcionará [XmlElement(DataType = "string")], pero puede intentarlo. El uso de [XmlElement(DataType = "hexBinary")] generará los bytes sin procesar.

+0

Gracias, probé su sugerencia, obtuve una excepción al crear el 'XmlSerializer' personalizado: "'cadena' es un valor no válido para la propiedad XmlElementAttribute.DataType. La cadena no se puede convertir a System.Byte []". En cuanto a la otra opción, el resultado "HexBinary" fue: '' –

+0

@IIan - Sí, eso es lo que esperaba. Creo que si quieres un resultado de valor de cadena, tendrás que implementar IXmlSerializable y hacerlo tú mismo. – SwDevMan81

+0

funciona para mí. Gracias – Antonio

0

que tiene esto funcione utilizando la siguiente:

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

que sería entonces sólo acceder a la "AsString" versión de la propiedad.

0

Esto es cómo lo hice:

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

Los bytes son entonces formateados como valores hexadecimales y se separan con un signo menos: 00-AF-B1

Cuestiones relacionadas