如何在C#中使用XmlSerializer将字节数组序列化为XML?
假设我们有一个结构,它的数据是由使用Marshal.PtrToStructure的非托管字节数组提供的 C#struct布局:如何在C#中使用XmlSerializer将字节数组序列化为XML?,c#,xml,serialization,unmanaged,C#,Xml,Serialization,Unmanaged,假设我们有一个结构,它的数据是由使用Marshal.PtrToStructure的非托管字节数组提供的 C#struct布局: [StructLayout(LayoutKind.Sequential, Size = 128, CharSet = CharSet.Ansi, Pack = 1)] public struct MNG_Y_Params { public byte Number; public byte Version; [MarshalAs(Unmanaged
[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 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>
1.
圣卢西亚1号
35
1.
#1
15
结果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>
1.
圣卢西亚1号
35
1.
化=
15
请关注字节数组成员(OliNumber)结果
这里有一个我们可以使用的属性吗?
我错过了什么
谢谢你的时间和帮助
宜兰
对于,默认情况下
XmlSerializer
将使用base 64编码对字节数组进行编码。如果使用站点并粘贴到IzE=
,然后对其进行解码,结果将是#1
。您可以通过设置来更改编码。我不确定[xmlement(DataType=“string”)]
是否有效,但您可以试试。使用[xmlement(DataType=“hexBinary”)]
将生成原始字节。我使用以下方法实现了这一点:
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”版本。我就是这样做的:
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反序列化时,OliNumber中的数据是否与序列化之前不同?XML中的值可能很好,可能只是XMLSerializer用于字节数组的格式。@Kipotlov感谢您的评论。反序列化工作正常,但关键是在XML中表示来自非托管代码的数据,其中字节数组表示(ascii)字符串。序列化程序将
byte[]
视为二进制数据而不是字符串,因此它使用传输编码(base64)允许任意二进制数据通过XML。请阅读规范,XML不允许在内容中使用大多数非打印字符。如果您发送的是字符串,请将其称为string
。我知道这很旧,但我相信如果您更改编码。。。对于utf-16,它可能会起作用。您没有讨论基本字符集,因此可能在XML转换器中遇到了一个问题。我在处理其他语言集的翻译时遇到了这个问题。utf-16拾取了utf-8未拾取的双字节字符。谢谢,尝试了您的建议。在创建自定义的“XmlSerializer”时出现异常:““string”是XmlElementAttribute.DataType属性的无效值。string无法转换为System.byte[]”。至于另一个选项“HexBinary”的结果是:'2331'@IIan-是的,这正是我所期望的。我认为,如果想要字符串值输出,就必须实现IXmlSerializable并自己完成。
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;
}
}