【问题标题】:How to serialize byte array to XML using XmlSerializer in C#?如何在 C# 中使用 XmlSerializer 将字节数组序列化为 XML?
【发布时间】:2011-07-19 16:09:50
【问题描述】:

假设我们有一个结构,它的数据由使用 Marshal.PtrToStructure 的非托管字节数组提供。

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

字节数组表示非托管代码中的(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)结果。

我们可以在这里使用一个属性吗? 我错过了什么?

感谢您的时间和帮助。

宜兰

对于reference

【问题讨论】:

  • 反序列化时,OliNumber中的数据和序列化前的数据有区别吗? XML中的值可能很好,可能只是XMLSerializer用于字节数组的格式。
  • @Kipotlov 感谢您的评论。反序列化工作正常,但重点是在 XML 中表示来自非托管代码的数据,其中字节数组表示(ascii)字符串。
  • 序列化程序将byte[] 视为二进制数据而不是字符串,因此它使用传输编码(base64)来允许任意二进制数据通过XML。请阅读规范,XML 不允许内容中包含大多数非打印字符。如果您要发送字符串,请将其命名为String
  • 我知道这是旧的,但我相信如果你改变你的编码... 到 utf-16,它可能会工作.您没有讨论基本字符集,因此您可能会在 XML 转换器中遇到问题。我在处理来自其他语言集的翻译时遇到了这个问题。 utf-16 拾取双字节字符,而 utf-8 没有。

标签: c# xml serialization unmanaged


【解决方案1】:

XmlSerializer 默认情况下将使用 base 64 编码对字节数组进行编码。如果您使用this 站点并粘贴IzE=,并对其进行解码,则结果将为#1。您可以通过设置XmlElementAttribute.DataType 来更改编码。我不确定[XmlElement(DataType = "string")] 是否有效,但您可以尝试一下。使用[XmlElement(DataType = "hexBinary")] 将生成原始字节。

【讨论】:

  • 谢谢,在创建自定义的“XmlSerializer”时尝试您的建议出现异常:“'string' 是 XmlElementAttribute.DataType 属性的无效值。字符串无法转换为 System.Byte[]” .至于另一个选项“HexBinary”的结果是:'2331'
  • @IIan - 是的,这就是我所期望的。我想如果你想要一个字符串值输出,你将不得不实现 IXmlSerializable 并自己做。
【解决方案2】:

我就是这样做的:

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

【讨论】:

    【解决方案3】:

    我使用以下方法让它工作:

      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”版本。

    【讨论】:

      猜你喜欢
      • 2020-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-16
      • 1970-01-01
      相关资源
      最近更新 更多